From 3e54808144a3a7eb08fde6213453847633fde031 Mon Sep 17 00:00:00 2001 From: SDartayet <44068466+SDartayet@users.noreply.github.com> Date: Fri, 7 Nov 2025 11:57:59 -0300 Subject: [PATCH 1/8] Refactored chainconfig --- crates/blockchain/blockchain.rs | 25 +- crates/blockchain/constants.rs | 5 +- crates/blockchain/mempool.rs | 46 +-- crates/blockchain/payload.rs | 36 +- crates/common/types/block.rs | 8 +- crates/common/types/genesis.rs | 323 +++++++----------- .../block_producer/payload_builder.rs | 12 - crates/networking/rpc/engine/blobs.rs | 6 +- crates/networking/rpc/engine/fork_choice.rs | 10 +- crates/networking/rpc/engine/payload.rs | 14 +- crates/networking/rpc/eth/block.rs | 4 +- crates/networking/rpc/eth/client.rs | 2 +- crates/networking/rpc/eth/fee_market.rs | 4 +- crates/vm/backends/levm/mod.rs | 6 +- crates/vm/backends/mod.rs | 2 +- crates/vm/levm/src/environment.rs | 4 +- 16 files changed, 193 insertions(+), 314 deletions(-) diff --git a/crates/blockchain/blockchain.rs b/crates/blockchain/blockchain.rs index 101eb183df7..012fdade3b3 100644 --- a/crates/blockchain/blockchain.rs +++ b/crates/blockchain/blockchain.rs @@ -19,9 +19,9 @@ use ethrex_common::types::fee_config::FeeConfig; use ethrex_common::types::requests::{EncodedRequests, Requests, compute_requests_hash}; use ethrex_common::types::{ AccountState, AccountUpdate, Block, BlockHash, BlockHeader, BlockNumber, ChainConfig, Code, - EIP4844Transaction, Receipt, Transaction, WrappedEIP4844Transaction, compute_receipts_root, - validate_block_header, validate_cancun_header_fields, validate_prague_header_fields, - validate_pre_cancun_header_fields, + EIP4844Transaction, Fork::*, Receipt, Transaction, WrappedEIP4844Transaction, + compute_receipts_root, validate_block_header, validate_cancun_header_fields, + validate_prague_header_fields, validate_pre_cancun_header_fields, }; use ethrex_common::types::{ELASTICITY_MULTIPLIER, P2PTransaction}; use ethrex_common::types::{Fork, MempoolTransaction}; @@ -1275,7 +1275,7 @@ impl Blockchain { // NOTE: We could add a tx size limit here, but it's not in the actual spec // Check init code size - if config.is_shanghai_activated(header.timestamp) + if config.is_fork_activated(Shanghai, header.timestamp) && tx.is_contract_creation() && tx.data().len() > MAX_INITCODE_SIZE as usize { @@ -1286,7 +1286,8 @@ impl Blockchain { return Err(MempoolError::TxMaxDataSizeError); } - if config.is_osaka_activated(header.timestamp) && tx.gas_limit() > POST_OSAKA_GAS_LIMIT_CAP + if config.is_fork_activated(Osaka, header.timestamp) + && tx.gas_limit() > POST_OSAKA_GAS_LIMIT_CAP { // https://eips.ethereum.org/EIPS/eip-7825 return Err(MempoolError::TxMaxGasLimitExceededError( @@ -1419,7 +1420,7 @@ impl Blockchain { .storage .get_block_header(latest_block_number)? .ok_or(StoreError::Custom("Latest block not in DB".to_string()))?; - Ok(chain_config.fork(latest_block.timestamp)) + Ok(chain_config.get_fork(latest_block.timestamp)) } } @@ -1442,7 +1443,7 @@ pub fn validate_requests_hash( chain_config: &ChainConfig, requests: &[Requests], ) -> Result<(), ChainError> { - if !chain_config.is_prague_activated(header.timestamp) { + if !chain_config.is_fork_activated(Prague, header.timestamp) { return Ok(()); } @@ -1529,7 +1530,7 @@ pub fn validate_block( validate_block_header(&block.header, parent_header, elasticity_multiplier) .map_err(InvalidBlockError::from)?; - if chain_config.is_osaka_activated(block.header.timestamp) { + if chain_config.is_fork_activated(Osaka, block.header.timestamp) { let block_rlp_size = block.encode_to_vec().len(); if block_rlp_size > MAX_RLP_BLOCK_SIZE as usize { return Err(error::ChainError::InvalidBlock( @@ -1540,14 +1541,14 @@ pub fn validate_block( )); } } - if chain_config.is_prague_activated(block.header.timestamp) { + if chain_config.is_fork_activated(Prague, block.header.timestamp) { validate_prague_header_fields(&block.header, parent_header, chain_config) .map_err(InvalidBlockError::from)?; verify_blob_gas_usage(block, chain_config)?; - if chain_config.is_osaka_activated(block.header.timestamp) { + if chain_config.is_fork_activated(Osaka, block.header.timestamp) { verify_transaction_max_gas_limit(block)?; } - } else if chain_config.is_cancun_activated(block.header.timestamp) { + } else if chain_config.is_fork_activated(Cancun, block.header.timestamp) { validate_cancun_header_fields(&block.header, parent_header, chain_config) .map_err(InvalidBlockError::from)?; verify_blob_gas_usage(block, chain_config)?; @@ -1589,7 +1590,7 @@ fn verify_blob_gas_usage(block: &Block, config: &ChainConfig) -> Result<(), Chai let mut blob_gas_used = 0_u32; let mut blobs_in_block = 0_u32; let max_blob_number_per_block = config - .get_fork_blob_schedule(block.header.timestamp) + .get_current_blob_schedule(block.header.timestamp) .map(|schedule| schedule.max) .ok_or(ChainError::Custom("Provided block fork is invalid".into()))?; let max_blob_gas_per_block = max_blob_number_per_block * GAS_PER_BLOB; diff --git a/crates/blockchain/constants.rs b/crates/blockchain/constants.rs index e0ba1f698d9..4cc8dcdcda2 100644 --- a/crates/blockchain/constants.rs +++ b/crates/blockchain/constants.rs @@ -18,9 +18,6 @@ pub const TX_ACCESS_LIST_ADDRESS_GAS: u64 = 2400; // Gas cost for each storage key specified on access lists pub const TX_ACCESS_LIST_STORAGE_KEY_GAS: u64 = 1900; -// Gas cost for each non zero byte on transaction data -pub const TX_DATA_NON_ZERO_GAS: u64 = 68; - // === EIP-170 constants === // Max bytecode size @@ -37,7 +34,7 @@ pub const MAX_TRANSACTION_DATA_SIZE: u32 = 4 * 32 * 1024; // 128 Kb // === EIP-2028 constants === // Gas cost for each non zero byte on transaction data -pub const TX_DATA_NON_ZERO_GAS_EIP2028: u64 = 16; +pub const TX_DATA_NON_ZERO_GAS: u64 = 16; // === EIP-4844 constants === diff --git a/crates/blockchain/mempool.rs b/crates/blockchain/mempool.rs index db14719c79a..b6b98a5c5de 100644 --- a/crates/blockchain/mempool.rs +++ b/crates/blockchain/mempool.rs @@ -6,14 +6,15 @@ use std::{ use crate::{ constants::{ TX_ACCESS_LIST_ADDRESS_GAS, TX_ACCESS_LIST_STORAGE_KEY_GAS, TX_CREATE_GAS_COST, - TX_DATA_NON_ZERO_GAS, TX_DATA_NON_ZERO_GAS_EIP2028, TX_DATA_ZERO_GAS_COST, TX_GAS_COST, - TX_INIT_CODE_WORD_GAS_COST, + TX_DATA_NON_ZERO_GAS, TX_DATA_ZERO_GAS_COST, TX_GAS_COST, TX_INIT_CODE_WORD_GAS_COST, }, error::MempoolError, }; use ethrex_common::{ Address, H160, H256, U256, - types::{BlobsBundle, BlockHeader, ChainConfig, MempoolTransaction, Transaction, TxType}, + types::{ + BlobsBundle, BlockHeader, ChainConfig, Fork::*, MempoolTransaction, Transaction, TxType, + }, }; use ethrex_storage::error::StoreError; use std::collections::HashSet; @@ -426,16 +427,10 @@ pub fn transaction_intrinsic_gas( let data_len = tx.data().len() as u64; if data_len > 0 { - let non_zero_gas_cost = if config.is_istanbul_activated(header.number) { - TX_DATA_NON_ZERO_GAS_EIP2028 - } else { - TX_DATA_NON_ZERO_GAS - }; - let non_zero_count = tx.data().iter().filter(|&&x| x != 0u8).count() as u64; gas = gas - .checked_add(non_zero_count * non_zero_gas_cost) + .checked_add(non_zero_count * TX_DATA_NON_ZERO_GAS) .ok_or(MempoolError::TxGasOverflowError)?; let zero_count = data_len - non_zero_count; @@ -444,7 +439,7 @@ pub fn transaction_intrinsic_gas( .checked_add(zero_count * TX_DATA_ZERO_GAS_COST) .ok_or(MempoolError::TxGasOverflowError)?; - if is_contract_creation && config.is_shanghai_activated(header.timestamp) { + if is_contract_creation && config.is_fork_activated(Shanghai, header.timestamp) { // Len in 32 bytes sized words let len_in_words = data_len.saturating_add(31) / 32; @@ -477,8 +472,7 @@ mod tests { use crate::error::MempoolError; use crate::mempool::{ Mempool, TX_ACCESS_LIST_ADDRESS_GAS, TX_ACCESS_LIST_STORAGE_KEY_GAS, TX_CREATE_GAS_COST, - TX_DATA_NON_ZERO_GAS, TX_DATA_NON_ZERO_GAS_EIP2028, TX_DATA_ZERO_GAS_COST, TX_GAS_COST, - TX_INIT_CODE_WORD_GAS_COST, + TX_DATA_NON_ZERO_GAS, TX_DATA_ZERO_GAS_COST, TX_GAS_COST, TX_INIT_CODE_WORD_GAS_COST, }; use std::collections::HashMap; @@ -572,29 +566,6 @@ mod tests { assert_eq!(intrinsic_gas, expected_gas_cost); } - #[test] - fn transaction_intrinsic_data_gas_pre_istanbul() { - let (config, header) = build_basic_config_and_header(false, false); - - let tx = EIP1559Transaction { - nonce: 3, - max_priority_fee_per_gas: 0, - max_fee_per_gas: 0, - gas_limit: 100_000, - to: TxKind::Call(Address::from_low_u64_be(1)), // Normal tx - value: U256::zero(), // Value zero - data: Bytes::from(vec![0x0, 0x1, 0x1, 0x0, 0x1, 0x1]), // 6 bytes of data - access_list: Default::default(), // No access list - ..Default::default() - }; - - let tx = Transaction::EIP1559Transaction(tx); - let expected_gas_cost = TX_GAS_COST + 2 * TX_DATA_ZERO_GAS_COST + 4 * TX_DATA_NON_ZERO_GAS; - let intrinsic_gas = - transaction_intrinsic_gas(&tx, &header, &config).expect("Intrinsic gas"); - assert_eq!(intrinsic_gas, expected_gas_cost); - } - #[test] fn transaction_intrinsic_data_gas_post_istanbul() { let (config, header) = build_basic_config_and_header(true, false); @@ -612,8 +583,7 @@ mod tests { }; let tx = Transaction::EIP1559Transaction(tx); - let expected_gas_cost = - TX_GAS_COST + 2 * TX_DATA_ZERO_GAS_COST + 4 * TX_DATA_NON_ZERO_GAS_EIP2028; + let expected_gas_cost = TX_GAS_COST + 2 * TX_DATA_ZERO_GAS_COST + 4 * TX_DATA_NON_ZERO_GAS; let intrinsic_gas = transaction_intrinsic_gas(&tx, &header, &config).expect("Intrinsic gas"); assert_eq!(intrinsic_gas, expected_gas_cost); diff --git a/crates/blockchain/payload.rs b/crates/blockchain/payload.rs index c3b1d845b00..5b4fb78ff6e 100644 --- a/crates/blockchain/payload.rs +++ b/crates/blockchain/payload.rs @@ -11,7 +11,9 @@ use ethrex_common::{ constants::{DEFAULT_OMMERS_HASH, DEFAULT_REQUESTS_HASH, GAS_PER_BLOB, MAX_RLP_BLOCK_SIZE}, types::{ AccountUpdate, BlobsBundle, Block, BlockBody, BlockHash, BlockHeader, BlockNumber, - ChainConfig, MempoolTransaction, Receipt, Transaction, TxType, Withdrawal, bloom_from_logs, + ChainConfig, + Fork::*, + MempoolTransaction, Receipt, Transaction, TxType, Withdrawal, bloom_from_logs, calc_excess_blob_gas, calculate_base_fee_per_blob_gas, calculate_base_fee_per_gas, compute_receipts_root, compute_transactions_root, compute_withdrawals_root, requests::{EncodedRequests, compute_requests_hash}, @@ -129,10 +131,10 @@ pub fn create_payload( .get_block_header_by_hash(args.parent)? .ok_or_else(|| ChainError::ParentNotFound)?; let chain_config = storage.get_chain_config(); - let fork = chain_config.fork(args.timestamp); + let fork = chain_config.get_fork(args.timestamp); let gas_limit = calc_gas_limit(parent_block.gas_limit, args.gas_ceil); let excess_blob_gas = chain_config - .get_fork_blob_schedule(args.timestamp) + .get_current_blob_schedule(args.timestamp) .map(|schedule| calc_excess_blob_gas(&parent_block, schedule, fork)); let header = BlockHeader { @@ -159,17 +161,17 @@ pub fn create_payload( args.elasticity_multiplier, ), withdrawals_root: chain_config - .is_shanghai_activated(args.timestamp) + .is_fork_activated(Shanghai, args.timestamp) .then_some(compute_withdrawals_root( args.withdrawals.as_ref().unwrap_or(&Vec::new()), )), blob_gas_used: chain_config - .is_cancun_activated(args.timestamp) + .is_fork_activated(Cancun, args.timestamp) .then_some(0), excess_blob_gas, parent_beacon_block_root: args.beacon_root, requests_hash: chain_config - .is_prague_activated(args.timestamp) + .is_fork_activated(Prague, args.timestamp) .then_some(*DEFAULT_REQUESTS_HASH), ..Default::default() }; @@ -230,7 +232,7 @@ impl PayloadBuildContext { let base_fee_per_blob_gas = calculate_base_fee_per_blob_gas( payload.header.excess_blob_gas.unwrap_or_default(), config - .get_fork_blob_schedule(payload.header.timestamp) + .get_current_blob_schedule(payload.header.timestamp) .map(|schedule| schedule.base_fee_update_fraction) .unwrap_or_default(), ); @@ -247,7 +249,7 @@ impl PayloadBuildContext { remaining_gas: payload.header.gas_limit, receipts: vec![], requests: config - .is_prague_activated(payload.header.timestamp) + .is_fork_activated(Prague, payload.header.timestamp) .then_some(Vec::new()), block_value: U256::zero(), base_fee_per_blob_gas, @@ -494,7 +496,7 @@ impl Blockchain { pub fn fill_transactions(&self, context: &mut PayloadBuildContext) -> Result<(), ChainError> { let chain_config = context.chain_config(); let max_blob_number_per_block = chain_config - .get_fork_blob_schedule(context.payload.header.timestamp) + .get_current_blob_schedule(context.payload.header.timestamp) .map(|schedule| schedule.max) .unwrap_or_default() as usize; @@ -543,7 +545,7 @@ impl Blockchain { context.payload_size + head_tx.encode_canonical_to_vec().len() as u64; if context .chain_config() - .is_osaka_activated(context.payload.header.timestamp) + .is_fork_activated(Osaka, context.payload.header.timestamp) && potential_rlp_block_size > MAX_RLP_BLOCK_SIZE { break; @@ -553,16 +555,6 @@ impl Blockchain { // TODO: maybe fetch hash too when filtering mempool so we don't have to compute it here (we can do this in the same refactor as adding timestamp) let tx_hash = head_tx.tx.hash(); - // Check whether the tx is replay-protected - if head_tx.tx.protected() && !chain_config.is_eip155_activated(context.block_number()) { - // Ignore replay protected tx & all txs from the sender - // Pull transaction from the mempool - debug!("Ignoring replay-protected transaction: {}", tx_hash); - txs.pop(); - self.remove_transaction_from_pool(&tx_hash)?; - continue; - } - // Execute tx let receipt = match self.apply_transaction(&head_tx, context) { Ok(receipt) => { @@ -610,7 +602,7 @@ impl Blockchain { let tx_hash = head.tx.hash(); let chain_config = context.chain_config(); let max_blob_number_per_block = chain_config - .get_fork_blob_schedule(context.payload.header.timestamp) + .get_current_blob_schedule(context.payload.header.timestamp) .map(|schedule| schedule.max) .unwrap_or_default() as usize; let Some(blobs_bundle) = self.mempool.get_blobs_bundle(tx_hash)? else { @@ -636,7 +628,7 @@ impl Blockchain { pub fn extract_requests(&self, context: &mut PayloadBuildContext) -> Result<(), EvmError> { if !context .chain_config() - .is_prague_activated(context.payload.header.timestamp) + .is_fork_activated(Prague, context.payload.header.timestamp) { return Ok(()); }; diff --git a/crates/common/types/block.rs b/crates/common/types/block.rs index 0634a3095e7..9a66ff2b78d 100644 --- a/crates/common/types/block.rs +++ b/crates/common/types/block.rs @@ -730,9 +730,13 @@ fn validate_excess_blob_gas( chain_config: &ChainConfig, ) -> Result<(), InvalidBlockHeaderError> { let expected_excess_blob_gas = chain_config - .get_fork_blob_schedule(header.timestamp) + .get_current_blob_schedule(header.timestamp) .map(|schedule| { - calc_excess_blob_gas(parent_header, schedule, chain_config.fork(header.timestamp)) + calc_excess_blob_gas( + parent_header, + schedule, + chain_config.get_fork(header.timestamp), + ) }) .unwrap_or_default(); if header diff --git a/crates/common/types/genesis.rs b/crates/common/types/genesis.rs index 1ceeb867144..01e3c227b04 100644 --- a/crates/common/types/genesis.rs +++ b/crates/common/types/genesis.rs @@ -1,3 +1,4 @@ +use self::Fork::*; use bytes::Bytes; use ethereum_types::{Address, Bloom, H256, U256}; use ethrex_rlp::encode::RLPEncode; @@ -13,8 +14,8 @@ use std::{ use tracing::warn; use super::{ - AccountState, Block, BlockBody, BlockHeader, BlockNumber, INITIAL_BASE_FEE, - compute_receipts_root, compute_transactions_root, compute_withdrawals_root, + AccountState, Block, BlockBody, BlockHeader, INITIAL_BASE_FEE, compute_receipts_root, + compute_transactions_root, compute_withdrawals_root, }; use crate::{ constants::{DEFAULT_OMMERS_HASH, DEFAULT_REQUESTS_HASH}, @@ -282,43 +283,68 @@ lazy_static::lazy_static! { #[repr(u8)] #[derive(Debug, PartialEq, Eq, PartialOrd, Default, Hash, Clone, Copy, Serialize, Deserialize)] pub enum Fork { - Frontier = 0, - FrontierThawing = 1, - Homestead = 2, - DaoFork = 3, - Tangerine = 4, - SpuriousDragon = 5, - Byzantium = 6, - Constantinople = 7, - Petersburg = 8, - Istanbul = 9, - MuirGlacier = 10, - Berlin = 11, - London = 12, - ArrowGlacier = 13, - GrayGlacier = 14, - Paris = 15, - Shanghai = 16, + Homestead = 0, + DaoFork = 1, + EIP150 = 2, + EIP155 = 3, + EIP158 = 4, + Byzantium = 5, + Constantinople = 6, + Petersburg = 7, + Istanbul = 8, + MuirGlacier = 9, + Berlin = 10, + London = 11, + ArrowGlacier = 12, + GrayGlacier = 13, + Paris = 14, + Shanghai = 15, #[default] - Cancun = 17, - Prague = 18, - Osaka = 19, - BPO1 = 20, - BPO2 = 21, - BPO3 = 22, - BPO4 = 23, - BPO5 = 24, + Cancun = 16, + Prague = 17, + Osaka = 18, + BPO1 = 19, + BPO2 = 20, + BPO3 = 21, + BPO4 = 22, + BPO5 = 23, } +pub const FORKS: [Fork; 24] = [ + Homestead, + DaoFork, + EIP150, + EIP155, + EIP158, + Byzantium, + Constantinople, + Petersburg, + Istanbul, + MuirGlacier, + Berlin, + London, + ArrowGlacier, + GrayGlacier, + Paris, + Shanghai, + Cancun, + Prague, + Osaka, + BPO1, + BPO2, + BPO3, + BPO4, + BPO5, +]; + impl From for &str { fn from(fork: Fork) -> Self { match fork { - Fork::Frontier => "Frontier", - Fork::FrontierThawing => "FrontierThawing", Fork::Homestead => "Homestead", Fork::DaoFork => "DaoFork", - Fork::Tangerine => "Tangerine", - Fork::SpuriousDragon => "SpuriousDragon", + Fork::EIP150 => "EIP150", + Fork::EIP155 => "EIP155", + Fork::EIP158 => "EIP158", Fork::Byzantium => "Byzantium", Fork::Constantinople => "Constantinople", Fork::Petersburg => "Petersburg", @@ -343,53 +369,52 @@ impl From for &str { } impl ChainConfig { - pub fn is_bpo1_activated(&self, block_timestamp: u64) -> bool { - self.bpo1_time.is_some_and(|time| time <= block_timestamp) - } - - pub fn is_bpo2_activated(&self, block_timestamp: u64) -> bool { - self.bpo2_time.is_some_and(|time| time <= block_timestamp) - } - - pub fn is_bpo3_activated(&self, block_timestamp: u64) -> bool { - self.bpo3_time.is_some_and(|time| time <= block_timestamp) - } - - pub fn is_bpo4_activated(&self, block_timestamp: u64) -> bool { - self.bpo4_time.is_some_and(|time| time <= block_timestamp) - } - - pub fn is_bpo5_activated(&self, block_timestamp: u64) -> bool { - self.bpo5_time.is_some_and(|time| time <= block_timestamp) - } - - pub fn is_osaka_activated(&self, block_timestamp: u64) -> bool { - self.osaka_time.is_some_and(|time| time <= block_timestamp) - } - - pub fn is_prague_activated(&self, block_timestamp: u64) -> bool { - self.prague_time.is_some_and(|time| time <= block_timestamp) - } - - pub fn is_shanghai_activated(&self, block_timestamp: u64) -> bool { - self.shanghai_time - .is_some_and(|time| time <= block_timestamp) - } - - pub fn is_cancun_activated(&self, block_timestamp: u64) -> bool { - self.cancun_time.is_some_and(|time| time <= block_timestamp) - } - - pub fn is_istanbul_activated(&self, block_number: BlockNumber) -> bool { - self.istanbul_block.is_some_and(|num| num <= block_number) + pub fn fork_activation_time_or_block(&self, fork: Fork) -> Option { + match fork { + Fork::Homestead => self.homestead_block, + Fork::DaoFork => self.dao_fork_block, + Fork::EIP150 => self.eip150_block, + Fork::EIP155 => self.eip155_block, + Fork::EIP158 => self.eip158_block, + Fork::Byzantium => self.byzantium_block, + Fork::Constantinople => self.constantinople_block, + Fork::Petersburg => self.petersburg_block, + Fork::Istanbul => self.istanbul_block, + Fork::MuirGlacier => self.muir_glacier_block, + Fork::Berlin => self.berlin_block, + Fork::London => self.london_block, + Fork::ArrowGlacier => self.arrow_glacier_block, + Fork::GrayGlacier => self.gray_glacier_block, + Fork::Paris => self.merge_netsplit_block, + Fork::Shanghai => self.shanghai_time, + Fork::Cancun => self.cancun_time, + Fork::Prague => self.prague_time, + Fork::Osaka => self.osaka_time, + Fork::BPO1 => self.bpo1_time, + Fork::BPO2 => self.bpo2_time, + Fork::BPO3 => self.bpo3_time, + Fork::BPO4 => self.bpo4_time, + Fork::BPO5 => self.bpo5_time, + } } - pub fn is_london_activated(&self, block_number: BlockNumber) -> bool { - self.london_block.is_some_and(|num| num <= block_number) + pub fn get_blob_schedule_for_fork(&self, fork: Fork) -> Option { + match fork { + Fork::Cancun => Some(self.blob_schedule.cancun), + Fork::Prague => Some(self.blob_schedule.prague), + Fork::Osaka => Some(self.blob_schedule.osaka), + Fork::BPO1 => Some(self.blob_schedule.bpo1), + Fork::BPO2 => Some(self.blob_schedule.bpo2), + Fork::BPO3 => self.blob_schedule.bpo3, + Fork::BPO4 => self.blob_schedule.bpo4, + Fork::BPO5 => self.blob_schedule.bpo5, + _ => None, + } } - pub fn is_eip155_activated(&self, block_number: BlockNumber) -> bool { - self.eip155_block.is_some_and(|num| num <= block_number) + pub fn is_fork_activated(&self, fork: Fork, timestamp_or_block: u64) -> bool { + self.fork_activation_time_or_block(fork) + .is_some_and(|time_or_number| time_or_number <= timestamp_or_block) } pub fn display_config(&self) -> String { @@ -400,7 +425,6 @@ impl ChainConfig { ("Shanghai", self.shanghai_time), ("Cancun", self.cancun_time), ("Prague", self.prague_time), - ("Verkle", self.verkle_time), ("Osaka", self.osaka_time), ]; @@ -421,134 +445,39 @@ impl ChainConfig { } pub fn get_fork(&self, block_timestamp: u64) -> Fork { - if self.is_osaka_activated(block_timestamp) { - Fork::Osaka - } else if self.is_prague_activated(block_timestamp) { - Fork::Prague - } else if self.is_cancun_activated(block_timestamp) { - Fork::Cancun - } else if self.is_shanghai_activated(block_timestamp) { - Fork::Shanghai - } else { - Fork::Paris - } - } - - pub fn get_fork_blob_schedule(&self, block_timestamp: u64) -> Option { - if self.is_bpo5_activated(block_timestamp) { - Some(self.blob_schedule.bpo5.unwrap_or_default()) - } else if self.is_bpo4_activated(block_timestamp) { - Some(self.blob_schedule.bpo4.unwrap_or_default()) - } else if self.is_bpo3_activated(block_timestamp) { - Some(self.blob_schedule.bpo3.unwrap_or_default()) - } else if self.is_bpo2_activated(block_timestamp) { - Some(self.blob_schedule.bpo2) - } else if self.is_bpo1_activated(block_timestamp) { - Some(self.blob_schedule.bpo1) - } else if self.is_osaka_activated(block_timestamp) { - Some(self.blob_schedule.osaka) - } else if self.is_prague_activated(block_timestamp) { - Some(self.blob_schedule.prague) - } else if self.is_cancun_activated(block_timestamp) { - Some(self.blob_schedule.cancun) + FORKS + .into_iter() + .rfind(|fork| self.is_fork_activated(*fork, block_timestamp)) + .unwrap_or(Paris) + } + + pub fn get_current_blob_schedule(&self, block_timestamp: u64) -> Option { + if let Some(fork_with_current_blob_schedule) = FORKS.into_iter().rfind(|fork| { + self.get_blob_schedule_for_fork(*fork).is_some() + && self.is_fork_activated(*fork, block_timestamp) + }) { + self.get_blob_schedule_for_fork(fork_with_current_blob_schedule) } else { None } } - pub fn fork(&self, block_timestamp: u64) -> Fork { - self.get_fork(block_timestamp) - } - pub fn next_fork(&self, block_timestamp: u64) -> Option { - let next = if self.is_bpo5_activated(block_timestamp) { - None - } else if self.is_bpo4_activated(block_timestamp) && self.bpo5_time.is_some() { - Some(Fork::BPO5) - } else if self.is_bpo3_activated(block_timestamp) && self.bpo4_time.is_some() { - Some(Fork::BPO4) - } else if self.is_bpo2_activated(block_timestamp) && self.bpo3_time.is_some() { - Some(Fork::BPO3) - } else if self.is_bpo1_activated(block_timestamp) && self.bpo2_time.is_some() { - Some(Fork::BPO2) - } else if self.is_osaka_activated(block_timestamp) && self.bpo1_time.is_some() { - Some(Fork::BPO1) - } else if self.is_prague_activated(block_timestamp) && self.osaka_time.is_some() { - Some(Fork::Osaka) - } else if self.is_cancun_activated(block_timestamp) && self.prague_time.is_some() { - Some(Fork::Prague) - } else if self.is_shanghai_activated(block_timestamp) && self.cancun_time.is_some() { - Some(Fork::Cancun) + let current_fork = self.get_fork(block_timestamp); + if (current_fork as usize) < FORKS.len() { + FORKS.into_iter().find(|fork| { + *fork > current_fork && self.fork_activation_time_or_block(*fork).is_some() + }) } else { None - }; - match next { - Some(fork) if fork > self.fork(block_timestamp) => next, - _ => None, } } pub fn get_last_scheduled_fork(&self) -> Fork { - if self.bpo5_time.is_some() { - Fork::BPO5 - } else if self.bpo4_time.is_some() { - Fork::BPO4 - } else if self.bpo3_time.is_some() { - Fork::BPO3 - } else if self.bpo2_time.is_some() { - Fork::BPO2 - } else if self.bpo1_time.is_some() { - Fork::BPO1 - } else if self.osaka_time.is_some() { - Fork::Osaka - } else if self.prague_time.is_some() { - Fork::Prague - } else if self.cancun_time.is_some() { - Fork::Cancun - } else { - Fork::Paris - } - } - - pub fn get_activation_timestamp_for_fork(&self, fork: Fork) -> Option { - match fork { - Fork::Cancun => self.cancun_time, - Fork::Prague => self.prague_time, - Fork::Osaka => self.osaka_time, - Fork::BPO1 => self.bpo1_time, - Fork::BPO2 => self.bpo2_time, - Fork::BPO3 => self.bpo3_time, - Fork::BPO4 => self.bpo4_time, - Fork::BPO5 => self.bpo5_time, - Fork::Homestead => self.homestead_block, - Fork::DaoFork => self.dao_fork_block, - Fork::Byzantium => self.byzantium_block, - Fork::Constantinople => self.constantinople_block, - Fork::Petersburg => self.petersburg_block, - Fork::Istanbul => self.istanbul_block, - Fork::MuirGlacier => self.muir_glacier_block, - Fork::Berlin => self.berlin_block, - Fork::London => self.london_block, - Fork::ArrowGlacier => self.arrow_glacier_block, - Fork::GrayGlacier => self.gray_glacier_block, - Fork::Paris => self.merge_netsplit_block, - Fork::Shanghai => self.shanghai_time, - _ => None, - } - } - - pub fn get_blob_schedule_for_fork(&self, fork: Fork) -> Option { - match fork { - Fork::Cancun => Some(self.blob_schedule.cancun), - Fork::Prague => Some(self.blob_schedule.prague), - Fork::Osaka => Some(self.blob_schedule.osaka), - Fork::BPO1 => Some(self.blob_schedule.bpo1), - Fork::BPO2 => Some(self.blob_schedule.bpo2), - Fork::BPO3 => self.blob_schedule.bpo3, - Fork::BPO4 => self.blob_schedule.bpo4, - Fork::BPO5 => self.blob_schedule.bpo5, - _ => None, - } + FORKS + .into_iter() + .rfind(|fork| self.fork_activation_time_or_block(*fork).is_some()) + .unwrap_or(Paris) } pub fn gather_forks(&self, genesis_header: BlockHeader) -> (Vec, Vec) { @@ -637,25 +566,21 @@ impl Genesis { blob_gas_used = Some(self.blob_gas_used.unwrap_or(0)); excess_blob_gas = Some(self.excess_blob_gas.unwrap_or(0)); } - let base_fee_per_gas = self.base_fee_per_gas.or_else(|| { - self.config - .is_london_activated(0) - .then_some(INITIAL_BASE_FEE) - }); + let base_fee_per_gas = self.base_fee_per_gas.or(Some(INITIAL_BASE_FEE)); let withdrawals_root = self .config - .is_shanghai_activated(self.timestamp) + .is_fork_activated(Shanghai, self.timestamp) .then_some(compute_withdrawals_root(&[])); let parent_beacon_block_root = self .config - .is_cancun_activated(self.timestamp) + .is_fork_activated(Cancun, self.timestamp) .then_some(H256::zero()); let requests_hash = self .config - .is_prague_activated(self.timestamp) + .is_fork_activated(Prague, self.timestamp) .then_some(self.requests_hash.unwrap_or(*DEFAULT_REQUESTS_HASH)); BlockHeader { diff --git a/crates/l2/sequencer/block_producer/payload_builder.rs b/crates/l2/sequencer/block_producer/payload_builder.rs index 32eb17d8591..79854f46b65 100644 --- a/crates/l2/sequencer/block_producer/payload_builder.rs +++ b/crates/l2/sequencer/block_producer/payload_builder.rs @@ -114,8 +114,6 @@ pub async fn fill_transactions( let safe_bytes_per_blob: u64 = SAFE_BYTES_PER_BLOB.try_into()?; let mut privileged_tx_count = 0; - let chain_config = store.get_chain_config(); - debug!("Fetching transactions from mempool"); // Fetch mempool transactions let latest_block_number = store.get_latest_block_number().await?; @@ -167,16 +165,6 @@ pub async fn fill_transactions( // TODO: maybe fetch hash too when filtering mempool so we don't have to compute it here (we can do this in the same refactor as adding timestamp) let tx_hash = head_tx.tx.hash(); - // Check whether the tx is replay-protected - if head_tx.tx.protected() && !chain_config.is_eip155_activated(context.block_number()) { - // Ignore replay protected tx & all txs from the sender - // Pull transaction from the mempool - debug!("Ignoring replay-protected transaction: {}", tx_hash); - txs.pop(); - blockchain.remove_transaction_from_pool(&tx_hash)?; - continue; - } - let maybe_sender_acc_info = store .get_account_info(latest_block_number, head_tx.tx.sender()) .await?; diff --git a/crates/networking/rpc/engine/blobs.rs b/crates/networking/rpc/engine/blobs.rs index 7a1c68408ac..532807f8c3d 100644 --- a/crates/networking/rpc/engine/blobs.rs +++ b/crates/networking/rpc/engine/blobs.rs @@ -1,7 +1,9 @@ use ethrex_common::{ H256, serde_utils::{self}, - types::{Blob, CELLS_PER_EXT_BLOB, Proof, blobs_bundle::kzg_commitment_to_versioned_hash}, + types::{ + Blob, CELLS_PER_EXT_BLOB, Fork::*, Proof, blobs_bundle::kzg_commitment_to_versioned_hash, + }, }; use serde::{Deserialize, Serialize}; use serde_json::Value; @@ -120,7 +122,7 @@ impl RpcHandler for BlobsV2Request { && !context .storage .get_chain_config() - .is_osaka_activated(current_block_header.timestamp) + .is_fork_activated(Osaka, current_block_header.timestamp) { // validation requested in https://github.com/ethereum/execution-apis/blob/a1d95fb555cd91efb3e0d6555e4ab556d9f5dd06/src/engine/osaka.md?plain=1#L130 return Err(RpcErr::UnsuportedFork( diff --git a/crates/networking/rpc/engine/fork_choice.rs b/crates/networking/rpc/engine/fork_choice.rs index 5ee2984015c..2f332d400ad 100644 --- a/crates/networking/rpc/engine/fork_choice.rs +++ b/crates/networking/rpc/engine/fork_choice.rs @@ -3,7 +3,7 @@ use ethrex_blockchain::{ fork_choice::apply_fork_choice, payload::{BuildPayloadArgs, create_payload}, }; -use ethrex_common::types::{BlockHeader, ELASTICITY_MULTIPLIER}; +use ethrex_common::types::{BlockHeader, ELASTICITY_MULTIPLIER, Fork::*}; use serde_json::Value; use tracing::{info, warn}; @@ -37,7 +37,7 @@ impl RpcHandler for ForkChoiceUpdatedV1 { handle_forkchoice(&self.fork_choice_state, context.clone(), 1).await?; if let (Some(head_block), Some(attributes)) = (head_block_opt, &self.payload_attributes) { let chain_config = context.storage.get_chain_config(); - if chain_config.is_cancun_activated(attributes.timestamp) { + if chain_config.is_fork_activated(Cancun, attributes.timestamp) { return Err(RpcErr::UnsuportedFork( "forkChoiceV1 used to build Cancun payload".to_string(), )); @@ -70,11 +70,11 @@ impl RpcHandler for ForkChoiceUpdatedV2 { handle_forkchoice(&self.fork_choice_state, context.clone(), 2).await?; if let (Some(head_block), Some(attributes)) = (head_block_opt, &self.payload_attributes) { let chain_config = context.storage.get_chain_config(); - if chain_config.is_cancun_activated(attributes.timestamp) { + if chain_config.is_fork_activated(Cancun, attributes.timestamp) { return Err(RpcErr::UnsuportedFork( "forkChoiceV2 used to build Cancun payload".to_string(), )); - } else if chain_config.is_shanghai_activated(attributes.timestamp) { + } else if chain_config.is_fork_activated(Shanghai, attributes.timestamp) { validate_attributes_v2(attributes, &head_block)?; } else { // Behave as a v1 @@ -352,7 +352,7 @@ fn validate_attributes_v3( "Attribute parent_beacon_block_root is null".to_string(), )); } - if !chain_config.is_cancun_activated(attributes.timestamp) { + if !chain_config.is_fork_activated(Cancun, attributes.timestamp) { return Err(RpcErr::UnsuportedFork( "forkChoiceV3 used to build pre-Cancun payload".to_string(), )); diff --git a/crates/networking/rpc/engine/payload.rs b/crates/networking/rpc/engine/payload.rs index a99ef9b9cc4..633698d79c5 100644 --- a/crates/networking/rpc/engine/payload.rs +++ b/crates/networking/rpc/engine/payload.rs @@ -2,7 +2,7 @@ use ethrex_blockchain::error::ChainError; use ethrex_blockchain::payload::PayloadBuildResult; use ethrex_common::types::payload::PayloadBundle; use ethrex_common::types::requests::{EncodedRequests, compute_requests_hash}; -use ethrex_common::types::{Block, BlockBody, BlockHash, BlockNumber, Fork}; +use ethrex_common::types::{Block, BlockBody, BlockHash, BlockNumber, Fork, Fork::*}; use ethrex_common::{H256, U256}; use ethrex_p2p::sync::SyncMode; use ethrex_rlp::error::RLPDecodeError; @@ -62,7 +62,7 @@ impl RpcHandler for NewPayloadV2Request { async fn handle(&self, context: RpcApiContext) -> Result { let chain_config = &context.storage.get_chain_config(); - if chain_config.is_shanghai_activated(self.payload.timestamp) { + if chain_config.is_fork_activated(Shanghai, self.payload.timestamp) { validate_execution_payload_v2(&self.payload)?; } else { // Behave as a v1 @@ -206,7 +206,7 @@ impl RpcHandler for NewPayloadV4Request { let chain_config = context.storage.get_chain_config(); - if !chain_config.is_prague_activated(block.header.timestamp) { + if !chain_config.is_fork_activated(Prague, block.header.timestamp) { return Err(RpcErr::UnsuportedFork(format!( "{:?}", chain_config.get_fork(block.header.timestamp) @@ -334,13 +334,13 @@ impl RpcHandler for GetPayloadV4Request { let payload_bundle = get_payload(self.payload_id, &context).await?; let chain_config = &context.storage.get_chain_config(); - if !chain_config.is_prague_activated(payload_bundle.block.header.timestamp) { + if !chain_config.is_fork_activated(Prague, payload_bundle.block.header.timestamp) { return Err(RpcErr::UnsuportedFork(format!( "{:?}", chain_config.get_fork(payload_bundle.block.header.timestamp) ))); } - if chain_config.is_osaka_activated(payload_bundle.block.header.timestamp) { + if chain_config.is_fork_activated(Osaka, payload_bundle.block.header.timestamp) { return Err(RpcErr::UnsuportedFork(format!("{:?}", Fork::Osaka))); } @@ -386,7 +386,7 @@ impl RpcHandler for GetPayloadV5Request { let payload_bundle = get_payload(self.payload_id, &context).await?; let chain_config = &context.storage.get_chain_config(); - if !chain_config.is_osaka_activated(payload_bundle.block.header.timestamp) { + if !chain_config.is_fork_activated(Osaka, payload_bundle.block.header.timestamp) { return Err(RpcErr::UnsuportedFork(format!( "{:?}", chain_config.get_fork(payload_bundle.block.header.timestamp) @@ -541,7 +541,7 @@ fn validate_execution_payload_v3(payload: &ExecutionPayload) -> Result<(), RpcEr fn validate_payload_v1_v2(block: &Block, context: &RpcApiContext) -> Result<(), RpcErr> { let chain_config = &context.storage.get_chain_config(); - if chain_config.is_cancun_activated(block.header.timestamp) { + if chain_config.is_fork_activated(Cancun, block.header.timestamp) { return Err(RpcErr::UnsuportedFork( "Cancun payload received".to_string(), )); diff --git a/crates/networking/rpc/eth/block.rs b/crates/networking/rpc/eth/block.rs index bf1c56d51d0..55d73eee2ca 100644 --- a/crates/networking/rpc/eth/block.rs +++ b/crates/networking/rpc/eth/block.rs @@ -320,7 +320,7 @@ impl RpcHandler for GetBlobBaseFee { let blob_base_fee = calculate_base_fee_per_blob_gas( parent_header.excess_blob_gas.unwrap_or_default(), config - .get_fork_blob_schedule(header.timestamp) + .get_current_blob_schedule(header.timestamp) .map(|schedule| schedule.base_fee_update_fraction) .unwrap_or_default(), ); @@ -347,7 +347,7 @@ pub async fn get_all_block_rpc_receipts( let blob_base_fee = calculate_base_fee_per_blob_gas( header.excess_blob_gas.unwrap_or_default(), config - .get_fork_blob_schedule(header.timestamp) + .get_current_blob_schedule(header.timestamp) .map(|schedule| schedule.base_fee_update_fraction) .unwrap_or_default(), ); diff --git a/crates/networking/rpc/eth/client.rs b/crates/networking/rpc/eth/client.rs index 04a6181c963..311595cdbeb 100644 --- a/crates/networking/rpc/eth/client.rs +++ b/crates/networking/rpc/eth/client.rs @@ -141,7 +141,7 @@ async fn get_config_for_fork( context: &RpcApiContext, ) -> Result { let chain_config = context.storage.get_chain_config(); - let activation_time = chain_config.get_activation_timestamp_for_fork(fork); + let activation_time = chain_config.fork_activation_time_or_block(fork); let genesis_header = context .storage .get_block_by_number(0) diff --git a/crates/networking/rpc/eth/fee_market.rs b/crates/networking/rpc/eth/fee_market.rs index 0164b59f1e3..bb742eefd15 100644 --- a/crates/networking/rpc/eth/fee_market.rs +++ b/crates/networking/rpc/eth/fee_market.rs @@ -123,7 +123,7 @@ impl RpcHandler for FeeHistoryRequest { )))?; let max_blob_gas_per_block = config - .get_fork_blob_schedule(header.timestamp) + .get_current_blob_schedule(header.timestamp) .map(|schedule| schedule.max * GAS_PER_BLOB); let blob_gas_used_r = match (header.blob_gas_used, max_blob_gas_per_block) { (Some(blob_gas_used), Some(max_blob_gas)) => { @@ -133,7 +133,7 @@ impl RpcHandler for FeeHistoryRequest { }; let blob_schedule = config - .get_fork_blob_schedule(header.timestamp) + .get_current_blob_schedule(header.timestamp) .unwrap_or_default(); let fork = config.get_fork(header.timestamp); diff --git a/crates/vm/backends/levm/mod.rs b/crates/vm/backends/levm/mod.rs index 75a08724997..71c3648d07f 100644 --- a/crates/vm/backends/levm/mod.rs +++ b/crates/vm/backends/levm/mod.rs @@ -430,7 +430,7 @@ impl LEVM { ) -> Result<(), EvmError> { let chain_config = db.store.get_chain_config()?; let block_header = &block.header; - let fork = chain_config.fork(block_header.timestamp); + let fork = chain_config.get_fork(block_header.timestamp); // TODO: I don't like deciding the behavior based on the VMType here. if let VMType::L2(_) = vm_type { @@ -542,7 +542,7 @@ pub fn extract_all_requests_levm( } let chain_config = db.store.get_chain_config()?; - let fork = chain_config.fork(header.timestamp); + let fork = chain_config.get_fork(header.timestamp); if fork < Fork::Prague { return Ok(Default::default()); @@ -580,7 +580,7 @@ pub fn extract_all_requests_levm_pipeline( } let chain_config = db.store.get_chain_config()?; - let fork = chain_config.fork(header.timestamp); + let fork = chain_config.get_fork(header.timestamp); if fork < Fork::Prague { return Ok(Default::default()); diff --git a/crates/vm/backends/mod.rs b/crates/vm/backends/mod.rs index 90d73602c75..a5d765fce45 100644 --- a/crates/vm/backends/mod.rs +++ b/crates/vm/backends/mod.rs @@ -121,7 +121,7 @@ impl Evm { /// This function is used to run/apply all the system contracts to the state. pub fn apply_system_calls(&mut self, block_header: &BlockHeader) -> Result<(), EvmError> { let chain_config = self.db.store.get_chain_config()?; - let fork = chain_config.fork(block_header.timestamp); + let fork = chain_config.get_fork(block_header.timestamp); if block_header.parent_beacon_block_root.is_some() && fork >= Fork::Cancun { LEVM::beacon_root_contract_call(block_header, &mut self.db, self.vm_type)?; diff --git a/crates/vm/levm/src/environment.rs b/crates/vm/levm/src/environment.rs index 0a7d1c81cb2..d17bb1cd851 100644 --- a/crates/vm/levm/src/environment.rs +++ b/crates/vm/levm/src/environment.rs @@ -63,10 +63,10 @@ impl EVMConfig { } pub fn new_from_chain_config(chain_config: &ChainConfig, block_header: &BlockHeader) -> Self { - let fork = chain_config.fork(block_header.timestamp); + let fork = chain_config.get_fork(block_header.timestamp); let blob_schedule = chain_config - .get_fork_blob_schedule(block_header.timestamp) + .get_current_blob_schedule(block_header.timestamp) .unwrap_or_else(|| EVMConfig::canonical_values(fork)); EVMConfig::new(fork, blob_schedule) From f2a880ddacb455c03a594bb7ae7c6f8a3844347b Mon Sep 17 00:00:00 2001 From: SDartayet <44068466+SDartayet@users.noreply.github.com> Date: Fri, 7 Nov 2025 15:09:16 -0300 Subject: [PATCH 2/8] Fixed tests and addressed comment --- crates/blockchain/blockchain.rs | 2 +- crates/blockchain/payload.rs | 8 +-- crates/common/types/block.rs | 2 +- crates/common/types/genesis.rs | 62 +++++++++++--------- crates/networking/rpc/eth/block.rs | 4 +- crates/networking/rpc/eth/fee_market.rs | 4 +- crates/vm/levm/src/environment.rs | 2 +- tooling/ef_tests/state/deserialize.rs | 8 ++- tooling/ef_tests/state/runner/revm_runner.rs | 4 +- 9 files changed, 53 insertions(+), 43 deletions(-) diff --git a/crates/blockchain/blockchain.rs b/crates/blockchain/blockchain.rs index 012fdade3b3..be5fd3e283e 100644 --- a/crates/blockchain/blockchain.rs +++ b/crates/blockchain/blockchain.rs @@ -1590,7 +1590,7 @@ fn verify_blob_gas_usage(block: &Block, config: &ChainConfig) -> Result<(), Chai let mut blob_gas_used = 0_u32; let mut blobs_in_block = 0_u32; let max_blob_number_per_block = config - .get_current_blob_schedule(block.header.timestamp) + .get_blob_schedule_for_time(block.header.timestamp) .map(|schedule| schedule.max) .ok_or(ChainError::Custom("Provided block fork is invalid".into()))?; let max_blob_gas_per_block = max_blob_number_per_block * GAS_PER_BLOB; diff --git a/crates/blockchain/payload.rs b/crates/blockchain/payload.rs index 5b4fb78ff6e..dda55f45649 100644 --- a/crates/blockchain/payload.rs +++ b/crates/blockchain/payload.rs @@ -134,7 +134,7 @@ pub fn create_payload( let fork = chain_config.get_fork(args.timestamp); let gas_limit = calc_gas_limit(parent_block.gas_limit, args.gas_ceil); let excess_blob_gas = chain_config - .get_current_blob_schedule(args.timestamp) + .get_blob_schedule_for_time(args.timestamp) .map(|schedule| calc_excess_blob_gas(&parent_block, schedule, fork)); let header = BlockHeader { @@ -232,7 +232,7 @@ impl PayloadBuildContext { let base_fee_per_blob_gas = calculate_base_fee_per_blob_gas( payload.header.excess_blob_gas.unwrap_or_default(), config - .get_current_blob_schedule(payload.header.timestamp) + .get_blob_schedule_for_time(payload.header.timestamp) .map(|schedule| schedule.base_fee_update_fraction) .unwrap_or_default(), ); @@ -496,7 +496,7 @@ impl Blockchain { pub fn fill_transactions(&self, context: &mut PayloadBuildContext) -> Result<(), ChainError> { let chain_config = context.chain_config(); let max_blob_number_per_block = chain_config - .get_current_blob_schedule(context.payload.header.timestamp) + .get_blob_schedule_for_time(context.payload.header.timestamp) .map(|schedule| schedule.max) .unwrap_or_default() as usize; @@ -602,7 +602,7 @@ impl Blockchain { let tx_hash = head.tx.hash(); let chain_config = context.chain_config(); let max_blob_number_per_block = chain_config - .get_current_blob_schedule(context.payload.header.timestamp) + .get_blob_schedule_for_time(context.payload.header.timestamp) .map(|schedule| schedule.max) .unwrap_or_default() as usize; let Some(blobs_bundle) = self.mempool.get_blobs_bundle(tx_hash)? else { diff --git a/crates/common/types/block.rs b/crates/common/types/block.rs index 9a66ff2b78d..d22e03955d3 100644 --- a/crates/common/types/block.rs +++ b/crates/common/types/block.rs @@ -730,7 +730,7 @@ fn validate_excess_blob_gas( chain_config: &ChainConfig, ) -> Result<(), InvalidBlockHeaderError> { let expected_excess_blob_gas = chain_config - .get_current_blob_schedule(header.timestamp) + .get_blob_schedule_for_time(header.timestamp) .map(|schedule| { calc_excess_blob_gas( parent_header, diff --git a/crates/common/types/genesis.rs b/crates/common/types/genesis.rs index 01e3c227b04..f732400d108 100644 --- a/crates/common/types/genesis.rs +++ b/crates/common/types/genesis.rs @@ -283,34 +283,36 @@ lazy_static::lazy_static! { #[repr(u8)] #[derive(Debug, PartialEq, Eq, PartialOrd, Default, Hash, Clone, Copy, Serialize, Deserialize)] pub enum Fork { - Homestead = 0, - DaoFork = 1, - EIP150 = 2, - EIP155 = 3, - EIP158 = 4, - Byzantium = 5, - Constantinople = 6, - Petersburg = 7, - Istanbul = 8, - MuirGlacier = 9, - Berlin = 10, - London = 11, - ArrowGlacier = 12, - GrayGlacier = 13, - Paris = 14, - Shanghai = 15, + Frontier = 0, + Homestead = 1, + DaoFork = 2, + EIP150 = 3, + EIP155 = 4, + EIP158 = 5, + Byzantium = 6, + Constantinople = 7, + Petersburg = 8, + Istanbul = 9, + MuirGlacier = 10, + Berlin = 11, + London = 12, + ArrowGlacier = 13, + GrayGlacier = 14, + Paris = 15, + Shanghai = 16, #[default] - Cancun = 16, - Prague = 17, - Osaka = 18, - BPO1 = 19, - BPO2 = 20, - BPO3 = 21, - BPO4 = 22, - BPO5 = 23, + Cancun = 17, + Prague = 18, + Osaka = 19, + BPO1 = 20, + BPO2 = 21, + BPO3 = 22, + BPO4 = 23, + BPO5 = 24, } -pub const FORKS: [Fork; 24] = [ +pub const FORKS: [Fork; 25] = [ + Frontier, Homestead, DaoFork, EIP150, @@ -340,6 +342,7 @@ pub const FORKS: [Fork; 24] = [ impl From for &str { fn from(fork: Fork) -> Self { match fork { + Fork::Frontier => "Frontier", Fork::Homestead => "Homestead", Fork::DaoFork => "DaoFork", Fork::EIP150 => "EIP150", @@ -371,6 +374,7 @@ impl From for &str { impl ChainConfig { pub fn fork_activation_time_or_block(&self, fork: Fork) -> Option { match fork { + Fork::Frontier => Some(0), Fork::Homestead => self.homestead_block, Fork::DaoFork => self.dao_fork_block, Fork::EIP150 => self.eip150_block, @@ -451,7 +455,7 @@ impl ChainConfig { .unwrap_or(Paris) } - pub fn get_current_blob_schedule(&self, block_timestamp: u64) -> Option { + pub fn get_blob_schedule_for_time(&self, block_timestamp: u64) -> Option { if let Some(fork_with_current_blob_schedule) = FORKS.into_iter().rfind(|fork| { self.get_blob_schedule_for_fork(*fork).is_some() && self.is_fork_activated(*fork, block_timestamp) @@ -566,7 +570,11 @@ impl Genesis { blob_gas_used = Some(self.blob_gas_used.unwrap_or(0)); excess_blob_gas = Some(self.excess_blob_gas.unwrap_or(0)); } - let base_fee_per_gas = self.base_fee_per_gas.or(Some(INITIAL_BASE_FEE)); + let base_fee_per_gas = self.base_fee_per_gas.or_else(|| { + self.config + .is_fork_activated(London, 0) + .then_some(INITIAL_BASE_FEE) + }); let withdrawals_root = self .config diff --git a/crates/networking/rpc/eth/block.rs b/crates/networking/rpc/eth/block.rs index 55d73eee2ca..1f5636c2378 100644 --- a/crates/networking/rpc/eth/block.rs +++ b/crates/networking/rpc/eth/block.rs @@ -320,7 +320,7 @@ impl RpcHandler for GetBlobBaseFee { let blob_base_fee = calculate_base_fee_per_blob_gas( parent_header.excess_blob_gas.unwrap_or_default(), config - .get_current_blob_schedule(header.timestamp) + .get_blob_schedule_for_time(header.timestamp) .map(|schedule| schedule.base_fee_update_fraction) .unwrap_or_default(), ); @@ -347,7 +347,7 @@ pub async fn get_all_block_rpc_receipts( let blob_base_fee = calculate_base_fee_per_blob_gas( header.excess_blob_gas.unwrap_or_default(), config - .get_current_blob_schedule(header.timestamp) + .get_blob_schedule_for_time(header.timestamp) .map(|schedule| schedule.base_fee_update_fraction) .unwrap_or_default(), ); diff --git a/crates/networking/rpc/eth/fee_market.rs b/crates/networking/rpc/eth/fee_market.rs index bb742eefd15..71478f783da 100644 --- a/crates/networking/rpc/eth/fee_market.rs +++ b/crates/networking/rpc/eth/fee_market.rs @@ -123,7 +123,7 @@ impl RpcHandler for FeeHistoryRequest { )))?; let max_blob_gas_per_block = config - .get_current_blob_schedule(header.timestamp) + .get_blob_schedule_for_time(header.timestamp) .map(|schedule| schedule.max * GAS_PER_BLOB); let blob_gas_used_r = match (header.blob_gas_used, max_blob_gas_per_block) { (Some(blob_gas_used), Some(max_blob_gas)) => { @@ -133,7 +133,7 @@ impl RpcHandler for FeeHistoryRequest { }; let blob_schedule = config - .get_current_blob_schedule(header.timestamp) + .get_blob_schedule_for_time(header.timestamp) .unwrap_or_default(); let fork = config.get_fork(header.timestamp); diff --git a/crates/vm/levm/src/environment.rs b/crates/vm/levm/src/environment.rs index d17bb1cd851..fa556f11518 100644 --- a/crates/vm/levm/src/environment.rs +++ b/crates/vm/levm/src/environment.rs @@ -66,7 +66,7 @@ impl EVMConfig { let fork = chain_config.get_fork(block_header.timestamp); let blob_schedule = chain_config - .get_current_blob_schedule(block_header.timestamp) + .get_blob_schedule_for_time(block_header.timestamp) .unwrap_or_else(|| EVMConfig::canonical_values(fork)); EVMConfig::new(fork, blob_schedule) diff --git a/tooling/ef_tests/state/deserialize.rs b/tooling/ef_tests/state/deserialize.rs index f4772d7fc90..4c5c6abd754 100644 --- a/tooling/ef_tests/state/deserialize.rs +++ b/tooling/ef_tests/state/deserialize.rs @@ -3,7 +3,7 @@ use crate::types::{ TransactionExpectedException, }; use bytes::Bytes; -use ethrex_common::{H256, U256, types::Fork}; +use ethrex_common::{types::Fork, H256, U256}; use serde::{Deserialize, Deserializer}; use std::{collections::HashMap, str::FromStr}; @@ -314,8 +314,10 @@ where "Prague" => Fork::Prague, "Osaka" => Fork::Osaka, "Byzantium" => Fork::Byzantium, - "EIP158" => Fork::SpuriousDragon, - "EIP150" => Fork::Tangerine, + "EIP158" => Fork::EIP158, + "EIP150" => Fork::EIP150, + "EIP155" => Fork::EIP155, + other => { return Err(serde::de::Error::custom(format!( "Unknown fork name: {other}", diff --git a/tooling/ef_tests/state/runner/revm_runner.rs b/tooling/ef_tests/state/runner/revm_runner.rs index c04d74c19aa..100c51b9be7 100644 --- a/tooling/ef_tests/state/runner/revm_runner.rs +++ b/tooling/ef_tests/state/runner/revm_runner.rs @@ -679,8 +679,8 @@ pub fn fork_to_spec_id(fork: Fork) -> SpecId { Fork::FrontierThawing => SpecId::FRONTIER_THAWING, Fork::Homestead => SpecId::HOMESTEAD, Fork::DaoFork => SpecId::DAO_FORK, - Fork::Tangerine => SpecId::TANGERINE, - Fork::SpuriousDragon => SpecId::SPURIOUS_DRAGON, + Fork::EIP150 => SpecId::TANGERINE, + Fork::EIP158 => SpecId::SPURIOUS_DRAGON, Fork::Byzantium => SpecId::BYZANTIUM, Fork::Constantinople => SpecId::CONSTANTINOPLE, Fork::Petersburg => SpecId::PETERSBURG, From 8340a235f9ada4034dc114b7466dc5006fe4e803 Mon Sep 17 00:00:00 2001 From: SDartayet <44068466+SDartayet@users.noreply.github.com> Date: Fri, 7 Nov 2025 18:54:39 -0300 Subject: [PATCH 3/8] Remove leftover removed fork --- tooling/ef_tests/state/runner/revm_runner.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tooling/ef_tests/state/runner/revm_runner.rs b/tooling/ef_tests/state/runner/revm_runner.rs index 100c51b9be7..63962ba2a29 100644 --- a/tooling/ef_tests/state/runner/revm_runner.rs +++ b/tooling/ef_tests/state/runner/revm_runner.rs @@ -676,7 +676,6 @@ pub async fn _ensure_post_state_revm( pub fn fork_to_spec_id(fork: Fork) -> SpecId { match fork { Fork::Frontier => SpecId::FRONTIER, - Fork::FrontierThawing => SpecId::FRONTIER_THAWING, Fork::Homestead => SpecId::HOMESTEAD, Fork::DaoFork => SpecId::DAO_FORK, Fork::EIP150 => SpecId::TANGERINE, From 89f8911be4bf0d62aa3a01414aa1e15229944585 Mon Sep 17 00:00:00 2001 From: SDartayet <44068466+SDartayet@users.noreply.github.com> Date: Mon, 10 Nov 2025 11:18:43 -0300 Subject: [PATCH 4/8] Added missing fork --- tooling/ef_tests/state/runner/revm_runner.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tooling/ef_tests/state/runner/revm_runner.rs b/tooling/ef_tests/state/runner/revm_runner.rs index 63962ba2a29..d1805d20ccf 100644 --- a/tooling/ef_tests/state/runner/revm_runner.rs +++ b/tooling/ef_tests/state/runner/revm_runner.rs @@ -679,6 +679,7 @@ pub fn fork_to_spec_id(fork: Fork) -> SpecId { Fork::Homestead => SpecId::HOMESTEAD, Fork::DaoFork => SpecId::DAO_FORK, Fork::EIP150 => SpecId::TANGERINE, + Fork::EIP155 => SpecId::SPURIOUS_DRAGON, Fork::EIP158 => SpecId::SPURIOUS_DRAGON, Fork::Byzantium => SpecId::BYZANTIUM, Fork::Constantinople => SpecId::CONSTANTINOPLE, From 0c5036f4b69cbd3d95983561813861c2fe660a00 Mon Sep 17 00:00:00 2001 From: SDartayet <44068466+SDartayet@users.noreply.github.com> Date: Mon, 10 Nov 2025 11:27:18 -0300 Subject: [PATCH 5/8] fixing compile errors --- tooling/Cargo.lock | 4 ++++ tooling/ef_tests/state_v2/src/modules/deserialize.rs | 6 +++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/tooling/Cargo.lock b/tooling/Cargo.lock index 34d4b2965ba..e5c33350347 100644 --- a/tooling/Cargo.lock +++ b/tooling/Cargo.lock @@ -3162,6 +3162,8 @@ dependencies = [ "secp256k1 0.30.0", "serde", "serde_json", + "spawned-concurrency", + "spawned-rt", "thiserror 2.0.17", "tikv-jemallocator", "tokio", @@ -3570,6 +3572,8 @@ dependencies = [ "serde_json", "sha2 0.10.9", "sha3", + "spawned-concurrency", + "spawned-rt", "thiserror 2.0.17", "tokio", "tokio-util", diff --git a/tooling/ef_tests/state_v2/src/modules/deserialize.rs b/tooling/ef_tests/state_v2/src/modules/deserialize.rs index d8d61457577..e242bbe84c5 100644 --- a/tooling/ef_tests/state_v2/src/modules/deserialize.rs +++ b/tooling/ef_tests/state_v2/src/modules/deserialize.rs @@ -2,7 +2,7 @@ use crate::modules::types::{ AccessListItem, AuthorizationListTuple, RawPostValue, TransactionExpectedException, }; -use ethrex_common::{U256, types::Fork}; +use ethrex_common::{types::Fork, U256}; use serde::{Deserialize, Deserializer}; use std::collections::HashMap; @@ -151,8 +151,8 @@ where "Cancun" => Fork::Cancun, "Prague" => Fork::Prague, "Byzantium" => Fork::Byzantium, - "EIP158" => Fork::SpuriousDragon, - "EIP150" => Fork::Tangerine, + "EIP158" => Fork::EIP158, + "EIP150" => Fork::EIP150, other => { return Err(serde::de::Error::custom(format!( "Unknown fork name: {other}", From 1fd404ac149e4beb802815dadfcdd53612cbaa3c Mon Sep 17 00:00:00 2001 From: SDartayet <44068466+SDartayet@users.noreply.github.com> Date: Mon, 10 Nov 2025 12:25:46 -0300 Subject: [PATCH 6/8] Cargo fmt --- tooling/ef_tests/state/deserialize.rs | 2 +- tooling/ef_tests/state_v2/src/modules/deserialize.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tooling/ef_tests/state/deserialize.rs b/tooling/ef_tests/state/deserialize.rs index 4c5c6abd754..ef8e1f5748b 100644 --- a/tooling/ef_tests/state/deserialize.rs +++ b/tooling/ef_tests/state/deserialize.rs @@ -3,7 +3,7 @@ use crate::types::{ TransactionExpectedException, }; use bytes::Bytes; -use ethrex_common::{types::Fork, H256, U256}; +use ethrex_common::{H256, U256, types::Fork}; use serde::{Deserialize, Deserializer}; use std::{collections::HashMap, str::FromStr}; diff --git a/tooling/ef_tests/state_v2/src/modules/deserialize.rs b/tooling/ef_tests/state_v2/src/modules/deserialize.rs index e242bbe84c5..018569722ec 100644 --- a/tooling/ef_tests/state_v2/src/modules/deserialize.rs +++ b/tooling/ef_tests/state_v2/src/modules/deserialize.rs @@ -2,7 +2,7 @@ use crate::modules::types::{ AccessListItem, AuthorizationListTuple, RawPostValue, TransactionExpectedException, }; -use ethrex_common::{types::Fork, U256}; +use ethrex_common::{U256, types::Fork}; use serde::{Deserialize, Deserializer}; use std::collections::HashMap; From 4b5da78830ecdf72df37a514f30171b31f80dd92 Mon Sep 17 00:00:00 2001 From: SDartayet <44068466+SDartayet@users.noreply.github.com> Date: Thu, 13 Nov 2025 18:54:56 -0300 Subject: [PATCH 7/8] fix compile issue --- crates/networking/rpc/eth/transaction.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/networking/rpc/eth/transaction.rs b/crates/networking/rpc/eth/transaction.rs index 87ea64fb372..df8e52a3c0c 100644 --- a/crates/networking/rpc/eth/transaction.rs +++ b/crates/networking/rpc/eth/transaction.rs @@ -447,7 +447,7 @@ impl RpcHandler for EstimateGasRequest { _ => return Ok(Value::Null), }; - let current_fork = chain_config.fork(block_header.timestamp); + let current_fork = chain_config.get_fork(block_header.timestamp); let transaction = match self.transaction.nonce { Some(_nonce) => self.transaction.clone(), From 2868af43fb80ca0439fc9e4cd58b772bc7be65fc Mon Sep 17 00:00:00 2001 From: SDartayet <44068466+SDartayet@users.noreply.github.com> Date: Fri, 14 Nov 2025 11:35:13 -0300 Subject: [PATCH 8/8] Fixed lint --- crates/l2/sequencer/block_producer/payload_builder.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/l2/sequencer/block_producer/payload_builder.rs b/crates/l2/sequencer/block_producer/payload_builder.rs index 31fb0d1632a..f9c5b10f64c 100644 --- a/crates/l2/sequencer/block_producer/payload_builder.rs +++ b/crates/l2/sequencer/block_producer/payload_builder.rs @@ -101,7 +101,6 @@ pub async fn fill_transactions( }; let mut acc_encoded_size = context.payload.encode_to_vec().len(); let fee_config_len = fee_config.to_vec().len(); - let chain_config = store.get_chain_config(); debug!("Fetching transactions from mempool"); // Fetch mempool transactions