Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: eip-7623 #1744

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
46 changes: 31 additions & 15 deletions crates/interpreter/src/gas/calc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,26 +363,22 @@ pub const fn memory_gas(num_words: u64) -> u64 {

/// Initial gas that is deducted for transaction to be included.
/// Initial gas contains initial stipend gas, gas for access list and input data.
pub fn validate_initial_tx_gas(
///
/// # Returns
///
/// - Intrinsic gas
/// - Number of tokens in calldata
pub fn calculate_initial_tx_gas(
spec_id: SpecId,
input: &[u8],
is_create: bool,
access_list: &[AccessListItem],
authorization_list_num: u64,
) -> u64 {
) -> (u64, u64) {
let mut initial_gas = 0;
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;

// initdate stipend
initial_gas += zero_data_len * TRANSACTION_ZERO_DATA;
// EIP-2028: Transaction data gas cost reduction
initial_gas += non_zero_data_len
* if spec_id.is_enabled_in(SpecId::ISTANBUL) {
16
} else {
68
};
let tokens_in_calldata = get_tokens_in_calldata(input, spec_id.is_enabled_in(SpecId::ISTANBUL));
initial_gas += tokens_in_calldata * STANDARD_TOKEN_COST;

// get number of access list account and storages.
if spec_id.is_enabled_in(SpecId::BERLIN) {
Expand All @@ -409,10 +405,30 @@ pub fn validate_initial_tx_gas(
initial_gas += initcode_cost(input.len() as u64)
}

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

initial_gas
(initial_gas, tokens_in_calldata)
}

/// 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
}
16 changes: 13 additions & 3 deletions crates/interpreter/src/gas/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,19 @@ pub const SSTORE_SET: u64 = 20000;
pub const SSTORE_RESET: u64 = 5000;
pub const REFUND_SSTORE_CLEARS: i64 = 15000;

pub const TRANSACTION_ZERO_DATA: u64 = 4;
pub const TRANSACTION_NON_ZERO_DATA_INIT: u64 = 16;
pub const TRANSACTION_NON_ZERO_DATA_FRONTIER: u64 = 68;
/// The standard cost of calldata token.
pub const STANDARD_TOKEN_COST: u64 = 4;
/// The cost of a non-zero byte in calldata.
pub const NON_ZERO_BYTE_DATA_COST: u64 = 68;
/// The multiplier for a non zero byte in calldata.
pub const NON_ZERO_BYTE_MULTIPLIER: u64 = NON_ZERO_BYTE_DATA_COST / STANDARD_TOKEN_COST;
/// The cost of a non-zero byte in calldata adjusted by [EIP-2028](https://eips.ethereum.org/EIPS/eip-2028).
pub const NON_ZERO_BYTE_DATA_COST_ISTANBUL: u64 = 16;
/// The multiplier for a non zero byte in calldata adjusted by [EIP-2028](https://eips.ethereum.org/EIPS/eip-2028).
pub const NON_ZERO_BYTE_MULTIPLIER_ISTANBUL: u64 =
NON_ZERO_BYTE_DATA_COST_ISTANBUL / STANDARD_TOKEN_COST;
// The cost floor per token as defined by [EIP-2028](https://eips.ethereum.org/EIPS/eip-2028).
pub const TOTAL_COST_FLOOR_PER_TOKEN: u64 = 10;

pub const EOF_CREATE_GAS: u64 = 32000;

Expand Down
19 changes: 19 additions & 0 deletions crates/revm/src/evm.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
use revm_interpreter::gas::{
calc_tx_floor_cost, get_tokens_in_calldata, TOTAL_COST_FLOOR_PER_TOKEN,
};

use crate::{
builder::{EvmBuilder, HandlerStage, SetGenericStage},
db::{Database, DatabaseCommit, EmptyDB},
Expand Down Expand Up @@ -382,6 +386,21 @@ impl<EXT, DB: Database> Evm<'_, EXT, DB> {
.execution()
.last_frame_return(ctx, &mut result)?;

// EIP-7623: Increase calldata cost
if ctx.evm.spec_id().is_enabled_in(SpecId::PRAGUE) {
let tokens_in_calldata = get_tokens_in_calldata(
ctx.env().tx.data.as_ref(),
true, // Istanbul is enabled in Prague
);
let floor = calc_tx_floor_cost(tokens_in_calldata);

let gas = result.gas_mut();
let gas_used = gas.spent();
if gas.spent() < floor {
gas.record_cost(floor - gas.spent());
}
}

let post_exec = self.handler.post_execution();
// calculate final refund and add EIP-7702 refund to gas.
post_exec.refund(ctx, result.gas_mut(), eip7702_gas_refund);
Expand Down
1 change: 1 addition & 0 deletions crates/revm/src/handler/mainnet/post_execution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::{
},
Context, FrameResult,
};
use revm_interpreter::{gas::*, Host};

/// Mainnet end handle does not change the output.
#[inline]
Expand Down
14 changes: 11 additions & 3 deletions crates/revm/src/handler/mainnet/validation.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use revm_interpreter::gas;
use revm_interpreter::gas::{self, calc_tx_floor_cost};

use crate::{
handler::SpecId,
primitives::{db::Database, EVMError, Env, InvalidTransaction, Spec},
Context,
};
Expand Down Expand Up @@ -49,16 +50,23 @@ pub fn validate_initial_tx_gas<SPEC: Spec, DB: Database>(
.map(|l| l.len() as u64)
.unwrap_or_default();

let initial_gas_spend = gas::validate_initial_tx_gas(
let (initial_gas_spend, tokens_in_calldata) = gas::calculate_initial_tx_gas(
SPEC::SPEC_ID,
input,
is_create,
access_list,
authorization_list_num,
);

// EIP-7623
let floor = if SPEC::SPEC_ID.is_enabled_in(SpecId::PRAGUE) {
calc_tx_floor_cost(tokens_in_calldata)
} else {
0
};

// Additional check to see if limit is big enough to cover initial gas.
if initial_gas_spend > env.tx.gas_limit {
if initial_gas_spend.max(floor) > env.tx.gas_limit {
return Err(InvalidTransaction::CallGasCostMoreThanGasLimit.into());
}
Ok(initial_gas_spend)
Expand Down