diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 40b2c5f38d..32a20befbd 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -215,7 +215,7 @@ jobs: fail-fast: false matrix: special_features: ["", "lambdaworks-felt"] - target: [ test#1, test#2, test#3, test#4, test-no_std, test-wasm ] + target: [ test#1, test#2, test#3, test#4, test-no_std#1, test-no_std#2, test-no_std#3, test-no_std#4, test-wasm ] name: Run tests runs-on: ubuntu-22.04 steps: @@ -260,6 +260,7 @@ jobs: ;; 'test-no_std') cargo llvm-cov nextest --lcov --output-path lcov-${{ matrix.target }}-${{ matrix.special_features }}.info \ + --partition count:${PARTITION}/4 \ --workspace --no-default-features --features "${{ matrix.special_features }}" ;; 'test-wasm') diff --git a/CHANGELOG.md b/CHANGELOG.md index 827a300531..9c735c65a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,11 @@ #### Upcoming Changes -* feat: Implement a CLI to run cairo programs [#1370](https://github.com/lambdaclass/cairo-vm/pull/1370) +* feat: Use only program builtins when running cairo 1 programs [#1457](https://github.com/lambdaclass/cairo-vm/pull/1457) + +* feat: Use latest cairo-vm version in cairo1-run crate [#1455](https://github.com/lambdaclass/cairo-vm/pull/1455) + +* feat: Implement a CLI to run cairo 1 programs [#1370](https://github.com/lambdaclass/cairo-vm/pull/1370) * fix: Fix string code of `BLAKE2S_ADD_UINT256` hint [#1454](https://github.com/lambdaclass/cairo-vm/pull/1454) diff --git a/Cargo.lock b/Cargo.lock index 138916eaac..910ac58e8e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -108,23 +108,6 @@ dependencies = [ "derive_arbitrary", ] -[[package]] -name = "ark-ec" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" -dependencies = [ - "ark-ff", - "ark-poly", - "ark-serialize", - "ark-std", - "derivative", - "hashbrown 0.13.2", - "itertools 0.10.5", - "num-traits 0.2.16", - "zeroize", -] - [[package]] name = "ark-ff" version = "0.4.2" @@ -168,64 +151,17 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "ark-poly" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" -dependencies = [ - "ark-ff", - "ark-serialize", - "ark-std", - "derivative", - "hashbrown 0.13.2", -] - -[[package]] -name = "ark-secp256k1" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c02e954eaeb4ddb29613fee20840c2bbc85ca4396d53e33837e11905363c5f2" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-std", -] - -[[package]] -name = "ark-secp256r1" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3975a01b0a6e3eae0f72ec7ca8598a6620fc72fa5981f6f5cca33b7cd788f633" -dependencies = [ - "ark-ec", - "ark-ff", - "ark-std", -] - [[package]] name = "ark-serialize" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" dependencies = [ - "ark-serialize-derive", "ark-std", "digest", "num-bigint", ] -[[package]] -name = "ark-serialize-derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "ark-std" version = "0.4.0" @@ -576,43 +512,6 @@ dependencies = [ "toml", ] -[[package]] -name = "cairo-lang-runner" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d66ef01350e2e7f7e6b2b43b865da2513a42600082ee1a2975d3af3da7f0ca" -dependencies = [ - "anyhow", - "ark-ff", - "ark-secp256k1", - "ark-secp256r1", - "ark-std", - "cairo-felt 0.8.7", - "cairo-lang-casm", - "cairo-lang-compiler", - "cairo-lang-defs", - "cairo-lang-diagnostics", - "cairo-lang-filesystem", - "cairo-lang-lowering", - "cairo-lang-semantic", - "cairo-lang-sierra", - "cairo-lang-sierra-ap-change", - "cairo-lang-sierra-gas", - "cairo-lang-sierra-generator", - "cairo-lang-sierra-to-casm", - "cairo-lang-sierra-type-size", - "cairo-lang-starknet", - "cairo-lang-utils", - "cairo-vm 0.8.7", - "itertools 0.11.0", - "keccak", - "num-bigint", - "num-integer", - "num-traits 0.2.16", - "salsa", - "thiserror", -] - [[package]] name = "cairo-lang-semantic" version = "2.2.0" @@ -832,36 +731,6 @@ dependencies = [ "serde", ] -[[package]] -name = "cairo-vm" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00d9bf139b0fe845627cf09d11af43eec9575dba702033bf6b08050c776b8553" -dependencies = [ - "anyhow", - "bincode", - "bitvec", - "cairo-felt 0.8.7", - "generic-array", - "hashbrown 0.14.1", - "hex", - "keccak", - "lazy_static", - "mimalloc", - "nom", - "num-bigint", - "num-integer", - "num-prime", - "num-traits 0.2.16", - "rand", - "serde", - "serde_json", - "sha2", - "sha3", - "starknet-crypto", - "thiserror-no-std", -] - [[package]] name = "cairo-vm" version = "0.9.0" @@ -907,7 +776,7 @@ version = "0.9.0" dependencies = [ "assert_matches", "bincode", - "cairo-vm 0.9.0", + "cairo-vm", "clap", "mimalloc", "nom", @@ -921,15 +790,18 @@ version = "0.9.0" dependencies = [ "assert_matches", "bincode", + "cairo-lang-casm", "cairo-lang-compiler", - "cairo-lang-runner", "cairo-lang-sierra", + "cairo-lang-sierra-ap-change", + "cairo-lang-sierra-gas", "cairo-lang-sierra-to-casm", "cairo-lang-sierra-type-size", "cairo-lang-utils", - "cairo-vm 0.8.7", + "cairo-vm", "clap", "itertools 0.11.0", + "mimalloc", "rstest", "thiserror", ] @@ -1481,15 +1353,6 @@ dependencies = [ "ahash 0.7.6", ] -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" -dependencies = [ - "ahash 0.8.3", -] - [[package]] name = "hashbrown" version = "0.14.1" @@ -1545,7 +1408,7 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" name = "hint_accountant" version = "0.9.0" dependencies = [ - "cairo-vm 0.9.0", + "cairo-vm", "serde", "serde_json", ] @@ -3007,7 +2870,7 @@ dependencies = [ name = "wasm-demo" version = "0.9.0" dependencies = [ - "cairo-vm 0.9.0", + "cairo-vm", "console_error_panic_hook", "serde_json", "wasm-bindgen", diff --git a/Cargo.toml b/Cargo.toml index a4f16bf970..396ddd2f46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ default-members = [ "cairo-vm-cli", "felt", "vm", + "cairo1-run", ] exclude = ["ensure-no_std"] diff --git a/cairo1-run/Cargo.toml b/cairo1-run/Cargo.toml index 57f982e439..290b295387 100644 --- a/cairo1-run/Cargo.toml +++ b/cairo1-run/Cargo.toml @@ -9,18 +9,25 @@ keywords.workspace = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -# To match the cairo-vm version used by cairo-lang-runner crate -cairo-vm = {version = "0.8.2", features = ["std"]} +cairo-vm = {workspace = true, features = ["std", "cairo-1-hints"]} -cairo-lang-sierra-type-size = { version = "2.2.0", default-features = false } +cairo-lang-sierra-type-size = { version = "2.2.0", default-features = false } +cairo-lang-sierra-ap-change = { version = "2.2.0", default-features = false } +cairo-lang-sierra-gas = { version = "2.2.0", default-features = false } cairo-lang-sierra-to-casm.workspace = true cairo-lang-compiler.workspace = true cairo-lang-sierra.workspace = true -cairo-lang-runner.workspace = true cairo-lang-utils.workspace = true +cairo-lang-casm.workspace = true itertools = "0.11.0" clap = { version = "4.3.10", features = ["derive"] } thiserror = { version = "1.0.40" } bincode.workspace = true assert_matches = "1.5.0" rstest = "0.17.0" +mimalloc = { version = "0.1.37", default-features = false, optional = true } + +[features] +default = ["with_mimalloc"] +with_mimalloc = ["cairo-vm/with_mimalloc", "mimalloc"] +lambdaworks-felt = ["cairo-vm/lambdaworks-felt"] diff --git a/cairo1-run/Makefile b/cairo1-run/Makefile index cc8f985876..bb00dbebab 100644 --- a/cairo1-run/Makefile +++ b/cairo1-run/Makefile @@ -3,10 +3,10 @@ CAIRO_1_FOLDER=../cairo_programs/cairo-1-programs $(CAIRO_1_FOLDER)/%.trace: $(CAIRO_1_FOLDER)/%.cairo - cargo run --release $< --trace_file $@ + cargo run --release $< --trace_file $@ --layout all_cairo $(CAIRO_1_FOLDER)/%.memory: $(CAIRO_1_FOLDER)/%.cairo - cargo run --release $< --memory_file $@ + cargo run --release $< --memory_file $@ --layout all_cairo CAIRO_1_PROGRAMS=$(wildcard ../cairo_programs/cairo-1-programs/*.cairo) TRACES:=$(patsubst $(CAIRO_1_FOLDER)/%.cairo, $(CAIRO_1_FOLDER)/%.trace, $(CAIRO_1_PROGRAMS)) diff --git a/cairo1-run/src/main.rs b/cairo1-run/src/main.rs index 299bef2920..24632000b7 100644 --- a/cairo1-run/src/main.rs +++ b/cairo1-run/src/main.rs @@ -1,23 +1,43 @@ #![allow(unused_imports)] use bincode::enc::write::Writer; +use cairo_lang_casm::casm; +use cairo_lang_casm::casm_extend; +use cairo_lang_casm::hints::Hint; +use cairo_lang_casm::instructions::Instruction; use cairo_lang_compiler::{compile_cairo_project_at_path, CompilerConfig}; -use cairo_lang_runner::RunnerError as CairoLangRunnerError; -use cairo_lang_runner::{ - build_hints_dict, casm_run::RunFunctionContext, token_gas_cost, CairoHintProcessor, - SierraCasmRunner, StarknetState, -}; +use cairo_lang_sierra::extensions::bitwise::BitwiseType; use cairo_lang_sierra::extensions::core::{CoreLibfunc, CoreType}; +use cairo_lang_sierra::extensions::ec::EcOpType; +use cairo_lang_sierra::extensions::gas::GasBuiltinType; +use cairo_lang_sierra::extensions::pedersen::PedersenType; +use cairo_lang_sierra::extensions::poseidon::PoseidonType; +use cairo_lang_sierra::extensions::range_check::RangeCheckType; +use cairo_lang_sierra::extensions::segment_arena::SegmentArenaType; +use cairo_lang_sierra::extensions::starknet::syscalls::SystemType; +use cairo_lang_sierra::extensions::ConcreteType; +use cairo_lang_sierra::extensions::NamedType; use cairo_lang_sierra::ids::ConcreteTypeId; +use cairo_lang_sierra::program::Function; +use cairo_lang_sierra::program::Program as SierraProgram; use cairo_lang_sierra::program_registry::{ProgramRegistry, ProgramRegistryError}; use cairo_lang_sierra::{extensions::gas::CostTokenType, ProgramParser}; +use cairo_lang_sierra_ap_change::calc_ap_changes; +use cairo_lang_sierra_gas::gas_info::GasInfo; +use cairo_lang_sierra_to_casm::compiler::CairoProgram; use cairo_lang_sierra_to_casm::compiler::CompilationError; +use cairo_lang_sierra_to_casm::metadata::Metadata; +use cairo_lang_sierra_to_casm::metadata::MetadataComputationConfig; use cairo_lang_sierra_to_casm::metadata::MetadataError; use cairo_lang_sierra_to_casm::{compiler::compile, metadata::calc_metadata}; use cairo_lang_sierra_type_size::get_type_size_map; use cairo_lang_utils::ordered_hash_map::OrderedHashMap; +use cairo_lang_utils::unordered_hash_map::UnorderedHashMap; use cairo_vm::air_public_input::PublicInputError; use cairo_vm::cairo_run; use cairo_vm::cairo_run::EncodeTraceError; +use cairo_vm::hint_processor::cairo_1_hint_processor::hint_processor::Cairo1HintProcessor; +use cairo_vm::serde::deserialize_program::BuiltinName; +use cairo_vm::serde::deserialize_program::{ApTracking, FlowTrackingData, HintParams}; use cairo_vm::types::errors::program_errors::ProgramError; use cairo_vm::types::relocatable::Relocatable; use cairo_vm::vm::errors::cairo_run_errors::CairoRunError; @@ -77,8 +97,6 @@ enum Error { Cli(#[from] clap::Error), #[error("Failed to interact with the file system")] IO(#[from] std::io::Error), - #[error("The cairo program execution failed")] - CairoRunner(#[from] CairoLangRunnerError), #[error(transparent)] EncodeTrace(#[from] EncodeTraceError), #[error(transparent)] @@ -109,6 +127,8 @@ enum Error { NoTypeSizeForId(ConcreteTypeId), #[error("Concrete type id has no debug name: {0}")] TypeIdNoDebugName(ConcreteTypeId), + #[error("No info in sierra program registry for concrete type id: {0}")] + NoInfoForType(ConcreteTypeId), #[error("Failed to extract return values from VM")] FailedToExtractReturnValues, } @@ -157,28 +177,29 @@ fn run(args: impl Iterator) -> Result, Erro .map_err(|err| Error::SierraCompilation(err.to_string()))?) .clone(); - // variable needed for the SierraCasmRunner - let contracts_info = OrderedHashMap::default(); - - // We need this runner to use the `find_function` method for main(). - let casm_runner = SierraCasmRunner::new( - sierra_program.clone(), - Some(Default::default()), - contracts_info, - )?; - + let metadata_config = Some(Default::default()); + let gas_usage_check = metadata_config.is_some(); + let metadata = create_metadata(&sierra_program, metadata_config)?; let sierra_program_registry = ProgramRegistry::::new(&sierra_program)?; let type_sizes = get_type_size_map(&sierra_program, &sierra_program_registry).unwrap_or_default(); + let casm_program = + cairo_lang_sierra_to_casm::compiler::compile(&sierra_program, &metadata, gas_usage_check)?; - let main_func = casm_runner.find_function("::main")?; + let main_func = find_function(&sierra_program, "::main")?; let initial_gas = 9999999999999_usize; // Entry code and footer are part of the whole instructions that are // ran by the VM. - let (entry_code, builtins) = casm_runner.create_entry_code(main_func, &[], initial_gas)?; - let footer = casm_runner.create_code_footer(); + let (entry_code, builtins) = create_entry_code( + &sierra_program_registry, + &casm_program, + &type_sizes, + main_func, + initial_gas, + )?; + let footer = create_code_footer(); let check_gas_usage = true; let metadata = calc_metadata(&sierra_program, Default::default())?; @@ -190,7 +211,8 @@ fn run(args: impl Iterator) -> Result, Erro footer.iter() ); - let (hints_dict, string_to_hint) = build_hints_dict(instructions.clone()); + let (processor_hints, program_hints) = build_hints_vec(instructions.clone()); + let mut hint_processor = Cairo1HintProcessor::new(&processor_hints, RunResources::default()); let data: Vec = instructions .flat_map(|inst| inst.assemble().encode()) @@ -204,7 +226,7 @@ fn run(args: impl Iterator) -> Result, Erro builtins, data, Some(0), - hints_dict, + program_hints, ReferenceManager { references: Vec::new(), }, @@ -213,23 +235,11 @@ fn run(args: impl Iterator) -> Result, Erro None, )?; - let mut runner = CairoRunner::new(&program, "all_cairo", false)?; - let mut vm = VirtualMachine::new(true); + let mut runner = CairoRunner::new(&program, &args.layout, false)?; + let mut vm = VirtualMachine::new(args.trace_file.is_some()); let end = runner.initialize(&mut vm)?; - let function_context = RunFunctionContext { - vm: &mut vm, - data_len, - }; - - additional_initialization(function_context)?; - - let mut hint_processor = CairoHintProcessor { - runner: None, - string_to_hint, - starknet_state: StarknetState::default(), - run_resources: RunResources::default(), - }; + additional_initialization(&mut vm, data_len)?; runner.run_until_pc(end, &mut vm, &mut hint_processor)?; runner.end_run(true, false, &mut vm, &mut hint_processor)?; @@ -283,8 +293,8 @@ fn run(args: impl Iterator) -> Result, Erro runner.relocate(&mut vm, true)?; - let relocated_trace = vm.get_relocated_trace()?; if let Some(trace_path) = args.trace_file { + let relocated_trace = vm.get_relocated_trace()?; let trace_file = std::fs::File::create(trace_path)?; let mut trace_writer = FileWriter::new(io::BufWriter::with_capacity(3 * 1024 * 1024, trace_file)); @@ -304,21 +314,20 @@ fn run(args: impl Iterator) -> Result, Erro Ok(return_values) } -fn additional_initialization(context: RunFunctionContext) -> Result<(), Error> { - let vm = context.vm; +fn additional_initialization(vm: &mut VirtualMachine, data_len: usize) -> Result<(), Error> { // Create the builtin cost segment let builtin_cost_segment = vm.add_memory_segment(); for token_type in CostTokenType::iter_precost() { vm.insert_value( (builtin_cost_segment + (token_type.offset_in_builtin_costs() as usize)) .map_err(VirtualMachineError::Math)?, - Felt252::from(token_gas_cost(*token_type)), + Felt252::default(), )? } // Put a pointer to the builtin cost segment at the end of the program (after the // additional `ret` statement). vm.insert_value( - (vm.get_pc() + context.data_len).map_err(VirtualMachineError::Math)?, + (vm.get_pc() + data_len).map_err(VirtualMachineError::Math)?, builtin_cost_segment, )?; @@ -358,24 +367,356 @@ fn main() -> Result<(), Error> { } } +#[allow(clippy::type_complexity)] +fn build_hints_vec<'b>( + instructions: impl Iterator, +) -> (Vec<(usize, Vec)>, HashMap>) { + let mut hints: Vec<(usize, Vec)> = Vec::new(); + let mut program_hints: HashMap> = HashMap::new(); + + let mut hint_offset = 0; + + for instruction in instructions { + if !instruction.hints.is_empty() { + hints.push((hint_offset, instruction.hints.clone())); + program_hints.insert( + hint_offset, + vec![HintParams { + code: hint_offset.to_string(), + accessible_scopes: Vec::new(), + flow_tracking_data: FlowTrackingData { + ap_tracking: ApTracking::default(), + reference_ids: HashMap::new(), + }, + }], + ); + } + hint_offset += instruction.body.op_size(); + } + (hints, program_hints) +} + +/// Finds first function ending with `name_suffix`. +fn find_function<'a>( + sierra_program: &'a SierraProgram, + name_suffix: &'a str, +) -> Result<&'a Function, RunnerError> { + sierra_program + .funcs + .iter() + .find(|f| { + if let Some(name) = &f.id.debug_name { + name.ends_with(name_suffix) + } else { + false + } + }) + .ok_or_else(|| RunnerError::MissingMain) +} + +/// Creates a list of instructions that will be appended to the program's bytecode. +fn create_code_footer() -> Vec { + casm! { + // Add a `ret` instruction used in libfuncs that retrieve the current value of the `fp` + // and `pc` registers. + ret; + } + .instructions +} + +/// Returns the instructions to add to the beginning of the code to successfully call the main +/// function, as well as the builtins required to execute the program. +fn create_entry_code( + sierra_program_registry: &ProgramRegistry, + casm_program: &CairoProgram, + type_sizes: &UnorderedHashMap, + func: &Function, + initial_gas: usize, +) -> Result<(Vec, Vec), Error> { + let mut ctx = casm! {}; + // The builtins in the formatting expected by the runner. + let (builtins, builtin_offset) = get_function_builtins(func); + // Load all vecs to memory. + let mut ap_offset: i16 = 0; + let after_vecs_offset = ap_offset; + if func.signature.param_types.iter().any(|ty| { + get_info(sierra_program_registry, ty) + .map(|x| x.long_id.generic_id == SegmentArenaType::ID) + .unwrap_or_default() + }) { + casm_extend! {ctx, + // SegmentArena segment. + %{ memory[ap + 0] = segments.add() %} + // Infos segment. + %{ memory[ap + 1] = segments.add() %} + ap += 2; + [ap + 0] = 0, ap++; + // Write Infos segment, n_constructed (0), and n_destructed (0) to the segment. + [ap - 2] = [[ap - 3]]; + [ap - 1] = [[ap - 3] + 1]; + [ap - 1] = [[ap - 3] + 2]; + } + ap_offset += 3; + } + for ty in func.signature.param_types.iter() { + let info = get_info(sierra_program_registry, ty) + .ok_or_else(|| Error::NoInfoForType(ty.clone()))?; + let ty_size = type_sizes[ty]; + let generic_ty = &info.long_id.generic_id; + if let Some(offset) = builtin_offset.get(generic_ty) { + casm_extend! {ctx, + [ap + 0] = [fp - offset], ap++; + } + } else if generic_ty == &SystemType::ID { + casm_extend! {ctx, + %{ memory[ap + 0] = segments.add() %} + ap += 1; + } + } else if generic_ty == &GasBuiltinType::ID { + casm_extend! {ctx, + [ap + 0] = initial_gas, ap++; + } + } else if generic_ty == &SegmentArenaType::ID { + let offset = -ap_offset + after_vecs_offset; + casm_extend! {ctx, + [ap + 0] = [ap + offset] + 3, ap++; + } + // } else if let Some(Arg::Array(_)) = arg_iter.peek() { + // let values = extract_matches!(arg_iter.next().unwrap(), Arg::Array); + // let offset = -ap_offset + vecs.pop().unwrap(); + // expected_arguments_size += 1; + // casm_extend! {ctx, + // [ap + 0] = [ap + (offset)], ap++; + // [ap + 0] = [ap - 1] + (values.len()), ap++; + // } + // } else { + // let arg_size = ty_size; + // expected_arguments_size += arg_size as usize; + // for _ in 0..arg_size { + // if let Some(value) = arg_iter.next() { + // let value = extract_matches!(value, Arg::Value); + // casm_extend! {ctx, + // [ap + 0] = (value.to_bigint()), ap++; + // } + // } + // } + }; + ap_offset += ty_size; + } + // if expected_arguments_size != args.len() { + // return Err(RunnerError::ArgumentsSizeMismatch { + // expected: expected_arguments_size, + // actual: args.len(), + // }); + // } + let before_final_call = ctx.current_code_offset; + let final_call_size = 3; + let offset = final_call_size + + casm_program.debug_info.sierra_statement_info[func.entry_point.0].code_offset; + casm_extend! {ctx, + call rel offset; + ret; + } + assert_eq!(before_final_call + final_call_size, ctx.current_code_offset); + Ok((ctx.instructions, builtins)) +} + +fn get_info<'a>( + sierra_program_registry: &'a ProgramRegistry, + ty: &'a cairo_lang_sierra::ids::ConcreteTypeId, +) -> Option<&'a cairo_lang_sierra::extensions::types::TypeInfo> { + sierra_program_registry + .get_type(ty) + .ok() + .map(|ctc| ctc.info()) +} + +/// Creates the metadata required for a Sierra program lowering to casm. +fn create_metadata( + sierra_program: &cairo_lang_sierra::program::Program, + metadata_config: Option, +) -> Result { + if let Some(metadata_config) = metadata_config { + calc_metadata(sierra_program, metadata_config).map_err(|err| match err { + MetadataError::ApChangeError(_) => VirtualMachineError::Unexpected, + MetadataError::CostError(_) => VirtualMachineError::Unexpected, + }) + } else { + Ok(Metadata { + ap_change_info: calc_ap_changes(sierra_program, |_, _| 0) + .map_err(|_| VirtualMachineError::Unexpected)?, + gas_info: GasInfo { + variable_values: Default::default(), + function_costs: Default::default(), + }, + }) + } +} + +fn get_function_builtins( + func: &Function, +) -> ( + Vec, + HashMap, +) { + let entry_params = &func.signature.param_types; + let mut builtins = Vec::new(); + let mut builtin_offset: HashMap = HashMap::new(); + let mut current_offset = 3; + // Fetch builtins from the entry_params in the standard order + if entry_params + .iter() + .any(|ti| ti.debug_name == Some("Poseidon".into())) + { + builtins.push(BuiltinName::poseidon); + builtin_offset.insert(PoseidonType::ID, current_offset); + current_offset += 1; + } + if entry_params + .iter() + .any(|ti| ti.debug_name == Some("EcOp".into())) + { + builtins.push(BuiltinName::ec_op); + builtin_offset.insert(EcOpType::ID, current_offset); + current_offset += 1 + } + if entry_params + .iter() + .any(|ti| ti.debug_name == Some("Bitwise".into())) + { + builtins.push(BuiltinName::bitwise); + builtin_offset.insert(BitwiseType::ID, current_offset); + current_offset += 1; + } + if entry_params + .iter() + .any(|ti| ti.debug_name == Some("RangeCheck".into())) + { + builtins.push(BuiltinName::range_check); + builtin_offset.insert(RangeCheckType::ID, current_offset); + current_offset += 1; + } + if entry_params + .iter() + .any(|ti| ti.debug_name == Some("Pedersen".into())) + { + builtins.push(BuiltinName::pedersen); + builtin_offset.insert(PedersenType::ID, current_offset); + } + builtins.reverse(); + (builtins, builtin_offset) +} + #[cfg(test)] mod tests { #![allow(clippy::too_many_arguments)] use super::*; use assert_matches::assert_matches; + use cairo_vm::felt::felt_str; use rstest::rstest; #[rstest] - #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/fibonacci.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/fibonacci.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] fn test_run_fibonacci_ok(#[case] args: &[&str]) { let args = args.iter().cloned().map(String::from); assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(89)]); } #[rstest] - #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/factorial.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null"].as_slice())] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/factorial.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] fn test_run_factorial_ok(#[case] args: &[&str]) { let args = args.iter().cloned().map(String::from); assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(3628800)]); } + + #[rstest] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/array_get.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + fn test_run_array_get_ok(#[case] args: &[&str]) { + let args = args.iter().cloned().map(String::from); + assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(3)]); + } + + #[rstest] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/enum_flow.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + fn test_run_enum_flow_ok(#[case] args: &[&str]) { + let args = args.iter().cloned().map(String::from); + assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(300)]); + } + + #[rstest] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/enum_match.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + fn test_run_enum_match_ok(#[case] args: &[&str]) { + let args = args.iter().cloned().map(String::from); + assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(10), MaybeRelocatable::from(felt_str!("3618502788666131213697322783095070105623107215331596699973092056135872020471"))]); + } + + #[rstest] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/hello.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + fn test_run_hello_ok(#[case] args: &[&str]) { + let args = args.iter().cloned().map(String::from); + assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(1), MaybeRelocatable::from(1234)]); + } + + #[rstest] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/ops.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + fn test_run_ops_ok(#[case] args: &[&str]) { + let args = args.iter().cloned().map(String::from); + assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(6)]); + } + + #[rstest] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/print.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + fn test_run_print_ok(#[case] args: &[&str]) { + let args = args.iter().cloned().map(String::from); + assert_matches!(run(args), Ok(res) if res == vec![]); + } + + #[rstest] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/recursion.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + fn test_run_recursion_ok(#[case] args: &[&str]) { + let args = args.iter().cloned().map(String::from); + assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(felt_str!("1154076154663935037074198317650845438095734251249125412074882362667803016453"))]); + } + + #[rstest] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/sample.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + fn test_run_sample_ok(#[case] args: &[&str]) { + let args = args.iter().cloned().map(String::from); + assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(felt_str!("500000500000"))]); + } + + #[rstest] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/poseidon.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + fn test_run_poseidon_ok(#[case] args: &[&str]) { + let args = args.iter().cloned().map(String::from); + assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(felt_str!("1099385018355113290651252669115094675591288647745213771718157553170111442461"))]); + } + + #[rstest] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/poseidon_pedersen.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + fn test_run_poseidon_pedersen_ok(#[case] args: &[&str]) { + let args = args.iter().cloned().map(String::from); + assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(felt_str!("1036257840396636296853154602823055519264738423488122322497453114874087006398"))]); + } + + #[rstest] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/pedersen_example.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + fn test_run_pedersen_example_ok(#[case] args: &[&str]) { + let args = args.iter().cloned().map(String::from); + assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(felt_str!("1089549915800264549621536909767699778745926517555586332772759280702396009108"))]); + } + + #[rstest] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/simple.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + fn test_run_simple_ok(#[case] args: &[&str]) { + let args = args.iter().cloned().map(String::from); + assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(1)]); + } + + #[rstest] + #[case(["cairo1-run", "../cairo_programs/cairo-1-programs/simple_struct.cairo", "--trace_file", "/dev/null", "--memory_file", "/dev/null", "--layout", "all_cairo"].as_slice())] + fn test_run_simple_struct_ok(#[case] args: &[&str]) { + let args = args.iter().cloned().map(String::from); + assert_matches!(run(args), Ok(res) if res == vec![MaybeRelocatable::from(100)]); + } } diff --git a/cairo_programs/cairo-1-programs/pedersen_example.cairo b/cairo_programs/cairo-1-programs/pedersen_example.cairo new file mode 100644 index 0000000000..ad0c7a3a37 --- /dev/null +++ b/cairo_programs/cairo-1-programs/pedersen_example.cairo @@ -0,0 +1,5 @@ +use core::pedersen::pedersen; + +fn main() -> felt252 { + pedersen(1, 0) +} diff --git a/cairo_programs/cairo-1-programs/poseidon.cairo b/cairo_programs/cairo-1-programs/poseidon.cairo new file mode 100644 index 0000000000..96a3c8beef --- /dev/null +++ b/cairo_programs/cairo-1-programs/poseidon.cairo @@ -0,0 +1,14 @@ +use core::felt252; +use core::poseidon::poseidon_hash_span; +use array::ArrayTrait; +use array::SpanTrait; + +fn main() -> felt252 { + let mut data: Array = ArrayTrait::new(); + data.append(1); + data.append(2); + data.append(3); + data.append(4); + + poseidon_hash_span(data.span()) +} diff --git a/cairo_programs/cairo-1-programs/poseidon_pedersen.cairo b/cairo_programs/cairo-1-programs/poseidon_pedersen.cairo new file mode 100644 index 0000000000..c78820c63a --- /dev/null +++ b/cairo_programs/cairo-1-programs/poseidon_pedersen.cairo @@ -0,0 +1,16 @@ +use core::felt252; +use core::poseidon::poseidon_hash_span; +use array::ArrayTrait; +use array::SpanTrait; +use core::pedersen::pedersen; + +fn main() -> felt252 { + let mut data: Array = ArrayTrait::new(); + data.append(1); + data.append(2); + data.append(3); + data.append(4); + + let res = poseidon_hash_span(data.span()); + pedersen(res, 0) +}