Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
75a9754
feat: move GasParams to Cfg
rakita Dec 16, 2025
dad347b
propagate spec id
rakita Dec 17, 2025
551fd21
use cfg spec when evm is created
rakita Dec 17, 2025
2d40c8f
nits
rakita Dec 17, 2025
92c6a93
nit
rakita Dec 17, 2025
fc11160
doc tests
rakita Dec 17, 2025
a552ff9
use derive-where to skip fn
rakita Dec 17, 2025
c4fc69b
Move SetSpecTr and use it as main tr
rakita Dec 18, 2025
f279e2a
feat: add codedeposit price in GasParams
rakita Dec 18, 2025
21f8548
remove SetSpecTr, introduce is_custom_gas_param flag
rakita Dec 22, 2025
40b09ce
Merge remote-tracking branch 'origin/main' into cfggasp
rakita Dec 22, 2025
9b627c9
simplification
rakita Dec 22, 2025
eb14b9c
nits and tests fix
rakita Dec 22, 2025
cf341fa
morf spec type
rakita Dec 22, 2025
7a7eed7
dont compare ptr
rakita Dec 22, 2025
99355ba
import fix
rakita Dec 22, 2025
ee3ef23
typo
rakita Dec 22, 2025
dd9084b
ref alloy-eips
rakita Dec 23, 2025
de242a7
add core::error::Error impl to BalError
rakita Dec 23, 2025
473d1ae
send/sync on GasParams
rakita Dec 23, 2025
ae4625a
Merge remote-tracking branch 'origin/main' into cfggasp
rakita Dec 23, 2025
6e69a27
Merge remote-tracking branch 'origin/main' into cfggasp
rakita Dec 24, 2025
3617014
relex generic for some Cfg functions
rakita Dec 26, 2025
6e5b61e
Merge remote-tracking branch 'origin/rakita/cfg-gas-params' into code…
rakita Dec 26, 2025
965bd1f
load_account_mut_skip_cold
rakita Dec 29, 2025
270d8ce
WIP
rakita Dec 31, 2025
27c996d
Merge remote-tracking branch 'origin/main' into cfggasp
rakita Dec 31, 2025
166f4dc
Merge remote-tracking branch 'origin/rakita/cfg-gas-params' into code…
rakita Dec 31, 2025
8cb29b1
move initial tx gas calc to GasParams
rakita Dec 31, 2025
f7a4d8d
fixes
rakita Jan 5, 2026
536cfb1
Merge remote-tracking branch 'origin/main' into cfgg
rakita Jan 8, 2026
3c57a22
Merge branch 'cfgg' into new-gasp
rakita Jan 8, 2026
1f868bd
Merge remote-tracking branch 'origin/main' into cfgg
rakita Jan 8, 2026
deb1680
Merge branch 'cfgg' into new-gasp
rakita Jan 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 16 additions & 111 deletions crates/context/interface/src/cfg/gas.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Gas constants and functions for gas calculation.

use crate::{transaction::AccessListItemTr as _, Transaction, TransactionType};
use primitives::{eip7702, hardfork::SpecId, U256};
use crate::{cfg::GasParams, transaction::AccessListItemTr as _, Transaction, TransactionType};
use primitives::hardfork::SpecId;

/// Gas cost for operations that consume zero gas.
pub const ZERO: u64 = 0;
Expand Down Expand Up @@ -107,57 +107,6 @@ pub const INITCODE_WORD_COST: u64 = 2;
/// Gas stipend provided to the recipient of a CALL with value transfer.
pub const CALL_STIPEND: u64 = 2300;

#[inline]
pub(crate) const fn log2floor(value: U256) -> u64 {
let mut l: u64 = 256;
let mut i = 3;
loop {
if value.as_limbs()[i] == 0u64 {
l -= 64;
} else {
l -= value.as_limbs()[i].leading_zeros() as u64;
if l == 0 {
return l;
} else {
return l - 1;
}
}
if i == 0 {
break;
}
i -= 1;
}
l
}

/// Calculate the cost of buffer per word.
#[inline]
pub const fn cost_per_word(len: usize, multiple: u64) -> Option<u64> {
multiple.checked_mul(num_words(len) as u64)
}

/// EIP-3860: Limit and meter initcode
///
/// Apply extra gas cost of 2 for every 32-byte chunk of initcode.
///
/// This cannot overflow as the initcode length is assumed to be checked.
#[inline]
pub const fn initcode_cost(len: usize) -> u64 {
let Some(cost) = cost_per_word(len, INITCODE_WORD_COST) else {
panic!("initcode cost overflow")
};
cost
}

/// Memory expansion cost calculation for a given number of words.
#[inline]
pub const fn memory_gas(num_words: usize, linear_cost: u64, quadratic_cost: u64) -> u64 {
let num_words = num_words as u64;
linear_cost
.saturating_mul(num_words)
.saturating_add(num_words.saturating_mul(num_words) / quadratic_cost)
}

/// Init and floor gas from transaction
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
Expand Down Expand Up @@ -195,44 +144,13 @@ pub fn calculate_initial_tx_gas(
access_list_storages: u64,
authorization_list_num: u64,
) -> InitialAndFloorGas {
let mut gas = InitialAndFloorGas::default();

// Initdate stipend
let tokens_in_calldata = get_tokens_in_calldata(input, spec_id.is_enabled_in(SpecId::ISTANBUL));

gas.initial_gas += tokens_in_calldata * STANDARD_TOKEN_COST;

// Get number of access list account and storages.
gas.initial_gas += access_list_accounts * ACCESS_LIST_ADDRESS;
gas.initial_gas += access_list_storages * ACCESS_LIST_STORAGE_KEY;

// Base stipend
gas.initial_gas += if is_create {
if spec_id.is_enabled_in(SpecId::HOMESTEAD) {
// EIP-2: Homestead Hard-fork Changes
53000
} else {
21000
}
} else {
21000
};

// EIP-3860: Limit and meter initcode
// Init code stipend for bytecode analysis
if spec_id.is_enabled_in(SpecId::SHANGHAI) && is_create {
gas.initial_gas += initcode_cost(input.len())
}

// EIP-7702
if spec_id.is_enabled_in(SpecId::PRAGUE) {
gas.initial_gas += authorization_list_num * eip7702::PER_EMPTY_ACCOUNT_COST;

// Calculate gas floor for EIP-7623
gas.floor_gas = calc_tx_floor_cost(tokens_in_calldata);
}

gas
GasParams::new_spec(spec_id).initial_tx_gas(
input,
is_create,
access_list_accounts,
access_list_storages,
authorization_list_num,
)
}

/// Initial gas that is deducted for transaction to be included.
Expand Down Expand Up @@ -272,27 +190,14 @@ pub fn calculate_initial_tx_gas_for_tx(tx: impl Transaction, spec: SpecId) -> In

/// Retrieve the total number of tokens in calldata.
#[inline]
pub fn get_tokens_in_calldata(input: &[u8], is_istanbul: bool) -> u64 {
let zero_data_len = input.iter().filter(|v| **v == 0).count() as u64;
let non_zero_data_len = input.len() as u64 - zero_data_len;
let non_zero_data_multiplier = if is_istanbul {
// EIP-2028: Transaction data gas cost reduction
NON_ZERO_BYTE_MULTIPLIER_ISTANBUL
} else {
NON_ZERO_BYTE_MULTIPLIER
};
zero_data_len + non_zero_data_len * non_zero_data_multiplier
}

/// Calculate the transaction cost floor as specified in EIP-7623.
#[inline]
pub fn calc_tx_floor_cost(tokens_in_calldata: u64) -> u64 {
tokens_in_calldata * TOTAL_COST_FLOOR_PER_TOKEN + 21_000
pub fn get_tokens_in_calldata_istanbul(input: &[u8]) -> u64 {
get_tokens_in_calldata(input, NON_ZERO_BYTE_MULTIPLIER_ISTANBUL)
}

/// Returns number of words what would fit to provided number of bytes,
/// i.e. it rounds up the number bytes to number of words.
/// Retrieve the total number of tokens in calldata.
#[inline]
pub const fn num_words(len: usize) -> usize {
len.div_ceil(32)
pub fn get_tokens_in_calldata(input: &[u8], non_zero_data_multiplier: u64) -> u64 {
let zero_data_len = input.iter().filter(|v| **v == 0).count() as u64;
let non_zero_data_len = input.len() as u64 - zero_data_len;
zero_data_len + non_zero_data_len * non_zero_data_multiplier
}
Loading