-
Notifications
You must be signed in to change notification settings - Fork 66
Expand file tree
/
Copy pathexecution_resources.rs
More file actions
293 lines (264 loc) · 9.5 KB
/
execution_resources.rs
File metadata and controls
293 lines (264 loc) · 9.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
use std::collections::HashMap;
use apollo_sizeof::SizeOf;
use serde::{Deserialize, Serialize};
use starknet_types_core::felt::Felt;
use strum_macros::EnumIter;
use crate::block::{GasPrice, GasPriceVector, NonzeroGasPrice};
use crate::transaction::fields::{Fee, Resource, Tip};
#[cfg_attr(
any(test, feature = "testing"),
derive(
derive_more::Sum,
derive_more::Div,
derive_more::SubAssign,
derive_more::Sub,
derive_more::Add,
derive_more::AddAssign,
)
)]
#[derive(
derive_more::Display,
Clone,
Copy,
Debug,
Default,
Eq,
PartialEq,
PartialOrd,
Ord,
Serialize,
Deserialize,
Hash,
SizeOf,
)]
pub struct GasAmount(pub u64);
impl From<GasAmount> for Felt {
fn from(gas_amount: GasAmount) -> Self {
Self::from(gas_amount.0)
}
}
macro_rules! impl_from_uint_for_gas_amount {
($($uint:ty),*) => {
$(
impl From<$uint> for GasAmount {
fn from(value: $uint) -> Self {
Self(u64::from(value))
}
}
)*
};
}
impl_from_uint_for_gas_amount!(u8, u16, u32, u64);
impl GasAmount {
pub const ZERO: Self = Self(0);
pub const MAX: Self = Self(u64::MAX);
pub fn checked_add(self, rhs: Self) -> Option<Self> {
self.0.checked_add(rhs.0).map(Self)
}
pub fn checked_add_panic_on_overflow(self, added_gas: GasAmount) -> GasAmount {
self.checked_add(added_gas).unwrap_or_else(|| {
panic!(
"Addition overflow while adding gas. current gas: {self}, try to add
gas: {added_gas}.",
)
})
}
pub fn checked_sub(self, rhs: Self) -> Option<Self> {
self.0.checked_sub(rhs.0).map(Self)
}
pub const fn nonzero_saturating_mul(self, rhs: NonzeroGasPrice) -> Fee {
rhs.saturating_mul(self)
}
pub const fn saturating_mul(self, rhs: GasPrice) -> Fee {
rhs.saturating_mul(self)
}
pub fn checked_mul(self, rhs: GasPrice) -> Option<Fee> {
rhs.checked_mul(self)
}
pub fn checked_factor_mul(self, factor: u64) -> Option<Self> {
self.0.checked_mul(factor).map(Self)
}
pub fn checked_factor_div(self, factor: u64) -> Option<Self> {
self.0.checked_div(factor).map(Self)
}
}
#[cfg_attr(
any(test, feature = "testing"),
derive(derive_more::Add, derive_more::Sum, derive_more::AddAssign)
)]
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Deserialize, Serialize)]
pub struct GasVector {
pub l1_gas: GasAmount,
pub l1_data_gas: GasAmount,
#[serde(default)]
pub l2_gas: GasAmount,
}
impl GasVector {
pub const ZERO: GasVector =
GasVector { l1_gas: GasAmount(0), l1_data_gas: GasAmount(0), l2_gas: GasAmount(0) };
pub fn from_l1_gas(l1_gas: GasAmount) -> Self {
Self { l1_gas, ..Default::default() }
}
pub fn from_l1_data_gas(l1_data_gas: GasAmount) -> Self {
Self { l1_data_gas, ..Default::default() }
}
pub fn from_l2_gas(l2_gas: GasAmount) -> Self {
Self { l2_gas, ..Default::default() }
}
pub fn checked_add(self, rhs: Self) -> Option<Self> {
match (
self.l1_gas.checked_add(rhs.l1_gas),
self.l1_data_gas.checked_add(rhs.l1_data_gas),
self.l2_gas.checked_add(rhs.l2_gas),
) {
(Some(l1_gas), Some(l1_data_gas), Some(l2_gas)) => {
Some(Self { l1_gas, l1_data_gas, l2_gas })
}
_ => None,
}
}
pub fn checked_scalar_mul(self, factor: u64) -> Option<Self> {
match (
self.l1_gas.checked_factor_mul(factor),
self.l1_data_gas.checked_factor_mul(factor),
self.l2_gas.checked_factor_mul(factor),
) {
(Some(l1_gas), Some(l1_data_gas), Some(l2_gas)) => {
Some(Self { l1_gas, l1_data_gas, l2_gas })
}
_ => None,
}
}
/// Computes the cost (in fee token units) of the gas vector (panicking on overflow).
pub fn cost(&self, gas_prices: &GasPriceVector, tip: Tip) -> Fee {
let tipped_l2_gas_price =
gas_prices.l2_gas_price.checked_add(tip.into()).unwrap_or_else(|| {
panic!(
"Tip overflowed: addition of L2 gas price ({}) and tip ({}) resulted in \
overflow.",
gas_prices.l2_gas_price, tip
)
});
let mut sum = Fee(0);
for (gas, price, resource) in [
(self.l1_gas, gas_prices.l1_gas_price, Resource::L1Gas),
(self.l1_data_gas, gas_prices.l1_data_gas_price, Resource::L1DataGas),
(self.l2_gas, tipped_l2_gas_price, Resource::L2Gas),
] {
let cost = gas.checked_mul(price.get()).unwrap_or_else(|| {
panic!(
"{resource} cost overflowed: multiplication of gas amount ({gas}) by price \
per unit ({price}) resulted in overflow."
)
});
sum = sum.checked_add(cost).unwrap_or_else(|| {
panic!(
"Total cost overflowed: addition of current sum ({sum}) and cost of \
{resource} ({cost}) resulted in overflow."
)
});
}
sum
}
}
/// Computes the total L1 gas amount estimation from the different given L1 gas arguments using the
/// following formula:
/// One byte of data costs either 1 data gas (in blob mode) or 16 gas (in calldata
/// mode). For gas price GP and data gas price DGP, the discount for using blobs
/// would be DGP / (16 * GP).
/// X non-data-related gas consumption and Y bytes of data, in non-blob mode, would
/// cost (X + 16*Y) units of gas. Applying the discount ratio to the data-related
/// summand, we get total_gas = (X + Y * DGP / GP).
/// If this function is called with kzg_flag==false, then l1_data_gas==0, and this discount
/// function does nothing.
/// Panics on overflow.
/// Does not take L2 gas into account - more context is required to convert L2 gas units to L1 gas
/// units (context defined outside of the current crate).
pub fn to_discounted_l1_gas(
l1_gas_price: NonzeroGasPrice,
l1_data_gas_price: GasPrice,
l1_gas: GasAmount,
l1_data_gas: GasAmount,
) -> GasAmount {
let l1_data_gas_fee = l1_data_gas.checked_mul(l1_data_gas_price).unwrap_or_else(|| {
panic!(
"Discounted L1 gas cost overflowed: multiplication of L1 data gas ({l1_data_gas}) by \
L1 data gas price ({l1_data_gas_price}) resulted in overflow."
);
});
let l1_data_gas_in_l1_gas_units =
l1_data_gas_fee.checked_div_ceil(l1_gas_price).unwrap_or_else(|| {
panic!(
"Discounted L1 gas cost overflowed: division of L1 data fee ({l1_data_gas_fee}) \
by regular L1 gas price ({l1_gas_price}) resulted in overflow."
);
});
l1_gas.checked_add(l1_data_gas_in_l1_gas_units).unwrap_or_else(|| {
panic!(
"Overflow while computing discounted L1 gas: L1 gas ({l1_gas}) + L1 data gas in L1 \
gas units ({l1_data_gas_in_l1_gas_units}) resulted in overflow."
)
})
}
/// The execution resources used by a transaction.
#[derive(Debug, Default, Deserialize, Serialize, Clone, Eq, PartialEq)]
pub struct ExecutionResources {
pub steps: u64,
pub builtin_instance_counter: HashMap<Builtin, u64>,
pub memory_holes: u64,
pub da_gas_consumed: GasVector,
pub gas_consumed: GasVector,
}
#[derive(Clone, Copy, Debug, Deserialize, EnumIter, Eq, Hash, PartialEq, Serialize)]
pub enum Builtin {
#[serde(rename = "range_check_builtin_applications")]
RangeCheck,
#[serde(rename = "pedersen_builtin_applications")]
Pedersen,
#[serde(rename = "poseidon_builtin_applications")]
Poseidon,
#[serde(rename = "ec_op_builtin_applications")]
EcOp,
#[serde(rename = "ecdsa_builtin_applications")]
Ecdsa,
#[serde(rename = "bitwise_builtin_applications")]
Bitwise,
#[serde(rename = "keccak_builtin_applications")]
Keccak,
#[serde(rename = "segment_arena_builtin")]
SegmentArena,
#[serde(rename = "add_mod_builtin")]
AddMod,
#[serde(rename = "mul_mod_builtin")]
MulMod,
#[serde(rename = "range_check96_builtin")]
RangeCheck96,
}
const RANGE_CHACK_BUILTIN_NAME: &str = "range_check";
const PEDERSEN_BUILTIN_NAME: &str = "pedersen";
const POSEIDON_BUILTIN_NAME: &str = "poseidon";
const EC_OP_BUILTIN_NAME: &str = "ec_op";
const ECDSA_BUILTIN_NAME: &str = "ecdsa";
const BITWISE_BUILTIN_NAME: &str = "bitwise";
const KECCAK_BUILTIN_NAME: &str = "keccak";
const SEGMENT_ARENA_BUILTIN_NAME: &str = "segment_arena";
const ADD_MOD_BUILTIN_NAME: &str = "add_mod";
const MUL_MOD_BUILTIN_NAME: &str = "mul_mod";
const RANGE_CHECK96_BUILTIN_NAME: &str = "range_check96";
impl Builtin {
pub fn name(&self) -> &'static str {
match self {
Builtin::RangeCheck => RANGE_CHACK_BUILTIN_NAME,
Builtin::Pedersen => PEDERSEN_BUILTIN_NAME,
Builtin::Poseidon => POSEIDON_BUILTIN_NAME,
Builtin::EcOp => EC_OP_BUILTIN_NAME,
Builtin::Ecdsa => ECDSA_BUILTIN_NAME,
Builtin::Bitwise => BITWISE_BUILTIN_NAME,
Builtin::Keccak => KECCAK_BUILTIN_NAME,
Builtin::SegmentArena => SEGMENT_ARENA_BUILTIN_NAME,
Builtin::AddMod => ADD_MOD_BUILTIN_NAME,
Builtin::MulMod => MUL_MOD_BUILTIN_NAME,
Builtin::RangeCheck96 => RANGE_CHECK96_BUILTIN_NAME,
}
}
}