diff --git a/crates/common/types/genesis.rs b/crates/common/types/genesis.rs index af082071f9..559c4fcb1b 100644 --- a/crates/common/types/genesis.rs +++ b/crates/common/types/genesis.rs @@ -111,9 +111,9 @@ impl TryFrom<&Path> for Genesis { )] #[serde(rename_all = "camelCase")] pub struct ForkBlobSchedule { - pub target: u32, - pub max: u32, pub base_fee_update_fraction: u64, + pub max: u32, + pub target: u32, } #[allow(unused)] @@ -460,6 +460,97 @@ impl ChainConfig { 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) + } 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, + } + } + pub fn gather_forks(&self, genesis_header: BlockHeader) -> (Vec, Vec) { let mut block_number_based_forks: Vec = vec![ self.homestead_block, diff --git a/crates/networking/rpc/engine/blobs.rs b/crates/networking/rpc/engine/blobs.rs index 929aac2e8b..3ea05ca3da 100644 --- a/crates/networking/rpc/engine/blobs.rs +++ b/crates/networking/rpc/engine/blobs.rs @@ -44,6 +44,7 @@ impl RpcHandler for BlobsV1Request { async fn handle(&self, context: RpcApiContext) -> Result { info!("Received new engine request: Requested Blobs"); + if self.blob_versioned_hashes.len() >= GET_BLOBS_V1_REQUEST_MAX_SIZE { return Err(RpcErr::TooLargeRequest); } diff --git a/crates/networking/rpc/eth/client.rs b/crates/networking/rpc/eth/client.rs index ba520da4fd..4472ceb856 100644 --- a/crates/networking/rpc/eth/client.rs +++ b/crates/networking/rpc/eth/client.rs @@ -1,4 +1,12 @@ +use std::collections::BTreeMap; + +use ethrex_common::H32; +use ethrex_common::H160; use ethrex_common::serde_utils; +use ethrex_common::types::Fork; +use ethrex_common::types::ForkBlobSchedule; +use ethrex_common::types::ForkId; +use ethrex_vm::{precompiles_for_fork, system_contracts::system_contracts_for_fork}; use serde::{Deserialize, Serialize}; use serde_json::Value; use tracing::debug; @@ -62,3 +70,110 @@ impl RpcHandler for Syncing { } } } + +pub struct Config; + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct EthConfigObject { + activation_time: Option, + blob_schedule: Option, + #[serde(with = "serde_utils::u64::hex_str")] + chain_id: u64, + fork_id: H32, + precompiles: BTreeMap, + system_contracts: BTreeMap, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +struct EthConfigResponse { + current: EthConfigObject, + next: Option, + last: Option, +} + +impl RpcHandler for Config { + fn parse(_params: &Option>) -> Result { + Ok(Self {}) + } + + async fn handle(&self, context: RpcApiContext) -> Result { + let chain_config = context.storage.get_chain_config()?; + let Some(latest_block) = context + .storage + .get_block_by_number(context.storage.get_latest_block_number().await?) + .await? + else { + return Err(RpcErr::Internal("Failed to fetch latest block".to_string())); + }; + + let latest_block_timestamp = latest_block.header.timestamp; + let current_fork = chain_config.get_fork(latest_block_timestamp); + + if current_fork < Fork::Paris { + return Err(RpcErr::UnsuportedFork( + "eth-config is not supported for forks prior to Paris".to_string(), + )); + } + + let current = get_config_for_fork(current_fork, &context).await?; + let next = if let Some(next_fork) = chain_config.next_fork(latest_block_timestamp) { + Some(get_config_for_fork(next_fork, &context).await?) + } else { + None + }; + let last_fork = chain_config.get_last_scheduled_fork(); + let last = if last_fork > current_fork { + Some(get_config_for_fork(last_fork, &context).await?) + } else { + None + }; + let response = EthConfigResponse { + current, + next, + last, + }; + + serde_json::to_value(response).map_err(|error| RpcErr::Internal(error.to_string())) + } +} + +async fn get_config_for_fork( + fork: Fork, + context: &RpcApiContext, +) -> Result { + let chain_config = context.storage.get_chain_config()?; + let activation_time = chain_config.get_activation_timestamp_for_fork(fork); + let genesis_header = context + .storage + .get_block_by_number(0) + .await? + .expect("Failed to get genesis block. This should not happen.") + .header; + let block_number = context.storage.get_latest_block_number().await?; + let fork_id = if let Some(timestamp) = activation_time { + ForkId::new(chain_config, genesis_header, timestamp, block_number).fork_hash + } else { + H32::zero() + }; + let mut system_contracts = BTreeMap::new(); + for contract in system_contracts_for_fork(fork) { + system_contracts.insert(contract.name.to_string(), contract.address); + } + + let mut precompiles = BTreeMap::new(); + + for precompile in precompiles_for_fork(fork) { + precompiles.insert(precompile.name.to_string(), precompile.address); + } + + Ok(EthConfigObject { + activation_time, + blob_schedule: chain_config.get_blob_schedule_for_fork(fork), + chain_id: chain_config.chain_id, + fork_id, + precompiles, + system_contracts, + }) +} diff --git a/crates/networking/rpc/rpc.rs b/crates/networking/rpc/rpc.rs index c058b84c4a..01f4d8d603 100644 --- a/crates/networking/rpc/rpc.rs +++ b/crates/networking/rpc/rpc.rs @@ -11,6 +11,7 @@ use crate::engine::{ NewPayloadV2Request, NewPayloadV3Request, NewPayloadV4Request, }, }; +use crate::eth::client::Config; use crate::eth::{ account::{ GetBalanceRequest, GetCodeRequest, GetProofRequest, GetStorageAtRequest, @@ -424,6 +425,7 @@ pub async fn map_eth_requests(req: &RpcRequest, context: RpcApiContext) -> Resul "eth_maxPriorityFeePerGas" => { eth::max_priority_fee::MaxPriorityFee::call(req, context).await } + "eth_config" => Config::call(req, context).await, unknown_eth_method => Err(RpcErr::MethodNotFound(unknown_eth_method.to_owned())), } } @@ -536,9 +538,9 @@ mod tests { }; use ethrex_storage::{EngineType, Store}; use sha3::{Digest, Keccak256}; - use std::fs::File; use std::io::BufReader; use std::str::FromStr; + use std::{fs::File, path::Path}; // Maps string rpc response to RpcSuccessResponse as serde Value // This is used to avoid failures due to field order and allow easier string comparisons for responses @@ -563,11 +565,11 @@ mod tests { let result = map_http_requests(&request, context).await; let rpc_response = rpc_response(request.id, result).unwrap(); let blob_schedule = serde_json::json!({ - "cancun": { "target": 3, "max": 6, "baseFeeUpdateFraction": 3338477 }, - "prague": { "target": 6, "max": 9, "baseFeeUpdateFraction": 5007716 }, - "osaka": { "target": 6, "max": 9, "baseFeeUpdateFraction": 5007716 }, - "bpo1": { "target": 10, "max": 15, "baseFeeUpdateFraction": 8346193 }, - "bpo2": { "target": 14, "max": 21, "baseFeeUpdateFraction": 11684671 }, + "cancun": { "baseFeeUpdateFraction": 3338477, "max": 6, "target": 3, }, + "prague": { "baseFeeUpdateFraction": 5007716, "max": 9, "target": 6, }, + "osaka": { "baseFeeUpdateFraction": 5007716, "max": 9, "target": 6, }, + "bpo1": { "baseFeeUpdateFraction": 8346193, "max": 15, "target": 10, }, + "bpo2": { "baseFeeUpdateFraction": 11684671, "max": 21, "target": 14, }, }); let json = serde_json::json!({ "jsonrpc": "2.0", @@ -706,4 +708,126 @@ mod tests { let expected_response = to_rpc_response_success_value(&expected_response_string); assert_eq!(response.to_string(), expected_response.to_string()); } + + #[tokio::test] + async fn eth_config_request_cancun_with_prague_scheduled() { + let body = r#"{"jsonrpc":"2.0", "method":"eth_config", "params":[], "id":1}"#; + let request: RpcRequest = serde_json::from_str(body).unwrap(); + let storage = Store::new_from_genesis( + Path::new("temp.db"), + EngineType::InMemory, + "../../../cmd/ethrex/networks/hoodi/genesis.json", + ) + .await + .expect("Failed to create test DB"); + let context = default_context_with_storage(storage).await; + let result = map_http_requests(&request, context).await; + let rpc_response = rpc_response(request.id, result).unwrap(); + let json = serde_json::json!({ + "id": 1, + "jsonrpc": "2.0", + "result": { + "current": { + "activationTime": 0, + "blobSchedule": { + "baseFeeUpdateFraction": 3338477, + "max": 6, + "target": 3 + }, + "chainId": "0x88bb0", + "forkId": "0xbef71d30", + "precompiles": { + "BLAKE2F": "0x0000000000000000000000000000000000000009", + "BN254_ADD": "0x0000000000000000000000000000000000000006", + "BN254_MUL": "0x0000000000000000000000000000000000000007", + "BN254_PAIRING": "0x0000000000000000000000000000000000000008", + "ECREC": "0x0000000000000000000000000000000000000001", + "ID": "0x0000000000000000000000000000000000000004", + "KZG_POINT_EVALUATION": "0x000000000000000000000000000000000000000a", + "MODEXP": "0x0000000000000000000000000000000000000005", + "RIPEMD160": "0x0000000000000000000000000000000000000003", + "SHA256": "0x0000000000000000000000000000000000000002" + }, + "systemContracts": { + "BEACON_ROOTS_ADDRESS": "0x000f3df6d732807ef1319fb7b8bb8522d0beac02" + } + }, + "next": { + "activationTime": 1742999832, + "blobSchedule": { + "baseFeeUpdateFraction": 5007716, + "max": 9, + "target": 6 + }, + "chainId": "0x88bb0", + "forkId": "0x0929e24e", + "precompiles": { + "BLAKE2F": "0x0000000000000000000000000000000000000009", + "BLS12_G1ADD": "0x000000000000000000000000000000000000000b", + "BLS12_G1MSM": "0x000000000000000000000000000000000000000c", + "BLS12_G2ADD": "0x000000000000000000000000000000000000000d", + "BLS12_G2MSM": "0x000000000000000000000000000000000000000e", + "BLS12_MAP_FP2_TO_G2": "0x0000000000000000000000000000000000000011", + "BLS12_MAP_FP_TO_G1": "0x0000000000000000000000000000000000000010", + "BLS12_PAIRING_CHECK": "0x000000000000000000000000000000000000000f", + "BN254_ADD": "0x0000000000000000000000000000000000000006", + "BN254_MUL": "0x0000000000000000000000000000000000000007", + "BN254_PAIRING": "0x0000000000000000000000000000000000000008", + "ECREC": "0x0000000000000000000000000000000000000001", + "ID": "0x0000000000000000000000000000000000000004", + "KZG_POINT_EVALUATION": "0x000000000000000000000000000000000000000a", + "MODEXP": "0x0000000000000000000000000000000000000005", + "RIPEMD160": "0x0000000000000000000000000000000000000003", + "SHA256": "0x0000000000000000000000000000000000000002" + }, + "systemContracts": { + "BEACON_ROOTS_ADDRESS": "0x000f3df6d732807ef1319fb7b8bb8522d0beac02", + "CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS": "0x0000bbddc7ce488642fb579f8b00f3a590007251", + "DEPOSIT_CONTRACT_ADDRESS": "0x00000000219ab540356cbb839cbe05303d7705fa", + "HISTORY_STORAGE_ADDRESS": "0x0000f90827f1c53a10cb7a02335b175320002935", + "WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS": "0x00000961ef480eb55e80d19ad83579a64c007002" + } + }, + "last": { + "activationTime": 1762955544, + "blobSchedule": { + "baseFeeUpdateFraction": 11684671, + "max": 21, + "target": 14, + }, + "chainId": "0x88bb0", + "forkId": "0x23aa1351", + "precompiles": { + "BLAKE2F": "0x0000000000000000000000000000000000000009", + "BLS12_G1ADD": "0x000000000000000000000000000000000000000b", + "BLS12_G1MSM": "0x000000000000000000000000000000000000000c", + "BLS12_G2ADD": "0x000000000000000000000000000000000000000d", + "BLS12_G2MSM": "0x000000000000000000000000000000000000000e", + "BLS12_MAP_FP2_TO_G2": "0x0000000000000000000000000000000000000011", + "BLS12_MAP_FP_TO_G1": "0x0000000000000000000000000000000000000010", + "BLS12_PAIRING_CHECK": "0x000000000000000000000000000000000000000f", + "BN254_ADD": "0x0000000000000000000000000000000000000006", + "BN254_MUL": "0x0000000000000000000000000000000000000007", + "BN254_PAIRING": "0x0000000000000000000000000000000000000008", + "ECREC": "0x0000000000000000000000000000000000000001", + "ID": "0x0000000000000000000000000000000000000004", + "KZG_POINT_EVALUATION": "0x000000000000000000000000000000000000000a", + "MODEXP": "0x0000000000000000000000000000000000000005", + "P256_VERIFICATION":"0x0000000000000000000000000000000000000100", + "RIPEMD160": "0x0000000000000000000000000000000000000003", + "SHA256": "0x0000000000000000000000000000000000000002" + }, + "systemContracts": { + "BEACON_ROOTS_ADDRESS": "0x000f3df6d732807ef1319fb7b8bb8522d0beac02", + "CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS": "0x0000bbddc7ce488642fb579f8b00f3a590007251", + "DEPOSIT_CONTRACT_ADDRESS": "0x00000000219ab540356cbb839cbe05303d7705fa", + "HISTORY_STORAGE_ADDRESS": "0x0000f90827f1c53a10cb7a02335b175320002935", + "WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS": "0x00000961ef480eb55e80d19ad83579a64c007002" + } + }, + } + }); + let expected_response = to_rpc_response_success_value(&json.to_string()); + assert_eq!(rpc_response.to_string(), expected_response.to_string()) + } } diff --git a/crates/vm/backends/levm/mod.rs b/crates/vm/backends/levm/mod.rs index 3c92fe62ca..158878d7f0 100644 --- a/crates/vm/backends/levm/mod.rs +++ b/crates/vm/backends/levm/mod.rs @@ -2,7 +2,7 @@ pub mod db; mod tracing; use super::BlockExecutionResult; -use crate::constants::{ +use crate::system_contracts::{ BEACON_ROOTS_ADDRESS, CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS, HISTORY_STORAGE_ADDRESS, SYSTEM_ADDRESS, WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS, }; @@ -207,8 +207,8 @@ impl LEVM { block_header, Bytes::copy_from_slice(beacon_root.as_bytes()), db, - *BEACON_ROOTS_ADDRESS, - *SYSTEM_ADDRESS, + BEACON_ROOTS_ADDRESS.address, + SYSTEM_ADDRESS, vm_type, )?; Ok(()) @@ -229,8 +229,8 @@ impl LEVM { block_header, Bytes::copy_from_slice(block_header.parent_hash.as_bytes()), db, - *HISTORY_STORAGE_ADDRESS, - *SYSTEM_ADDRESS, + HISTORY_STORAGE_ADDRESS.address, + SYSTEM_ADDRESS, vm_type, )?; Ok(()) @@ -250,8 +250,8 @@ impl LEVM { block_header, Bytes::new(), db, - *WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS, - *SYSTEM_ADDRESS, + WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS.address, + SYSTEM_ADDRESS, vm_type, )?; @@ -279,8 +279,8 @@ impl LEVM { block_header, Bytes::new(), db, - *CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS, - *SYSTEM_ADDRESS, + CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS.address, + SYSTEM_ADDRESS, vm_type, )?; diff --git a/crates/vm/constants.rs b/crates/vm/constants.rs deleted file mode 100644 index 24c9b683da..0000000000 --- a/crates/vm/constants.rs +++ /dev/null @@ -1,23 +0,0 @@ -use ethrex_common::Address; -use std::{str::FromStr, sync::LazyLock}; - -pub static SYSTEM_ADDRESS: LazyLock
= LazyLock::new(|| { - Address::from_str("fffffffffffffffffffffffffffffffffffffffe") - .expect("Failed to get address from string") -}); -pub static BEACON_ROOTS_ADDRESS: LazyLock
= LazyLock::new(|| { - Address::from_str("000F3df6D732807Ef1319fB7B8bB8522d0Beac02") - .expect("Failed to get address from string") -}); -pub static HISTORY_STORAGE_ADDRESS: LazyLock
= LazyLock::new(|| { - Address::from_str("0000F90827F1C53a10cb7A02335B175320002935") - .expect("Failed to get address from string") -}); -pub static WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS: LazyLock
= LazyLock::new(|| { - Address::from_str("00000961Ef480Eb55e80D19ad83579A64c007002") - .expect("Failed to get address from string") -}); -pub static CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS: LazyLock
= LazyLock::new(|| { - Address::from_str("0000BBdDc7CE488642fb579F8B00f3a590007251") - .expect("Failed to get address from string") -}); diff --git a/crates/vm/levm/src/precompiles.rs b/crates/vm/levm/src/precompiles.rs index 9b30410885..d9806545be 100644 --- a/crates/vm/levm/src/precompiles.rs +++ b/crates/vm/levm/src/precompiles.rs @@ -6,9 +6,10 @@ use bls12_381::{ hash_to_curve::MapToCurve, multi_miller_loop, }; use bytes::{Buf, Bytes}; +use ethrex_common::H160; use ethrex_common::utils::{keccak, u256_from_big_endian_const}; use ethrex_common::{ - Address, H160, H256, U256, kzg::verify_kzg_proof, serde_utils::bool, types::Fork, + Address, H256, U256, kzg::verify_kzg_proof, serde_utils::bool, types::Fork, types::Fork::*, utils::u256_from_big_endian, }; use ethrex_crypto::blake2f::blake2b_f; @@ -72,102 +73,6 @@ use lambdaworks_math::elliptic_curve::short_weierstrass::curves::bls12_381::fiel use lambdaworks_math::elliptic_curve::short_weierstrass::traits::IsShortWeierstrass; use lambdaworks_math::field::fields::montgomery_backed_prime_fields::IsModulus; -pub const ECRECOVER_ADDRESS: H160 = H160([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, -]); -pub const SHA2_256_ADDRESS: H160 = H160([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x02, -]); -pub const RIPEMD_160_ADDRESS: H160 = H160([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, -]); -pub const IDENTITY_ADDRESS: H160 = H160([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x04, -]); -pub const MODEXP_ADDRESS: H160 = H160([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x05, -]); -pub const ECADD_ADDRESS: H160 = H160([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, -]); -pub const ECMUL_ADDRESS: H160 = H160([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x07, -]); -pub const ECPAIRING_ADDRESS: H160 = H160([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x08, -]); -pub const BLAKE2F_ADDRESS: H160 = H160([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x09, -]); -pub const POINT_EVALUATION_ADDRESS: H160 = H160([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0a, -]); -pub const BLS12_G1ADD_ADDRESS: H160 = H160([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0b, -]); -pub const BLS12_G1MSM_ADDRESS: H160 = H160([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0c, -]); -pub const BLS12_G2ADD_ADDRESS: H160 = H160([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0d, -]); -pub const BLS12_G2MSM_ADDRESS: H160 = H160([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0e, -]); -pub const BLS12_PAIRING_CHECK_ADDRESS: H160 = H160([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0f, -]); -pub const BLS12_MAP_FP_TO_G1_ADDRESS: H160 = H160([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x10, -]); -pub const BLS12_MAP_FP2_TO_G2_ADDRESS: H160 = H160([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x11, -]); -pub const P256_VERIFICATION_ADDRESS: H160 = H160([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x00, -]); - -pub const PRECOMPILES: [H160; 10] = [ - ECRECOVER_ADDRESS, - SHA2_256_ADDRESS, - RIPEMD_160_ADDRESS, - IDENTITY_ADDRESS, - MODEXP_ADDRESS, - ECADD_ADDRESS, - ECMUL_ADDRESS, - ECPAIRING_ADDRESS, - BLAKE2F_ADDRESS, - POINT_EVALUATION_ADDRESS, -]; - -pub const PRECOMPILES_POST_CANCUN: [H160; 7] = [ - BLS12_G1ADD_ADDRESS, - BLS12_G1MSM_ADDRESS, - BLS12_G2ADD_ADDRESS, - BLS12_G2MSM_ADDRESS, - BLS12_PAIRING_CHECK_ADDRESS, - BLS12_MAP_FP_TO_G1_ADDRESS, - BLS12_MAP_FP2_TO_G2_ADDRESS, -]; - pub const BLAKE2F_ELEMENT_SIZE: usize = 8; pub const SIZE_PRECOMPILES_PRE_CANCUN: u64 = 9; @@ -201,26 +106,205 @@ 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(address: &Address, fork: Fork, vm_type: VMType) -> bool { - // Cancun specs is the only one that allows point evaluation precompile - if *address == POINT_EVALUATION_ADDRESS && fork < Fork::Cancun { - return false; - } - // Prague or newers forks should only use these precompiles - // https://eips.ethereum.org/EIPS/eip-2537 - if PRECOMPILES_POST_CANCUN.contains(address) && fork < Fork::Prague { - return false; - } +pub struct Precompile { + pub address: H160, + pub name: &'static str, + pub active_since_fork: Fork, +} - // P256 verify Precompile only existed on L2 before Osaka - if fork < Fork::Osaka && matches!(vm_type, VMType::L1) && address == &P256_VERIFICATION_ADDRESS - { - return false; - } +pub const ECRECOVER: Precompile = Precompile { + address: H160([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, + ]), + name: "ECREC", + active_since_fork: Paris, +}; + +pub const SHA2_256: Precompile = Precompile { + address: H160([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, + ]), + name: "SHA256", + active_since_fork: Paris, +}; + +pub const RIPEMD_160: Precompile = Precompile { + address: H160([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, + ]), + name: "RIPEMD160", + active_since_fork: Paris, +}; + +pub const IDENTITY: Precompile = Precompile { + address: H160([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, + ]), + name: "ID", + active_since_fork: Paris, +}; + +pub const MODEXP: Precompile = Precompile { + address: H160([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x05, + ]), + name: "MODEXP", + active_since_fork: Paris, +}; + +pub const ECADD: Precompile = Precompile { + address: H160([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x06, + ]), + name: "BN254_ADD", + active_since_fork: Paris, +}; + +pub const ECMUL: Precompile = Precompile { + address: H160([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, + ]), + name: "BN254_MUL", + active_since_fork: Paris, +}; + +pub const ECPAIRING: Precompile = Precompile { + address: H160([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, + ]), + name: "BN254_PAIRING", + active_since_fork: Paris, +}; + +pub const BLAKE2F: Precompile = Precompile { + address: H160([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, + ]), + name: "BLAKE2F", + active_since_fork: Paris, +}; + +pub const POINT_EVALUATION: Precompile = Precompile { + address: H160([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0a, + ]), + name: "KZG_POINT_EVALUATION", + active_since_fork: Cancun, +}; + +pub const BLS12_G1ADD: Precompile = Precompile { + address: H160([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0b, + ]), + name: "BLS12_G1ADD", + active_since_fork: Prague, +}; + +pub const BLS12_G1MSM: Precompile = Precompile { + address: H160([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, + ]), + name: "BLS12_G1MSM", + active_since_fork: Prague, +}; + +pub const BLS12_G2ADD: Precompile = Precompile { + address: H160([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, + ]), + name: "BLS12_G2ADD", + active_since_fork: Prague, +}; + +pub const BLS12_G2MSM: Precompile = Precompile { + address: H160([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0e, + ]), + name: "BLS12_G2MSM", + active_since_fork: Prague, +}; + +pub const BLS12_PAIRING_CHECK: Precompile = Precompile { + address: H160([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0f, + ]), + name: "BLS12_PAIRING_CHECK", + active_since_fork: Prague, +}; - PRECOMPILES.contains(address) - || PRECOMPILES_POST_CANCUN.contains(address) - || address == &P256_VERIFICATION_ADDRESS +pub const BLS12_MAP_FP_TO_G1: Precompile = Precompile { + address: H160([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, + ]), + name: "BLS12_MAP_FP_TO_G1", + active_since_fork: Prague, +}; + +pub const BLS12_MAP_FP2_TO_G2: Precompile = Precompile { + address: H160([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x11, + ]), + name: "BLS12_MAP_FP2_TO_G2", + active_since_fork: Prague, +}; + +pub const P256_VERIFICATION: Precompile = Precompile { + address: H160([ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, + ]), + name: "P256_VERIFICATION", + active_since_fork: Osaka, +}; + +pub const PRECOMPILES: [Precompile; 19] = [ + ECRECOVER, + SHA2_256, + RIPEMD_160, + IDENTITY, + MODEXP, + ECADD, + ECMUL, + ECPAIRING, + BLAKE2F, + POINT_EVALUATION, + BLS12_G1ADD, + BLS12_G1MSM, + BLS12_G2ADD, + BLS12_G2MSM, + BLS12_MAP_FP_TO_G1, + BLS12_MAP_FP2_TO_G2, + BLS12_MAP_FP_TO_G1, + BLS12_PAIRING_CHECK, + P256_VERIFICATION, +]; + +pub fn precompiles_for_fork(fork: Fork) -> impl Iterator { + PRECOMPILES + .into_iter() + .filter(move |precompile| precompile.active_since_fork <= fork) +} + +pub fn is_precompile(address: &Address, fork: Fork, vm_type: VMType) -> bool { + (matches!(vm_type, VMType::L2) && *address == P256_VERIFICATION.address) + || precompiles_for_fork(fork).any(|precompile| precompile.address == *address) } #[expect(clippy::as_conversions, clippy::indexing_slicing)] @@ -234,30 +318,30 @@ pub fn execute_precompile( const PRECOMPILES: [Option; 512] = const { let mut precompiles = [const { None }; 512]; - precompiles[ECRECOVER_ADDRESS.0[19] as usize] = Some(ecrecover as PrecompileFn); - precompiles[IDENTITY_ADDRESS.0[19] as usize] = Some(identity as PrecompileFn); - precompiles[SHA2_256_ADDRESS.0[19] as usize] = Some(sha2_256 as PrecompileFn); - precompiles[RIPEMD_160_ADDRESS.0[19] as usize] = Some(ripemd_160 as PrecompileFn); - precompiles[MODEXP_ADDRESS.0[19] as usize] = Some(modexp as PrecompileFn); - precompiles[ECADD_ADDRESS.0[19] as usize] = Some(ecadd as PrecompileFn); - precompiles[ECMUL_ADDRESS.0[19] as usize] = Some(ecmul as PrecompileFn); - precompiles[ECPAIRING_ADDRESS.0[19] as usize] = Some(ecpairing as PrecompileFn); - precompiles[BLAKE2F_ADDRESS.0[19] as usize] = Some(blake2f as PrecompileFn); - precompiles[POINT_EVALUATION_ADDRESS.0[19] as usize] = + precompiles[ECRECOVER.address.0[19] as usize] = Some(ecrecover as PrecompileFn); + precompiles[IDENTITY.address.0[19] as usize] = Some(identity as PrecompileFn); + precompiles[SHA2_256.address.0[19] as usize] = Some(sha2_256 as PrecompileFn); + precompiles[RIPEMD_160.address.0[19] as usize] = Some(ripemd_160 as PrecompileFn); + precompiles[MODEXP.address.0[19] as usize] = Some(modexp as PrecompileFn); + precompiles[ECADD.address.0[19] as usize] = Some(ecadd as PrecompileFn); + precompiles[ECMUL.address.0[19] as usize] = Some(ecmul as PrecompileFn); + precompiles[ECPAIRING.address.0[19] as usize] = Some(ecpairing as PrecompileFn); + precompiles[BLAKE2F.address.0[19] as usize] = Some(blake2f as PrecompileFn); + precompiles[POINT_EVALUATION.address.0[19] as usize] = Some(point_evaluation as PrecompileFn); - precompiles[BLS12_G1ADD_ADDRESS.0[19] as usize] = Some(bls12_g1add as PrecompileFn); - precompiles[BLS12_G1MSM_ADDRESS.0[19] as usize] = Some(bls12_g1msm as PrecompileFn); - precompiles[BLS12_G2ADD_ADDRESS.0[19] as usize] = Some(bls12_g2add as PrecompileFn); - precompiles[BLS12_G2MSM_ADDRESS.0[19] as usize] = Some(bls12_g2msm as PrecompileFn); - precompiles[BLS12_PAIRING_CHECK_ADDRESS.0[19] as usize] = + precompiles[BLS12_G1ADD.address.0[19] as usize] = Some(bls12_g1add as PrecompileFn); + precompiles[BLS12_G1MSM.address.0[19] as usize] = Some(bls12_g1msm as PrecompileFn); + precompiles[BLS12_G2ADD.address.0[19] as usize] = Some(bls12_g2add as PrecompileFn); + precompiles[BLS12_G2MSM.address.0[19] as usize] = Some(bls12_g2msm as PrecompileFn); + precompiles[BLS12_PAIRING_CHECK.address.0[19] as usize] = Some(bls12_pairing_check as PrecompileFn); - precompiles[BLS12_MAP_FP_TO_G1_ADDRESS.0[19] as usize] = + precompiles[BLS12_MAP_FP_TO_G1.address.0[19] as usize] = Some(bls12_map_fp_to_g1 as PrecompileFn); - precompiles[BLS12_MAP_FP2_TO_G2_ADDRESS.0[19] as usize] = + precompiles[BLS12_MAP_FP2_TO_G2.address.0[19] as usize] = Some(bls12_map_fp2_tp_g2 as PrecompileFn); precompiles[u16::from_be_bytes([ - P256_VERIFICATION_ADDRESS.0[18], - P256_VERIFICATION_ADDRESS.0[19], + P256_VERIFICATION.address.0[18], + P256_VERIFICATION.address.0[19], ]) as usize] = Some(p_256_verify as PrecompileFn); precompiles }; diff --git a/crates/vm/lib.rs b/crates/vm/lib.rs index dd4e05aa5d..9cd0b61a42 100644 --- a/crates/vm/lib.rs +++ b/crates/vm/lib.rs @@ -1,4 +1,3 @@ -mod constants; mod db; mod errors; mod execution_result; @@ -10,5 +9,7 @@ pub mod backends; pub use backends::{BlockExecutionResult, Evm}; pub use db::{DynVmDatabase, VmDatabase}; pub use errors::EvmError; +pub use ethrex_levm::precompiles::precompiles_for_fork; pub use execution_result::ExecutionResult; pub use witness_db::GuestProgramStateWrapper; +pub mod system_contracts; diff --git a/crates/vm/system_contracts.rs b/crates/vm/system_contracts.rs new file mode 100644 index 0000000000..d7be861a31 --- /dev/null +++ b/crates/vm/system_contracts.rs @@ -0,0 +1,71 @@ +use ethrex_common::{H160, types::Fork, types::Fork::*}; + +pub struct SystemContract { + pub address: H160, + pub name: &'static str, + pub active_since_fork: Fork, +} + +pub const SYSTEM_ADDRESS: H160 = H160([ + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFE, +]); + +pub const DEPOSIT_CONTRACT_ADDRESS: SystemContract = SystemContract { + address: H160([ + 0x00, 0x00, 0x00, 0x00, 0x21, 0x9A, 0xB5, 0x40, 0x35, 0x6C, 0xBB, 0x83, 0x9C, 0xBE, 0x05, + 0x30, 0x3D, 0x77, 0x05, 0xFA, + ]), + name: "DEPOSIT_CONTRACT_ADDRESS", + active_since_fork: Prague, +}; + +pub const BEACON_ROOTS_ADDRESS: SystemContract = SystemContract { + address: H160([ + 0x00, 0x0F, 0x3D, 0xF6, 0xD7, 0x32, 0x80, 0x7E, 0xF1, 0x31, 0x9F, 0xB7, 0xB8, 0xBB, 0x85, + 0x22, 0xD0, 0xBE, 0xAC, 0x02, + ]), + name: "BEACON_ROOTS_ADDRESS", + active_since_fork: Paris, +}; + +pub const HISTORY_STORAGE_ADDRESS: SystemContract = SystemContract { + address: H160([ + 0x00, 0x00, 0xF9, 0x08, 0x27, 0xF1, 0xC5, 0x3A, 0x10, 0xCB, 0x7A, 0x02, 0x33, 0x5B, 0x17, + 0x53, 0x20, 0x00, 0x29, 0x35, + ]), + name: "HISTORY_STORAGE_ADDRESS", + active_since_fork: Prague, +}; + +pub const WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS: SystemContract = SystemContract { + address: H160([ + 0x00, 0x00, 0x09, 0x61, 0xEF, 0x48, 0x0E, 0xB5, 0x5E, 0x80, 0xD1, 0x9A, 0xD8, 0x35, 0x79, + 0xA6, 0x4C, 0x00, 0x70, 0x02, + ]), + name: "WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS", + active_since_fork: Prague, +}; + +pub const CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS: SystemContract = SystemContract { + address: H160([ + 0x00, 0x00, 0xBB, 0xDD, 0xC7, 0xCE, 0x48, 0x86, 0x42, 0xFB, 0x57, 0x9F, 0x8B, 0x00, 0xF3, + 0xA5, 0x90, 0x00, 0x72, 0x51, + ]), + name: "CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS", + active_since_fork: Prague, +}; + +pub const SYSTEM_CONTRACTS: [SystemContract; 5] = [ + BEACON_ROOTS_ADDRESS, + HISTORY_STORAGE_ADDRESS, + DEPOSIT_CONTRACT_ADDRESS, + WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS, + CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS, +]; + +pub fn system_contracts_for_fork(fork: Fork) -> impl Iterator { + SYSTEM_CONTRACTS + .into_iter() + .filter(move |system_contract| system_contract.active_since_fork <= fork) +}