From f41c64ed76e5190381e24bca910ec48d02117712 Mon Sep 17 00:00:00 2001 From: Olivier Desenfans Date: Wed, 27 Mar 2024 17:30:11 +0100 Subject: [PATCH] Feature: GET_STATE_ENTRY_AND_SET_NEW_STATE_ENTRY hints (#98) --- src/hints/execution.rs | 121 ++++++++++++++++++++++++++++++++----- src/hints/mod.rs | 14 ++++- src/hints/unimplemented.rs | 33 ---------- src/hints/vars.rs | 4 +- 4 files changed, 121 insertions(+), 51 deletions(-) diff --git a/src/hints/execution.rs b/src/hints/execution.rs index 4a77cd54..b5feba3d 100644 --- a/src/hints/execution.rs +++ b/src/hints/execution.rs @@ -10,7 +10,7 @@ use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::{ use cairo_vm::hint_processor::hint_processor_definition::HintReference; use cairo_vm::serde::deserialize_program::ApTracking; use cairo_vm::types::exec_scope::ExecutionScopes; -use cairo_vm::types::relocatable::MaybeRelocatable; +use cairo_vm::types::relocatable::{MaybeRelocatable, Relocatable}; use cairo_vm::vm::errors::hint_errors::HintError; use cairo_vm::vm::vm_core::VirtualMachine; use cairo_vm::Felt252; @@ -174,33 +174,124 @@ pub fn enter_scope_syscall_handler( Ok(()) } -pub const GET_STATE_ENTRY: &str = indoc! {r##" - # Fetch a state_entry in this hint and validate it in the update at the end - # of this function. - ids.state_entry = __dict_manager.get_dict(ids.contract_state_changes)[ids.contract_address]"## -}; -pub fn get_state_entry( +fn get_state_entry( + dict_ptr: Relocatable, + key: Felt252, vm: &mut VirtualMachine, exec_scopes: &mut ExecutionScopes, ids_data: &HashMap, ap_tracking: &ApTracking, - _constants: &HashMap, ) -> Result<(), HintError> { - let key = get_integer_from_var_name("contract_address", vm, ids_data, ap_tracking)?; - let dict_ptr = get_ptr_from_var_name("contract_state_changes", vm, ids_data, ap_tracking)?; let val = match exec_scopes.get_dict_manager()?.borrow().get_tracker(dict_ptr)?.data.clone() { - Dictionary::SimpleDictionary(dict) => dict - .get(&MaybeRelocatable::Int(key.into_owned())) - .expect("State changes dictionnary shouldn't be None") - .clone(), + Dictionary::SimpleDictionary(dict) => dict.get(&MaybeRelocatable::Int(key)).cloned(), Dictionary::DefaultDictionary { dict: _d, default_value: _v } => { - panic!("State changes dict shouldn't be a default dict") + return Err(HintError::CustomHint( + "State changes dictionary should not be a default dict".to_string().into_boxed_str(), + )); } }; + let val = + val.ok_or(HintError::CustomHint("State changes dictionnary should not be None".to_string().into_boxed_str()))?; + insert_value_from_var_name("state_entry", val, vm, ids_data, ap_tracking)?; Ok(()) } +pub const GET_CONTRACT_ADDRESS_STATE_ENTRY: &str = indoc! {r##" + # Fetch a state_entry in this hint and validate it in the update at the end + # of this function. + ids.state_entry = __dict_manager.get_dict(ids.contract_state_changes)[ids.contract_address]"## +}; + +pub const GET_CONTRACT_ADDRESS_STATE_ENTRY_2: &str = indoc! {r#" + # Fetch a state_entry in this hint and validate it in the update that comes next. + ids.state_entry = __dict_manager.get_dict(ids.contract_state_changes)[ + ids.contract_address + ]"# +}; + +pub fn get_contract_address_state_entry( + vm: &mut VirtualMachine, + exec_scopes: &mut ExecutionScopes, + ids_data: &HashMap, + ap_tracking: &ApTracking, + _constants: &HashMap, +) -> Result<(), HintError> { + let dict_ptr = get_ptr_from_var_name(vars::ids::CONTRACT_STATE_CHANGES, vm, ids_data, ap_tracking)?; + let key = get_integer_from_var_name(vars::ids::CONTRACT_ADDRESS, vm, ids_data, ap_tracking)?; + + get_state_entry(dict_ptr, key.into_owned(), vm, exec_scopes, ids_data, ap_tracking)?; + + Ok(()) +} +fn get_state_entry_and_set_new_state_entry( + dict_ptr: Relocatable, + key: Felt252, + vm: &mut VirtualMachine, + exec_scopes: &mut ExecutionScopes, + ids_data: &HashMap, + ap_tracking: &ApTracking, +) -> Result<(), HintError> { + get_state_entry(dict_ptr, key, vm, exec_scopes, ids_data, ap_tracking)?; + + let new_segment = vm.add_memory_segment(); + insert_value_from_var_name(vars::ids::NEW_STATE_ENTRY, new_segment, vm, ids_data, ap_tracking)?; + + Ok(()) +} + +pub const GET_BLOCK_HASH_CONTRACT_ADDRESS_STATE_ENTRY_AND_SET_NEW_STATE_ENTRY: &str = indoc! {r#" + # Fetch a state_entry in this hint. Validate it in the update that comes next. + ids.state_entry = __dict_manager.get_dict(ids.contract_state_changes)[ + ids.BLOCK_HASH_CONTRACT_ADDRESS] + ids.new_state_entry = segments.add()"# +}; + +pub fn get_block_hash_contract_address_state_entry_and_set_new_state_entry( + vm: &mut VirtualMachine, + exec_scopes: &mut ExecutionScopes, + ids_data: &HashMap, + ap_tracking: &ApTracking, + _constants: &HashMap, +) -> Result<(), HintError> { + let dict_ptr = get_ptr_from_var_name(vars::ids::CONTRACT_STATE_CHANGES, vm, ids_data, ap_tracking)?; + let key = get_integer_from_var_name(vars::ids::BLOCK_HASH_CONTRACT_ADDRESS, vm, ids_data, ap_tracking)?; + + get_state_entry_and_set_new_state_entry(dict_ptr, key.into_owned(), vm, exec_scopes, ids_data, ap_tracking)?; + + Ok(()) +} + +pub const GET_CONTRACT_ADDRESS_STATE_ENTRY_AND_SET_NEW_STATE_ENTRY: &str = indoc! {r#" + # Fetch a state_entry in this hint and validate it in the update that comes next. + ids.state_entry = __dict_manager.get_dict(ids.contract_state_changes)[ids.contract_address] + ids.new_state_entry = segments.add()"# +}; + +pub const GET_CONTRACT_ADDRESS_STATE_ENTRY_AND_SET_NEW_STATE_ENTRY_2: &str = indoc! {r#" + # Fetch a state_entry in this hint and validate it in the update that comes next. + ids.state_entry = __dict_manager.get_dict(ids.contract_state_changes)[ + ids.contract_address + ] + + ids.new_state_entry = segments.add()"# +}; + +pub fn get_contract_address_state_entry_and_set_new_state_entry( + vm: &mut VirtualMachine, + exec_scopes: &mut ExecutionScopes, + ids_data: &HashMap, + ap_tracking: &ApTracking, + _constants: &HashMap, +) -> Result<(), HintError> { + let dict_ptr = get_ptr_from_var_name(vars::ids::CONTRACT_STATE_CHANGES, vm, ids_data, ap_tracking)?; + let key = get_integer_from_var_name(vars::ids::CONTRACT_ADDRESS, vm, ids_data, ap_tracking)?; + + get_state_entry_and_set_new_state_entry(dict_ptr, key.into_owned(), vm, exec_scopes, ids_data, ap_tracking)?; + + Ok(()) +} + pub const CHECK_IS_DEPRECATED: &str = "is_deprecated = 1 if ids.execution_context.class_hash in __deprecated_class_hashes else 0"; pub fn check_is_deprecated( diff --git a/src/hints/mod.rs b/src/hints/mod.rs index 73274a45..05b5beca 100644 --- a/src/hints/mod.rs +++ b/src/hints/mod.rs @@ -43,7 +43,7 @@ type HintImpl = fn( &HashMap, ) -> Result<(), HintError>; -static HINTS: [(&str, HintImpl); 87] = [ +static HINTS: [(&str, HintImpl); 91] = [ (INITIALIZE_CLASS_HASHES, initialize_class_hashes), (INITIALIZE_STATE_CHANGES, initialize_state_changes), (IS_N_GE_TWO, is_n_ge_two), @@ -86,7 +86,17 @@ static HINTS: [(&str, HintImpl); 87] = [ (execution::ENTER_SYSCALL_SCOPES, execution::enter_syscall_scopes), (execution::EXIT_CALL, execution::exit_call), (execution::GEN_SIGNATURE_ARG, execution::gen_signature_arg), - (execution::GET_STATE_ENTRY, execution::get_state_entry), + (execution::GET_CONTRACT_ADDRESS_STATE_ENTRY, execution::get_contract_address_state_entry), + (execution::GET_CONTRACT_ADDRESS_STATE_ENTRY_2, execution::get_contract_address_state_entry), + ( + execution::GET_BLOCK_HASH_CONTRACT_ADDRESS_STATE_ENTRY_AND_SET_NEW_STATE_ENTRY, + execution::get_block_hash_contract_address_state_entry_and_set_new_state_entry, + ), + (execution::GET_CONTRACT_ADDRESS_STATE_ENTRY, execution::get_contract_address_state_entry_and_set_new_state_entry), + ( + execution::GET_CONTRACT_ADDRESS_STATE_ENTRY_2, + execution::get_contract_address_state_entry_and_set_new_state_entry, + ), (execution::IS_DEPRECATED, execution::is_deprecated), (execution::IS_REVERTED, execution::is_reverted), (execution::LOAD_NEXT_TX, execution::load_next_tx), diff --git a/src/hints/unimplemented.rs b/src/hints/unimplemented.rs index 271d347e..9db4b9ef 100644 --- a/src/hints/unimplemented.rs +++ b/src/hints/unimplemented.rs @@ -8,14 +8,6 @@ const CACHE_CONTRACT_STORAGE: &str = indoc! {r#" assert ids.value == value, "Inconsistent storage value.""# }; -#[allow(unused)] -const FETCH_STATE_ENTRY: &str = indoc! {r#" - # Fetch a state_entry in this hint. Validate it in the update that comes next. - ids.state_entry = __dict_manager.get_dict(ids.contract_state_changes)[ - ids.BLOCK_HASH_CONTRACT_ADDRESS] - ids.new_state_entry = segments.add()"# -}; - #[allow(unused)] const SET_INITIAL_STATE_UPDATES_PTR: &str = indoc! {r#" # This hint shouldn't be whitelisted. @@ -262,14 +254,6 @@ const SPLIT_DESCEND: &str = "ids.length, ids.word = descend"; const HEIGHT_IS_ZERO_OR_LEN_NODE_PREIMAGE_IS_TWO: &str = "memory[ap] = 1 if ids.height == 0 or len(preimage[ids.node]) == 2 else 0"; -#[allow(unused)] -const FETCH_STATE_ENTRY_3: &str = indoc! {r#" - # Fetch a state_entry in this hint and validate it in the update that comes next. - ids.state_entry = __dict_manager.get_dict(ids.contract_state_changes)[ - ids.contract_address - ]"# -}; - #[allow(unused)] const ENTER_SCOPE_NEW_TREE: &str = indoc! {r#" new_node = node @@ -335,13 +319,6 @@ const CHECK_RETURN_VALUE_2: &str = indoc! {r#" assert expected == actual, f'Return value mismatch; expected={expected}, actual={actual}.'"# }; -#[allow(unused)] -const FETCH_STATE_ENTRY_4: &str = indoc! {r#" - # Fetch a state_entry in this hint and validate it in the update that comes next. - ids.state_entry = __dict_manager.get_dict(ids.contract_state_changes)[ids.contract_address] - ids.new_state_entry = segments.add()"# -}; - #[allow(unused)] const BUILD_DESCENT_MAP: &str = indoc! {r#" from starkware.cairo.common.patricia_utils import canonic, patricia_guess_descents @@ -422,16 +399,6 @@ const START_TX_2: &str = indoc! {r#" const GET_SEQUENCER_ADDRESS: &str = "syscall_handler.get_sequencer_address(segments=segments, syscall_ptr=ids.syscall_ptr)"; -#[allow(unused)] -const FETCH_STATE_ENTRY_5: &str = indoc! {r#" - # Fetch a state_entry in this hint and validate it in the update that comes next. - ids.state_entry = __dict_manager.get_dict(ids.contract_state_changes)[ - ids.contract_address - ] - - ids.new_state_entry = segments.add()"# -}; - #[allow(unused)] const ENTER_SCOPE_RIGHT_CHILD: &str = "vm_enter_scope(dict(node=right_child, **common_args))"; diff --git a/src/hints/vars.rs b/src/hints/vars.rs index e21b2bd5..1870876d 100644 --- a/src/hints/vars.rs +++ b/src/hints/vars.rs @@ -9,10 +9,11 @@ pub mod scopes { } pub mod ids { + pub const BLOCK_HASH_CONTRACT_ADDRESS: &str = "BLOCK_HASH_CONTRACT_ADDRESS"; pub const COMPILED_CLASS: &str = "compiled_class"; pub const COMPILED_CLASS_FACT: &str = "compiled_class_fact"; - pub const CONTRACT_STATE_CHANGES: &str = "contract_state_changes"; pub const CONTRACT_ADDRESS: &str = "contract_address"; + pub const CONTRACT_STATE_CHANGES: &str = "contract_state_changes"; pub const DEPRECATED_TX_INFO: &str = "deprecated_tx_info"; pub const EDGE: &str = "edge"; pub const FINAL_ROOT: &str = "final_root"; @@ -21,6 +22,7 @@ pub mod ids { pub const IS_ON_CURVE: &str = "is_on_curve"; pub const MERKLE_HEIGHT: &str = "MERKLE_HEIGHT"; pub const N: &str = "n"; + pub const NEW_STATE_ENTRY: &str = "new_state_entry"; pub const NODE: &str = "node"; pub const OS_CONTEXT: &str = "os_context"; pub const REQUEST: &str = "request";