Skip to content
This repository was archived by the owner on Jul 22, 2024. It is now read-only.

Commit a015b7a

Browse files
author
fannyguthmann
committed
Merge branch 'main' into change_error_type_hash_utils
2 parents 6dd2f8b + 20206ef commit a015b7a

File tree

5 files changed

+390
-38
lines changed

5 files changed

+390
-38
lines changed

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ $(CAIRO_1_CONTRACTS_TEST_DIR)/%.sierra: $(CAIRO_1_CONTRACTS_TEST_DIR)/%.cairo
7070
$(STARKNET_COMPILE_CAIRO_1) --allowed-libfuncs-list-name experimental_v0.1.0 $< $@
7171

7272
$(CAIRO_1_CONTRACTS_TEST_DIR)/%.casm: $(CAIRO_1_CONTRACTS_TEST_DIR)/%.sierra
73-
$(STARKNET_SIERRA_COMPILE_CAIRO_1) --allowed-libfuncs-list-name experimental_v0.1.0 $< $@
73+
$(STARKNET_SIERRA_COMPILE_CAIRO_1) --allowed-libfuncs-list-name experimental_v0.1.0 --add-pythonic-hints $< $@
7474

7575

7676
cairo-repo-1-dir = cairo1
@@ -103,7 +103,7 @@ $(CAIRO_2_CONTRACTS_TEST_DIR)/%.sierra: $(CAIRO_2_CONTRACTS_TEST_DIR)/%.cairo
103103
$(STARKNET_COMPILE_CAIRO_2) $< $@
104104

105105
$(CAIRO_2_CONTRACTS_TEST_DIR)/%.casm: $(CAIRO_2_CONTRACTS_TEST_DIR)/%.sierra
106-
$(STARKNET_SIERRA_COMPILE_CAIRO_2) $< $@
106+
$(STARKNET_SIERRA_COMPILE_CAIRO_2) --add-pythonic-hints $< $@
107107

108108

109109
cairo-repo-2-dir = cairo2
Lines changed: 268 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
use crate::core::errors::contract_address_errors::ContractAddressError;
2+
use crate::services::api::contract_classes::deprecated_contract_class::EntryPointType;
3+
use cairo_lang_starknet::casm_contract_class::{CasmContractClass, CasmContractEntryPoint};
4+
use cairo_vm::felt::Felt252;
5+
use starknet_crypto::{poseidon_hash_many, FieldElement};
6+
7+
const CONTRACT_CLASS_VERSION: &[u8] = b"COMPILED_CLASS_V1";
8+
9+
fn get_contract_entry_points_hashed(
10+
contract_class: &CasmContractClass,
11+
entry_point_type: &EntryPointType,
12+
) -> Result<FieldElement, ContractAddressError> {
13+
let contract_entry_points = get_contract_entry_points(contract_class, entry_point_type);
14+
15+
// for each entry_point, we need to store 3 FieldElements: [selector, offset, poseidon_hash_many(builtin_list)].
16+
let mut entry_points_flatted = Vec::with_capacity(contract_entry_points.len() * 3);
17+
18+
for entry_point in contract_entry_points {
19+
entry_points_flatted.push(
20+
// fix this conversion later
21+
FieldElement::from_bytes_be(&Felt252::from(entry_point.selector).to_be_bytes())
22+
.map_err(|_err| {
23+
ContractAddressError::Cast("Felt252".to_string(), "FieldElement".to_string())
24+
})?,
25+
);
26+
entry_points_flatted.push(FieldElement::from(entry_point.offset));
27+
let builtins_flatted = entry_point
28+
.builtins
29+
.iter()
30+
.map(|builtin| FieldElement::from_byte_slice_be(builtin.as_bytes()))
31+
.collect::<Result<Vec<FieldElement>, _>>()
32+
.map_err(|_err| {
33+
ContractAddressError::Cast("Felt252".to_string(), "FieldElement".to_string())
34+
})?;
35+
entry_points_flatted.push(poseidon_hash_many(&builtins_flatted));
36+
}
37+
38+
Ok(poseidon_hash_many(&entry_points_flatted))
39+
}
40+
41+
pub fn compute_casm_class_hash(
42+
contract_class: &CasmContractClass,
43+
) -> Result<Felt252, ContractAddressError> {
44+
let api_version =
45+
FieldElement::from_bytes_be(&Felt252::from_bytes_be(CONTRACT_CLASS_VERSION).to_be_bytes())
46+
.map_err(|_err| {
47+
ContractAddressError::Cast("Felt252".to_string(), "FieldElement".to_string())
48+
})?;
49+
50+
// Entrypoints by type, hashed.
51+
let external_functions =
52+
get_contract_entry_points_hashed(contract_class, &EntryPointType::External)?;
53+
let l1_handlers = get_contract_entry_points_hashed(contract_class, &EntryPointType::L1Handler)?;
54+
let constructors =
55+
get_contract_entry_points_hashed(contract_class, &EntryPointType::Constructor)?;
56+
57+
let mut casm_program_vector = Vec::with_capacity(contract_class.bytecode.len());
58+
for number in &contract_class.bytecode {
59+
casm_program_vector.push(
60+
FieldElement::from_bytes_be(&Felt252::from(number.value.clone()).to_be_bytes())
61+
.map_err(|_err| {
62+
ContractAddressError::Cast("Felt252".to_string(), "FieldElement".to_string())
63+
})?,
64+
);
65+
}
66+
67+
// Hash casm program.
68+
let casm_program_ptr = poseidon_hash_many(&casm_program_vector);
69+
70+
let flatted_contract_class = vec![
71+
api_version,
72+
external_functions,
73+
l1_handlers,
74+
constructors,
75+
casm_program_ptr,
76+
];
77+
78+
Ok(Felt252::from_bytes_be(
79+
&poseidon_hash_many(&flatted_contract_class).to_bytes_be(),
80+
))
81+
}
82+
83+
fn get_contract_entry_points(
84+
contract_class: &CasmContractClass,
85+
entry_point_type: &EntryPointType,
86+
) -> Vec<CasmContractEntryPoint> {
87+
match entry_point_type {
88+
EntryPointType::Constructor => contract_class.entry_points_by_type.constructor.clone(),
89+
EntryPointType::External => contract_class.entry_points_by_type.external.clone(),
90+
EntryPointType::L1Handler => contract_class.entry_points_by_type.l1_handler.clone(),
91+
}
92+
}
93+
94+
#[cfg(test)]
95+
mod tests {
96+
/// THE VALUES IN THIS TESTS WERE TAKEN FROM THE CONTRACTS IN THE STARKNET_PROGRAMS FOLDER.
97+
/// AND WE USE A [TOOL FOUND IN CAIRO-LANG](https://github.com/starkware-libs/cairo-lang/blob/master/src/starkware/starknet/cli/compiled_class_hash.py)
98+
/// TO GET THE RIGHT HASH VALUE.
99+
use std::{fs::File, io::BufReader};
100+
101+
use super::*;
102+
use cairo_vm::felt::felt_str;
103+
use coverage_helper::test;
104+
105+
#[test]
106+
fn test_compute_casm_class_hash_contract_a() {
107+
// Open the file in read-only mode with buffer.
108+
let file;
109+
let expected_result;
110+
#[cfg(not(feature = "cairo_1_tests"))]
111+
{
112+
file = File::open("starknet_programs/cairo2/contract_a.casm").unwrap();
113+
expected_result = felt_str!(
114+
"321aadcf42b0a4ad905616598d16c42fa9b87c812dc398e49b57bf77930629f",
115+
16
116+
);
117+
}
118+
#[cfg(feature = "cairo_1_tests")]
119+
{
120+
file = File::open("starknet_programs/cairo1/contract_a.casm").unwrap();
121+
expected_result = felt_str!(
122+
"3a4f00bf75ba3b9230a94f104c7a4605a1901c4bd475beb59eeeeb7aceb9795",
123+
16
124+
);
125+
}
126+
let reader = BufReader::new(file);
127+
128+
// Read the JSON contents of the file as an instance of `CasmContractClass`.
129+
let contract_class: CasmContractClass = serde_json::from_reader(reader).unwrap();
130+
131+
assert_eq!(
132+
compute_casm_class_hash(&contract_class).unwrap(),
133+
expected_result
134+
);
135+
}
136+
137+
#[test]
138+
fn test_compute_casm_class_hash_deploy() {
139+
// Open the file in read-only mode with buffer.
140+
let file;
141+
let expected_result;
142+
#[cfg(not(feature = "cairo_1_tests"))]
143+
{
144+
file = File::open("starknet_programs/cairo2/deploy.casm").unwrap();
145+
expected_result = felt_str!(
146+
"53ad3bfb13f39cf1a9940108be4f9c6a8d9cc48a59d5f9b3c73432f877f8cf0",
147+
16
148+
);
149+
}
150+
151+
#[cfg(feature = "cairo_1_tests")]
152+
{
153+
file = File::open("starknet_programs/cairo1/deploy.casm").unwrap();
154+
expected_result = felt_str!(
155+
"3bd56f1c3c1c595ac2ee6d07bdedc027d09df56235e20374649f0b3535c1f15",
156+
16
157+
);
158+
}
159+
let reader = BufReader::new(file);
160+
161+
// Read the JSON contents of the file as an instance of `CasmContractClass`.
162+
let contract_class: CasmContractClass = serde_json::from_reader(reader).unwrap();
163+
164+
assert_eq!(
165+
compute_casm_class_hash(&contract_class).unwrap(),
166+
expected_result
167+
);
168+
}
169+
170+
#[test]
171+
fn test_compute_casm_class_hash_fibonacci() {
172+
// Open the file in read-only mode with buffer.
173+
let file;
174+
let expected_result;
175+
#[cfg(not(feature = "cairo_1_tests"))]
176+
{
177+
file = File::open("starknet_programs/cairo2/fibonacci.casm").unwrap();
178+
expected_result = felt_str!(
179+
"6638ce6c9bf336d1781a388668fa2206d928df5d1fa6b92e4cb41004c7e3f89",
180+
16
181+
);
182+
}
183+
184+
#[cfg(feature = "cairo_1_tests")]
185+
{
186+
file = File::open("starknet_programs/cairo1/fibonacci.casm").unwrap();
187+
expected_result = felt_str!(
188+
"44f12e6e59232e9909d7428b913b3cc8d9059458e5027740a3ccdbdc4b1ffd2",
189+
16
190+
);
191+
}
192+
let reader = BufReader::new(file);
193+
194+
// Read the JSON contents of the file as an instance of `CasmContractClass`.
195+
let contract_class: CasmContractClass = serde_json::from_reader(reader).unwrap();
196+
197+
assert_eq!(
198+
compute_casm_class_hash(&contract_class).unwrap(),
199+
expected_result
200+
);
201+
}
202+
203+
#[test]
204+
fn test_compute_casm_class_hash_factorial() {
205+
// Open the file in read-only mode with buffer.
206+
let file;
207+
let expected_result;
208+
#[cfg(not(feature = "cairo_1_tests"))]
209+
{
210+
file = File::open("starknet_programs/cairo2/factorial.casm").unwrap();
211+
expected_result = felt_str!(
212+
"7c48d040ceb3183837a0aff2adf33d879f790e202eb2c4b8622005c12252641",
213+
16
214+
);
215+
}
216+
217+
#[cfg(feature = "cairo_1_tests")]
218+
{
219+
file = File::open("starknet_programs/cairo1/factorial.casm").unwrap();
220+
expected_result = felt_str!(
221+
"189a9b8b852aedbb225aa28dce9cfc3133145dd623e2d2ca5e962b7d4e61e15",
222+
16
223+
);
224+
}
225+
let reader = BufReader::new(file);
226+
227+
// Read the JSON contents of the file as an instance of `CasmContractClass`.
228+
let contract_class: CasmContractClass = serde_json::from_reader(reader).unwrap();
229+
230+
assert_eq!(
231+
compute_casm_class_hash(&contract_class).unwrap(),
232+
expected_result
233+
);
234+
}
235+
236+
#[test]
237+
fn test_compute_casm_class_hash_emit_event() {
238+
// Open the file in read-only mode with buffer.
239+
let file;
240+
let expected_result;
241+
#[cfg(not(feature = "cairo_1_tests"))]
242+
{
243+
file = File::open("starknet_programs/cairo2/emit_event.casm").unwrap();
244+
expected_result = felt_str!(
245+
"3010533bd60cb0e70ac1bf776e171713f0e5229a084989d3894c171c160ace2",
246+
16
247+
);
248+
}
249+
250+
#[cfg(feature = "cairo_1_tests")]
251+
{
252+
file = File::open("starknet_programs/cairo1/emit_event.casm").unwrap();
253+
expected_result = felt_str!(
254+
"3335fe731ceda1116eda8bbc2e282953ce54618309ad474189e627c59328fff",
255+
16
256+
);
257+
}
258+
let reader = BufReader::new(file);
259+
260+
// Read the JSON contents of the file as an instance of `CasmContractClass`.
261+
let contract_class: CasmContractClass = serde_json::from_reader(reader).unwrap();
262+
263+
assert_eq!(
264+
compute_casm_class_hash(&contract_class).unwrap(),
265+
expected_result
266+
);
267+
}
268+
}

src/core/contract_address/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1+
mod casm_contract_address;
12
mod deprecated_contract_address;
23
mod sierra_contract_address;
34

5+
pub use casm_contract_address::compute_casm_class_hash;
46
pub use deprecated_contract_address::compute_deprecated_class_hash;
57
pub(crate) use deprecated_contract_address::compute_hinted_class_hash;
68
pub use sierra_contract_address::compute_sierra_class_hash;

src/state/in_memory_state_reader.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ use cairo_vm::felt::Felt252;
1414
use getset::{Getters, MutGetters};
1515
use std::collections::HashMap;
1616

17+
/// A [StateReader] that holds all the data in memory.
18+
///
19+
/// This implementation is used for testing and debugging.
20+
/// It uses HashMaps to store the data.
1721
#[derive(Debug, MutGetters, Getters, PartialEq, Clone, Default)]
1822
pub struct InMemoryStateReader {
1923
#[getset(get_mut = "pub")]
@@ -31,6 +35,15 @@ pub struct InMemoryStateReader {
3135
}
3236

3337
impl InMemoryStateReader {
38+
/// Creates a new InMemoryStateReader.
39+
///
40+
/// # Parameters
41+
/// - `address_to_class_hash` - A HashMap from contract addresses to their class hashes.
42+
/// - `address_to_nonce` - A HashMap from contract addresses to their nonces.
43+
/// - `address_to_storage` - A HashMap from storage entries to their values.
44+
/// - `class_hash_to_contract_class` - A HashMap from class hashes to their contract classes.
45+
/// - `casm_contract_classes` - A [CasmClassCache].
46+
/// - `class_hash_to_compiled_class_hash` - A HashMap from class hashes to their compiled class hashes.
3447
pub fn new(
3548
address_to_class_hash: HashMap<Address, ClassHash>,
3649
address_to_nonce: HashMap<Address, Felt252>,
@@ -49,6 +62,18 @@ impl InMemoryStateReader {
4962
}
5063
}
5164

65+
/// Gets the [CompiledClass] with the given [CompiledClassHash].
66+
///
67+
/// It looks for the [CompiledClass] both in the cache and the storage.
68+
///
69+
/// # Parameters
70+
/// - `compiled_class_hash` - The [CompiledClassHash] of the [CompiledClass] to get.
71+
///
72+
/// # Errors
73+
/// - [StateError::NoneCompiledClass] - If the [CompiledClass] is not found.
74+
///
75+
/// # Returns
76+
/// The [CompiledClass] with the given [CompiledClassHash].
5277
fn get_compiled_class(
5378
&mut self,
5479
compiled_class_hash: &CompiledClassHash,

0 commit comments

Comments
 (0)