cairo_lang_sierra_to_casm/
metadata.rs1use cairo_lang_sierra::extensions::gas::CostTokenType;
2use cairo_lang_sierra::ids::FunctionId;
3use cairo_lang_sierra::program::Program;
4use cairo_lang_sierra_ap_change::ap_change_info::ApChangeInfo;
5use cairo_lang_sierra_ap_change::compute::calc_ap_changes as linear_calc_ap_changes;
6use cairo_lang_sierra_ap_change::{ApChangeError, calc_ap_changes};
7use cairo_lang_sierra_gas::gas_info::GasInfo;
8use cairo_lang_sierra_gas::objects::ConstCost;
9use cairo_lang_sierra_gas::{
10 CostError, calc_gas_postcost_info, calc_gas_precost_info, compute_postcost_info,
11 compute_precost_info,
12};
13use cairo_lang_utils::ordered_hash_map::OrderedHashMap;
14use thiserror::Error;
15
16#[derive(Default)]
17pub struct Metadata {
19 pub ap_change_info: ApChangeInfo,
21 pub gas_info: GasInfo,
23}
24
25#[derive(Debug, Error, Eq, PartialEq)]
27pub enum MetadataError {
28 #[error(transparent)]
29 ApChangeError(#[from] ApChangeError),
30 #[error(transparent)]
31 CostError(#[from] CostError),
32}
33
34#[derive(Clone)]
36pub struct MetadataComputationConfig {
37 pub function_set_costs: OrderedHashMap<FunctionId, OrderedHashMap<CostTokenType, i32>>,
39 pub linear_gas_solver: bool,
42 pub linear_ap_change_solver: bool,
45 pub skip_non_linear_solver_comparisons: bool,
48 pub compute_runtime_costs: bool,
51}
52
53impl Default for MetadataComputationConfig {
54 fn default() -> Self {
55 Self {
56 function_set_costs: Default::default(),
57 linear_gas_solver: true,
58 linear_ap_change_solver: true,
59 skip_non_linear_solver_comparisons: false,
60 compute_runtime_costs: false,
61 }
62 }
63}
64
65pub fn calc_metadata_ap_change_only(program: &Program) -> Result<Metadata, MetadataError> {
67 Ok(Metadata {
68 ap_change_info: linear_calc_ap_changes(program, |_, _| 0)?,
69 gas_info: GasInfo {
70 variable_values: Default::default(),
71 function_costs: Default::default(),
72 },
73 })
74}
75
76pub fn calc_metadata(
81 program: &Program,
82 config: MetadataComputationConfig,
83) -> Result<Metadata, MetadataError> {
84 let pre_function_set_costs = config
85 .function_set_costs
86 .iter()
87 .map(|(func, costs)| {
88 (
89 func.clone(),
90 CostTokenType::iter_precost()
91 .filter_map(|token| costs.get(token).map(|v| (*token, *v)))
92 .collect(),
93 )
94 })
95 .collect();
96 let pre_gas_info_new = compute_precost_info(program)?;
97 let pre_gas_info = if config.linear_gas_solver {
98 pre_gas_info_new
99 } else {
100 let pre_gas_info_old = calc_gas_precost_info(program, pre_function_set_costs)?;
101 if !config.skip_non_linear_solver_comparisons {
102 pre_gas_info_old.assert_eq_variables(&pre_gas_info_new, program);
103 pre_gas_info_old.assert_eq_functions(&pre_gas_info_new);
104 }
105 pre_gas_info_old
106 };
107
108 let ap_change_info =
109 if config.linear_ap_change_solver { linear_calc_ap_changes } else { calc_ap_changes }(
110 program,
111 |idx, token_type| pre_gas_info.variable_values[&(idx, token_type)] as usize,
112 )?;
113
114 let mut post_gas_info = if config.linear_gas_solver {
115 let enforced_function_costs: OrderedHashMap<FunctionId, i32> = config
116 .function_set_costs
117 .iter()
118 .map(|(func, costs)| (func.clone(), costs[&CostTokenType::Const]))
119 .collect();
120 compute_postcost_info(
121 program,
122 &|idx| ap_change_info.variable_values.get(idx).copied().unwrap_or_default(),
123 &pre_gas_info,
124 &enforced_function_costs,
125 )
126 } else {
127 let post_function_set_costs = config
128 .function_set_costs
129 .iter()
130 .map(|(func, costs)| {
131 (
132 func.clone(),
133 [CostTokenType::Const]
134 .iter()
135 .filter_map(|token| costs.get(token).map(|v| (*token, *v)))
136 .collect(),
137 )
138 })
139 .collect();
140 calc_gas_postcost_info(program, post_function_set_costs, &pre_gas_info, |idx| {
141 ap_change_info.variable_values.get(&idx).copied().unwrap_or_default()
142 })
143 }?;
144
145 if config.compute_runtime_costs {
146 let post_gas_info_runtime = compute_postcost_info::<ConstCost>(
147 program,
148 &|idx| ap_change_info.variable_values.get(idx).copied().unwrap_or_default(),
149 &pre_gas_info,
150 &Default::default(),
151 )?;
152 post_gas_info = post_gas_info.combine(post_gas_info_runtime);
153 }
154
155 Ok(Metadata { ap_change_info, gas_info: pre_gas_info.combine(post_gas_info) })
156}