Skip to content

Commit 924c452

Browse files
authored
feat: introduce gas_floor_base_cost for EIP-7623 compliance (#101)
* feat: introduce gas_floor_base_cost for EIP-7623 compliance * fix: replace simple arithmetic operations with saturating_* analogs for gas calculations * chore: remove gas_floor_base_cost constant
1 parent f13b0c8 commit 924c452

2 files changed

Lines changed: 75 additions & 36 deletions

File tree

evm/src/gasometer/mod.rs

Lines changed: 74 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -343,10 +343,29 @@ impl<'config> Gasometer<'config> {
343343
/// - [EIP-2028](https://eips.ethereum.org/EIPS/eip-2028)
344344
/// - [EIP-7623](https://eips.ethereum.org/EIPS/eip-7623)
345345
#[must_use]
346+
#[allow(clippy::as_conversions)] // NOTE: in that context usize->u64 `as_conversions` is safe
346347
pub const fn intrinsic_gas_and_gas_floor(cost: TransactionCost, config: &Config) -> (u64, u64) {
348+
const fn floor_gas_calc(
349+
config: &Config,
350+
zero_data_len: usize,
351+
non_zero_data_len: usize,
352+
) -> u64 {
353+
if config.has_floor_gas {
354+
// According to EIP-2028: non-zero byte = 16, zero-byte = 4
355+
// According to EIP-7623: tokens_in_calldata = zero_bytes_in_calldata + nonzero_bytes_in_calldata * 4
356+
let tokens_in_calldata = non_zero_data_len
357+
.saturating_mul(4)
358+
.saturating_add(zero_data_len) as u64;
359+
360+
tokens_in_calldata
361+
.saturating_mul(config.total_cost_floor_per_token)
362+
.saturating_add(config.gas_transaction_call)
363+
} else {
364+
0
365+
}
366+
}
367+
347368
match cost {
348-
// NOTE: in that context usize->u64 `as_conversions` is safe
349-
#[allow(clippy::as_conversions)]
350369
TransactionCost::Call {
351370
zero_data_len,
352371
non_zero_data_len,
@@ -355,52 +374,72 @@ impl<'config> Gasometer<'config> {
355374
authorization_list_len,
356375
} => {
357376
#[deny(clippy::let_and_return)]
358-
let cost = config.gas_transaction_call
359-
+ zero_data_len as u64 * config.gas_transaction_zero_data
360-
+ non_zero_data_len as u64 * config.gas_transaction_non_zero_data
361-
+ access_list_address_len as u64 * config.gas_access_list_address
362-
+ access_list_storage_len as u64 * config.gas_access_list_storage_key
363-
+ authorization_list_len as u64 * config.gas_per_empty_account_cost;
364-
365-
let floor_gas = if config.has_floor_gas {
366-
// According to EIP-2028: non-zero byte = 16, zero-byte = 4
367-
// According to EIP-7623: tokens_in_calldata = zero_bytes_in_calldata + nonzero_bytes_in_calldata * 4
368-
let tokens_in_calldata = (zero_data_len + non_zero_data_len * 4) as u64;
369-
tokens_in_calldata * config.total_cost_floor_per_token
370-
+ config.gas_transaction_call
371-
} else {
372-
0
373-
};
377+
let cost = config
378+
.gas_transaction_call
379+
.saturating_add(
380+
config
381+
.gas_transaction_zero_data
382+
.saturating_mul(zero_data_len as u64),
383+
)
384+
.saturating_add(
385+
config
386+
.gas_transaction_non_zero_data
387+
.saturating_mul(non_zero_data_len as u64),
388+
)
389+
.saturating_add(
390+
config
391+
.gas_access_list_address
392+
.saturating_mul(access_list_address_len as u64),
393+
)
394+
.saturating_add(
395+
config
396+
.gas_access_list_storage_key
397+
.saturating_mul(access_list_storage_len as u64),
398+
)
399+
.saturating_add(
400+
config
401+
.gas_per_empty_account_cost
402+
.saturating_mul(authorization_list_len as u64),
403+
);
404+
let floor_gas = floor_gas_calc(config, zero_data_len, non_zero_data_len);
374405

375406
(cost, floor_gas)
376407
}
377-
// NOTE: in that context usize->u64 `as_conversions` is safe
378-
#[allow(clippy::as_conversions)]
379408
TransactionCost::Create {
380409
zero_data_len,
381410
non_zero_data_len,
382411
access_list_address_len,
383412
access_list_storage_len,
384413
initcode_cost,
385414
} => {
386-
let mut cost = config.gas_transaction_create
387-
+ zero_data_len as u64 * config.gas_transaction_zero_data
388-
+ non_zero_data_len as u64 * config.gas_transaction_non_zero_data
389-
+ access_list_address_len as u64 * config.gas_access_list_address
390-
+ access_list_storage_len as u64 * config.gas_access_list_storage_key;
415+
let mut cost = config
416+
.gas_transaction_create
417+
.saturating_add(
418+
config
419+
.gas_transaction_zero_data
420+
.saturating_mul(zero_data_len as u64),
421+
)
422+
.saturating_add(
423+
config
424+
.gas_transaction_non_zero_data
425+
.saturating_mul(non_zero_data_len as u64),
426+
)
427+
.saturating_add(
428+
config
429+
.gas_access_list_address
430+
.saturating_mul(access_list_address_len as u64),
431+
)
432+
.saturating_add(
433+
config
434+
.gas_access_list_storage_key
435+
.saturating_mul(access_list_storage_len as u64),
436+
);
437+
391438
if config.max_initcode_size.is_some() {
392-
cost += initcode_cost;
439+
cost = cost.saturating_add(initcode_cost);
393440
}
394441

395-
let floor_gas = if config.has_floor_gas {
396-
// According to EIP-2028: non-zero byte = 16, zero-byte = 4
397-
// According to EIP-7623: tokens_in_calldata = zero_bytes_in_calldata + nonzero_bytes_in_calldata * 4
398-
let tokens_in_calldata = (zero_data_len + non_zero_data_len * 4) as u64;
399-
tokens_in_calldata * config.total_cost_floor_per_token
400-
+ config.gas_transaction_call
401-
} else {
402-
0
403-
};
442+
let floor_gas = floor_gas_calc(config, zero_data_len, non_zero_data_len);
404443

405444
(cost, floor_gas)
406445
}

evm/src/runtime/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ pub struct Config {
173173
/// Gas paid for a contract creation transaction.
174174
pub gas_transaction_create: u64,
175175
/// Gas paid for a message call transaction.
176-
pub gas_transaction_call: u64,
176+
pub gas_transaction_call: u64, // TODO: Rename in 3.0.0 because the constant is related not to transaction call only.
177177
/// Gas paid for zero data in a transaction.
178178
pub gas_transaction_zero_data: u64,
179179
/// Gas paid for non-zero data in a transaction.

0 commit comments

Comments
 (0)