1use 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 GetUnspentGas(GetUnspentGasLibfunc),
36 BuiltinWithdrawGas(BuiltinCostWithdrawGasLibfunc),
37 GetBuiltinCosts(BuiltinCostGetBuiltinCostsLibfunc),
38 }, GasConcreteLibfunc
39}
40
41#[derive(Default)]
43pub struct WithdrawGasLibfunc {}
44impl NoGenericArgsGenericLibfunc for WithdrawGasLibfunc {
45 const STR_ID: &'static str = "withdraw_gas";
46
47 fn specialize_signature(
48 &self,
49 context: &dyn SignatureSpecializationContext,
50 ) -> Result<LibfuncSignature, SpecializationError> {
51 let gas_builtin_type = context.get_concrete_type(GasBuiltinType::id(), &[])?;
52 let range_check_type = context.get_concrete_type(RangeCheckType::id(), &[])?;
53 let rc_output_info = OutputVarInfo::new_builtin(range_check_type.clone(), 0);
54 Ok(LibfuncSignature {
55 param_signatures: vec![
56 ParamSignature::new(range_check_type).with_allow_add_const(),
57 ParamSignature::new(gas_builtin_type.clone()),
58 ],
59 branch_signatures: vec![
60 BranchSignature {
62 vars: vec![
63 rc_output_info.clone(),
64 OutputVarInfo {
65 ty: gas_builtin_type.clone(),
66 ref_info: OutputVarReferenceInfo::NewTempVar { idx: 0 },
67 },
68 ],
69 ap_change: SierraApChange::Known { new_vars_only: false },
70 },
71 BranchSignature {
73 vars: vec![
74 rc_output_info,
75 OutputVarInfo {
76 ty: gas_builtin_type,
77 ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 1 },
78 },
79 ],
80 ap_change: SierraApChange::Known { new_vars_only: false },
81 },
82 ],
83 fallthrough: Some(0),
84 })
85 }
86}
87
88#[derive(Default)]
90pub struct RedepositGasLibfunc {}
91impl NoGenericArgsGenericLibfunc for RedepositGasLibfunc {
92 const STR_ID: &'static str = "redeposit_gas";
93
94 fn specialize_signature(
95 &self,
96 context: &dyn SignatureSpecializationContext,
97 ) -> Result<LibfuncSignature, SpecializationError> {
98 let gas_builtin_type = context.get_concrete_type(GasBuiltinType::id(), &[])?;
99 Ok(LibfuncSignature::new_non_branch(
100 vec![gas_builtin_type.clone()],
101 vec![OutputVarInfo {
102 ty: gas_builtin_type,
103 ref_info: OutputVarReferenceInfo::Deferred(DeferredOutputKind::Generic),
104 }],
105 SierraApChange::Known { new_vars_only: false },
106 ))
107 }
108}
109
110#[derive(Default)]
112pub struct GetAvailableGasLibfunc {}
113impl NoGenericArgsGenericLibfunc for GetAvailableGasLibfunc {
114 const STR_ID: &'static str = "get_available_gas";
115
116 fn specialize_signature(
117 &self,
118 context: &dyn SignatureSpecializationContext,
119 ) -> Result<LibfuncSignature, SpecializationError> {
120 let gas_builtin_type = context.get_concrete_type(GasBuiltinType::id(), &[])?;
121 Ok(LibfuncSignature::new_non_branch(
122 vec![gas_builtin_type.clone()],
123 vec![
124 OutputVarInfo {
125 ty: gas_builtin_type,
126 ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 0 },
127 },
128 OutputVarInfo {
129 ty: context.get_concrete_type(Uint128Type::id(), &[])?,
130 ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 0 },
131 },
132 ],
133 SierraApChange::Known { new_vars_only: true },
134 ))
135 }
136}
137
138#[derive(Default)]
140pub struct GetUnspentGasLibfunc {}
141impl NoGenericArgsGenericLibfunc for GetUnspentGasLibfunc {
142 const STR_ID: &'static str = "get_unspent_gas";
143
144 fn specialize_signature(
145 &self,
146 context: &dyn SignatureSpecializationContext,
147 ) -> Result<LibfuncSignature, SpecializationError> {
148 let gas_builtin_type = context.get_concrete_type(GasBuiltinType::id(), &[])?;
149 Ok(LibfuncSignature::new_non_branch(
150 vec![gas_builtin_type.clone()],
151 vec![
152 OutputVarInfo {
153 ty: gas_builtin_type,
154 ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 0 },
155 },
156 OutputVarInfo {
157 ty: context.get_concrete_type(Uint128Type::id(), &[])?,
158 ref_info: OutputVarReferenceInfo::SimpleDerefs,
159 },
160 ],
161 SierraApChange::Known { new_vars_only: false },
162 ))
163 }
164}
165
166#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
169pub enum CostTokenType {
170 Const,
174
175 Step,
178 Hole,
180 RangeCheck,
182 RangeCheck96,
184
185 Pedersen,
188 Poseidon,
190 Bitwise,
192 EcOp,
194 AddMod,
196 MulMod,
198}
199impl CostTokenType {
200 pub fn iter_precost() -> std::slice::Iter<'static, Self> {
202 [
203 CostTokenType::Pedersen,
204 CostTokenType::Poseidon,
205 CostTokenType::Bitwise,
206 CostTokenType::EcOp,
207 CostTokenType::AddMod,
208 CostTokenType::MulMod,
209 ]
210 .iter()
211 }
212
213 pub fn iter_casm_tokens()
216 -> std::iter::Chain<std::slice::Iter<'static, Self>, std::slice::Iter<'static, Self>> {
217 chain!(Self::iter_precost(), [CostTokenType::Const].iter())
218 }
219
220 pub fn name(&self) -> String {
222 match self {
223 CostTokenType::Const => "const",
224 CostTokenType::Step => "step",
225 CostTokenType::Hole => "hole",
226 CostTokenType::RangeCheck => "range_check",
227 CostTokenType::RangeCheck96 => "range_check96",
228 CostTokenType::Pedersen => "pedersen",
229 CostTokenType::Bitwise => "bitwise",
230 CostTokenType::EcOp => "ec_op",
231 CostTokenType::Poseidon => "poseidon",
232 CostTokenType::AddMod => "add_mod",
233 CostTokenType::MulMod => "mul_mod",
234 }
235 .into()
236 }
237
238 pub fn camel_case_name(&self) -> String {
239 self.name().to_case(convert_case::Case::UpperCamel)
240 }
241
242 pub fn offset_in_builtin_costs(&self) -> i16 {
243 match self {
244 CostTokenType::Const
245 | CostTokenType::Step
246 | CostTokenType::Hole
247 | CostTokenType::RangeCheck
248 | CostTokenType::RangeCheck96 => {
249 panic!("offset_in_builtin_costs is not supported for '{}'.", self.camel_case_name())
250 }
251
252 CostTokenType::Pedersen => 0,
253 CostTokenType::Bitwise => 1,
254 CostTokenType::EcOp => 2,
255 CostTokenType::Poseidon => 3,
256 CostTokenType::AddMod => 4,
258 CostTokenType::MulMod => 5,
259 }
260 }
261}
262
263#[derive(Default)]
268pub struct BuiltinCostsType {}
269impl NoGenericArgsGenericType for BuiltinCostsType {
270 const ID: GenericTypeId = GenericTypeId::new_inline("BuiltinCosts");
271 const STORABLE: bool = true;
272 const DUPLICATABLE: bool = true;
273 const DROPPABLE: bool = true;
274 const ZERO_SIZED: bool = false;
275}
276impl BuiltinCostsType {
277 pub fn cost_computation_steps<TokenUsages: Fn(CostTokenType) -> usize>(
282 table_available: bool,
283 token_usages: TokenUsages,
284 ) -> usize {
285 let calculation_steps = CostTokenType::iter_precost()
286 .map(|token_type| match token_usages(*token_type) {
287 0 => 0,
288 1 => 2,
289 _ => 3,
290 })
291 .sum();
292 if calculation_steps > 0 && !table_available {
293 calculation_steps + 4
294 } else {
295 calculation_steps
296 }
297 }
298}
299
300#[derive(Default)]
302pub struct BuiltinCostWithdrawGasLibfunc;
303impl NoGenericArgsGenericLibfunc for BuiltinCostWithdrawGasLibfunc {
304 const STR_ID: &'static str = "withdraw_gas_all";
305
306 fn specialize_signature(
307 &self,
308 context: &dyn SignatureSpecializationContext,
309 ) -> Result<LibfuncSignature, SpecializationError> {
310 let gas_builtin_type = context.get_concrete_type(GasBuiltinType::id(), &[])?;
311 let range_check_type = context.get_concrete_type(RangeCheckType::id(), &[])?;
312 let builtin_costs_type = context.get_concrete_type(BuiltinCostsType::id(), &[])?;
313 let rc_output_info = OutputVarInfo::new_builtin(range_check_type.clone(), 0);
314 Ok(LibfuncSignature {
315 param_signatures: vec![
316 ParamSignature::new(range_check_type).with_allow_add_const(),
317 ParamSignature::new(gas_builtin_type.clone()),
318 ParamSignature::new(builtin_costs_type),
319 ],
320 branch_signatures: vec![
321 BranchSignature {
323 vars: vec![
324 rc_output_info.clone(),
325 OutputVarInfo {
326 ty: gas_builtin_type.clone(),
327 ref_info: OutputVarReferenceInfo::NewTempVar { idx: 0 },
328 },
329 ],
330 ap_change: SierraApChange::Known { new_vars_only: false },
331 },
332 BranchSignature {
334 vars: vec![
335 rc_output_info,
336 OutputVarInfo {
337 ty: gas_builtin_type,
338 ref_info: OutputVarReferenceInfo::SameAsParam { param_idx: 1 },
339 },
340 ],
341 ap_change: SierraApChange::Known { new_vars_only: false },
342 },
343 ],
344 fallthrough: Some(0),
345 })
346 }
347}
348
349#[derive(Default)]
352pub struct BuiltinCostGetBuiltinCostsLibfunc {}
353
354impl NoGenericArgsGenericLibfunc for BuiltinCostGetBuiltinCostsLibfunc {
355 const STR_ID: &'static str = "get_builtin_costs";
356
357 fn specialize_signature(
358 &self,
359 context: &dyn SignatureSpecializationContext,
360 ) -> Result<LibfuncSignature, SpecializationError> {
361 let builtin_costs_type = context.get_concrete_type(BuiltinCostsType::id(), &[])?;
362 Ok(LibfuncSignature::new_non_branch(
363 vec![],
364 vec![OutputVarInfo {
365 ty: builtin_costs_type,
366 ref_info: OutputVarReferenceInfo::Deferred(DeferredOutputKind::Generic),
367 }],
368 SierraApChange::Known { new_vars_only: false },
369 ))
370 }
371}