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

Commit fe0aed3

Browse files
Add casm class hash
1 parent dce8b59 commit fe0aed3

File tree

3 files changed

+194
-2
lines changed

3 files changed

+194
-2
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: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
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 mut builtins_flatted = Vec::new();
28+
entry_point.builtins.iter().for_each(|builtin| {
29+
builtins_flatted.push(FieldElement::from_byte_slice_be(builtin.as_bytes()).unwrap());
30+
});
31+
entry_points_flatted.push(poseidon_hash_many(&builtins_flatted));
32+
}
33+
34+
Ok(poseidon_hash_many(&entry_points_flatted))
35+
}
36+
37+
pub fn compute_casm_class_hash(
38+
contract_class: &CasmContractClass,
39+
) -> Result<Felt252, ContractAddressError> {
40+
let api_version =
41+
FieldElement::from_bytes_be(&Felt252::from_bytes_be(CONTRACT_CLASS_VERSION).to_be_bytes())
42+
.map_err(|_err| {
43+
ContractAddressError::Cast("Felt252".to_string(), "FieldElement".to_string())
44+
})?;
45+
46+
// Entrypoints by type, hashed.
47+
let external_functions =
48+
get_contract_entry_points_hashed(contract_class, &EntryPointType::External)?;
49+
let l1_handlers = get_contract_entry_points_hashed(contract_class, &EntryPointType::L1Handler)?;
50+
let constructors =
51+
get_contract_entry_points_hashed(contract_class, &EntryPointType::Constructor)?;
52+
53+
let mut casm_program_vector = Vec::with_capacity(contract_class.bytecode.len());
54+
for number in &contract_class.bytecode {
55+
casm_program_vector.push(
56+
FieldElement::from_bytes_be(&Felt252::from(number.value.clone()).to_be_bytes())
57+
.map_err(|_err| {
58+
ContractAddressError::Cast("Felt252".to_string(), "FieldElement".to_string())
59+
})?,
60+
);
61+
}
62+
63+
// Hash casm program.
64+
let casm_program_ptr = poseidon_hash_many(&casm_program_vector);
65+
66+
let flatted_contract_class = vec![
67+
api_version,
68+
external_functions,
69+
l1_handlers,
70+
constructors,
71+
casm_program_ptr,
72+
];
73+
74+
Ok(Felt252::from_bytes_be(
75+
&poseidon_hash_many(&flatted_contract_class).to_bytes_be(),
76+
))
77+
}
78+
79+
fn get_contract_entry_points(
80+
contract_class: &CasmContractClass,
81+
entry_point_type: &EntryPointType,
82+
) -> Vec<CasmContractEntryPoint> {
83+
match entry_point_type {
84+
EntryPointType::Constructor => contract_class.entry_points_by_type.constructor.clone(),
85+
EntryPointType::External => contract_class.entry_points_by_type.external.clone(),
86+
EntryPointType::L1Handler => contract_class.entry_points_by_type.l1_handler.clone(),
87+
}
88+
}
89+
90+
#[cfg(test)]
91+
mod tests {
92+
/// THE VALUES IN THIS TESTS WERE TAKEN FROM THE CONTRACTS IN THE STARKNET_PROGRAMS FOLDER.
93+
/// 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)
94+
/// TO GET THE RIGHT HASH VALUE.
95+
use std::{fs::File, io::BufReader};
96+
97+
use super::*;
98+
use cairo_vm::felt::felt_str;
99+
use coverage_helper::test;
100+
101+
#[test]
102+
fn test_compute_casm_class_hash_contract_a() {
103+
// Open the file in read-only mode with buffer.
104+
let file = File::open("starknet_programs/cairo1/contract_a.casm").unwrap();
105+
let reader = BufReader::new(file);
106+
107+
// Read the JSON contents of the file as an instance of `User`.
108+
let contract_class: CasmContractClass = serde_json::from_reader(reader).unwrap();
109+
110+
assert_eq!(
111+
compute_casm_class_hash(&contract_class).unwrap(),
112+
felt_str!(
113+
"3a4f00bf75ba3b9230a94f104c7a4605a1901c4bd475beb59eeeeb7aceb9795",
114+
16
115+
)
116+
);
117+
}
118+
119+
#[test]
120+
fn test_compute_casm_class_hash_deploy() {
121+
// Open the file in read-only mode with buffer.
122+
let file = File::open("starknet_programs/cairo1/deploy.casm").unwrap();
123+
let reader = BufReader::new(file);
124+
125+
// Read the JSON contents of the file as an instance of `User`.
126+
let contract_class: CasmContractClass = serde_json::from_reader(reader).unwrap();
127+
128+
assert_eq!(
129+
compute_casm_class_hash(&contract_class).unwrap(),
130+
felt_str!(
131+
"3bd56f1c3c1c595ac2ee6d07bdedc027d09df56235e20374649f0b3535c1f15",
132+
16
133+
)
134+
);
135+
}
136+
137+
#[test]
138+
fn test_compute_casm_class_hash_fibonacci() {
139+
// Open the file in read-only mode with buffer.
140+
let file = File::open("starknet_programs/cairo1/fibonacci.casm").unwrap();
141+
let reader = BufReader::new(file);
142+
143+
// Read the JSON contents of the file as an instance of `User`.
144+
let contract_class: CasmContractClass = serde_json::from_reader(reader).unwrap();
145+
146+
assert_eq!(
147+
compute_casm_class_hash(&contract_class).unwrap(),
148+
felt_str!(
149+
"44f12e6e59232e9909d7428b913b3cc8d9059458e5027740a3ccdbdc4b1ffd2",
150+
16
151+
)
152+
);
153+
}
154+
155+
#[test]
156+
fn test_compute_casm_class_hash_factorial() {
157+
// Open the file in read-only mode with buffer.
158+
let file = File::open("starknet_programs/cairo1/factorial.casm").unwrap();
159+
let reader = BufReader::new(file);
160+
161+
// Read the JSON contents of the file as an instance of `User`.
162+
let contract_class: CasmContractClass = serde_json::from_reader(reader).unwrap();
163+
164+
assert_eq!(
165+
compute_casm_class_hash(&contract_class).unwrap(),
166+
felt_str!(
167+
"189a9b8b852aedbb225aa28dce9cfc3133145dd623e2d2ca5e962b7d4e61e15",
168+
16
169+
)
170+
);
171+
}
172+
173+
#[test]
174+
fn test_compute_casm_class_hash_emit_event() {
175+
// Open the file in read-only mode with buffer.
176+
let file = File::open("starknet_programs/cairo1/emit_event.casm").unwrap();
177+
let reader = BufReader::new(file);
178+
179+
// Read the JSON contents of the file as an instance of `User`.
180+
let contract_class: CasmContractClass = serde_json::from_reader(reader).unwrap();
181+
182+
assert_eq!(
183+
compute_casm_class_hash(&contract_class).unwrap(),
184+
felt_str!(
185+
"3335fe731ceda1116eda8bbc2e282953ce54618309ad474189e627c59328fff",
186+
16
187+
)
188+
);
189+
}
190+
}

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;

0 commit comments

Comments
 (0)