cairo_lang_sierra/extensions/modules/
gas.rs1use convert_case::Casing;
2use itertools::chain;
3use serde::{Deserialize, Serialize};
4
5use super::int::unsigned128::Uint128Type;
6use super::range_check::RangeCheckType;
8use crate::define_libfunc_hierarchy;
9use crate::extensions::lib_func::{
10 BranchSignature, DeferredOutputKind, LibfuncSignature, OutputVarInfo, ParamSignature,
11 SierraApChange, SignatureSpecializationContext,
12};
13use crate::extensions::{
14 NamedType, NoGenericArgsGenericLibfunc, NoGenericArgsGenericType, OutputVarReferenceInfo,
15 SpecializationError,
16};
17use crate::ids::GenericTypeId;
18
19#[derive(Default)]
21pub struct GasBuiltinType {}
22impl NoGenericArgsGenericType for GasBuiltinType {
23 const ID: GenericTypeId = GenericTypeId::new_inline("GasBuiltin");
24 const STORABLE: bool = true;
25 const DUPLICATABLE: bool = false;
26 const DROPPABLE: bool = false;
27 const ZERO_SIZED: bool = false;
28}
29
30define_libfunc_hierarchy! {
31 pub enum GasLibfunc {
32 WithdrawGas(WithdrawGasLibfunc),
33 RedepositGas(RedepositGasLibfunc),
34 GetAvailableGas(GetAvailableGasLibfunc),
35 BuiltinWithdrawGas(BuiltinCostWithdrawGasLibfunc),
36 GetBuiltinCosts(BuiltinCostGetBuiltinCostsLibfunc),
37 }, GasConcreteLibfunc
38}
39
40#[derive(Default)]
42pub struct WithdrawGasLibfunc {}
43impl NoGenericArgsGenericLibfunc for WithdrawGasLibfunc {
44 const STR_ID: &'static str = "withdraw_gas";
45
46 fn specialize_signature(
47 &self,
48 context: &dyn SignatureSpecializationContext,
49 ) -> Result<LibfuncSignature, SpecializationError> {
50 let gas_builtin_type = context.get_concrete_type(GasBuiltinType::id(), &[])?;
51 let range_check_type = context.get_concrete_type(RangeCheckType::id(), &[])?;
52 let rc_output_info = OutputVarInfo::new_builtin(range_check_type.clone(), 0);
53 Ok(LibfuncSignature {
54 param_signatures: vec![
55 ParamSignature::new(range_check_type).with_allow_add_const(),
56 ParamSignature::new(gas_builtin_type.clone()),
57 ],
58 branch_signatures: vec![
59 BranchSignature {
61 vars: vec![rc_output_info.clone(), OutputVarInfo {
62 ty: gas_builtin_type.clone(),
63 ref_info: OutputVarReferenceInfo::NewTempVar { idx: 0 },
64 }],
65 ap_change: SierraApChange::Known { new_vars_only: false },
66 },
67 BranchSignature {
69 vars: vec![rc_output_info, OutputVarInfo {
70 ty: gas_builtin_type,
71 ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 1 },
72 }],
73 ap_change: SierraApChange::Known { new_vars_only: false },
74 },
75 ],
76 fallthrough: Some(0),
77 })
78 }
79}
80
81#[derive(Default)]
83pub struct RedepositGasLibfunc {}
84impl NoGenericArgsGenericLibfunc for RedepositGasLibfunc {
85 const STR_ID: &'static str = "redeposit_gas";
86
87 fn specialize_signature(
88 &self,
89 context: &dyn SignatureSpecializationContext,
90 ) -> Result<LibfuncSignature, SpecializationError> {
91 let gas_builtin_type = context.get_concrete_type(GasBuiltinType::id(), &[])?;
92 Ok(LibfuncSignature::new_non_branch(
93 vec![gas_builtin_type.clone()],
94 vec![OutputVarInfo {
95 ty: gas_builtin_type,
96 ref_info: OutputVarReferenceInfo::Deferred(DeferredOutputKind::Generic),
97 }],
98 SierraApChange::Known { new_vars_only: false },
99 ))
100 }
101}
102
103#[derive(Default)]
105pub struct GetAvailableGasLibfunc {}
106impl NoGenericArgsGenericLibfunc for GetAvailableGasLibfunc {
107 const STR_ID: &'static str = "get_available_gas";
108
109 fn specialize_signature(
110 &self,
111 context: &dyn SignatureSpecializationContext,
112 ) -> Result<LibfuncSignature, SpecializationError> {
113 let gas_builtin_type = context.get_concrete_type(GasBuiltinType::id(), &[])?;
114 Ok(LibfuncSignature::new_non_branch(
115 vec![gas_builtin_type.clone()],
116 vec![
117 OutputVarInfo {
118 ty: gas_builtin_type,
119 ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 0 },
120 },
121 OutputVarInfo {
122 ty: context.get_concrete_type(Uint128Type::id(), &[])?,
123 ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 0 },
124 },
125 ],
126 SierraApChange::Known { new_vars_only: true },
127 ))
128 }
129}
130
131#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
134pub enum CostTokenType {
135 Const,
139
140 Step,
143 Hole,
145 RangeCheck,
147 RangeCheck96,
149
150 Pedersen,
153 Poseidon,
155 Bitwise,
157 EcOp,
159 AddMod,
161 MulMod,
163}
164impl CostTokenType {
165 pub fn iter_precost() -> std::slice::Iter<'static, Self> {
167 [
168 CostTokenType::Pedersen,
169 CostTokenType::Poseidon,
170 CostTokenType::Bitwise,
171 CostTokenType::EcOp,
172 CostTokenType::AddMod,
173 CostTokenType::MulMod,
174 ]
175 .iter()
176 }
177
178 pub fn iter_casm_tokens()
181 -> std::iter::Chain<std::slice::Iter<'static, Self>, std::slice::Iter<'static, Self>> {
182 chain!(Self::iter_precost(), [CostTokenType::Const].iter())
183 }
184
185 pub fn name(&self) -> String {
187 match self {
188 CostTokenType::Const => "const",
189 CostTokenType::Step => "step",
190 CostTokenType::Hole => "hole",
191 CostTokenType::RangeCheck => "range_check",
192 CostTokenType::RangeCheck96 => "range_check96",
193 CostTokenType::Pedersen => "pedersen",
194 CostTokenType::Bitwise => "bitwise",
195 CostTokenType::EcOp => "ec_op",
196 CostTokenType::Poseidon => "poseidon",
197 CostTokenType::AddMod => "add_mod",
198 CostTokenType::MulMod => "mul_mod",
199 }
200 .into()
201 }
202
203 pub fn camel_case_name(&self) -> String {
204 self.name().to_case(convert_case::Case::UpperCamel)
205 }
206
207 pub fn offset_in_builtin_costs(&self) -> i16 {
208 match self {
209 CostTokenType::Const
210 | CostTokenType::Step
211 | CostTokenType::Hole
212 | CostTokenType::RangeCheck
213 | CostTokenType::RangeCheck96 => {
214 panic!("offset_in_builtin_costs is not supported for '{}'.", self.camel_case_name())
215 }
216
217 CostTokenType::Pedersen => 0,
218 CostTokenType::Bitwise => 1,
219 CostTokenType::EcOp => 2,
220 CostTokenType::Poseidon => 3,
221 CostTokenType::AddMod => 4,
223 CostTokenType::MulMod => 5,
224 }
225 }
226}
227
228#[derive(Default)]
233pub struct BuiltinCostsType {}
234impl NoGenericArgsGenericType for BuiltinCostsType {
235 const ID: GenericTypeId = GenericTypeId::new_inline("BuiltinCosts");
236 const STORABLE: bool = true;
237 const DUPLICATABLE: bool = true;
238 const DROPPABLE: bool = true;
239 const ZERO_SIZED: bool = false;
240}
241impl BuiltinCostsType {
242 pub fn cost_computation_steps<TokenUsages: Fn(CostTokenType) -> usize>(
247 table_available: bool,
248 token_usages: TokenUsages,
249 ) -> usize {
250 let calculation_steps = CostTokenType::iter_precost()
251 .map(|token_type| match token_usages(*token_type) {
252 0 => 0,
253 1 => 2,
254 _ => 3,
255 })
256 .sum();
257 if calculation_steps > 0 && !table_available {
258 calculation_steps + 4
259 } else {
260 calculation_steps
261 }
262 }
263}
264
265#[derive(Default)]
267pub struct BuiltinCostWithdrawGasLibfunc;
268impl NoGenericArgsGenericLibfunc for BuiltinCostWithdrawGasLibfunc {
269 const STR_ID: &'static str = "withdraw_gas_all";
270
271 fn specialize_signature(
272 &self,
273 context: &dyn SignatureSpecializationContext,
274 ) -> Result<LibfuncSignature, SpecializationError> {
275 let gas_builtin_type = context.get_concrete_type(GasBuiltinType::id(), &[])?;
276 let range_check_type = context.get_concrete_type(RangeCheckType::id(), &[])?;
277 let builtin_costs_type = context.get_concrete_type(BuiltinCostsType::id(), &[])?;
278 let rc_output_info = OutputVarInfo::new_builtin(range_check_type.clone(), 0);
279 Ok(LibfuncSignature {
280 param_signatures: vec![
281 ParamSignature::new(range_check_type).with_allow_add_const(),
282 ParamSignature::new(gas_builtin_type.clone()),
283 ParamSignature::new(builtin_costs_type),
284 ],
285 branch_signatures: vec![
286 BranchSignature {
288 vars: vec![rc_output_info.clone(), OutputVarInfo {
289 ty: gas_builtin_type.clone(),
290 ref_info: OutputVarReferenceInfo::NewTempVar { idx: 0 },
291 }],
292 ap_change: SierraApChange::Known { new_vars_only: false },
293 },
294 BranchSignature {
296 vars: vec![rc_output_info, OutputVarInfo {
297 ty: gas_builtin_type,
298 ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 1 },
299 }],
300 ap_change: SierraApChange::Known { new_vars_only: false },
301 },
302 ],
303 fallthrough: Some(0),
304 })
305 }
306}
307
308#[derive(Default)]
311pub struct BuiltinCostGetBuiltinCostsLibfunc {}
312
313impl NoGenericArgsGenericLibfunc for BuiltinCostGetBuiltinCostsLibfunc {
314 const STR_ID: &'static str = "get_builtin_costs";
315
316 fn specialize_signature(
317 &self,
318 context: &dyn SignatureSpecializationContext,
319 ) -> Result<LibfuncSignature, SpecializationError> {
320 let builtin_costs_type = context.get_concrete_type(BuiltinCostsType::id(), &[])?;
321 Ok(LibfuncSignature::new_non_branch(
322 vec![],
323 vec![OutputVarInfo {
324 ty: builtin_costs_type,
325 ref_info: OutputVarReferenceInfo::Deferred(DeferredOutputKind::Generic),
326 }],
327 SierraApChange::Known { new_vars_only: false },
328 ))
329 }
330}