1use std::{
10 collections::{BTreeMap, HashMap},
11 fmt,
12 sync::Arc,
13};
14
15use crate::{types::builtin_name::BuiltinName, utils::CAIRO_PRIME};
16
17use crate::utils::PRIME_STR;
18use crate::Felt252;
19use crate::{
20 serde::deserialize_utils,
21 types::{
22 errors::program_errors::ProgramError,
23 instruction::Register,
24 program::{HintsCollection, Program, SharedProgramData},
25 relocatable::MaybeRelocatable,
26 },
27};
28use num_bigint::BigInt;
29use num_traits::{float::FloatCore, Num};
30use serde::{de, de::MapAccess, de::SeqAccess, Deserialize, Deserializer, Serialize};
31use serde_json::Number;
32
33#[cfg(feature = "test_utils")]
34use arbitrary::{self, Arbitrary, Unstructured};
35
36#[cfg_attr(feature = "test_utils", derive(Arbitrary, Clone))]
37#[derive(Deserialize, Debug)]
38pub struct ProgramJson {
39 pub prime: String,
40 pub builtins: Vec<BuiltinName>,
41 #[serde(deserialize_with = "deserialize_array_of_bigint_hex")]
42 pub data: Vec<MaybeRelocatable>,
43 pub identifiers: HashMap<String, Identifier>,
44 pub hints: BTreeMap<usize, Vec<HintParams>>,
45 pub reference_manager: ReferenceManager,
46 #[serde(default)]
47 pub attributes: Vec<Attribute>,
48 pub debug_info: Option<DebugInfo>,
49}
50
51#[cfg_attr(feature = "test_utils", derive(Arbitrary))]
52#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
53pub struct HintParams {
54 pub code: String,
55 pub accessible_scopes: Vec<String>,
56 pub flow_tracking_data: FlowTrackingData,
57}
58
59#[cfg_attr(feature = "test_utils", derive(Arbitrary))]
60#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
61pub struct FlowTrackingData {
62 pub ap_tracking: ApTracking,
63 #[serde(deserialize_with = "deserialize_map_to_string_and_usize_hashmap")]
64 pub reference_ids: HashMap<String, usize>,
65}
66
67#[cfg_attr(feature = "test_utils", derive(Arbitrary))]
68#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
69pub struct ApTracking {
70 pub group: usize,
71 pub offset: usize,
72}
73
74impl ApTracking {
75 pub fn new() -> ApTracking {
76 ApTracking {
77 group: 0,
78 offset: 0,
79 }
80 }
81}
82
83impl Default for ApTracking {
84 fn default() -> Self {
85 Self::new()
86 }
87}
88
89#[cfg_attr(feature = "test_utils", derive(Arbitrary))]
90#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
91pub struct Identifier {
92 pub pc: Option<usize>,
93 #[serde(rename(deserialize = "type"))]
94 pub type_: Option<String>,
95 #[serde(default)]
96 #[serde(deserialize_with = "felt_from_number")]
97 pub value: Option<Felt252>,
98
99 pub full_name: Option<String>,
100 pub members: Option<HashMap<String, Member>>,
101 pub cairo_type: Option<String>,
102 pub size: Option<usize>,
103 pub destination: Option<String>,
105}
106
107#[cfg_attr(feature = "test_utils", derive(Arbitrary))]
108#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
109pub struct Member {
110 pub cairo_type: String,
111 pub offset: usize,
112}
113
114#[cfg_attr(feature = "test_utils", derive(Arbitrary))]
115#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
116pub struct Attribute {
117 pub name: String,
118 pub start_pc: usize,
119 pub end_pc: usize,
120 pub value: String,
121 #[cfg_attr(feature = "test_utils", serde(skip_serializing_if = "Option::is_none"))]
122 pub flow_tracking_data: Option<FlowTrackingData>,
123}
124
125#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
126pub struct Location {
127 pub end_line: u32,
128 pub end_col: u32,
129 pub input_file: InputFile,
130 pub parent_location: Option<(Box<Location>, String)>,
131 pub start_line: u32,
132 pub start_col: u32,
133}
134
135#[cfg(feature = "test_utils")]
136impl<'a> Arbitrary<'a> for Location {
137 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
138 arbitrary_parent_location(u, 20)
139 }
140}
141
142#[cfg(feature = "test_utils")]
143fn arbitrary_parent_location(u: &mut Unstructured, depth: u8) -> arbitrary::Result<Location> {
144 let parent_location = if depth > 0 {
145 Some((
146 Box::new(arbitrary_parent_location(u, depth - 1)?),
147 String::arbitrary(u)?,
148 ))
149 } else {
150 None
151 };
152 Ok(Location {
153 end_line: u32::arbitrary(u)?,
154 end_col: u32::arbitrary(u)?,
155 input_file: InputFile::arbitrary(u)?,
156 parent_location,
157 start_line: u32::arbitrary(u)?,
158 start_col: u32::arbitrary(u)?,
159 })
160}
161
162#[cfg_attr(feature = "test_utils", derive(Arbitrary, Clone))]
163#[derive(Serialize, Deserialize, Debug, PartialEq, Eq)]
164pub struct DebugInfo {
165 pub(crate) instruction_locations: HashMap<usize, InstructionLocation>,
166}
167
168impl DebugInfo {
169 pub fn new(instruction_locations: HashMap<usize, InstructionLocation>) -> Self {
170 Self {
171 instruction_locations,
172 }
173 }
174 pub fn get_instruction_locations(&self) -> HashMap<usize, InstructionLocation> {
175 self.instruction_locations.clone()
176 }
177}
178
179#[cfg_attr(feature = "test_utils", derive(Arbitrary))]
180#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
181pub struct InstructionLocation {
182 pub inst: Location,
183 pub hints: Vec<HintLocation>,
184}
185
186#[cfg_attr(feature = "test_utils", derive(Arbitrary))]
187#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
188pub struct InputFile {
189 pub filename: String,
190}
191
192impl InputFile {
193 pub fn get_content(&self) -> Result<String, String> {
194 let content = std::fs::read_to_string(self.filename.clone());
195 if let Ok(content) = content {
196 return Ok(content);
197 }
198 Err(format!("Failed to read file {}", self.filename.clone()))
199 }
200}
201
202#[cfg_attr(feature = "test_utils", derive(Arbitrary))]
203#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
204pub struct HintLocation {
205 pub location: Location,
206 pub n_prefix_newlines: u32,
207}
208
209fn felt_from_number<'de, D>(deserializer: D) -> Result<Option<Felt252>, D::Error>
210where
211 D: Deserializer<'de>,
212{
213 let n = Number::deserialize(deserializer)?;
214 match Felt252::from_dec_str(&n.to_string()).ok() {
215 Some(x) => Ok(Some(x)),
216 None => {
217 let felt = deserialize_scientific_notation(n);
220 if felt.is_some() {
221 return Ok(felt);
222 }
223
224 Err(de::Error::custom(String::from(
225 "felt_from_number parse error",
226 )))
227 }
228 }
229}
230
231fn deserialize_scientific_notation(n: Number) -> Option<Felt252> {
232 match n.as_f64() {
233 None => {
234 let str = n.to_string();
235 let list: [&str; 2] = str.split('e').collect::<Vec<&str>>().try_into().ok()?;
236 let exponent = list[1].parse::<u128>().ok()?;
237
238 let prime_bigint = BigInt::from_biguint(num_bigint::Sign::Plus, CAIRO_PRIME.clone());
240 let base_bigint = BigInt::from_str_radix(list[0], 10).ok()? % prime_bigint;
241 let base = Felt252::from_dec_str(&base_bigint.to_string()).ok()?;
242
243 Some(base * Felt252::from(10).pow(exponent))
244 }
245 Some(float) => {
246 let prime_bigint = BigInt::from_biguint(num_bigint::Sign::Plus, CAIRO_PRIME.clone());
248 let number = BigInt::from_str_radix(&FloatCore::round(float).to_string(), 10).ok()?
249 % prime_bigint;
250 Felt252::from_dec_str(&number.to_string()).ok()
251 }
252 }
253}
254
255#[cfg_attr(feature = "test_utils", derive(Arbitrary))]
256#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone, Default)]
257pub struct ReferenceManager {
258 pub references: Vec<Reference>,
259}
260
261#[cfg_attr(feature = "test_utils", derive(Arbitrary))]
262#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
263pub struct Reference {
264 pub ap_tracking_data: ApTracking,
265 pub pc: Option<usize>,
266 #[serde(deserialize_with = "deserialize_value_address")]
267 #[serde(rename(deserialize = "value"))]
268 pub value_address: ValueAddress,
269}
270
271#[cfg_attr(feature = "test_utils", derive(Arbitrary))]
272#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
273pub enum OffsetValue {
274 Immediate(Felt252),
275 Value(i32),
276 Reference(Register, i32, bool, bool),
277}
278
279#[cfg_attr(feature = "test_utils", derive(Arbitrary))]
280#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
281pub struct ValueAddress {
282 pub offset1: OffsetValue, pub offset2: OffsetValue, pub outer_dereference: bool, pub inner_dereference: bool, pub value_type: String, }
288
289impl ValueAddress {
290 pub fn no_hint_reference_default() -> ValueAddress {
298 ValueAddress {
299 offset1: OffsetValue::Value(99),
300 offset2: OffsetValue::Value(99),
301 outer_dereference: false,
302 inner_dereference: false,
303 value_type: String::from("felt"),
304 }
305 }
306}
307
308struct Felt252Visitor;
309
310impl de::Visitor<'_> for Felt252Visitor {
311 type Value = Felt252;
312
313 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
314 formatter.write_str("Could not deserialize hexadecimal string")
315 }
316
317 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
318 where
319 E: de::Error,
320 {
321 let value = deserialize_utils::maybe_add_padding(value.to_string());
323 Felt252::from_hex(&value).map_err(de::Error::custom)
324 }
325}
326
327struct MaybeRelocatableVisitor;
328
329impl<'de> de::Visitor<'de> for MaybeRelocatableVisitor {
330 type Value = Vec<MaybeRelocatable>;
331
332 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
333 formatter.write_str("Could not deserialize array of hexadecimal")
334 }
335
336 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
337 where
338 A: SeqAccess<'de>,
339 {
340 let mut data: Vec<MaybeRelocatable> = vec![];
341
342 while let Some(value) = seq.next_element::<String>()? {
343 let value = deserialize_utils::maybe_add_padding(value.to_string());
345 data.push(MaybeRelocatable::Int(
346 Felt252::from_hex(&value).map_err(de::Error::custom)?,
347 ));
348 }
349 Ok(data)
350 }
351}
352
353struct ReferenceIdsVisitor;
354
355impl<'de> de::Visitor<'de> for ReferenceIdsVisitor {
356 type Value = HashMap<String, usize>;
357
358 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
359 formatter.write_str("a map with string keys and integer values")
360 }
361
362 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
363 where
364 A: MapAccess<'de>,
365 {
366 let mut data: HashMap<String, usize> = HashMap::new();
367
368 while let Some((key, value)) = map.next_entry::<String, usize>()? {
369 data.insert(key, value);
370 }
371
372 Ok(data)
373 }
374}
375
376struct ValueAddressVisitor;
377
378impl de::Visitor<'_> for ValueAddressVisitor {
379 type Value = ValueAddress;
380
381 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
382 formatter.write_str("a string representing the address in memory of a variable")
383 }
384
385 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
386 where
387 E: de::Error,
388 {
389 let parse_res = deserialize_utils::parse_value(value);
390
391 if let Ok((_, res)) = parse_res {
392 return Ok(res);
393 }
394
395 Ok(ValueAddress::no_hint_reference_default())
396 }
397}
398
399pub fn deserialize_felt_hex<'de, D: Deserializer<'de>>(d: D) -> Result<Felt252, D::Error> {
400 d.deserialize_str(Felt252Visitor)
401}
402
403pub fn deserialize_array_of_bigint_hex<'de, D: Deserializer<'de>>(
404 d: D,
405) -> Result<Vec<MaybeRelocatable>, D::Error> {
406 d.deserialize_seq(MaybeRelocatableVisitor)
407}
408
409pub fn deserialize_map_to_string_and_usize_hashmap<'de, D: Deserializer<'de>>(
410 d: D,
411) -> Result<HashMap<String, usize>, D::Error> {
412 d.deserialize_map(ReferenceIdsVisitor)
413}
414
415pub fn deserialize_value_address<'de, D: Deserializer<'de>>(
416 d: D,
417) -> Result<ValueAddress, D::Error> {
418 d.deserialize_str(ValueAddressVisitor)
419}
420
421pub fn deserialize_program_json(reader: &[u8]) -> Result<ProgramJson, ProgramError> {
422 let program_json = serde_json::from_slice(reader)?;
423 Ok(program_json)
424}
425pub fn deserialize_and_parse_program(
426 reader: &[u8],
427 entrypoint: Option<&str>,
428) -> Result<Program, ProgramError> {
429 let program_json: ProgramJson = deserialize_program_json(reader)?;
430 parse_program_json(program_json, entrypoint)
431}
432
433pub fn parse_program_json(
434 program_json: ProgramJson,
435 entrypoint: Option<&str>,
436) -> Result<Program, ProgramError> {
437 if PRIME_STR != program_json.prime {
438 return Err(ProgramError::PrimeDiffers(program_json.prime));
439 }
440
441 let entrypoint_pc = match entrypoint {
442 Some(entrypoint) => match program_json
443 .identifiers
444 .get(&format!("__main__.{entrypoint}"))
445 {
446 Some(entrypoint_identifier) => entrypoint_identifier.pc,
447 None => return Err(ProgramError::EntrypointNotFound(entrypoint.to_string())),
448 },
449 None => None,
450 };
451
452 let start = match program_json.identifiers.get("__main__.__start__") {
453 Some(identifier) => identifier.pc,
454 None => None,
455 };
456 let end = match program_json.identifiers.get("__main__.__end__") {
457 Some(identifier) => identifier.pc,
458 None => None,
459 };
460
461 let mut constants = HashMap::new();
462 for (key, value) in program_json.identifiers.iter() {
463 if value.type_.as_deref() == Some("const") {
464 let value = value
465 .value
466 .ok_or_else(|| ProgramError::ConstWithoutValue(key.clone()))?;
467 constants.insert(key.clone(), value);
468 }
469 }
470
471 let hints_collection = HintsCollection::new(&program_json.hints, program_json.data.len())?;
472
473 let shared_program_data = SharedProgramData {
474 data: program_json.data,
475 hints_collection,
476 main: entrypoint_pc,
477 start,
478 end,
479 error_message_attributes: program_json
480 .attributes
481 .into_iter()
482 .filter(|attr| attr.name == "error_message")
483 .collect(),
484 instruction_locations: program_json
485 .debug_info
486 .map(|debug_info| debug_info.instruction_locations),
487 identifiers: program_json.identifiers,
488 reference_manager: Program::get_reference_list(&program_json.reference_manager),
489 };
490 Ok(Program {
491 shared_program_data: Arc::new(shared_program_data),
492 constants: Arc::new(constants),
493 builtins: program_json.builtins,
494 })
495}
496
497#[cfg(test)]
498mod tests {
499 use super::*;
500 use crate::felt_str;
501 use assert_matches::assert_matches;
502 use core::num::NonZeroUsize;
503
504 #[test]
505 fn deserialize_bigint_from_string_json_gives_error() {
506 let invalid_even_length_hex_json = r#"
507 {
508 "prime": "0bx000A"
509 }"#;
510
511 let even_result: Result<ProgramJson, _> =
513 serde_json::from_str(invalid_even_length_hex_json);
514
515 assert!(even_result.is_err());
516
517 let invalid_odd_length_hex_json = r#"
518 {
519 "prime": "0bx00A"
520 }"#;
521
522 let odd_result: Result<ProgramJson, _> = serde_json::from_str(invalid_odd_length_hex_json);
524
525 assert!(odd_result.is_err());
526 }
527
528 #[test]
529 fn deserialize_bigint_invalid_char_error() {
530 let invalid_char = r#"
531 {
532 "prime": "0xlambda"
533 }"#;
534
535 let invalid_char_error: Result<ProgramJson, _> = serde_json::from_str(invalid_char);
536
537 assert!(invalid_char_error.is_err());
538 }
539
540 #[test]
541 fn deserialize_bigint_no_prefix_error() {
542 let no_prefix = r#"
543 {
544 "prime": "00A"
545 }"#;
546
547 let no_prefix_error: Result<ProgramJson, _> = serde_json::from_str(no_prefix);
549
550 assert!(no_prefix_error.is_err());
551 }
552
553 #[test]
554 fn deserialize_from_string_json() {
555 let valid_json = r#"
556 {
557 "prime": "0x800000000000011000000000000000000000000000000000000000000000001",
558 "attributes": [],
559 "debug_info": {
560 "instruction_locations": {}
561 },
562 "builtins": [],
563 "data": [
564 "0x480680017fff8000",
565 "0x3e8",
566 "0x480680017fff8000",
567 "0x7d0",
568 "0x48307fff7ffe8000",
569 "0x208b7fff7fff7ffe"
570 ],
571 "identifiers": {
572 "__main__.main": {
573 "decorators": [],
574 "pc": 0,
575 "type": "function"
576 },
577 "__main__.main.Args": {
578 "full_name": "__main__.main.Args",
579 "members": {},
580 "size": 0,
581 "type": "struct"
582 },
583 "__main__.main.ImplicitArgs": {
584 "full_name": "__main__.main.ImplicitArgs",
585 "members": {},
586 "size": 0,
587 "type": "struct"
588 }
589 },
590 "hints": {
591 "0": [
592 {
593 "accessible_scopes": [
594 "starkware.cairo.common.alloc",
595 "starkware.cairo.common.alloc.alloc"
596 ],
597 "code": "memory[ap] = segments.add()",
598 "flow_tracking_data": {
599 "ap_tracking": {
600 "group": 0,
601 "offset": 0
602 },
603 "reference_ids": {
604 "starkware.cairo.common.math.split_felt.high": 0,
605 "starkware.cairo.common.math.split_felt.low": 14,
606 "starkware.cairo.common.math.split_felt.range_check_ptr": 16,
607 "starkware.cairo.common.math.split_felt.value": 12
608 }
609 }
610 }
611 ]
612 },
613 "reference_manager": {
614 "references": [
615 {
616 "ap_tracking_data": {
617 "group": 0,
618 "offset": 0
619 },
620 "pc": 0,
621 "value": "[cast(fp + (-4), felt*)]"
622 },
623 {
624 "ap_tracking_data": {
625 "group": 0,
626 "offset": 0
627 },
628 "pc": 0,
629 "value": "[cast(fp + (-3), felt*)]"
630 },
631 {
632 "ap_tracking_data": {
633 "group": 0,
634 "offset": 0
635 },
636 "pc": 0,
637 "value": "cast([fp + (-3)] + 2, felt)"
638 },
639 {
640 "ap_tracking_data": {
641 "group": 0,
642 "offset": 0
643 },
644 "pc": 0,
645 "value": "[cast(fp, felt**)]"
646 }
647 ]
648 }
649 }"#;
650
651 let program_json: ProgramJson = serde_json::from_str(valid_json).unwrap();
653
654 let data: Vec<MaybeRelocatable> = vec![
655 MaybeRelocatable::Int(Felt252::from(5189976364521848832_i64)),
656 MaybeRelocatable::Int(Felt252::from(1000_i64)),
657 MaybeRelocatable::Int(Felt252::from(5189976364521848832_i64)),
658 MaybeRelocatable::Int(Felt252::from(2000_i64)),
659 MaybeRelocatable::Int(Felt252::from(5201798304953696256_i64)),
660 MaybeRelocatable::Int(Felt252::from(2345108766317314046_i64)),
661 ];
662
663 let mut hints = BTreeMap::new();
664 hints.insert(
665 0,
666 vec![HintParams {
667 code: "memory[ap] = segments.add()".to_string(),
668 accessible_scopes: vec![
669 String::from("starkware.cairo.common.alloc"),
670 String::from("starkware.cairo.common.alloc.alloc"),
671 ],
672 flow_tracking_data: FlowTrackingData {
673 ap_tracking: ApTracking {
674 group: 0,
675 offset: 0,
676 },
677 reference_ids: HashMap::from([
678 (
679 String::from("starkware.cairo.common.math.split_felt.high"),
680 0,
681 ),
682 (
683 String::from("starkware.cairo.common.math.split_felt.low"),
684 14,
685 ),
686 (
687 String::from("starkware.cairo.common.math.split_felt.range_check_ptr"),
688 16,
689 ),
690 (
691 String::from("starkware.cairo.common.math.split_felt.value"),
692 12,
693 ),
694 ]),
695 },
696 }],
697 );
698
699 let reference_manager = ReferenceManager {
700 references: vec![
701 Reference {
702 ap_tracking_data: ApTracking {
703 group: 0,
704 offset: 0,
705 },
706 pc: Some(0),
707 value_address: ValueAddress {
708 offset1: OffsetValue::Reference(Register::FP, -4, false, true),
709 offset2: OffsetValue::Value(0),
710 outer_dereference: true,
711 inner_dereference: false,
712 value_type: "felt".to_string(),
713 },
714 },
715 Reference {
716 ap_tracking_data: ApTracking {
717 group: 0,
718 offset: 0,
719 },
720 pc: Some(0),
721 value_address: ValueAddress {
722 offset1: OffsetValue::Reference(Register::FP, -3, false, true),
723 offset2: OffsetValue::Value(0),
724 outer_dereference: true,
725 inner_dereference: false,
726 value_type: "felt".to_string(),
727 },
728 },
729 Reference {
730 ap_tracking_data: ApTracking {
731 group: 0,
732 offset: 0,
733 },
734 pc: Some(0),
735 value_address: ValueAddress {
736 offset1: OffsetValue::Reference(Register::FP, -3, true, true),
737 offset2: OffsetValue::Immediate(Felt252::from(2)),
738 outer_dereference: false,
739 inner_dereference: false,
740 value_type: "felt".to_string(),
741 },
742 },
743 Reference {
744 ap_tracking_data: ApTracking {
745 group: 0,
746 offset: 0,
747 },
748 pc: Some(0),
749 value_address: ValueAddress {
750 offset1: OffsetValue::Reference(Register::FP, 0, false, true),
751 offset2: OffsetValue::Value(0),
752 outer_dereference: true,
753 inner_dereference: false,
754 value_type: "felt*".to_string(),
755 },
756 },
757 ],
758 };
759
760 assert_eq!(
761 program_json.prime,
762 "0x800000000000011000000000000000000000000000000000000000000000001"
763 );
764 assert!(program_json.builtins.is_empty());
765 assert_eq!(program_json.data, data);
766 assert_eq!(program_json.identifiers["__main__.main"].pc, Some(0));
767 assert_eq!(program_json.hints, hints);
768 assert_eq!(program_json.reference_manager, reference_manager);
769 }
770
771 #[test]
772 fn deserialize_program_json_from_json_file_a() {
773 let reader =
775 include_bytes!("../../../cairo_programs/manually_compiled/valid_program_a.json");
776
777 let program_json: ProgramJson = serde_json::from_slice(reader).unwrap();
778
779 assert_eq!(
780 program_json.prime,
781 "0x800000000000011000000000000000000000000000000000000000000000001"
782 );
783 assert!(program_json.builtins.is_empty());
784 assert_eq!(program_json.data.len(), 6);
785 assert_eq!(program_json.identifiers["__main__.main"].pc, Some(0));
786 }
787
788 #[test]
789 fn deserialize_program_json_from_json_file_b() {
790 let reader =
792 include_bytes!("../../../cairo_programs/manually_compiled/valid_program_b.json");
793
794 let program_json: ProgramJson = serde_json::from_slice(reader).unwrap();
795 let builtins: Vec<BuiltinName> = vec![BuiltinName::output, BuiltinName::range_check];
796
797 assert_eq!(
798 program_json.prime,
799 "0x800000000000011000000000000000000000000000000000000000000000001"
800 );
801 assert_eq!(program_json.builtins, builtins);
802 assert_eq!(program_json.data.len(), 24);
803 assert_eq!(program_json.identifiers["__main__.main"].pc, Some(13));
804 }
805
806 #[test]
807 fn deserialize_program_json_from_json_file_gives_error() {
808 let reader = include_bytes!(
810 "../../../cairo_programs/manually_compiled/invalid_even_length_hex.json"
811 );
812
813 let even_result: Result<ProgramJson, _> = serde_json::from_slice(reader);
814
815 assert!(even_result.is_err());
816
817 let reader =
819 include_bytes!("../../../cairo_programs/manually_compiled/invalid_odd_length_hex.json");
820
821 let odd_result: Result<ProgramJson, _> = serde_json::from_slice(reader);
822
823 assert!(odd_result.is_err());
824 }
825
826 #[test]
827 fn deserialize_missing_entrypoint_gives_error() {
828 let reader =
829 include_bytes!("../../../cairo_programs/manually_compiled/valid_program_a.json");
830
831 let deserialization_result =
832 deserialize_and_parse_program(reader, Some("missing_function"));
833 assert!(deserialization_result.is_err());
834 assert_matches!(
835 deserialization_result,
836 Err(ProgramError::EntrypointNotFound(_))
837 );
838 }
839
840 fn get_hints_as_map(program: &Program) -> HashMap<usize, Vec<HintParams>> {
841 let hints_collection = &program.shared_program_data.hints_collection;
842 let hints_map: HashMap<usize, Vec<HintParams>> = hints_collection
843 .iter()
844 .map(|(pc, hints)| (pc, hints.to_vec()))
845 .collect();
846
847 hints_map
848 }
849
850 #[test]
851 fn deserialize_program_test() {
852 let reader =
853 include_bytes!("../../../cairo_programs/manually_compiled/valid_program_a.json");
854
855 let program: Program = deserialize_and_parse_program(reader, Some("main"))
856 .expect("Failed to deserialize program");
857
858 let builtins: Vec<BuiltinName> = Vec::new();
859 let data: Vec<MaybeRelocatable> = vec![
860 MaybeRelocatable::Int(Felt252::from(5189976364521848832_i64)),
861 MaybeRelocatable::Int(Felt252::from(1000)),
862 MaybeRelocatable::Int(Felt252::from(5189976364521848832_i64)),
863 MaybeRelocatable::Int(Felt252::from(2000)),
864 MaybeRelocatable::Int(Felt252::from(5201798304953696256_i64)),
865 MaybeRelocatable::Int(Felt252::from(2345108766317314046_i64)),
866 ];
867
868 let hints: HashMap<_, _> = [
869 (
870 0,
871 vec![HintParams {
872 code: "memory[ap] = segments.add()".to_string(),
873 accessible_scopes: vec![
874 String::from("starkware.cairo.common.alloc"),
875 String::from("starkware.cairo.common.alloc.alloc"),
876 ],
877 flow_tracking_data: FlowTrackingData {
878 ap_tracking: ApTracking {
879 group: 0,
880 offset: 0,
881 },
882 reference_ids: HashMap::new(),
883 },
884 }],
885 ),
886 (
887 4,
888 vec![HintParams {
889 code: "import math".to_string(),
890 accessible_scopes: vec![
891 String::from("__main__"),
892 String::from("__main__.main"),
893 ],
894 flow_tracking_data: FlowTrackingData {
895 ap_tracking: ApTracking {
896 group: 5,
897 offset: 0,
898 },
899 reference_ids: HashMap::new(),
900 },
901 }],
902 ),
903 ]
904 .into();
905 let mut hints_ranges = vec![None; 47];
906 hints_ranges[0] = Some((0, NonZeroUsize::new(1).unwrap()));
907 hints_ranges[46] = Some((1, NonZeroUsize::new(1).unwrap()));
908
909 assert_eq!(program.builtins, builtins);
910 assert_eq!(program.shared_program_data.data, data);
911 assert_eq!(program.shared_program_data.main, Some(0));
912
913 let program_hints = get_hints_as_map(&program);
914 assert_eq!(program_hints, hints);
915 }
916
917 #[test]
919 fn deserialize_program_without_entrypoint() {
920 let reader =
921 include_bytes!("../../../cairo_programs/manually_compiled/valid_program_a.json");
922
923 let program: Program =
924 deserialize_and_parse_program(reader, None).expect("Failed to deserialize program");
925
926 let builtins: Vec<BuiltinName> = Vec::new();
927 let data: Vec<MaybeRelocatable> = vec![
928 MaybeRelocatable::Int(Felt252::from(5189976364521848832_i64)),
929 MaybeRelocatable::Int(Felt252::from(1000)),
930 MaybeRelocatable::Int(Felt252::from(5189976364521848832_i64)),
931 MaybeRelocatable::Int(Felt252::from(2000)),
932 MaybeRelocatable::Int(Felt252::from(5201798304953696256_i64)),
933 MaybeRelocatable::Int(Felt252::from(2345108766317314046_i64)),
934 ];
935
936 let hints: HashMap<_, _> = [
937 (
938 0,
939 vec![HintParams {
940 code: "memory[ap] = segments.add()".to_string(),
941 accessible_scopes: vec![
942 String::from("starkware.cairo.common.alloc"),
943 String::from("starkware.cairo.common.alloc.alloc"),
944 ],
945 flow_tracking_data: FlowTrackingData {
946 ap_tracking: ApTracking {
947 group: 0,
948 offset: 0,
949 },
950 reference_ids: HashMap::new(),
951 },
952 }],
953 ),
954 (
955 4,
956 vec![HintParams {
957 code: "import math".to_string(),
958 accessible_scopes: vec![
959 String::from("__main__"),
960 String::from("__main__.main"),
961 ],
962 flow_tracking_data: FlowTrackingData {
963 ap_tracking: ApTracking {
964 group: 5,
965 offset: 0,
966 },
967 reference_ids: HashMap::new(),
968 },
969 }],
970 ),
971 ]
972 .into();
973
974 assert_eq!(program.builtins, builtins);
975 assert_eq!(program.shared_program_data.data, data);
976 assert_eq!(program.shared_program_data.main, None);
977
978 let program_hints = get_hints_as_map(&program);
979 assert_eq!(program_hints, hints);
980 }
981
982 #[test]
983 fn deserialize_constant() {
984 let reader = include_bytes!(
985 "../../../cairo_programs/manually_compiled/deserialize_constant_test.json"
986 );
987
988 let program_json: ProgramJson = serde_json::from_slice(reader).unwrap();
989 let mut identifiers: HashMap<String, Identifier> = HashMap::new();
990
991 identifiers.insert(
992 String::from("__main__.main"),
993 Identifier {
994 pc: Some(0),
995 type_: Some(String::from("function")),
996 value: None,
997 full_name: None,
998 members: None,
999 cairo_type: None,
1000 size: None,
1001 destination: None,
1002 },
1003 );
1004 identifiers.insert(
1005 String::from("__main__.compare_abs_arrays.SIZEOF_LOCALS"),
1006 Identifier {
1007 pc: None,
1008 type_: Some(String::from("const")),
1009 value: Some(felt_str!(
1010 "-3618502788666131213697322783095070105623107215331596699973092056135872020481"
1011 )),
1012 full_name: None,
1013 members: None,
1014 cairo_type: None,
1015 size: None,
1016 destination: None,
1017 },
1018 );
1019 identifiers.insert(
1020 String::from("starkware.cairo.common.cairo_keccak.keccak.unsigned_div_rem"),
1021 Identifier {
1022 pc: None,
1023 type_: Some(String::from("alias")),
1024 value: None,
1025 full_name: None,
1026 members: None,
1027 cairo_type: None,
1028 size: None,
1029 destination: Some(String::from("starkware.cairo.common.math.unsigned_div_rem")),
1030 },
1031 );
1032 identifiers.insert(
1033 String::from("starkware.cairo.common.cairo_keccak.packed_keccak.ALL_ONES"),
1034 Identifier {
1035 pc: None,
1036 type_: Some(String::from("const")),
1037 value: Some(felt_str!(
1038 "-106710729501573572985208420194530329073740042555888586719234"
1039 )),
1040 full_name: None,
1041 members: None,
1042 cairo_type: None,
1043 size: None,
1044 destination: None,
1045 },
1046 );
1047 identifiers.insert(
1048 String::from("starkware.cairo.common.cairo_keccak.packed_keccak.BLOCK_SIZE"),
1049 Identifier {
1050 pc: None,
1051 type_: Some(String::from("const")),
1052 value: Some(Felt252::from(3)),
1053 full_name: None,
1054 members: None,
1055 cairo_type: None,
1056 size: None,
1057 destination: None,
1058 },
1059 );
1060 identifiers.insert(
1061 String::from("starkware.cairo.common.alloc.alloc.SIZEOF_LOCALS"),
1062 Identifier {
1063 pc: None,
1064 type_: Some(String::from("const")),
1065 value: Some(Felt252::ZERO),
1066 full_name: None,
1067 members: None,
1068 cairo_type: None,
1069 size: None,
1070 destination: None,
1071 },
1072 );
1073 identifiers.insert(
1074 String::from("starkware.cairo.common.uint256.SHIFT"),
1075 Identifier {
1076 pc: None,
1077 type_: Some(String::from("const")),
1078 value: Some(felt_str!("340282366920938463463374607431768211456")),
1079 full_name: None,
1080 members: None,
1081 cairo_type: None,
1082 size: None,
1083 destination: None,
1084 },
1085 );
1086
1087 assert_eq!(program_json.identifiers, identifiers);
1088 }
1089
1090 #[test]
1091 fn value_address_no_hint_reference_default_test() {
1092 let valid_json = r#"
1093 {
1094 "prime": "0x800000000000011000000000000000000000000000000000000000000000001",
1095 "attributes": [],
1096 "debug_info": {
1097 "instruction_locations": {}
1098 },
1099 "builtins": [],
1100 "data": [
1101 ],
1102 "identifiers": {
1103 },
1104 "hints": {
1105 },
1106 "reference_manager": {
1107 "references": [
1108 {
1109 "ap_tracking_data": {
1110 "group": 0,
1111 "offset": 0
1112 },
1113 "pc": 0,
1114 "value": ""
1115 }
1116 ]
1117 }
1118 }"#;
1119
1120 let program_json: ProgramJson = serde_json::from_str(valid_json).unwrap();
1121
1122 let reference_manager = ReferenceManager {
1123 references: vec![Reference {
1124 ap_tracking_data: ApTracking {
1125 group: 0,
1126 offset: 0,
1127 },
1128 pc: Some(0),
1129 value_address: ValueAddress::no_hint_reference_default(),
1130 }],
1131 };
1132
1133 assert_eq!(program_json.reference_manager, reference_manager);
1134 }
1135
1136 #[test]
1137 fn deserialize_attributes_test() {
1138 let valid_json = r#"
1139 {
1140 "prime": "0x800000000000011000000000000000000000000000000000000000000000001",
1141 "attributes": [
1142 {
1143 "accessible_scopes": [
1144 "openzeppelin.security.safemath.library",
1145 "openzeppelin.security.safemath.library.SafeUint256",
1146 "openzeppelin.security.safemath.library.SafeUint256.add"
1147 ],
1148 "end_pc": 381,
1149 "flow_tracking_data": {
1150 "ap_tracking": {
1151 "group": 14,
1152 "offset": 35
1153 },
1154 "reference_ids": {}
1155 },
1156 "name": "error_message",
1157 "start_pc": 379,
1158 "value": "SafeUint256: addition overflow"
1159 },
1160 {
1161 "accessible_scopes": [
1162 "openzeppelin.security.safemath.library",
1163 "openzeppelin.security.safemath.library.SafeUint256",
1164 "openzeppelin.security.safemath.library.SafeUint256.sub_le"
1165 ],
1166 "end_pc": 404,
1167 "flow_tracking_data": {
1168 "ap_tracking": {
1169 "group": 15,
1170 "offset": 60
1171 },
1172 "reference_ids": {}
1173 },
1174 "name": "error_message",
1175 "start_pc": 402,
1176 "value": "SafeUint256: subtraction overflow"
1177 }
1178 ],
1179 "debug_info": {
1180 "instruction_locations": {}
1181 },
1182 "builtins": [],
1183 "data": [
1184 ],
1185 "identifiers": {
1186 },
1187 "hints": {
1188 },
1189 "reference_manager": {
1190 "references": [
1191 ]
1192 }
1193 }"#;
1194
1195 let program_json: ProgramJson = serde_json::from_str(valid_json).unwrap();
1196
1197 let attributes: Vec<Attribute> = vec![
1198 Attribute {
1199 name: String::from("error_message"),
1200 start_pc: 379,
1201 end_pc: 381,
1202 value: String::from("SafeUint256: addition overflow"),
1203 flow_tracking_data: Some(FlowTrackingData {
1204 ap_tracking: ApTracking {
1205 group: 14,
1206 offset: 35,
1207 },
1208 reference_ids: HashMap::new(),
1209 }),
1210 },
1211 Attribute {
1212 name: String::from("error_message"),
1213 start_pc: 402,
1214 end_pc: 404,
1215 value: String::from("SafeUint256: subtraction overflow"),
1216 flow_tracking_data: Some(FlowTrackingData {
1217 ap_tracking: ApTracking {
1218 group: 15,
1219 offset: 60,
1220 },
1221 reference_ids: HashMap::new(),
1222 }),
1223 },
1224 ];
1225
1226 assert_eq!(program_json.attributes, attributes);
1227 }
1228
1229 #[test]
1230 fn deserialize_instruction_locations_test_no_parent() {
1231 let valid_json = r#"
1232 {
1233 "prime": "0x800000000000011000000000000000000000000000000000000000000000001",
1234 "attributes": [],
1235 "debug_info": {
1236 "file_contents": {},
1237 "instruction_locations": {
1238 "0": {
1239 "accessible_scopes": [
1240 "starkware.cairo.lang.compiler.lib.registers",
1241 "starkware.cairo.lang.compiler.lib.registers.get_fp_and_pc"
1242 ],
1243 "flow_tracking_data": {
1244 "ap_tracking": {
1245 "group": 0,
1246 "offset": 0
1247 },
1248 "reference_ids": {}
1249 },
1250 "hints": [],
1251 "inst": {
1252 "end_col": 73,
1253 "end_line": 7,
1254 "input_file": {
1255 "filename": "/Users/user/test/env/lib/python3.9/site-packages/starkware/cairo/lang/compiler/lib/registers.cairo"
1256 },
1257 "start_col": 5,
1258 "start_line": 7
1259 }
1260 },
1261 "3": {
1262 "accessible_scopes": [
1263 "starkware.cairo.common.alloc",
1264 "starkware.cairo.common.alloc.alloc"
1265 ],
1266 "flow_tracking_data": {
1267 "ap_tracking": {
1268 "group": 1,
1269 "offset": 1
1270 },
1271 "reference_ids": {}
1272 },
1273 "hints": [],
1274 "inst": {
1275 "end_col": 40,
1276 "end_line": 5,
1277 "input_file": {
1278 "filename": "/Users/user/test/env/lib/python3.9/site-packages/starkware/cairo/common/alloc.cairo"
1279 },
1280 "start_col": 5,
1281 "start_line": 5
1282 }
1283 }
1284 }
1285 },
1286 "builtins": [],
1287 "data": [
1288 ],
1289 "identifiers": {
1290 },
1291 "hints": {
1292 },
1293 "reference_manager": {
1294 "references": [
1295 ]
1296 }
1297 }"#;
1298
1299 let program_json: ProgramJson = serde_json::from_str(valid_json).unwrap();
1300
1301 let debug_info: DebugInfo = DebugInfo {
1302 instruction_locations: HashMap::from([
1303 (
1304 0,
1305 InstructionLocation {
1306 inst: Location {
1307 end_line: 7,
1308 end_col: 73,
1309 input_file: InputFile { filename: String::from("/Users/user/test/env/lib/python3.9/site-packages/starkware/cairo/lang/compiler/lib/registers.cairo") },
1310 parent_location: None,
1311 start_line: 7,
1312 start_col: 5,
1313 },
1314 hints: vec![],
1315 },
1316 ),
1317 (
1318 3,
1319 InstructionLocation {
1320 inst: Location {
1321 end_line: 5,
1322 end_col: 40,
1323 input_file: InputFile { filename: String::from("/Users/user/test/env/lib/python3.9/site-packages/starkware/cairo/common/alloc.cairo") },
1324 parent_location: None,
1325 start_line: 5,
1326 start_col: 5,
1327 },
1328 hints: vec![],
1329 },
1330 ),
1331 ]),
1332 };
1333
1334 assert_eq!(program_json.debug_info, Some(debug_info));
1335 }
1336
1337 #[test]
1338 fn deserialize_instruction_locations_test_with_parent() {
1339 let valid_json = r#"
1340 {
1341 "prime": "0x800000000000011000000000000000000000000000000000000000000000001",
1342 "attributes": [],
1343 "debug_info": {
1344 "file_contents": {},
1345 "instruction_locations": {
1346 "4": {
1347 "accessible_scopes": [
1348 "__main__",
1349 "__main__",
1350 "__main__.constructor"
1351 ],
1352 "flow_tracking_data": null,
1353 "hints": [],
1354 "inst": {
1355 "end_col": 36,
1356 "end_line": 9,
1357 "input_file": {
1358 "filename": "test/contracts/cairo/always_fail.cairo"
1359 },
1360 "parent_location": [
1361 {
1362 "end_col": 36,
1363 "end_line": 9,
1364 "input_file": {
1365 "filename": "test/contracts/cairo/always_fail.cairo"
1366 },
1367 "parent_location": [
1368 {
1369 "end_col": 15,
1370 "end_line": 11,
1371 "input_file": {
1372 "filename": "test/contracts/cairo/always_fail.cairo"
1373 },
1374 "start_col": 5,
1375 "start_line": 11
1376 },
1377 "While trying to retrieve the implicit argument 'syscall_ptr' in:"
1378 ],
1379 "start_col": 18,
1380 "start_line": 9
1381 },
1382 "While expanding the reference 'syscall_ptr' in:"
1383 ],
1384 "start_col": 18,
1385 "start_line": 9
1386 }
1387 }
1388 }
1389 },
1390 "builtins": [],
1391 "data": [
1392 ],
1393 "identifiers": {
1394 },
1395 "hints": {
1396 },
1397 "reference_manager": {
1398 "references": [
1399 ]
1400 }
1401 }"#;
1402
1403 let program_json: ProgramJson = serde_json::from_str(valid_json).unwrap();
1404
1405 let debug_info: DebugInfo = DebugInfo { instruction_locations: HashMap::from(
1406 [
1407 (4, InstructionLocation {
1408 inst: Location { end_line: 9, end_col: 36,input_file: InputFile { filename: String::from("test/contracts/cairo/always_fail.cairo") }, parent_location: Some(
1409 (Box::new(Location {
1410 end_line: 9,
1411 end_col: 36,
1412 input_file: InputFile { filename: String::from("test/contracts/cairo/always_fail.cairo") },
1413 parent_location: Some(
1414 ( Box::new(Location {
1415 end_line: 11,
1416 end_col: 15,
1417 input_file: InputFile { filename: String::from("test/contracts/cairo/always_fail.cairo") },
1418 parent_location: None,
1419 start_line: 11,
1420 start_col: 5,
1421 })
1422 , String::from("While trying to retrieve the implicit argument 'syscall_ptr' in:")
1423 )
1424 ),
1425 start_line: 9,
1426 start_col: 18,
1427 }), String::from( "While expanding the reference 'syscall_ptr' in:"))
1428 ), start_line: 9, start_col: 18 },
1429 hints: vec![],
1430 }),
1431 ]
1432 ) };
1433
1434 assert_eq!(program_json.debug_info, Some(debug_info));
1435 }
1436
1437 #[test]
1438 fn deserialize_program_with_type_definition() {
1439 let reader = include_bytes!("../../../cairo_programs/uint256_integration_tests.json");
1440
1441 let program_json: ProgramJson = serde_json::from_slice(reader).unwrap();
1442
1443 assert_eq!(
1444 program_json.identifiers["starkware.cairo.common.alloc.alloc.Return"]
1445 .cairo_type
1446 .as_ref()
1447 .expect("key not found"),
1448 "(ptr: felt*)"
1449 );
1450 assert_eq!(
1451 program_json.identifiers["starkware.cairo.common.uint256.uint256_add.Return"]
1452 .cairo_type
1453 .as_ref()
1454 .expect("key not found"),
1455 "(res: starkware.cairo.common.uint256.Uint256, carry: felt)"
1456 );
1457 assert_eq!(
1458 program_json.identifiers["__main__.test_unsigned_div_rem.Return"]
1459 .cairo_type
1460 .as_ref()
1461 .expect("key not found"),
1462 "()"
1463 );
1464 }
1465
1466 #[test]
1467 fn deserialize_nonbase10_number_errors() {
1468 let valid_json = r#"
1469 {
1470 "value" : 0x123
1471 }"#;
1472
1473 let iden: Result<Identifier, serde_json::Error> = serde_json::from_str(valid_json);
1474 assert!(iden.err().is_some());
1475 }
1476
1477 #[test]
1478 fn test_felt_from_number_with_scientific_notation() {
1479 let n = Number::deserialize(serde_json::Value::from(1e27)).unwrap();
1480 assert_eq!(n.to_string(), "1e27".to_owned());
1481
1482 assert_matches!(
1483 felt_from_number(n),
1484 Ok(x) if x == Some(Felt252::ONE * Felt252::from(10).pow(27_u32))
1485 );
1486 }
1487
1488 #[test]
1489 fn test_felt_from_number_with_scientific_notation_with_fractional_part() {
1490 let n = serde_json::Value::Number(Number::from_f64(64e+74).unwrap());
1491
1492 assert_matches!(
1493 felt_from_number(n),
1494 Ok(x) if x == Some(Felt252::from_dec_str("64").unwrap() * Felt252::from(10).pow(74_u32))
1495 );
1496 }
1497
1498 #[test]
1499 fn test_felt_from_number_with_scientific_notation_with_fractional_part_f64_max() {
1500 let n = serde_json::Value::Number(Number::from_f64(f64::MAX).unwrap());
1501 assert_eq!(
1502 felt_from_number(n).unwrap(),
1503 Some(
1504 Felt252::from_dec_str(
1505 "2082797363194934431336897723140298717588791783575467744530053896730196177808",
1506 )
1507 .unwrap()
1508 )
1509 );
1510 }
1511
1512 #[test]
1513 fn test_felt_from_number_with_scientific_notation_big_exponent() {
1514 #[derive(Deserialize, Debug, PartialEq)]
1515 struct Test {
1516 #[serde(deserialize_with = "felt_from_number")]
1517 f: Option<Felt252>,
1518 }
1519 let malicious_input = &format!(
1520 "{{ \"f\": {}e{} }}",
1521 String::from_utf8(vec![b'9'; 1000]).unwrap(),
1522 u32::MAX
1523 );
1524 let f = serde_json::from_str::<Test>(malicious_input)
1525 .unwrap()
1526 .f
1527 .unwrap();
1528 assert_eq!(
1529 f,
1530 Felt252::from_dec_str(
1531 "2471602022505793130446032259107029522557827898253184929958153020344968292412",
1532 )
1533 .unwrap()
1534 );
1535 }
1536
1537 #[test]
1538 fn test_felt_from_number_with_scientific_notation_negative() {
1539 let n = Number::deserialize(serde_json::Value::from(-1e27)).unwrap();
1540 assert_eq!(n.to_string(), "-1e27".to_owned());
1541
1542 let felt = felt_from_number(n).unwrap().unwrap();
1543
1544 assert_eq!(felt, Felt252::from(-1) * Felt252::from(10).pow(27_u32));
1545 }
1546
1547 #[test]
1548 fn deserialize_program_with_invalid_hint_pc() {
1549 let reader = br#"{
1550 "attributes": [],
1551 "builtins": [],
1552 "compiler_version": "0.11.0",
1553 "data": [
1554 "0x41241"
1555 ],
1556 "debug_info": {
1557 "instruction_locations": {}
1558 },
1559 "hints": {
1560 "1": [
1561 {
1562 "accessible_scopes": [],
1563 "code": "",
1564 "flow_tracking_data": {
1565 "ap_tracking": {
1566 "group": 0,
1567 "offset": 0
1568 },
1569 "reference_ids": {}
1570 }
1571 }
1572 ]
1573 },
1574 "identifiers": {
1575 "__main__.main": {}
1576 },
1577 "main_scope": "",
1578 "prime": "0x800000000000011000000000000000000000000000000000000000000000001",
1579 "reference_manager": {
1580 "references": []
1581 }
1582 }"#;
1583
1584 let deserialization_result = deserialize_and_parse_program(reader, Some("main"));
1585
1586 assert!(deserialization_result.is_err());
1587 assert_matches!(
1588 deserialization_result.unwrap_err(),
1589 ProgramError::InvalidHintPc(1, 1)
1590 );
1591 }
1592
1593 #[test]
1594 fn parse_without_program_attributes() {
1595 let program = include_bytes!(concat!(
1597 env!("CARGO_MANIFEST_DIR"),
1598 "/../cairo_programs/manually_compiled/program_without_attributes.json",
1599 ));
1600 _ = deserialize_and_parse_program(program, None).expect("should be able to read file");
1601 }
1602
1603 #[test]
1604 fn parse_without_program_attributes_2() {
1605 let program = include_bytes!(concat!(
1607 env!("CARGO_MANIFEST_DIR"),
1608 "/../cairo_programs/manually_compiled/program_without_attributes_2.json",
1609 ));
1610 _ = deserialize_and_parse_program(program, None).expect("should be able to read file");
1611 }
1612}