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

Commit d3f4f03

Browse files
authored
fix: generate program_json directly from program string (#764)
* Fix gitignore not ignoring cairo2 dir * Add sample tests * Fix: generate `Value` from directly from `&str`
1 parent 66a978b commit d3f4f03

File tree

5 files changed

+162
-49
lines changed

5 files changed

+162
-49
lines changed

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ target/
3737

3838
# END AUTOGENERATED
3939

40-
cairo1/**/
41-
cairo2/**/
40+
cairo1
41+
cairo2
4242
starknet-venv/
4343
**/*.json
4444
cairo_programs/cairo_1_contracts/*.sierra

crates/starknet-contract-class/src/lib.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ use serde::Deserialize;
1515
use starknet_api::deprecated_contract_class::{ContractClassAbiEntry, EntryPoint};
1616
use std::{collections::HashMap, fs::File, io::BufReader, path::PathBuf};
1717

18+
// TODO: move this crate's functionality into SiR and remove the crate
19+
1820
pub type AbiType = Vec<ContractClassAbiEntry>;
1921

2022
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -131,15 +133,15 @@ fn convert_entry_points(
131133
entry_points: HashMap<starknet_api::deprecated_contract_class::EntryPointType, Vec<EntryPoint>>,
132134
) -> HashMap<EntryPointType, Vec<ContractEntryPoint>> {
133135
let mut converted_entries: HashMap<EntryPointType, Vec<ContractEntryPoint>> = HashMap::new();
134-
for (entry_type, vec) in entry_points {
136+
for (entry_type, entry_points) in entry_points {
135137
let en_type = entry_type.into();
136138

137-
let contracts_entry_points = vec
139+
let contracts_entry_points = entry_points
138140
.into_iter()
139141
.map(|e| {
140142
let selector = Felt252::from_bytes_be(e.selector.0.bytes());
141143
let offset = e.offset.0;
142-
ContractEntryPoint { selector, offset }
144+
ContractEntryPoint::new(selector, offset)
143145
})
144146
.collect::<Vec<ContractEntryPoint>>();
145147

src/services/api/contract_classes/deprecated_contract_class.rs

Lines changed: 146 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ use starknet_api::deprecated_contract_class::EntryPoint;
77
pub use starknet_contract_class::to_cairo_runner_program;
88
use starknet_contract_class::AbiType;
99
use starknet_contract_class::{ContractEntryPoint, EntryPointType};
10-
use std::{collections::HashMap, fs::File, io::BufReader, path::PathBuf};
10+
use std::collections::HashMap;
11+
use std::io::{BufReader, Read};
12+
use std::path::{Path, PathBuf};
1113

1214
// -------------------------------
1315
// Contract Class
@@ -33,12 +35,10 @@ impl ContractClass {
3335
abi: Option<AbiType>,
3436
) -> Result<Self, ContractClassError> {
3537
for entry_points in entry_points_by_type.values() {
36-
let mut index = 1;
37-
while let Some(entry_point) = entry_points.get(index) {
38-
if entry_point.selector() > entry_points[index - 1].selector() {
38+
for i in 1..entry_points.len() {
39+
if entry_points[i - 1].selector() > entry_points[i].selector() {
3940
return Err(ContractClassError::EntrypointError(entry_points.clone()));
4041
}
41-
index += 1;
4242
}
4343
}
4444

@@ -49,21 +49,29 @@ impl ContractClass {
4949
abi,
5050
})
5151
}
52+
53+
pub fn new_from_path<F>(path: F) -> Result<Self, ProgramError>
54+
where
55+
F: AsRef<Path>,
56+
{
57+
Self::try_from(std::fs::read_to_string(path)?.as_str())
58+
}
5259
}
5360

5461
// -------------------------------
5562
// From traits
5663
// -------------------------------
57-
impl TryFrom<starknet_api::deprecated_contract_class::ContractClass> for ContractClass {
64+
65+
impl TryFrom<&str> for ContractClass {
5866
type Error = ProgramError;
5967

60-
fn try_from(
61-
contract_class: starknet_api::deprecated_contract_class::ContractClass,
62-
) -> Result<Self, Self::Error> {
68+
fn try_from(s: &str) -> Result<Self, ProgramError> {
69+
let contract_class: starknet_api::deprecated_contract_class::ContractClass =
70+
serde_json::from_str(s)?;
6371
let program = to_cairo_runner_program(&contract_class.program)?;
6472
let entry_points_by_type =
6573
convert_entry_points(contract_class.clone().entry_points_by_type);
66-
let program_json = serde_json::to_value(&contract_class)?;
74+
let program_json = serde_json::from_str(s)?;
6775
Ok(ContractClass {
6876
program_json,
6977
program,
@@ -73,58 +81,52 @@ impl TryFrom<starknet_api::deprecated_contract_class::ContractClass> for Contrac
7381
}
7482
}
7583

76-
// -------------------
77-
// Helper Functions
78-
// -------------------
79-
80-
impl TryFrom<&str> for ContractClass {
84+
impl TryFrom<&Path> for ContractClass {
8185
type Error = ProgramError;
8286

83-
fn try_from(s: &str) -> Result<Self, ProgramError> {
84-
let raw_contract_class: starknet_api::deprecated_contract_class::ContractClass =
85-
serde_json::from_str(s)?;
86-
ContractClass::try_from(raw_contract_class)
87+
fn try_from(path: &Path) -> Result<Self, Self::Error> {
88+
Self::new_from_path(path)
8789
}
8890
}
8991

9092
impl TryFrom<PathBuf> for ContractClass {
9193
type Error = ProgramError;
9294

9395
fn try_from(path: PathBuf) -> Result<Self, Self::Error> {
94-
ContractClass::try_from(&path)
96+
Self::new_from_path(path)
9597
}
9698
}
9799

98100
impl TryFrom<&PathBuf> for ContractClass {
99101
type Error = ProgramError;
100102

101103
fn try_from(path: &PathBuf) -> Result<Self, Self::Error> {
102-
let file = File::open(path)?;
103-
let reader = BufReader::new(file);
104-
let raw_contract_class: starknet_api::deprecated_contract_class::ContractClass =
105-
serde_json::from_reader(reader)?;
106-
ContractClass::try_from(raw_contract_class)
104+
Self::new_from_path(path)
107105
}
108106
}
109107

110108
impl<T: std::io::Read> TryFrom<BufReader<T>> for ContractClass {
111109
type Error = ProgramError;
112110

113-
fn try_from(reader: BufReader<T>) -> Result<Self, Self::Error> {
114-
let raw_contract_class: starknet_api::deprecated_contract_class::ContractClass =
115-
serde_json::from_reader(reader)?;
116-
ContractClass::try_from(raw_contract_class)
111+
fn try_from(mut reader: BufReader<T>) -> Result<Self, Self::Error> {
112+
let mut s = String::new();
113+
reader.read_to_string(&mut s)?;
114+
Self::try_from(s.as_str())
117115
}
118116
}
119117

118+
// -------------------
119+
// Helper Functions
120+
// -------------------
121+
120122
fn convert_entry_points(
121123
entry_points: HashMap<starknet_api::deprecated_contract_class::EntryPointType, Vec<EntryPoint>>,
122124
) -> HashMap<EntryPointType, Vec<ContractEntryPoint>> {
123125
let mut converted_entries: HashMap<EntryPointType, Vec<ContractEntryPoint>> = HashMap::new();
124-
for (entry_type, vec) in entry_points {
126+
for (entry_type, entry_points) in entry_points {
125127
let en_type = entry_type.into();
126128

127-
let contracts_entry_points = vec
129+
let contracts_entry_points = entry_points
128130
.into_iter()
129131
.map(|e| {
130132
let selector = Felt252::from_bytes_be(e.selector.0.bytes());
@@ -141,20 +143,20 @@ fn convert_entry_points(
141143

142144
#[cfg(test)]
143145
mod tests {
146+
use crate::core::contract_address::compute_deprecated_class_hash;
147+
144148
use super::*;
145149
use cairo_vm::{
146150
felt::{felt_str, PRIME_STR},
147151
serde::deserialize_program::BuiltinName,
148152
};
149-
use std::io::Read;
153+
use starknet_contract_class::ParsedContractClass;
154+
use std::{fs, str::FromStr};
150155

151156
#[test]
152157
fn deserialize_contract_class() {
153-
let mut serialized = String::new();
154-
155158
// This specific contract compiles with --no_debug_info
156-
File::open(PathBuf::from("starknet_programs/AccountPreset.json"))
157-
.and_then(|mut f| f.read_to_string(&mut serialized))
159+
let serialized = fs::read_to_string("starknet_programs/AccountPreset.json")
158160
.expect("should be able to read file");
159161

160162
let res = ContractClass::try_from(serialized.as_str());
@@ -201,4 +203,112 @@ mod tests {
201203
)]
202204
);
203205
}
206+
207+
#[test]
208+
fn test_contract_class_new_equals_raw_instantiation() {
209+
let contract_str = fs::read_to_string("starknet_programs/raw_contract_classes/0x4479c3b883b34f1eafa5065418225d78a11ee7957c371e1b285e4b77afc6dad.json").unwrap();
210+
211+
let parsed_contract_class = ParsedContractClass::try_from(contract_str.as_str()).unwrap();
212+
let contract_class = ContractClass {
213+
program_json: serde_json::Value::from_str(&contract_str).unwrap(),
214+
program: parsed_contract_class.program.clone(),
215+
entry_points_by_type: parsed_contract_class.entry_points_by_type.clone(),
216+
abi: parsed_contract_class.abi.clone(),
217+
};
218+
219+
let contract_class_new = ContractClass::new(
220+
serde_json::Value::from_str(&contract_str).unwrap(),
221+
parsed_contract_class.program,
222+
parsed_contract_class.entry_points_by_type,
223+
parsed_contract_class.abi,
224+
)
225+
.unwrap();
226+
227+
assert_eq!(contract_class, contract_class_new);
228+
}
229+
230+
#[test]
231+
fn test_compute_class_hash_0x4479c3b883b34f1eafa5065418225d78a11ee7957c371e1b285e4b77afc6dad_try_from(
232+
) {
233+
let contract_str = fs::read_to_string("starknet_programs/raw_contract_classes/0x4479c3b883b34f1eafa5065418225d78a11ee7957c371e1b285e4b77afc6dad.json").unwrap();
234+
235+
let contract_class = ContractClass::try_from(contract_str.as_str()).unwrap();
236+
237+
assert_eq!(
238+
compute_deprecated_class_hash(&contract_class).unwrap(),
239+
felt_str!(
240+
"4479c3b883b34f1eafa5065418225d78a11ee7957c371e1b285e4b77afc6dad",
241+
16
242+
)
243+
);
244+
}
245+
246+
#[test]
247+
fn test_new_equals_try_from() {
248+
let contract_str = fs::read_to_string("starknet_programs/raw_contract_classes/0x4479c3b883b34f1eafa5065418225d78a11ee7957c371e1b285e4b77afc6dad.json").unwrap();
249+
250+
let parsed_contract_class = ParsedContractClass::try_from(contract_str.as_str()).unwrap();
251+
252+
let contract_class_new = ContractClass::new(
253+
serde_json::Value::from_str(&contract_str).unwrap(),
254+
parsed_contract_class.program,
255+
parsed_contract_class.entry_points_by_type,
256+
parsed_contract_class.abi,
257+
)
258+
.unwrap();
259+
260+
let contract_class = ContractClass::try_from(contract_str.as_str()).unwrap();
261+
262+
assert_eq!(contract_class.abi, contract_class_new.abi);
263+
assert_eq!(contract_class.program, contract_class_new.program);
264+
assert_eq!(contract_class.program_json, contract_class_new.program_json);
265+
assert_eq!(
266+
contract_class.entry_points_by_type,
267+
contract_class_new.entry_points_by_type
268+
);
269+
}
270+
271+
#[test]
272+
fn test_compute_class_hash_0x4479c3b883b34f1eafa5065418225d78a11ee7957c371e1b285e4b77afc6dad_new(
273+
) {
274+
let contract_str = fs::read_to_string("starknet_programs/raw_contract_classes/0x4479c3b883b34f1eafa5065418225d78a11ee7957c371e1b285e4b77afc6dad.json").unwrap();
275+
276+
let parsed_contract_class = ParsedContractClass::try_from(contract_str.as_str()).unwrap();
277+
let contract_class = ContractClass::new(
278+
serde_json::Value::from_str(&contract_str).unwrap(),
279+
parsed_contract_class.program,
280+
parsed_contract_class.entry_points_by_type,
281+
parsed_contract_class.abi,
282+
)
283+
.unwrap();
284+
285+
assert_eq!(
286+
compute_deprecated_class_hash(&contract_class).unwrap(),
287+
felt_str!(
288+
"4479c3b883b34f1eafa5065418225d78a11ee7957c371e1b285e4b77afc6dad",
289+
16
290+
)
291+
);
292+
}
293+
294+
#[test]
295+
fn test_compute_class_hash_0x4479c3b883b34f1eafa5065418225d78a11ee7957c371e1b285e4b77afc6dad() {
296+
let contract_str = fs::read_to_string("starknet_programs/raw_contract_classes/0x4479c3b883b34f1eafa5065418225d78a11ee7957c371e1b285e4b77afc6dad.json").unwrap();
297+
298+
let parsed_contract_class = ParsedContractClass::try_from(contract_str.as_str()).unwrap();
299+
let contract_class = ContractClass {
300+
program_json: serde_json::Value::from_str(&contract_str).unwrap(),
301+
program: parsed_contract_class.program,
302+
entry_points_by_type: parsed_contract_class.entry_points_by_type,
303+
abi: parsed_contract_class.abi,
304+
};
305+
306+
assert_eq!(
307+
compute_deprecated_class_hash(&contract_class).unwrap(),
308+
felt_str!(
309+
"4479c3b883b34f1eafa5065418225d78a11ee7957c371e1b285e4b77afc6dad",
310+
16
311+
)
312+
);
313+
}
204314
}

starknet_programs/raw_contract_classes/0x4479c3b883b34f1eafa5065418225d78a11ee7957c371e1b285e4b77afc6dad.json

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

tests/complex_contracts/amm_contracts/amm_proxy.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -427,8 +427,8 @@ fn amm_proxy_get_account_token_balance() {
427427
retdata: [200.into()].to_vec(),
428428
storage_read_values: [200.into()].to_vec(),
429429
execution_resources: ExecutionResources {
430-
n_steps: 94,
431-
n_memory_holes: 10,
430+
n_steps: 92,
431+
n_memory_holes: 11,
432432
builtin_instance_counter: HashMap::from([
433433
("pedersen_builtin".to_string(), 2),
434434
("range_check_builtin".to_string(), 3),
@@ -448,8 +448,8 @@ fn amm_proxy_get_account_token_balance() {
448448
calldata: calldata.clone(),
449449
retdata: [200.into()].to_vec(),
450450
execution_resources: ExecutionResources {
451-
n_steps: 153,
452-
n_memory_holes: 10,
451+
n_steps: 151,
452+
n_memory_holes: 11,
453453
builtin_instance_counter: HashMap::from([
454454
("pedersen_builtin".to_string(), 2),
455455
("range_check_builtin".to_string(), 3),
@@ -561,8 +561,8 @@ fn amm_proxy_swap() {
561561
storage_read_values: [100.into(), 1000.into(), 1000.into(), 100.into(), 200.into()]
562562
.to_vec(),
563563
execution_resources: ExecutionResources {
564-
n_steps: 824,
565-
n_memory_holes: 93,
564+
n_steps: 826,
565+
n_memory_holes: 92,
566566
builtin_instance_counter: HashMap::from([
567567
("pedersen_builtin".to_string(), 14),
568568
("range_check_builtin".to_string(), 41),
@@ -582,8 +582,8 @@ fn amm_proxy_swap() {
582582
calldata: calldata.clone(),
583583
retdata: expected_result,
584584
execution_resources: ExecutionResources {
585-
n_steps: 883,
586-
n_memory_holes: 93,
585+
n_steps: 885,
586+
n_memory_holes: 92,
587587
builtin_instance_counter: HashMap::from([
588588
("pedersen_builtin".to_string(), 14),
589589
("range_check_builtin".to_string(), 41),

0 commit comments

Comments
 (0)