From 29487c6a90cced41eef9b07ace49a4d1d9b74435 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Kami=C5=84ski=20=40=20StarkWare?= Date: Wed, 20 Mar 2024 16:39:10 +0100 Subject: [PATCH] add Cairo1 builtin hint processor (#91) * wip * wip, some progress * WIP: Declare unimplemented hints * Fix unused warnings * Hint: SET_SYSCALL_PTR (#4) * Add is_n_ge_two hint (#3) * first iteration of is_n_ge_two hint * refactor is_n_ge_two hint. remove unused dependencies. start test * set vm memory in test * remove unused macros * fix test and remove debugging prints * add EOF line * add test cases * use rstest cases. refactor hint code to avoid using match. rename hint tests module. * apply formatter * add case for n > two * remove End of file line * run fmt+nightly command * run fmt+nightly command * add hint in hint map and use ids map (#6) * add hint in hint map and use ids map * remove unused macro. makes hint constant public * Add is_on_curve hint and basic test (#1) * Add is_on_curve hint and basic test * Improve test * Add TODO * Update Cargo.lock * Attempt at better ids_data * Set fp and add another segment * Clean up * fmt * Fix clippy lints * fmt * fmt * Add IS_ON_CURVE to hints map * Use constants for ONE and ZERO * fmt * Clean up secp_p comments * Use vars for var names * Remove duplicate mod tests * Add set_ap_to_actual_fee hint (#2) Co-authored-by: Olivier Desenfans Co-authored-by: Herman Obst Demaestri <70286869+HermanObst@users.noreply.github.com> * Add txn/call hints (#5) Co-authored-by: Olivier Desenfans * Add preimage hints (#8) Co-authored-by: Olivier Desenfans * Feature: read/write Cairo structs safely (#9) Problem: Cairo structs are accessed in some hints. The Python VM has abstractions to access fields by name that the Rust VM cannot implement. This leads to accessing these structs by hardcoding the offset of each field. Solution: The new `CairoType` trait allows to read/write an entire struct in one go. The derive implementation reads/writes fields one by one according to their place in the struct definition. For cases where reading/writing the whole struct is not appropriate, the new `FieldOffsetGetters` macro implements a `get__offset()` method for each field of the struct to avoid hardcoding values. * fix tests * one more hint * fix contracts in StarknetOsInput * few more hints * ignore block test * Add a couple missing hints * calculate tx_hash * fix TRANSACTIONS_LEN * Maybe-fix gen_signature_arg hint * Don't put signature in ap * remove unnecesary unwraps * fix post merge problems * remove outdated tests * is_reverted hint * wip * Pull in relevant hashing code from starknet_on_rust * Convert equivalent contract structs * wip * test with cairo1 * cairo1 test setup, breaks at hint trying to load v1 class * wip * wip * cairo1 class loading + execution without cairo1 hint processor * fix tests * fix clippy * first round of comments * wip * cairo1 syscall handler * fix imports * fix fmt, clippy * fix clippy * fix fmt --------- Co-authored-by: Olivier Desenfans Co-authored-by: Herman Obst Demaestri <70286869+HermanObst@users.noreply.github.com> Co-authored-by: Stephen Shelton --- src/hints/mod.rs | 46 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/src/hints/mod.rs b/src/hints/mod.rs index e997c6d9..78cb1096 100644 --- a/src/hints/mod.rs +++ b/src/hints/mod.rs @@ -1,9 +1,11 @@ use std::collections::{HashMap, HashSet}; +use cairo_lang_casm::hints::{Hint, StarknetHint}; use cairo_vm::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::{ BuiltinHintProcessor, HintProcessorData, }; use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::*; +use cairo_vm::hint_processor::cairo_1_hint_processor::hint_processor::Cairo1HintProcessor; use cairo_vm::hint_processor::hint_processor_definition::{ HintExtension, HintProcessor, HintProcessorLogic, HintReference, }; @@ -146,6 +148,7 @@ static EXTENSIVE_HINTS: [(&str, ExtensiveHintImpl); 2] = [ pub struct SnosHintProcessor { builtin_hint_proc: BuiltinHintProcessor, + cairo1_builtin_hint_proc: Cairo1HintProcessor, hints: HashMap, extensive_hints: HashMap, run_resources: RunResources, @@ -175,6 +178,7 @@ impl Default for SnosHintProcessor { let extensive_hints = EXTENSIVE_HINTS.into_iter().map(|(h, i)| (h.to_string(), i)).collect(); Self { builtin_hint_proc: BuiltinHintProcessor::new_empty(), + cairo1_builtin_hint_proc: Cairo1HintProcessor::new(Default::default(), RunResources::default()), hints, extensive_hints, run_resources: Default::default(), @@ -192,6 +196,14 @@ impl SnosHintProcessor { .cloned() .collect::>() } + fn execute_syscall_hint( + &mut self, + _vm: &mut VirtualMachine, + hint: &StarknetHint, + ) -> Result { + println!("TODO: execute syscall hint: {:?}", hint); + Ok(HintExtension::default()) + } } impl HintProcessorLogic for SnosHintProcessor { @@ -213,22 +225,32 @@ impl HintProcessorLogic for SnosHintProcessor { hint_data: &Box, constants: &HashMap, ) -> Result { - match self.builtin_hint_proc.execute_hint(vm, exec_scopes, hint_data, constants) { - Err(HintError::UnknownHint(_)) => {} - res => return res.map(|_| HintExtension::default()), - } - // First attempt to execute with builtin hint processor - let hint_data = hint_data.downcast_ref::().ok_or(HintError::WrongHintData)?; - let hint_code = hint_data.code.as_str(); - if let Some(hint_impl) = self.hints.get(hint_code) { - return hint_impl(vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking, constants) + if let Some(hpd) = hint_data.downcast_ref::() { + let hint_code = hpd.code.as_str(); + if let Some(hint_impl) = self.hints.get(hint_code) { + return hint_impl(vm, exec_scopes, &hpd.ids_data, &hpd.ap_tracking, constants) + .map(|_| HintExtension::default()); + } + + if let Some(hint_impl) = self.extensive_hints.get(hint_code) { + return hint_impl(self, vm, exec_scopes, &hpd.ids_data, &hpd.ap_tracking); + } + + return self + .builtin_hint_proc + .execute_hint(vm, exec_scopes, hint_data, constants) .map(|_| HintExtension::default()); } - match self.extensive_hints.get(hint_code) { - Some(hint_impl) => hint_impl(self, vm, exec_scopes, &hint_data.ids_data, &hint_data.ap_tracking), - None => Err(HintError::UnknownHint(hint_code.to_string().into_boxed_str())), + if let Some(hint) = hint_data.downcast_ref::() { + if let Hint::Starknet(starknet_hint) = hint { + return self.execute_syscall_hint(vm, starknet_hint); + } else { + return self.cairo1_builtin_hint_proc.execute(vm, exec_scopes, hint).map(|_| HintExtension::default()); + } } + + Err(HintError::WrongHintData) } }