From 15142305a9d41f589c5bc8d1cd8e1ead365dc848 Mon Sep 17 00:00:00 2001 From: enitrat Date: Sat, 25 Jan 2025 00:10:53 +0100 Subject: [PATCH] fix some hints --- cairo/src/utils/dict.cairo | 9 ++-- cairo/tests/conftest.py | 1 + cairo/tests/src/utils/test_dict.cairo | 17 ++++-- cairo/tests/src/utils/test_dict.py | 7 ++- .../src/vm/hint_definitions/dict.rs | 52 ++++++++++++++++++- .../src/vm/hint_definitions/hashdict.rs | 14 +++-- pyproject.toml | 2 +- .../src/cairo_addons/hints/hashdict.py | 8 ++- uv.lock | 8 +-- 9 files changed, 96 insertions(+), 22 deletions(-) diff --git a/cairo/src/utils/dict.cairo b/cairo/src/utils/dict.cairo index 10d4d109..bfcbb7c1 100644 --- a/cairo/src/utils/dict.cairo +++ b/cairo/src/utils/dict.cairo @@ -274,10 +274,6 @@ func squash_and_update{range_check_ptr}( return dst; } - let dict_ptr = squashed_src_end; - let parent_dict_end = dst; - %{ merge_dict_tracker_with_parent %} - // Loop on all keys and write the new_value to the dst dict. tempvar squashed_src = squashed_src_start; tempvar dst_end = dst; @@ -305,6 +301,11 @@ func squash_and_update{range_check_ptr}( jmp loop; done: + // Merge + let dict_ptr = squashed_src_end; + let parent_dict_end = dst; + %{ merge_dict_tracker_with_parent %} + let current_tracker_ptr = dst; let new_tracker_ptr = cast([ap - 5], DictAccess*); %{ update_dict_tracker %} diff --git a/cairo/tests/conftest.py b/cairo/tests/conftest.py index f7732d29..db564f5b 100644 --- a/cairo/tests/conftest.py +++ b/cairo/tests/conftest.py @@ -87,6 +87,7 @@ def pytest_addoption(parser): deadline=None, max_examples=300, phases=[Phase.explicit, Phase.reuse, Phase.generate, Phase.target], + print_blob=True, derandomize=True, ) settings.register_profile( diff --git a/cairo/tests/src/utils/test_dict.cairo b/cairo/tests/src/utils/test_dict.cairo index 9a75879f..11d2a28a 100644 --- a/cairo/tests/src/utils/test_dict.cairo +++ b/cairo/tests/src/utils/test_dict.cairo @@ -13,7 +13,13 @@ from ethereum.cancun.state import ( ListTupleAddressBytes32, ListTupleAddressBytes32Struct, ) -from src.utils.dict import prev_values, dict_update, get_keys_for_address_prefix, squash_and_update +from src.utils.dict import ( + prev_values, + dict_update, + get_keys_for_address_prefix, + squash_and_update, + dict_squash, +) func test_prev_values{range_check_ptr}() -> (prev_values_start_ptr: felt*) { alloc_locals; @@ -97,10 +103,15 @@ func test_squash_and_update{range_check_ptr}( cast(src_start, DictAccess*), cast(src_end, DictAccess*), cast(dst, DictAccess*) ); + // Squash the dict another time to ensure that the update was done correctly + let (final_start, final_end) = dict_squash( + cast(dst_dict.value.dict_ptr_start, DictAccess*), new_dst_end + ); + tempvar new_dst_dict = MappingTupleAddressBytes32U256( new MappingTupleAddressBytes32U256Struct( - dict_ptr_start=cast(dst_dict.value.dict_ptr_start, TupleAddressBytes32U256DictAccess*), - dict_ptr=cast(new_dst_end, TupleAddressBytes32U256DictAccess*), + dict_ptr_start=cast(final_start, TupleAddressBytes32U256DictAccess*), + dict_ptr=cast(final_end, TupleAddressBytes32U256DictAccess*), parent_dict=dst_dict.value.parent_dict, ), ); diff --git a/cairo/tests/src/utils/test_dict.py b/cairo/tests/src/utils/test_dict.py index fe8c2759..9f486e27 100644 --- a/cairo/tests/src/utils/test_dict.py +++ b/cairo/tests/src/utils/test_dict.py @@ -1,3 +1,4 @@ +from collections import defaultdict from typing import List, Mapping, Tuple from cairo_addons.hints.decorator import register_hint @@ -121,6 +122,10 @@ def test_squash_and_update( src_dict: Mapping[Tuple[Address, Bytes32], U256], dst_dict: Mapping[Tuple[Address, Bytes32], U256], ): - new_dst_dict = cairo_run("test_squash_and_update", src_dict, dst_dict) + new_dst_dict = cairo_run( + "test_squash_and_update", + defaultdict(lambda: U256(0), src_dict), + defaultdict(lambda: U256(0), dst_dict), + ) dst_dict.update(src_dict) assert new_dst_dict == dst_dict diff --git a/crates/cairo-addons/src/vm/hint_definitions/dict.rs b/crates/cairo-addons/src/vm/hint_definitions/dict.rs index dbc42cb1..03ab812f 100644 --- a/crates/cairo-addons/src/vm/hint_definitions/dict.rs +++ b/crates/cairo-addons/src/vm/hint_definitions/dict.rs @@ -2,8 +2,9 @@ use std::collections::HashMap; use cairo_vm::{ hint_processor::{ - builtin_hint_processor::hint_utils::{ - get_ptr_from_var_name, insert_value_from_var_name, insert_value_into_ap, + builtin_hint_processor::{ + dict_manager::DictTracker, + hint_utils::{get_ptr_from_var_name, insert_value_from_var_name, insert_value_into_ap}, }, hint_processor_definition::HintReference, }, @@ -18,6 +19,7 @@ use crate::vm::hints::Hint; pub const HINTS: &[fn() -> Hint] = &[ dict_new_empty, dict_squash, + dict_copy, copy_dict_segment, merge_dict_tracker_with_parent, update_dict_tracker, @@ -67,6 +69,52 @@ pub fn dict_squash() -> Hint { ) } +pub fn dict_copy() -> Hint { + Hint::new( + String::from("dict_copy"), + |vm: &mut VirtualMachine, + exec_scopes: &mut ExecutionScopes, + ids_data: &HashMap, + ap_tracking: &ApTracking, + _constants: &HashMap| + -> Result<(), HintError> { + // Get the new_start and dict_start pointers from ids + let new_start = get_ptr_from_var_name("new_start", vm, ids_data, ap_tracking)?; + let dict_start = get_ptr_from_var_name("dict_start", vm, ids_data, ap_tracking)?; + let new_end = get_ptr_from_var_name("new_end", vm, ids_data, ap_tracking)?; + + let dict_manager_ref = exec_scopes.get_dict_manager()?; + let mut dict_manager = dict_manager_ref.borrow_mut(); + + // Check if new segment already exists in trackers + // Get and copy data from the source dictionary + let source_tracker = dict_manager.trackers.get(&dict_start.segment_index).ok_or( + HintError::CustomHint(Box::from(format!( + "Segment {} already exists in dict_manager.trackers", + new_start.segment_index + ))), + )?; + let copied_data = source_tracker.get_dictionary_copy(); + let default_value = source_tracker.get_default_value().cloned(); + + // Create new tracker with copied data + if let Some(default_value) = default_value { + dict_manager.trackers.insert( + new_end.segment_index, + DictTracker::new_default_dict(new_end, &default_value, Some(copied_data)), + ); + } else { + dict_manager.trackers.insert( + new_end.segment_index, + DictTracker::new_with_initial(new_end, copied_data), + ); + } + + Ok(()) + }, + ) +} + pub fn copy_dict_segment() -> Hint { Hint::new( String::from("copy_dict_segment"), diff --git a/crates/cairo-addons/src/vm/hint_definitions/hashdict.rs b/crates/cairo-addons/src/vm/hint_definitions/hashdict.rs index 78e652c2..55ba193a 100644 --- a/crates/cairo-addons/src/vm/hint_definitions/hashdict.rs +++ b/crates/cairo-addons/src/vm/hint_definitions/hashdict.rs @@ -255,10 +255,14 @@ pub fn hashdict_read_from_key() -> Hint { // keys. let simple_key = DictKey::Simple(hashed_key.into()); let preimage = - get_preimage_for_hashed_key(hashed_key, tracker).unwrap_or(&simple_key).clone(); + _get_preimage_for_hashed_key(hashed_key, tracker).unwrap_or(&simple_key).clone(); let value = tracker .get_value(&preimage) - .map_err(|_| HintError::CustomHint("No value found for preimage".into()))? + .map_err(|_| { + HintError::CustomHint( + format!("No value found for preimage {}", preimage).into(), + ) + })? .clone(); // Set the value @@ -286,7 +290,7 @@ pub fn get_preimage_for_key() -> Hint { let tracker = dict.get_tracker(dict_ptr)?; // Find matching preimage - let preimage = get_preimage_for_hashed_key(hashed_key, tracker)?; + let preimage = _get_preimage_for_hashed_key(hashed_key, tracker)?; // Write preimage data to memory let preimage_data_ptr = @@ -330,7 +334,7 @@ pub fn copy_hashdict_tracker_entry() -> Hint { // Find matching preimage from source tracker data let key_hash = get_integer_from_var_name("source_key", vm, ids_data, ap_tracking)?; - let preimage = get_preimage_for_hashed_key(key_hash, source_tracker)?.clone(); + let preimage = _get_preimage_for_hashed_key(key_hash, source_tracker)?.clone(); let value = source_tracker .get_value(&preimage) .map_err(|_| { @@ -367,7 +371,7 @@ fn build_compound_key( } /// Helper function to find a preimage in a tracker's dictionary given a hashed key -fn get_preimage_for_hashed_key( +fn _get_preimage_for_hashed_key( hashed_key: Felt252, tracker: &DictTracker, ) -> Result<&DictKey, HintError> { diff --git a/pyproject.toml b/pyproject.toml index 2575471d..e9b35207 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ dev-dependencies = [ "eth-account>=0.13.3", "eth-keys>=0.5.1", "eth-utils>=5.0.0", - "hypothesis>=6.123.17", + "hypothesis>=6.124.3", "ipykernel>=6.29.5", "pytest-xdist>=3.6.1", "pytest>=8.3.3", diff --git a/python/cairo-addons/src/cairo_addons/hints/hashdict.py b/python/cairo-addons/src/cairo_addons/hints/hashdict.py index f68f08e9..b763d561 100644 --- a/python/cairo-addons/src/cairo_addons/hints/hashdict.py +++ b/python/cairo-addons/src/cairo_addons/hints/hashdict.py @@ -22,8 +22,12 @@ def hashdict_read_from_key( from cairo_addons.hints.hashdict import _get_preimage_for_hashed_key dict_tracker = dict_manager.get_tracker(ids.dict_ptr_stop) - preimage = _get_preimage_for_hashed_key(ids.key, dict_tracker) or ids.key - ids.value = dict_tracker.data[preimage] + try: + preimage = _get_preimage_for_hashed_key(ids.key, dict_tracker) or ids.key + except Exception: + ids.value = dict_tracker.data.default_factory() + else: + ids.value = dict_tracker.data[preimage] @register_hint diff --git a/uv.lock b/uv.lock index e8979047..5a778fa2 100644 --- a/uv.lock +++ b/uv.lock @@ -1215,16 +1215,16 @@ wheels = [ [[package]] name = "hypothesis" -version = "6.123.17" +version = "6.124.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "sortedcontainers" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/15/a7/695b2bcb4e8438e1d4683efa6877fc95be293a11251471d4552d6dd08259/hypothesis-6.123.17.tar.gz", hash = "sha256:5850893975b4f08e893ddc10f1d468bc7e011d59703f70fe06a10161e426e602", size = 418572 } +sdist = { url = "https://files.pythonhosted.org/packages/4e/a1/2853435ebd5a5850a3d288ce5078e0226532907abf923be187b6791c0325/hypothesis-6.124.3.tar.gz", hash = "sha256:cfb17e98daa572b51a8f26b3e2ea5b0f76cdae750ac746e0f561a426a77828ba", size = 419200 } wheels = [ - { url = "https://files.pythonhosted.org/packages/11/8a/f1c166f048df4b314d0d38e9530b7af516a16160873d724bb416084d6990/hypothesis-6.123.17-py3-none-any.whl", hash = "sha256:5c949fb44935e32c61c64abfcc3975eec41f8205ade2223073ba074c1e078ead", size = 480880 }, + { url = "https://files.pythonhosted.org/packages/37/f8/785307397987d2623c99376a63150da92c39117aab192d46af7dc9017dbb/hypothesis-6.124.3-py3-none-any.whl", hash = "sha256:8f7a2c995e4d5f110b7a427ddeda323e05277730e2885fafc23da84dcbb0667e", size = 481959 }, ] [[package]] @@ -1654,7 +1654,7 @@ dev = [ { name = "eth-keys", specifier = ">=0.5.1" }, { name = "eth-utils", specifier = ">=5.0.0" }, { name = "gprof2dot", specifier = ">=2024.6.6" }, - { name = "hypothesis", specifier = ">=6.123.17" }, + { name = "hypothesis", specifier = ">=6.124.3" }, { name = "ipykernel", specifier = ">=6.29.5" }, { name = "jupyter", specifier = ">=1.1.1" }, { name = "polars", specifier = ">=1.18.0" },