diff --git a/cmd/ef_tests/levm/report.rs b/cmd/ef_tests/levm/report.rs
index cef2d1b3e3..970e144aff 100644
--- a/cmd/ef_tests/levm/report.rs
+++ b/cmd/ef_tests/levm/report.rs
@@ -1,12 +1,11 @@
 use crate::runner::{EFTestRunnerError, InternalError};
 use colored::Colorize;
-use ethrex_core::{Address, H256};
+use ethrex_core::{types::Fork, Address, H256};
 use ethrex_levm::{
     errors::{TransactionReport, TxResult, VMError},
     Account, StorageSlot,
 };
 use ethrex_storage::{error::StoreError, AccountUpdate};
-use ethrex_vm::SpecId;
 use itertools::Itertools;
 use revm::primitives::{EVMError, ExecutionResult as RevmExecutionResult};
 use serde::{Deserialize, Serialize};
@@ -133,21 +132,21 @@ pub fn summary_for_slack(reports: &[EFTestReport]) -> String {
         }}
     ]
 }}"#,
-        fork_summary_for_slack(reports, SpecId::PRAGUE),
-        fork_summary_for_slack(reports, SpecId::CANCUN),
-        fork_summary_for_slack(reports, SpecId::SHANGHAI),
-        fork_summary_for_slack(reports, SpecId::HOMESTEAD),
-        fork_summary_for_slack(reports, SpecId::ISTANBUL),
-        fork_summary_for_slack(reports, SpecId::LONDON),
-        fork_summary_for_slack(reports, SpecId::BYZANTIUM),
-        fork_summary_for_slack(reports, SpecId::BERLIN),
-        fork_summary_for_slack(reports, SpecId::CONSTANTINOPLE),
-        fork_summary_for_slack(reports, SpecId::MERGE),
-        fork_summary_for_slack(reports, SpecId::FRONTIER),
+        fork_summary_for_slack(reports, Fork::Prague),
+        fork_summary_for_slack(reports, Fork::Cancun),
+        fork_summary_for_slack(reports, Fork::Shanghai),
+        fork_summary_for_slack(reports, Fork::Byzantium),
+        fork_summary_for_slack(reports, Fork::Berlin),
+        fork_summary_for_slack(reports, Fork::Constantinople),
+        fork_summary_for_slack(reports, Fork::Paris),
+        fork_summary_for_slack(reports, Fork::Homestead),
+        fork_summary_for_slack(reports, Fork::Istanbul),
+        fork_summary_for_slack(reports, Fork::London),
+        fork_summary_for_slack(reports, Fork::Frontier),
     )
 }
 
-fn fork_summary_for_slack(reports: &[EFTestReport], fork: SpecId) -> String {
+fn fork_summary_for_slack(reports: &[EFTestReport], fork: Fork) -> String {
     let fork_str: &str = fork.into();
     let (fork_tests, fork_passed_tests, fork_success_percentage) = fork_statistics(reports, fork);
     format!(r#"*{fork_str}:* {fork_passed_tests}/{fork_tests} ({fork_success_percentage:.2}%)"#)
@@ -173,21 +172,21 @@ pub fn summary_for_github(reports: &[EFTestReport]) -> String {
     let success_percentage = (total_passed as f64 / total_run as f64) * 100.0;
     format!(
         r#"Summary: {total_passed}/{total_run} ({success_percentage:.2}%)\n\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n{}\n"#,
-        fork_summary_for_github(reports, SpecId::PRAGUE),
-        fork_summary_for_github(reports, SpecId::CANCUN),
-        fork_summary_for_github(reports, SpecId::SHANGHAI),
-        fork_summary_for_github(reports, SpecId::HOMESTEAD),
-        fork_summary_for_github(reports, SpecId::ISTANBUL),
-        fork_summary_for_github(reports, SpecId::LONDON),
-        fork_summary_for_github(reports, SpecId::BYZANTIUM),
-        fork_summary_for_github(reports, SpecId::BERLIN),
-        fork_summary_for_github(reports, SpecId::CONSTANTINOPLE),
-        fork_summary_for_github(reports, SpecId::MERGE),
-        fork_summary_for_github(reports, SpecId::FRONTIER),
+        fork_summary_for_github(reports, Fork::Prague),
+        fork_summary_for_github(reports, Fork::Cancun),
+        fork_summary_for_github(reports, Fork::Shanghai),
+        fork_summary_for_github(reports, Fork::Byzantium),
+        fork_summary_for_github(reports, Fork::Berlin),
+        fork_summary_for_github(reports, Fork::Constantinople),
+        fork_summary_for_github(reports, Fork::Paris),
+        fork_summary_for_github(reports, Fork::Homestead),
+        fork_summary_for_github(reports, Fork::Istanbul),
+        fork_summary_for_github(reports, Fork::London),
+        fork_summary_for_github(reports, Fork::Frontier),
     )
 }
 
-fn fork_summary_for_github(reports: &[EFTestReport], fork: SpecId) -> String {
+fn fork_summary_for_github(reports: &[EFTestReport], fork: Fork) -> String {
     let fork_str: &str = fork.into();
     let (fork_tests, fork_passed_tests, fork_success_percentage) = fork_statistics(reports, fork);
     format!("{fork_str}: {fork_passed_tests}/{fork_tests} ({fork_success_percentage:.2}%)")
@@ -221,22 +220,22 @@ pub fn summary_for_shell(reports: &[EFTestReport]) -> String {
         } else {
             format!("{}", total_passed).red()
         },
-        fork_summary_shell(reports, SpecId::PRAGUE),
-        fork_summary_shell(reports, SpecId::CANCUN),
-        fork_summary_shell(reports, SpecId::SHANGHAI),
-        fork_summary_shell(reports, SpecId::MERGE),
-        fork_summary_shell(reports, SpecId::LONDON),
-        fork_summary_shell(reports, SpecId::BERLIN),
-        fork_summary_shell(reports, SpecId::ISTANBUL),
-        fork_summary_shell(reports, SpecId::CONSTANTINOPLE),
-        fork_summary_shell(reports, SpecId::BYZANTIUM),
-        fork_summary_shell(reports, SpecId::HOMESTEAD),
-        fork_summary_shell(reports, SpecId::FRONTIER),
+        fork_summary_shell(reports, Fork::Prague),
+        fork_summary_shell(reports, Fork::Cancun),
+        fork_summary_shell(reports, Fork::Shanghai),
+        fork_summary_shell(reports, Fork::Paris),
+        fork_summary_shell(reports, Fork::London),
+        fork_summary_shell(reports, Fork::Berlin),
+        fork_summary_shell(reports, Fork::Istanbul),
+        fork_summary_shell(reports, Fork::Constantinople),
+        fork_summary_shell(reports, Fork::Byzantium),
+        fork_summary_shell(reports, Fork::Homestead),
+        fork_summary_shell(reports, Fork::Frontier),
         test_dir_summary_for_shell(reports),
     )
 }
 
-fn fork_summary_shell(reports: &[EFTestReport], fork: SpecId) -> String {
+fn fork_summary_shell(reports: &[EFTestReport], fork: Fork) -> String {
     let fork_str: &str = fork.into();
     let (fork_tests, fork_passed_tests, fork_success_percentage) = fork_statistics(reports, fork);
     format!(
@@ -252,7 +251,7 @@ fn fork_summary_shell(reports: &[EFTestReport], fork: SpecId) -> String {
     )
 }
 
-fn fork_statistics(reports: &[EFTestReport], fork: SpecId) -> (usize, usize, f64) {
+fn fork_statistics(reports: &[EFTestReport], fork: Fork) -> (usize, usize, f64) {
     let fork_tests = reports.iter().filter(|report| report.fork == fork).count();
     let fork_passed_tests = reports
         .iter()
@@ -312,17 +311,17 @@ impl Display for EFTestsReport {
         let total_run = self.0.len();
         writeln!(f, "Summary: {total_passed}/{total_run}",)?;
         writeln!(f)?;
-        writeln!(f, "{}", fork_summary_shell(&self.0, SpecId::PRAGUE))?;
-        writeln!(f, "{}", fork_summary_shell(&self.0, SpecId::CANCUN))?;
-        writeln!(f, "{}", fork_summary_shell(&self.0, SpecId::SHANGHAI))?;
-        writeln!(f, "{}", fork_summary_shell(&self.0, SpecId::HOMESTEAD))?;
-        writeln!(f, "{}", fork_summary_shell(&self.0, SpecId::ISTANBUL))?;
-        writeln!(f, "{}", fork_summary_shell(&self.0, SpecId::LONDON))?;
-        writeln!(f, "{}", fork_summary_shell(&self.0, SpecId::BYZANTIUM))?;
-        writeln!(f, "{}", fork_summary_shell(&self.0, SpecId::BERLIN))?;
-        writeln!(f, "{}", fork_summary_shell(&self.0, SpecId::CONSTANTINOPLE))?;
-        writeln!(f, "{}", fork_summary_shell(&self.0, SpecId::MERGE))?;
-        writeln!(f, "{}", fork_summary_shell(&self.0, SpecId::FRONTIER))?;
+        writeln!(f, "{}", fork_summary_shell(&self.0, Fork::Prague))?;
+        writeln!(f, "{}", fork_summary_shell(&self.0, Fork::Cancun))?;
+        writeln!(f, "{}", fork_summary_shell(&self.0, Fork::Shanghai))?;
+        writeln!(f, "{}", fork_summary_shell(&self.0, Fork::Byzantium))?;
+        writeln!(f, "{}", fork_summary_shell(&self.0, Fork::Berlin))?;
+        writeln!(f, "{}", fork_summary_shell(&self.0, Fork::Constantinople))?;
+        writeln!(f, "{}", fork_summary_shell(&self.0, Fork::Paris))?;
+        writeln!(f, "{}", fork_summary_shell(&self.0, Fork::Homestead))?;
+        writeln!(f, "{}", fork_summary_shell(&self.0, Fork::Istanbul))?;
+        writeln!(f, "{}", fork_summary_shell(&self.0, Fork::London))?;
+        writeln!(f, "{}", fork_summary_shell(&self.0, Fork::Frontier))?;
         writeln!(f)?;
         writeln!(f, "Failed tests:")?;
         writeln!(f)?;
@@ -397,14 +396,14 @@ pub struct EFTestReport {
     pub name: String,
     pub dir: String,
     pub test_hash: H256,
-    pub fork: SpecId,
+    pub fork: Fork,
     pub skipped: bool,
     pub failed_vectors: HashMap<TestVector, EFTestRunnerError>,
     pub re_run_report: Option<TestReRunReport>,
 }
 
 impl EFTestReport {
-    pub fn new(name: String, dir: String, test_hash: H256, fork: SpecId) -> Self {
+    pub fn new(name: String, dir: String, test_hash: H256, fork: Fork) -> Self {
         EFTestReport {
             name,
             dir,
diff --git a/cmd/ef_tests/levm/runner/levm_runner.rs b/cmd/ef_tests/levm/runner/levm_runner.rs
index 10fc4ebc07..9bd1468929 100644
--- a/cmd/ef_tests/levm/runner/levm_runner.rs
+++ b/cmd/ef_tests/levm/runner/levm_runner.rs
@@ -108,7 +108,7 @@ pub fn prepare_vm_for_tx(vector: &TestVector, test: &EFTest) -> Result<VM, EFTes
             origin: tx.sender,
             refunded_gas: 0,
             gas_limit: tx.gas_limit,
-            spec_id: test.fork(),
+            fork: test.fork(),
             block_number: test.env.current_number,
             coinbase: test.env.current_coinbase,
             timestamp: test.env.current_timestamp,
diff --git a/cmd/ef_tests/levm/runner/revm_runner.rs b/cmd/ef_tests/levm/runner/revm_runner.rs
index cfcce780c6..baa42a13f6 100644
--- a/cmd/ef_tests/levm/runner/revm_runner.rs
+++ b/cmd/ef_tests/levm/runner/revm_runner.rs
@@ -14,7 +14,7 @@ use ethrex_levm::{
     Account, StorageSlot,
 };
 use ethrex_storage::{error::StoreError, AccountUpdate};
-use ethrex_vm::{db::StoreWrapper, EvmState, RevmAddress, RevmU256};
+use ethrex_vm::{db::StoreWrapper, fork_to_spec_id, EvmState, RevmAddress, RevmU256};
 use revm::{
     db::State,
     inspectors::TracerEip3155 as RevmTracerEip3155,
@@ -195,7 +195,7 @@ pub fn prepare_revm_for_tx<'state>(
         .with_block_env(block_env)
         .with_tx_env(tx_env)
         .modify_cfg_env(|cfg| cfg.chain_id = chain_spec.chain_id)
-        .with_spec_id(test.fork())
+        .with_spec_id(fork_to_spec_id(test.fork()))
         .with_external_context(
             RevmTracerEip3155::new(Box::new(std::io::stderr())).without_summary(),
         );
diff --git a/cmd/ef_tests/levm/types.rs b/cmd/ef_tests/levm/types.rs
index 5295f7f4da..80219ed677 100644
--- a/cmd/ef_tests/levm/types.rs
+++ b/cmd/ef_tests/levm/types.rs
@@ -11,10 +11,9 @@ use crate::{
 };
 use bytes::Bytes;
 use ethrex_core::{
-    types::{Genesis, GenesisAccount, TxKind},
+    types::{Fork, Genesis, GenesisAccount, TxKind},
     Address, H256, U256,
 };
-use ethrex_vm::SpecId;
 use serde::Deserialize;
 use std::collections::HashMap;
 
@@ -33,21 +32,21 @@ pub struct EFTest {
 }
 
 impl EFTest {
-    pub fn fork(&self) -> SpecId {
+    pub fn fork(&self) -> Fork {
         match &self.post {
-            EFTestPost::Prague(_) => SpecId::PRAGUE,
-            EFTestPost::Cancun(_) => SpecId::CANCUN,
-            EFTestPost::Shanghai(_) => SpecId::SHANGHAI,
-            EFTestPost::Homestead(_) => SpecId::HOMESTEAD,
-            EFTestPost::Istanbul(_) => SpecId::ISTANBUL,
-            EFTestPost::London(_) => SpecId::LONDON,
-            EFTestPost::Byzantium(_) => SpecId::BYZANTIUM,
-            EFTestPost::Berlin(_) => SpecId::BERLIN,
+            EFTestPost::Prague(_) => Fork::Prague,
+            EFTestPost::Cancun(_) => Fork::Cancun,
+            EFTestPost::Shanghai(_) => Fork::Shanghai,
+            EFTestPost::Homestead(_) => Fork::Homestead,
+            EFTestPost::Istanbul(_) => Fork::Istanbul,
+            EFTestPost::London(_) => Fork::London,
+            EFTestPost::Byzantium(_) => Fork::Byzantium,
+            EFTestPost::Berlin(_) => Fork::Berlin,
             EFTestPost::Constantinople(_) | EFTestPost::ConstantinopleFix(_) => {
-                SpecId::CONSTANTINOPLE
+                Fork::Constantinople
             }
-            EFTestPost::Paris(_) => SpecId::MERGE,
-            EFTestPost::Frontier(_) => SpecId::FRONTIER,
+            EFTestPost::Paris(_) => Fork::Paris,
+            EFTestPost::Frontier(_) => Fork::Frontier,
         }
     }
 }
diff --git a/crates/blockchain/payload.rs b/crates/blockchain/payload.rs
index 6b171fd7a9..8d1cd5a3cc 100644
--- a/crates/blockchain/payload.rs
+++ b/crates/blockchain/payload.rs
@@ -446,10 +446,9 @@ fn apply_plain_transaction(
             &context.payload.header,
             store_wrapper.clone(),
             block_cache,
-            spec_id(
-                &context.chain_config().map_err(ChainError::from)?,
-                context.payload.header.timestamp,
-            ),
+            context
+                .chain_config()?
+                .fork(context.payload.header.timestamp),
         )
         .map_err(EvmError::from)?;
 
diff --git a/crates/common/types/genesis.rs b/crates/common/types/genesis.rs
index cf4e0f9674..d84ede355d 100644
--- a/crates/common/types/genesis.rs
+++ b/crates/common/types/genesis.rs
@@ -87,11 +87,57 @@ pub struct ChainConfig {
     pub terminal_total_difficulty_passed: bool,
 }
 
-#[derive(Debug, PartialEq, PartialOrd)]
+#[repr(u8)]
+#[derive(Debug, PartialEq, PartialOrd, Default, Clone, Copy, Serialize, Deserialize)]
 pub enum Fork {
-    Paris = 0,
-    Shanghai = 1,
-    Cancun = 2,
+    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,
+    #[default]
+    Cancun = 17,
+    Prague = 18,
+    PragueEof = 19,
+}
+
+impl From<Fork> 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::Byzantium => "Byzantium",
+            Fork::Constantinople => "Constantinople",
+            Fork::Petersburg => "Petersburg",
+            Fork::Istanbul => "Istanbul",
+            Fork::MuirGlacier => "MuirGlacier",
+            Fork::Berlin => "Berlin",
+            Fork::London => "London",
+            Fork::ArrowGlacier => "ArrowGlacier",
+            Fork::GrayGlacier => "GrayGlacier",
+            Fork::Paris => "Paris",
+            Fork::Shanghai => "Shanghai",
+            Fork::Cancun => "Cancun",
+            Fork::Prague => "Prague",
+            Fork::PragueEof => "Prague EOF",
+        }
+    }
 }
 
 impl ChainConfig {
@@ -122,6 +168,10 @@ impl ChainConfig {
         }
     }
 
+    pub fn fork(&self, block_timestamp: u64) -> Fork {
+        self.get_fork(block_timestamp)
+    }
+
     pub fn gather_forks(&self) -> (Vec<u64>, Vec<u64>) {
         let block_number_based_forks: Vec<u64> = vec![
             self.homestead_block,
diff --git a/crates/vm/levm/src/environment.rs b/crates/vm/levm/src/environment.rs
index b1e1ae8956..3600b841c8 100644
--- a/crates/vm/levm/src/environment.rs
+++ b/crates/vm/levm/src/environment.rs
@@ -1,4 +1,4 @@
-use ethrex_core::{Address, H256, U256};
+use ethrex_core::{types::Fork, Address, H256, U256};
 pub use revm_primitives::SpecId;
 
 use std::collections::HashMap;
@@ -12,7 +12,7 @@ pub struct Environment {
     pub origin: Address,
     pub refunded_gas: u64,
     pub gas_limit: u64,
-    pub spec_id: SpecId,
+    pub fork: Fork,
     pub block_number: U256,
     pub coinbase: Address,
     pub timestamp: U256,
diff --git a/crates/vm/levm/src/gas_cost.rs b/crates/vm/levm/src/gas_cost.rs
index a659876415..9ddaac4b5d 100644
--- a/crates/vm/levm/src/gas_cost.rs
+++ b/crates/vm/levm/src/gas_cost.rs
@@ -6,9 +6,8 @@ use crate::{
 };
 use bytes::Bytes;
 /// Contains the gas costs of the EVM instructions
-use ethrex_core::U256;
+use ethrex_core::{types::Fork, U256};
 use num_bigint::BigUint;
-use revm_primitives::SpecId;
 
 // Opcodes cost
 pub const STOP: u64 = 0;
@@ -464,14 +463,14 @@ pub fn create(
     new_memory_size: usize,
     current_memory_size: usize,
     code_size_in_memory: usize,
-    spec_id: SpecId,
+    fork: Fork,
 ) -> Result<u64, VMError> {
     compute_gas_create(
         new_memory_size,
         current_memory_size,
         code_size_in_memory,
         false,
-        spec_id,
+        fork,
     )
 }
 
@@ -479,14 +478,14 @@ pub fn create_2(
     new_memory_size: usize,
     current_memory_size: usize,
     code_size_in_memory: usize,
-    spec_id: SpecId,
+    fork: Fork,
 ) -> Result<u64, VMError> {
     compute_gas_create(
         new_memory_size,
         current_memory_size,
         code_size_in_memory,
         true,
-        spec_id,
+        fork,
     )
 }
 
@@ -495,7 +494,7 @@ fn compute_gas_create(
     current_memory_size: usize,
     code_size_in_memory: usize,
     is_create_2: bool,
-    spec_id: SpecId,
+    fork: Fork,
 ) -> Result<u64, VMError> {
     let minimum_word_size = (code_size_in_memory
         .checked_add(31)
@@ -508,7 +507,7 @@ fn compute_gas_create(
         .map_err(|_| VMError::VeryLargeNumber)?;
 
     // [EIP-3860] - Apply extra gas cost of 2 for every 32-byte chunk of initcode
-    let init_code_cost = if spec_id >= SpecId::SHANGHAI {
+    let init_code_cost = if fork >= Fork::Shanghai {
         minimum_word_size
             .checked_mul(INIT_CODE_WORD_COST)
             .ok_or(OutOfGasError::GasCostOverflow)? // will not panic since it's 2
@@ -560,13 +559,13 @@ pub fn selfdestruct(
     Ok(gas_cost)
 }
 
-pub fn tx_calldata(calldata: &Bytes, spec_id: SpecId) -> Result<u64, OutOfGasError> {
+pub fn tx_calldata(calldata: &Bytes, fork: Fork) -> Result<u64, OutOfGasError> {
     // This cost applies both for call and create
     // 4 gas for each zero byte in the transaction data 16 gas for each non-zero byte in the transaction.
     let mut calldata_cost: u64 = 0;
     for byte in calldata {
         calldata_cost = if *byte != 0 {
-            if spec_id >= SpecId::ISTANBUL {
+            if fork >= Fork::Istanbul {
                 calldata_cost
                     .checked_add(CALLDATA_COST_NON_ZERO_BYTE)
                     .ok_or(OutOfGasError::GasUsedOverflow)?
@@ -681,7 +680,7 @@ pub fn call(
     value_to_transfer: U256,
     gas_from_stack: U256,
     gas_left: u64,
-    spec_id: SpecId,
+    fork: Fork,
 ) -> Result<(u64, u64), VMError> {
     let memory_expansion_cost = memory::expansion_cost(new_memory_size, current_memory_size)?;
 
@@ -689,7 +688,7 @@ pub fn call(
         address_was_cold,
         CALL_STATIC,
         CALL_COLD_DYNAMIC,
-        if spec_id >= SpecId::BERLIN {
+        if fork >= Fork::Berlin {
             CALL_WARM_DYNAMIC
         } else {
             //https://eips.ethereum.org/EIPS/eip-2929
@@ -966,7 +965,7 @@ pub fn modexp(
     base_size: usize,
     exponent_size: usize,
     modulus_size: usize,
-    spec_id: SpecId,
+    fork: Fork,
 ) -> Result<u64, VMError> {
     let base_size: u64 = base_size
         .try_into()
@@ -980,7 +979,7 @@ pub fn modexp(
 
     let max_length = base_size.max(modulus_size);
 
-    if spec_id >= SpecId::BERLIN {
+    if fork >= Fork::Berlin {
         modexp_eip2565(max_length, exponent_first_32_bytes, exponent_size)
     } else {
         modexp_eip198(max_length, exponent_first_32_bytes, exponent_size)
diff --git a/crates/vm/levm/src/opcode_handlers/block.rs b/crates/vm/levm/src/opcode_handlers/block.rs
index c0f52a02a1..17987d7dcd 100644
--- a/crates/vm/levm/src/opcode_handlers/block.rs
+++ b/crates/vm/levm/src/opcode_handlers/block.rs
@@ -7,10 +7,9 @@ use crate::{
     vm::VM,
 };
 use ethrex_core::{
-    types::{BLOB_BASE_FEE_UPDATE_FRACTION, MIN_BASE_FEE_PER_BLOB_GAS},
+    types::{Fork, BLOB_BASE_FEE_UPDATE_FRACTION, MIN_BASE_FEE_PER_BLOB_GAS},
     U256,
 };
-use revm_primitives::SpecId;
 
 // Block Information (11)
 // Opcodes: BLOCKHASH, COINBASE, TIMESTAMP, NUMBER, PREVRANDAO, GASLIMIT, CHAINID, SELFBALANCE, BASEFEE, BLOBHASH, BLOBBASEFEE
@@ -165,7 +164,7 @@ impl VM {
         current_call_frame: &mut CallFrame,
     ) -> Result<OpcodeSuccess, VMError> {
         // [EIP-4844] - BLOBHASH is only available from CANCUN
-        if self.env.spec_id < SpecId::CANCUN {
+        if self.env.fork < Fork::Cancun {
             return Err(VMError::InvalidOpcode);
         }
 
@@ -212,7 +211,7 @@ impl VM {
         current_call_frame: &mut CallFrame,
     ) -> Result<OpcodeSuccess, VMError> {
         // [EIP-7516] - BLOBBASEFEE is only available from CANCUN
-        if self.env.spec_id < SpecId::CANCUN {
+        if self.env.fork < Fork::Cancun {
             return Err(VMError::InvalidOpcode);
         }
         self.increase_consumed_gas(current_call_frame, gas_cost::BLOBBASEFEE)?;
diff --git a/crates/vm/levm/src/opcode_handlers/push.rs b/crates/vm/levm/src/opcode_handlers/push.rs
index ac4c7ab759..fa5cbde2a3 100644
--- a/crates/vm/levm/src/opcode_handlers/push.rs
+++ b/crates/vm/levm/src/opcode_handlers/push.rs
@@ -5,8 +5,7 @@ use crate::{
     gas_cost,
     vm::VM,
 };
-use ethrex_core::U256;
-use revm_primitives::SpecId;
+use ethrex_core::{types::Fork, U256};
 
 // Push Operations
 // Opcodes: PUSH0, PUSH1 ... PUSH32
@@ -38,7 +37,7 @@ impl VM {
         current_call_frame: &mut CallFrame,
     ) -> Result<OpcodeSuccess, VMError> {
         // [EIP-3855] - PUSH0 is only available from SHANGHAI
-        if self.env.spec_id < SpecId::SHANGHAI {
+        if self.env.fork < Fork::Shanghai {
             return Err(VMError::InvalidOpcode);
         }
 
diff --git a/crates/vm/levm/src/opcode_handlers/stack_memory_storage_flow.rs b/crates/vm/levm/src/opcode_handlers/stack_memory_storage_flow.rs
index d906e3ec65..eb5b0a95f8 100644
--- a/crates/vm/levm/src/opcode_handlers/stack_memory_storage_flow.rs
+++ b/crates/vm/levm/src/opcode_handlers/stack_memory_storage_flow.rs
@@ -6,8 +6,7 @@ use crate::{
     memory::{self, calculate_memory_size},
     vm::VM,
 };
-use ethrex_core::{H256, U256};
-use revm_primitives::SpecId;
+use ethrex_core::{types::Fork, H256, U256};
 
 // Stack, Memory, Storage and Flow Operations (15)
 // Opcodes: POP, MLOAD, MSTORE, MSTORE8, SLOAD, SSTORE, JUMP, JUMPI, PC, MSIZE, GAS, JUMPDEST, TLOAD, TSTORE, MCOPY
@@ -26,7 +25,7 @@ impl VM {
         current_call_frame: &mut CallFrame,
     ) -> Result<OpcodeSuccess, VMError> {
         // [EIP-1153] - TLOAD is only available from CANCUN
-        if self.env.spec_id < SpecId::CANCUN {
+        if self.env.fork < Fork::Cancun {
             return Err(VMError::InvalidOpcode);
         }
 
@@ -50,7 +49,7 @@ impl VM {
         current_call_frame: &mut CallFrame,
     ) -> Result<OpcodeSuccess, VMError> {
         // [EIP-1153] - TLOAD is only available from CANCUN
-        if self.env.spec_id < SpecId::CANCUN {
+        if self.env.fork < Fork::Cancun {
             return Err(VMError::InvalidOpcode);
         }
 
@@ -264,7 +263,7 @@ impl VM {
         current_call_frame: &mut CallFrame,
     ) -> Result<OpcodeSuccess, VMError> {
         // [EIP-5656] - MCOPY is only available from CANCUN
-        if self.env.spec_id < SpecId::CANCUN {
+        if self.env.fork < Fork::Cancun {
             return Err(VMError::InvalidOpcode);
         }
 
diff --git a/crates/vm/levm/src/opcode_handlers/system.rs b/crates/vm/levm/src/opcode_handlers/system.rs
index 3af13ae59d..37b530a774 100644
--- a/crates/vm/levm/src/opcode_handlers/system.rs
+++ b/crates/vm/levm/src/opcode_handlers/system.rs
@@ -11,8 +11,7 @@ use crate::{
     Account,
 };
 use bytes::Bytes;
-use ethrex_core::{Address, U256};
-use revm_primitives::SpecId;
+use ethrex_core::{types::Fork, Address, U256};
 
 // System Operations (10)
 // Opcodes: CREATE, CALL, CALLCODE, RETURN, DELEGATECALL, CREATE2, STATICCALL, REVERT, INVALID, SELFDESTRUCT
@@ -75,7 +74,7 @@ impl VM {
             value_to_transfer,
             gas,
             gas_left,
-            self.env.spec_id,
+            self.env.fork,
         )?;
 
         self.increase_consumed_gas(current_call_frame, cost)?;
@@ -395,7 +394,7 @@ impl VM {
                 new_size,
                 current_call_frame.memory.len(),
                 code_size_in_memory,
-                self.env.spec_id,
+                self.env.fork,
             )?,
         )?;
 
@@ -430,7 +429,7 @@ impl VM {
                 new_size,
                 current_call_frame.memory.len(),
                 code_size_in_memory,
-                self.env.spec_id,
+                self.env.fork,
             )?,
         )?;
 
@@ -520,7 +519,7 @@ impl VM {
         )?;
 
         // [EIP-6780] - SELFDESTRUCT only in same transaction from CANCUN
-        if self.env.spec_id >= SpecId::CANCUN {
+        if self.env.fork >= Fork::Cancun {
             increase_account_balance(
                 &mut self.cache,
                 &mut self.db,
@@ -583,7 +582,7 @@ impl VM {
             return Err(VMError::OpcodeNotAllowedInStaticContext);
         }
         // 2. [EIP-3860] - Cant exceed init code max size
-        if code_size_in_memory > INIT_CODE_MAX_SIZE && self.env.spec_id >= SpecId::SHANGHAI {
+        if code_size_in_memory > INIT_CODE_MAX_SIZE && self.env.fork >= Fork::Shanghai {
             return Err(VMError::OutOfGas(OutOfGasError::ConsumedGasOverflow));
         }
 
diff --git a/crates/vm/levm/src/precompiles.rs b/crates/vm/levm/src/precompiles.rs
index 2b0e14132a..eadca8619f 100644
--- a/crates/vm/levm/src/precompiles.rs
+++ b/crates/vm/levm/src/precompiles.rs
@@ -4,7 +4,7 @@ use bls12_381::{
 };
 
 use bytes::Bytes;
-use ethrex_core::{serde_utils::bool, Address, H160, H256, U256};
+use ethrex_core::{serde_utils::bool, types::Fork, Address, H160, H256, U256};
 use keccak_hash::keccak256;
 use kzg_rs::{Bytes32, Bytes48, KzgSettings};
 use lambdaworks_math::{
@@ -32,7 +32,6 @@ use lambdaworks_math::{
 };
 use libsecp256k1::{self, Message, RecoveryId, Signature};
 use num_bigint::BigUint;
-use revm_primitives::SpecId;
 use sha3::Digest;
 use std::ops::Mul;
 
@@ -176,14 +175,14 @@ const FP2_ZERO_MAPPED_TO_G2: [u8; 256] = [
 pub const G1_POINT_AT_INFINITY: [u8; 128] = [0_u8; 128];
 pub const G2_POINT_AT_INFINITY: [u8; 256] = [0_u8; 256];
 
-pub fn is_precompile(callee_address: &Address, spec_id: SpecId) -> bool {
+pub fn is_precompile(callee_address: &Address, fork: Fork) -> bool {
     // Cancun specs is the only one that allows point evaluation precompile
-    if *callee_address == POINT_EVALUATION_ADDRESS && spec_id < SpecId::CANCUN {
+    if *callee_address == POINT_EVALUATION_ADDRESS && fork < Fork::Cancun {
         return false;
     }
     // Prague or newers forks should only use this precompiles
     // https://eips.ethereum.org/EIPS/eip-2537
-    if PRECOMPILES_POST_CANCUN.contains(callee_address) && spec_id < SpecId::PRAGUE {
+    if PRECOMPILES_POST_CANCUN.contains(callee_address) && fork < Fork::Prague {
         return false;
     }
 
@@ -192,7 +191,7 @@ pub fn is_precompile(callee_address: &Address, spec_id: SpecId) -> bool {
 
 pub fn execute_precompile(
     current_call_frame: &mut CallFrame,
-    spec_id: SpecId,
+    fork: Fork,
 ) -> Result<Bytes, VMError> {
     let callee_address = current_call_frame.code_address;
     let gas_for_call = current_call_frame
@@ -218,7 +217,7 @@ pub fn execute_precompile(
             &current_call_frame.calldata,
             gas_for_call,
             consumed_gas,
-            spec_id,
+            fork,
         )?,
         address if address == ECADD_ADDRESS => {
             ecadd(&current_call_frame.calldata, gas_for_call, consumed_gas)?
@@ -400,7 +399,7 @@ pub fn modexp(
     calldata: &Bytes,
     gas_for_call: u64,
     consumed_gas: &mut u64,
-    spec_id: SpecId,
+    fork: Fork,
 ) -> Result<Bytes, VMError> {
     // If calldata does not reach the required length, we should fill the rest with zeros
     let calldata = fill_with_zeros(calldata, 96)?;
@@ -426,7 +425,7 @@ pub fn modexp(
     if base_size == U256::zero() && modulus_size == U256::zero() {
         // On Berlin or newer there is a floor cost for the modexp precompile
         // On older versions in this return there is no cost added, see more https://eips.ethereum.org/EIPS/eip-2565
-        if spec_id >= SpecId::BERLIN {
+        if fork >= Fork::Berlin {
             increase_precompile_consumed_gas(gas_for_call, MODEXP_STATIC_COST, consumed_gas)?;
         }
         return Ok(Bytes::new());
@@ -465,13 +464,7 @@ pub fn modexp(
     // Use of unwrap_or_default because if e == 0 get_slice_or_default returns an empty vec
     let exp_first_32 = BigUint::from_bytes_be(e.get(0..bytes_to_take).unwrap_or_default());
 
-    let gas_cost = gas_cost::modexp(
-        &exp_first_32,
-        base_size,
-        exponent_size,
-        modulus_size,
-        spec_id,
-    )?;
+    let gas_cost = gas_cost::modexp(&exp_first_32, base_size, exponent_size, modulus_size, fork)?;
 
     increase_precompile_consumed_gas(gas_for_call, gas_cost, consumed_gas)?;
 
diff --git a/crates/vm/levm/src/utils.rs b/crates/vm/levm/src/utils.rs
index beae2e8e98..d07653a27a 100644
--- a/crates/vm/levm/src/utils.rs
+++ b/crates/vm/levm/src/utils.rs
@@ -16,12 +16,11 @@ use crate::{
     AccountInfo,
 };
 use bytes::Bytes;
-use ethrex_core::{Address, H256, U256};
+use ethrex_core::{types::Fork, Address, H256, U256};
 use ethrex_rlp;
 use ethrex_rlp::encode::RLPEncode;
 use keccak_hash::keccak;
 use libsecp256k1::{Message, RecoveryId, Signature};
-use revm_primitives::SpecId;
 use sha3::{Digest, Keccak256};
 use std::{
     collections::{HashMap, HashSet},
@@ -219,7 +218,7 @@ pub fn update_account_bytecode(
 // ==================== Gas related functions =======================
 pub fn get_intrinsic_gas(
     is_create: bool,
-    spec_id: SpecId,
+    fork: Fork,
     access_list: &AccessList,
     authorization_list: &Option<AuthorizationList>,
     initial_call_frame: &CallFrame,
@@ -230,7 +229,7 @@ pub fn get_intrinsic_gas(
     // Calldata Cost
     // 4 gas for each zero byte in the transaction data 16 gas for each non-zero byte in the transaction.
     let calldata_cost =
-        gas_cost::tx_calldata(&initial_call_frame.calldata, spec_id).map_err(VMError::OutOfGas)?;
+        gas_cost::tx_calldata(&initial_call_frame.calldata, fork).map_err(VMError::OutOfGas)?;
 
     intrinsic_gas = intrinsic_gas
         .checked_add(calldata_cost)
@@ -300,10 +299,10 @@ pub fn get_intrinsic_gas(
 /// After EIP-7691 the maximum number of blob hashes changes. For more
 /// information see
 /// [EIP-7691](https://eips.ethereum.org/EIPS/eip-7691#specification).
-pub const fn max_blobs_per_block(specid: SpecId) -> usize {
-    match specid {
-        SpecId::PRAGUE => MAX_BLOB_COUNT_ELECTRA,
-        SpecId::PRAGUE_EOF => MAX_BLOB_COUNT_ELECTRA,
+pub const fn max_blobs_per_block(fork: Fork) -> usize {
+    match fork {
+        Fork::Prague => MAX_BLOB_COUNT_ELECTRA,
+        Fork::PragueEof => MAX_BLOB_COUNT_ELECTRA,
         _ => MAX_BLOB_COUNT,
     }
 }
@@ -315,22 +314,23 @@ pub const fn max_blobs_per_block(specid: SpecId) -> usize {
 /// calc_excess_blob_gas functions defined in EIP-4844 use the new
 /// values for the first block of the fork (and for all subsequent
 /// blocks)."
-pub const fn get_blob_base_fee_update_fraction_value(specid: SpecId) -> U256 {
-    match specid {
-        SpecId::PRAGUE => BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE,
-        SpecId::PRAGUE_EOF => BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE,
+
+pub const fn get_blob_base_fee_update_fraction_value(fork: Fork) -> U256 {
+    match fork {
+        Fork::Prague => BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE,
+        Fork::PragueEof => BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE,
         _ => BLOB_BASE_FEE_UPDATE_FRACTION,
     }
 }
 
 pub fn get_base_fee_per_blob_gas(
     block_excess_blob_gas: Option<U256>,
-    spec_id: SpecId,
+    fork: Fork,
 ) -> Result<U256, VMError> {
     fake_exponential(
         MIN_BASE_FEE_PER_BLOB_GAS,
         block_excess_blob_gas.unwrap_or_default(),
-        get_blob_base_fee_update_fraction_value(spec_id),
+        get_blob_base_fee_update_fraction_value(fork),
     )
 }
 
@@ -360,7 +360,7 @@ pub fn get_max_blob_gas_price(
 pub fn get_blob_gas_price(
     tx_blob_hashes: Vec<H256>,
     block_excess_blob_gas: Option<U256>,
-    spec_id: SpecId,
+    fork: Fork,
 ) -> Result<U256, VMError> {
     let blobhash_amount: u64 = tx_blob_hashes
         .len()
@@ -371,7 +371,7 @@ pub fn get_blob_gas_price(
         .checked_mul(BLOB_GAS_PER_BLOB)
         .unwrap_or_default();
 
-    let base_fee_per_blob_gas = get_base_fee_per_blob_gas(block_excess_blob_gas, spec_id)?;
+    let base_fee_per_blob_gas = get_base_fee_per_blob_gas(block_excess_blob_gas, fork)?;
 
     let blob_gas_price: U256 = blob_gas_price.into();
     let blob_fee: U256 = blob_gas_price
diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs
index eab730d63f..ce00ccb866 100644
--- a/crates/vm/levm/src/vm.rs
+++ b/crates/vm/levm/src/vm.rs
@@ -21,8 +21,10 @@ use crate::{
     AccountInfo, TransientStorage,
 };
 use bytes::Bytes;
-use ethrex_core::{types::TxKind, Address, H256, U256};
-use revm_primitives::SpecId;
+use ethrex_core::{
+    types::{Fork, TxKind},
+    Address, H256, U256,
+};
 use std::{
     cmp::max,
     collections::{HashMap, HashSet},
@@ -87,7 +89,7 @@ impl VM {
         let mut default_touched_accounts = HashSet::from_iter([env.origin].iter().cloned());
 
         // [EIP-3651] - Add coinbase to cache if the spec is SHANGHAI or higher
-        if env.spec_id >= SpecId::SHANGHAI {
+        if env.fork >= Fork::Shanghai {
             default_touched_accounts.insert(env.coinbase);
         }
 
@@ -105,10 +107,10 @@ impl VM {
 
         // Add precompiled contracts addresses to cache.
         // TODO: Use the addresses from precompiles.rs in a future
-        let max_precompile_address = match env.spec_id {
-            spec if spec >= SpecId::PRAGUE => SIZE_PRECOMPILES_PRAGUE,
-            spec if spec >= SpecId::CANCUN => SIZE_PRECOMPILES_CANCUN,
-            spec if spec < SpecId::CANCUN => SIZE_PRECOMPILES_PRE_CANCUN,
+        let max_precompile_address = match env.fork {
+            spec if spec >= Fork::Prague => SIZE_PRECOMPILES_PRAGUE,
+            spec if spec >= Fork::Cancun => SIZE_PRECOMPILES_CANCUN,
+            spec if spec < Fork::Cancun => SIZE_PRECOMPILES_PRE_CANCUN,
             _ => return Err(VMError::Internal(InternalError::InvalidSpecId)),
         };
         for i in 1..=max_precompile_address {
@@ -212,8 +214,8 @@ impl VM {
             self.env.transient_storage.clone(),
         );
 
-        if is_precompile(&current_call_frame.code_address, self.env.spec_id) {
-            let precompile_result = execute_precompile(current_call_frame, self.env.spec_id);
+        if is_precompile(&current_call_frame.code_address, self.env.fork) {
+            let precompile_result = execute_precompile(current_call_frame, self.env.fork);
 
             match precompile_result {
                 Ok(output) => {
@@ -508,7 +510,7 @@ impl VM {
 
         let intrinsic_gas = get_intrinsic_gas(
             self.is_create(),
-            self.env.spec_id,
+            self.env.fork,
             &self.access_list,
             &self.authorization_list,
             initial_call_frame,
@@ -525,7 +527,7 @@ impl VM {
         initial_call_frame: &CallFrame,
         report: &TransactionReport,
     ) -> Result<u64, VMError> {
-        if self.env.spec_id >= SpecId::PRAGUE {
+        if self.env.fork >= Fork::Prague {
             // If the transaction is a CREATE transaction, the calldata is emptied and the bytecode is assigned.
             let calldata = if self.is_create() {
                 &initial_call_frame.bytecode
@@ -537,7 +539,7 @@ impl VM {
             // tx_calldata = nonzero_bytes_in_calldata * 16 + zero_bytes_in_calldata * 4
             // this is actually tokens_in_calldata * STANDARD_TOKEN_COST
             // see it in https://eips.ethereum.org/EIPS/eip-7623
-            let tokens_in_calldata: u64 = gas_cost::tx_calldata(calldata, self.env.spec_id)
+            let tokens_in_calldata: u64 = gas_cost::tx_calldata(calldata, self.env.fork)
                 .map_err(VMError::OutOfGas)?
                 .checked_div(STANDARD_TOKEN_COST)
                 .ok_or(VMError::Internal(InternalError::DivisionError))?;
@@ -570,11 +572,11 @@ impl VM {
         let sender_address = self.env.origin;
         let sender_account = get_account(&mut self.cache, &self.db, sender_address);
 
-        if self.env.spec_id >= SpecId::PRAGUE {
+        if self.env.fork >= Fork::Prague {
             // check for gas limit is grater or equal than the minimum required
             let intrinsic_gas: u64 = get_intrinsic_gas(
                 self.is_create(),
-                self.env.spec_id,
+                self.env.fork,
                 &self.access_list,
                 &self.authorization_list,
                 initial_call_frame,
@@ -582,7 +584,7 @@ impl VM {
 
             // calldata_cost = tokens_in_calldata * 4
             let calldata_cost: u64 =
-                gas_cost::tx_calldata(&initial_call_frame.calldata, self.env.spec_id)
+                gas_cost::tx_calldata(&initial_call_frame.calldata, self.env.fork)
                     .map_err(VMError::OutOfGas)?;
 
             // same as calculated in gas_used()
@@ -652,13 +654,13 @@ impl VM {
         let blob_gas_cost = get_blob_gas_price(
             self.env.tx_blob_hashes.clone(),
             self.env.block_excess_blob_gas,
-            self.env.spec_id,
+            self.env.fork,
         )?;
 
         // (2) INSUFFICIENT_MAX_FEE_PER_BLOB_GAS
         if let Some(tx_max_fee_per_blob_gas) = self.env.tx_max_fee_per_blob_gas {
             if tx_max_fee_per_blob_gas
-                < get_base_fee_per_blob_gas(self.env.block_excess_blob_gas, self.env.spec_id)?
+                < get_base_fee_per_blob_gas(self.env.block_excess_blob_gas, self.env.fork)?
             {
                 return Err(VMError::TxValidation(
                     TxValidationError::InsufficientMaxFeePerBlobGas,
@@ -696,7 +698,7 @@ impl VM {
         if self.is_create() {
             // [EIP-3860] - INITCODE_SIZE_EXCEEDED
             if initial_call_frame.calldata.len() > INIT_CODE_MAX_SIZE
-                && self.env.spec_id >= SpecId::SHANGHAI
+                && self.env.fork >= Fork::Shanghai
             {
                 return Err(VMError::TxValidation(
                     TxValidationError::InitcodeSizeExceeded,
@@ -738,7 +740,7 @@ impl VM {
         // Transaction is type 3 if tx_max_fee_per_blob_gas is Some
         if self.env.tx_max_fee_per_blob_gas.is_some() {
             // (11) TYPE_3_TX_PRE_FORK
-            if self.env.spec_id < SpecId::CANCUN {
+            if self.env.fork < Fork::Cancun {
                 return Err(VMError::TxValidation(TxValidationError::Type3TxPreFork));
             }
 
@@ -762,7 +764,7 @@ impl VM {
             }
 
             // (14) TYPE_3_TX_BLOB_COUNT_EXCEEDED
-            if blob_hashes.len() > max_blobs_per_block(self.env.spec_id) {
+            if blob_hashes.len() > max_blobs_per_block(self.env.fork) {
                 return Err(VMError::TxValidation(
                     TxValidationError::Type3TxBlobCountExceeded,
                 ));
@@ -780,7 +782,7 @@ impl VM {
         // Transaction is type 4 if authorization_list is Some
         if let Some(auth_list) = &self.authorization_list {
             // (16) TYPE_4_TX_PRE_FORK
-            if self.env.spec_id < SpecId::PRAGUE {
+            if self.env.fork < Fork::Prague {
                 return Err(VMError::TxValidation(TxValidationError::Type4TxPreFork));
             }
 
@@ -1024,7 +1026,7 @@ impl VM {
     ) -> Result<(StorageSlot, bool), VMError> {
         // [EIP-2929] - Introduced conditional tracking of accessed storage slots for Berlin and later specs.
         let mut storage_slot_was_cold = false;
-        if self.env.spec_id >= SpecId::BERLIN {
+        if self.env.fork >= Fork::Berlin {
             storage_slot_was_cold = self
                 .accrued_substate
                 .touched_storage_slots
diff --git a/crates/vm/levm/tests/tests.rs b/crates/vm/levm/tests/tests.rs
index d366710156..904f4a28c6 100644
--- a/crates/vm/levm/tests/tests.rs
+++ b/crates/vm/levm/tests/tests.rs
@@ -2,7 +2,10 @@
 #![allow(clippy::unwrap_used)]
 
 use bytes::Bytes;
-use ethrex_core::{types::TxKind, Address, H256, U256};
+use ethrex_core::{
+    types::{Fork, TxKind},
+    Address, H256, U256,
+};
 use ethrex_levm::{
     account::Account,
     constants::*,
@@ -4559,13 +4562,7 @@ fn modexp_test() {
     let calldata = Bytes::from(calldata);
 
     let mut consumed_gas = 0;
-    let result = modexp(
-        &calldata,
-        10000,
-        &mut consumed_gas,
-        ethrex_levm::SpecId::CANCUN,
-    )
-    .unwrap();
+    let result = modexp(&calldata, 10000, &mut consumed_gas, Fork::Cancun).unwrap();
 
     let expected_result = Bytes::from(hex::decode("08").unwrap());
 
@@ -4580,13 +4577,7 @@ fn modexp_test_2() {
     let calldata = Bytes::from(calldata);
 
     let mut consumed_gas = 0;
-    let result = modexp(
-        &calldata,
-        10000,
-        &mut consumed_gas,
-        ethrex_levm::SpecId::CANCUN,
-    )
-    .unwrap();
+    let result = modexp(&calldata, 10000, &mut consumed_gas, Fork::Cancun).unwrap();
 
     let expected_result = Bytes::from(
         hex::decode("3b01b01ac41f2d6e917c6d6a221ce793802469026d9ab7578fa2e79e4da6aaab").unwrap(),
diff --git a/crates/vm/vm.rs b/crates/vm/vm.rs
index a52b3b86e6..a5490da971 100644
--- a/crates/vm/vm.rs
+++ b/crates/vm/vm.rs
@@ -94,7 +94,7 @@ cfg_if::cfg_if! {
         pub fn beacon_root_contract_call_levm(
             store_wrapper: Arc<StoreWrapper>,
             block_header: &BlockHeader,
-            spec_id: SpecId,
+            fork: Fork,
         ) -> Result<TransactionReport, EvmError> {
             lazy_static! {
                 static ref SYSTEM_ADDRESS: Address =
@@ -125,7 +125,7 @@ cfg_if::cfg_if! {
                 block_blob_gas_used: block_header.blob_gas_used.map(U256::from),
                 block_gas_limit: 30_000_000,
                 transient_storage: HashMap::new(),
-                spec_id,
+                fork,
                 ..Default::default()
             };
 
@@ -220,12 +220,12 @@ cfg_if::cfg_if! {
             });
             let mut block_cache: CacheDB = HashMap::new();
             let block_header = &block.header;
-            let spec_id = spec_id(&state.chain_config()?, block_header.timestamp);
+            let fork = state.chain_config()?.fork(block_header.timestamp);
             //eip 4788: execute beacon_root_contract_call before block transactions
             cfg_if::cfg_if! {
                 if #[cfg(not(feature = "l2"))] {
-                    if block_header.parent_beacon_block_root.is_some() && spec_id == SpecId::CANCUN {
-                        let report = beacon_root_contract_call_levm(store_wrapper.clone(), block_header, spec_id)?;
+                    if block_header.parent_beacon_block_root.is_some() && fork == Fork::Cancun {
+                        let report = beacon_root_contract_call_levm(store_wrapper.clone(), block_header, fork)?;
                         block_cache.extend(report.new_state);
                     }
                 }
@@ -239,7 +239,7 @@ cfg_if::cfg_if! {
             let mut cumulative_gas_used = 0;
 
             for tx in block.body.transactions.iter() {
-                let report = execute_tx_levm(tx, block_header, store_wrapper.clone(), block_cache.clone(), spec_id).map_err(EvmError::from)?;
+                let report = execute_tx_levm(tx, block_header, store_wrapper.clone(), block_cache.clone(), fork).map_err(EvmError::from)?;
 
                 let mut new_state = report.new_state.clone();
 
@@ -292,7 +292,7 @@ cfg_if::cfg_if! {
             block_header: &BlockHeader,
             db: Arc<dyn LevmDatabase>,
             block_cache: CacheDB,
-            spec_id: SpecId
+            fork: Fork
         ) -> Result<TransactionReport, VMError> {
             let gas_price : U256 = tx.effective_gas_price(block_header.base_fee_per_gas).ok_or(VMError::InvalidTransaction)?.into();
 
@@ -300,7 +300,7 @@ cfg_if::cfg_if! {
                 origin: tx.sender(),
                 refunded_gas: 0,
                 gas_limit: tx.gas_limit(),
-                spec_id,
+                fork,
                 block_number: block_header.number.into(),
                 coinbase: block_header.coinbase,
                 timestamp: block_header.timestamp.into(),
@@ -979,10 +979,31 @@ fn access_list_inspector(
 /// Returns the spec id according to the block timestamp and the stored chain config
 /// WARNING: Assumes at least Merge fork is active
 pub fn spec_id(chain_config: &ChainConfig, block_timestamp: u64) -> SpecId {
-    match chain_config.get_fork(block_timestamp) {
-        Fork::Cancun => SpecId::CANCUN,
-        Fork::Shanghai => SpecId::SHANGHAI,
+    fork_to_spec_id(chain_config.get_fork(block_timestamp))
+}
+
+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::Tangerine => SpecId::TANGERINE,
+        Fork::SpuriousDragon => SpecId::SPURIOUS_DRAGON,
+        Fork::Byzantium => SpecId::BYZANTIUM,
+        Fork::Constantinople => SpecId::CONSTANTINOPLE,
+        Fork::Petersburg => SpecId::PETERSBURG,
+        Fork::Istanbul => SpecId::ISTANBUL,
+        Fork::MuirGlacier => SpecId::MUIR_GLACIER,
+        Fork::Berlin => SpecId::BERLIN,
+        Fork::London => SpecId::LONDON,
+        Fork::ArrowGlacier => SpecId::ARROW_GLACIER,
+        Fork::GrayGlacier => SpecId::GRAY_GLACIER,
         Fork::Paris => SpecId::MERGE,
+        Fork::Shanghai => SpecId::SHANGHAI,
+        Fork::Cancun => SpecId::CANCUN,
+        Fork::Prague => SpecId::PRAGUE,
+        Fork::PragueEof => SpecId::PRAGUE_EOF,
     }
 }