Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
30 changes: 24 additions & 6 deletions crates/context/interface/src/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,12 +301,18 @@ pub enum InvalidTransaction {
/// Initial gas for a Call contains:
/// - initial stipend gas
/// - gas for access list and input data
CallGasCostMoreThanGasLimit,
CallGasCostMoreThanGasLimit {
initial_gas: u64,
gas_limit: u64,
},
/// Gas floor calculated from EIP-7623 Increase calldata cost
/// is more than the gas limit.
///
/// Tx data is too large to be executed.
GasFloorMoreThanGasLimit,
GasFloorMoreThanGasLimit {
gas_floor: u64,
gas_limit: u64,
},
/// EIP-3607 Reject transactions from senders with deployed code
RejectCallerWithCode,
/// Transaction account does not have enough amount of ether to cover transferred value and gas_limit*gas_price.
Expand Down Expand Up @@ -385,11 +391,23 @@ impl fmt::Display for InvalidTransaction {
Self::CallerGasLimitMoreThanBlock => {
write!(f, "caller gas limit exceeds the block gas limit")
}
Self::CallGasCostMoreThanGasLimit => {
write!(f, "call gas cost exceeds the gas limit")
Self::CallGasCostMoreThanGasLimit {
initial_gas,
gas_limit,
} => {
write!(
f,
"call gas cost ({initial_gas}) exceeds the gas limit ({gas_limit})"
)
}
Self::GasFloorMoreThanGasLimit => {
write!(f, "gas floor exceeds the gas limit")
Self::GasFloorMoreThanGasLimit {
gas_floor,
gas_limit,
} => {
write!(
f,
"gas floor ({gas_floor}) exceeds the gas limit ({gas_limit})"
)
}
Self::RejectCallerWithCode => {
write!(f, "reject transactions from senders with deployed code")
Expand Down
33 changes: 10 additions & 23 deletions crates/handler/src/validation.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use context_interface::{
journaled_state::JournalTr,
result::{InvalidHeader, InvalidTransaction},
transaction::{AccessListItemTr, Transaction, TransactionType},
transaction::{Transaction, TransactionType},
Block, Cfg, ContextTr, Database,
};
use core::cmp::{self, Ordering};
Expand Down Expand Up @@ -294,36 +294,23 @@ pub fn validate_initial_tx_gas(
tx: impl Transaction,
spec: SpecId,
) -> Result<InitialAndFloorGas, InvalidTransaction> {
let (accounts, storages) = tx
.access_list()
.map(|al| {
al.fold((0, 0), |(mut num_accounts, mut num_storage_slots), item| {
num_accounts += 1;
num_storage_slots += item.storage_slots().count();

(num_accounts, num_storage_slots)
})
})
.unwrap_or_default();

let gas = gas::calculate_initial_tx_gas(
spec,
tx.input(),
tx.kind().is_create(),
accounts as u64,
storages as u64,
tx.authorization_list_len() as u64,
);
let gas = gas::calculate_initial_tx_gas_for_tx(&tx, spec);

// Additional check to see if limit is big enough to cover initial gas.
if gas.initial_gas > tx.gas_limit() {
return Err(InvalidTransaction::CallGasCostMoreThanGasLimit);
return Err(InvalidTransaction::CallGasCostMoreThanGasLimit {
gas_limit: tx.gas_limit(),
initial_gas: gas.initial_gas,
});
}

// EIP-7623: Increase calldata cost
// floor gas should be less than gas limit.
if spec.is_enabled_in(SpecId::PRAGUE) && gas.floor_gas > tx.gas_limit() {
return Err(InvalidTransaction::GasFloorMoreThanGasLimit);
return Err(InvalidTransaction::GasFloorMoreThanGasLimit {
gas_floor: gas.floor_gas,
gas_limit: tx.gas_limit(),
});
};

Ok(gas)
Expand Down
34 changes: 33 additions & 1 deletion crates/interpreter/src/gas/calc.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use super::constants::*;
use crate::{num_words, tri, SStoreResult, SelfDestructResult, StateLoad};
use context_interface::journaled_state::AccountLoad;
use context_interface::{
journaled_state::AccountLoad, transaction::AccessListItemTr as _, Transaction,
};
use primitives::{eip7702, hardfork::SpecId, U256};

/// `SSTORE` opcode refund calculation.
Expand Down Expand Up @@ -409,6 +411,36 @@ pub fn calculate_initial_tx_gas(
gas
}

/// Initial gas that is deducted for transaction to be included.
/// Initial gas contains initial stipend gas, gas for access list and input data.
///
/// # Returns
///
/// - Intrinsic gas
/// - Number of tokens in calldata
pub fn calculate_initial_tx_gas_for_tx(tx: impl Transaction, spec: SpecId) -> InitialAndFloorGas {
let (accounts, storages) = tx
.access_list()
.map(|al| {
al.fold((0, 0), |(mut num_accounts, mut num_storage_slots), item| {
num_accounts += 1;
num_storage_slots += item.storage_slots().count();

(num_accounts, num_storage_slots)
})
})
.unwrap_or_default();

calculate_initial_tx_gas(
spec,
tx.input(),
tx.kind().is_create(),
accounts as u64,
storages as u64,
tx.authorization_list_len() as u64,
)
}

/// Retrieve the total number of tokens in calldata.
#[inline]
pub fn get_tokens_in_calldata(input: &[u8], is_istanbul: bool) -> u64 {
Expand Down
Loading