cairo_lang_starknet_classes/
contract_class.rs1use cairo_lang_sierra as sierra;
2use cairo_lang_utils::bigint::{BigUintAsHex, deserialize_big_uint, serialize_big_uint};
3use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
4use num_bigint::BigUint;
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7use starknet_types_core::felt::Felt as Felt252;
8use thiserror::Error;
9
10use crate::abi::Contract;
11use crate::allowed_libfuncs::{AllowedLibfuncsError, ListSelector, lookup_allowed_libfuncs_list};
12use crate::compiler_version::{VersionId, current_compiler_version_id, current_sierra_version_id};
13use crate::felt252_serde::{
14 Felt252SerdeError, sierra_from_felt252s, sierra_to_felt252s, version_id_from_felt252s,
15};
16
17#[cfg(test)]
18#[path = "contract_class_test.rs"]
19mod test;
20
21#[derive(Error, Debug, Eq, PartialEq)]
22pub enum StarknetCompilationError {
23 #[error("Invalid entry point.")]
24 EntryPointError,
25 #[error(transparent)]
26 AllowedLibfuncsError(#[from] AllowedLibfuncsError),
27}
28
29#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
31pub struct ContractClass {
32 pub sierra_program: Vec<BigUintAsHex>,
33 pub sierra_program_debug_info: Option<sierra::debug_info::DebugInfo>,
34 pub contract_class_version: String,
35 pub entry_points_by_type: ContractEntryPoints,
36 pub abi: Option<Contract>,
37}
38impl ContractClass {
39 pub fn new(
41 program: &sierra::program::Program,
42 entry_points_by_type: ContractEntryPoints,
43 abi: Option<Contract>,
44 annotations: OrderedHashMap<String, Value>,
45 ) -> Result<Self, Felt252SerdeError> {
46 let mut sierra_program_debug_info = sierra::debug_info::DebugInfo::extract(program);
47 sierra_program_debug_info.annotations.extend(annotations);
48
49 Ok(Self {
50 sierra_program: sierra_to_felt252s(
51 current_sierra_version_id(),
52 current_compiler_version_id(),
53 program,
54 )?,
55 sierra_program_debug_info: Some(sierra_program_debug_info),
56 contract_class_version: DEFAULT_CONTRACT_CLASS_VERSION.into(),
57 entry_points_by_type,
58 abi,
59 })
60 }
61
62 pub fn extract_sierra_program(
65 &self,
66 populate_debug_info: bool,
67 ) -> Result<ExtractedSierraProgram, Felt252SerdeError> {
68 let prime = Felt252::prime();
69 for felt252 in &self.sierra_program {
70 if felt252.value >= prime {
71 return Err(Felt252SerdeError::InvalidInputForDeserialization);
72 }
73 }
74 let (sierra_version, compiler_version, mut program) =
75 sierra_from_felt252s(&self.sierra_program)?;
76 if populate_debug_info && let Some(info) = &self.sierra_program_debug_info {
77 info.populate(&mut program);
78 }
79 Ok(ExtractedSierraProgram { program, sierra_version, compiler_version })
80 }
81
82 pub fn sanity_check(&self) {
85 if let Some(abi) = &self.abi {
86 abi.sanity_check(
87 self.entry_points_by_type.external.len(),
88 self.entry_points_by_type.l1_handler.len(),
89 self.entry_points_by_type.constructor.len(),
90 );
91 }
92 }
93}
94
95pub struct ExtractedSierraProgram {
97 pub program: sierra::program::Program,
99 pub sierra_version: VersionId,
101 pub compiler_version: VersionId,
103}
104impl ExtractedSierraProgram {
105 pub fn validate_version_compatible(
108 &self,
109 list_selector: ListSelector,
110 ) -> Result<(), AllowedLibfuncsError> {
111 let list_name = list_selector.to_string();
112 let allowed_libfuncs = lookup_allowed_libfuncs_list(list_selector)?;
113 for libfunc in &self.program.libfunc_declarations {
114 match allowed_libfuncs.allowed_libfuncs.get(&libfunc.long_id.generic_id) {
115 Some(None) => {}
116 Some(Some(required)) if self.sierra_version.supports(*required) => {}
117 Some(Some(required)) => {
118 return Err(AllowedLibfuncsError::UnsupportedLibfuncAtVersion {
119 invalid_libfunc: libfunc.long_id.generic_id.to_string(),
120 required_version: *required,
121 class_version: self.sierra_version,
122 });
123 }
124 None => {
125 return Err(AllowedLibfuncsError::UnsupportedLibfunc {
126 invalid_libfunc: libfunc.long_id.generic_id.to_string(),
127 allowed_libfuncs_list_name: list_name,
128 });
129 }
130 }
131 }
132 Ok(())
133 }
134}
135
136const DEFAULT_CONTRACT_CLASS_VERSION: &str = "0.1.0";
137
138#[derive(Clone, Default, Debug, PartialEq, Eq, Serialize, Deserialize)]
139pub struct ContractEntryPoints {
140 #[serde(rename = "EXTERNAL")]
141 pub external: Vec<ContractEntryPoint>,
142 #[serde(rename = "L1_HANDLER")]
143 pub l1_handler: Vec<ContractEntryPoint>,
144 #[serde(rename = "CONSTRUCTOR")]
145 pub constructor: Vec<ContractEntryPoint>,
146}
147
148#[derive(Clone, Default, Debug, PartialEq, Eq, Serialize, Deserialize)]
149pub struct ContractEntryPoint {
150 #[serde(serialize_with = "serialize_big_uint", deserialize_with = "deserialize_big_uint")]
152 pub selector: BigUint,
153 pub function_idx: usize,
155}
156
157pub fn version_id_from_serialized_sierra_program(
163 sierra_program: &[BigUintAsHex],
164) -> Result<(VersionId, VersionId), Felt252SerdeError> {
165 let (sierra_version_id, compiler_version_id, _) = version_id_from_felt252s(sierra_program)?;
166 Ok((sierra_version_id, compiler_version_id))
167}