From 8e5ca3a3d402ee2910668a2561406928133edf12 Mon Sep 17 00:00:00 2001 From: Julian Ventura Date: Mon, 3 Feb 2025 15:44:00 -0300 Subject: [PATCH 1/6] Implement eip-2935 --- crates/vm/vm.rs | 146 +++++++++++++++++++++++++-- test_data/genesis-execution-api.json | 4 + test_data/genesis-hive.json | 4 + test_data/genesis-kurtosis.json | 4 + test_data/genesis-l1.json | 4 + 5 files changed, 153 insertions(+), 9 deletions(-) diff --git a/crates/vm/vm.rs b/crates/vm/vm.rs index 440566406f..3dae663bf7 100644 --- a/crates/vm/vm.rs +++ b/crates/vm/vm.rs @@ -42,6 +42,10 @@ type AccessList = Vec<(Address, Vec)>; pub const WITHDRAWAL_MAGIC_DATA: &[u8] = b"burn"; pub const DEPOSIT_MAGIC_DATA: &[u8] = b"mint"; +pub const SYSTEM_ADDRESS_STR: &str = "fffffffffffffffffffffffffffffffffffffffe"; +pub const BEACON_ROOTS_ADDRESS_STR: &str = "000F3df6D732807Ef1319fB7B8bB8522d0Beac02"; +pub const HISTORY_STORAGE_ADDRESS_STR: &str = "0F792be4B0c0cb4DAE440Ef133E90C0eCD48CCCC"; + /// State used when running the EVM. The state can be represented with a [StoreWrapper] database, or /// with a [ExecutionDB] in case we only want to store the necessary data for some particular /// execution, for example when proving in L2 mode. @@ -98,9 +102,9 @@ cfg_if::cfg_if! { ) -> Result { lazy_static! { static ref SYSTEM_ADDRESS: Address = - Address::from_slice(&hex::decode("fffffffffffffffffffffffffffffffffffffffe").unwrap()); + Address::from_slice(&hex::decode(SYSTEM_ADDRESS_STR).unwrap()); static ref CONTRACT_ADDRESS: Address = - Address::from_slice(&hex::decode("000F3df6D732807Ef1319fB7B8bB8522d0Beac02").unwrap(),); + Address::from_slice(&hex::decode(BEACON_ROOTS_ADDRESS_STR).unwrap(),); }; // This is OK let beacon_root = match block_header.parent_beacon_block_root { @@ -153,6 +157,62 @@ cfg_if::cfg_if! { } + /// Calls the EIP-2935 process block hashes history system call contract + /// NOTE: This was implemented by making use of an EVM system contract, but can be changed to a + /// direct state trie update after the verkle fork, as explained in https://eips.ethereum.org/EIPS/eip-2935 + pub fn process_block_hash_history_levm( + store_wrapper: Arc, + block_header: &BlockHeader, + fork: Fork, + ) -> Result { + lazy_static! { + static ref SYSTEM_ADDRESS: Address = + Address::from_slice(&hex::decode(SYSTEM_ADDRESS_STR).unwrap()); + static ref CONTRACT_ADDRESS: Address = + Address::from_slice(&hex::decode(HISTORY_STORAGE_ADDRESS_STR).unwrap(),); + }; + + let env = Environment { + origin: *SYSTEM_ADDRESS, + gas_limit: 30_000_000, + block_number: block_header.number.into(), + coinbase: block_header.coinbase, + timestamp: block_header.timestamp.into(), + prev_randao: Some(block_header.prev_randao), + base_fee_per_gas: U256::zero(), + gas_price: U256::zero(), + block_excess_blob_gas: block_header.excess_blob_gas.map(U256::from), + block_blob_gas_used: block_header.blob_gas_used.map(U256::from), + block_gas_limit: 30_000_000, + transient_storage: HashMap::new(), + fork, + ..Default::default() + }; + + let calldata = Bytes::copy_from_slice(block_header.parent_hash.as_bytes()).into(); + + // Here execute with LEVM but just return transaction report. And I will handle it in the calling place. + + let mut vm = VM::new( + TxKind::Call(*CONTRACT_ADDRESS), + env, + U256::zero(), + calldata, + store_wrapper, + CacheDB::new(), + vec![], + None + ) + .map_err(EvmError::from)?; + + let mut report = vm.execute().map_err(EvmError::from)?; + + report.new_state.remove(&*SYSTEM_ADDRESS); + + Ok(report) + + } + pub fn get_state_transitions_levm( initial_state: &EvmState, block_hash: H256, @@ -248,7 +308,14 @@ cfg_if::cfg_if! { cfg_if::cfg_if! { if #[cfg(not(feature = "l2"))] { if block_header.parent_beacon_block_root.is_some() && fork >= Fork::Cancun { - let report = beacon_root_contract_call_levm(store_wrapper.clone(), block_header, config)?; + //eip 4788: execute beacon_root_contract_call before block transactions + let report = beacon_root_contract_call_levm(store_wrapper.clone(), block_header, fork)?; + block_cache.extend(report.new_state); + } + + if fork >= Fork::Prague { + //eip 2935: stores parent block hash in system contract + let report = process_block_hash_history_levm(store_wrapper.clone(), block_header, fork)?; block_cache.extend(report.new_state); } } @@ -371,6 +438,11 @@ cfg_if::cfg_if! { if block_header.parent_beacon_block_root.is_some() && spec_id >= SpecId::CANCUN { beacon_root_contract_call(state, block_header, spec_id)?; } + + //eip 2935: stores parent block hash in system contract + if spec_id >= SpecId::CANCUN { + process_block_hash_history(state, block_header, spec_id)?; + } } } let mut receipts = Vec::new(); @@ -778,12 +850,10 @@ pub fn beacon_root_contract_call( spec_id: SpecId, ) -> Result { lazy_static! { - static ref SYSTEM_ADDRESS: RevmAddress = RevmAddress::from_slice( - &hex::decode("fffffffffffffffffffffffffffffffffffffffe").unwrap() - ); - static ref CONTRACT_ADDRESS: RevmAddress = RevmAddress::from_slice( - &hex::decode("000F3df6D732807Ef1319fB7B8bB8522d0Beac02").unwrap(), - ); + static ref SYSTEM_ADDRESS: RevmAddress = + RevmAddress::from_slice(&hex::decode(SYSTEM_ADDRESS_STR).unwrap()); + static ref CONTRACT_ADDRESS: RevmAddress = + RevmAddress::from_slice(&hex::decode(BEACON_ROOTS_ADDRESS_STR).unwrap(),); }; let beacon_root = match header.parent_beacon_block_root { None => { @@ -838,6 +908,64 @@ pub fn beacon_root_contract_call( } } +/// Calls the EIP-2935 process block hashes history system call contract +/// NOTE: This was implemented by making use of an EVM system contract, but can be changed to a +/// direct state trie update after the verkle fork, as explained in https://eips.ethereum.org/EIPS/eip-2935 +pub fn process_block_hash_history( + state: &mut EvmState, + header: &BlockHeader, + spec_id: SpecId, +) -> Result { + lazy_static! { + static ref SYSTEM_ADDRESS: RevmAddress = + RevmAddress::from_slice(&hex::decode(SYSTEM_ADDRESS_STR).unwrap()); + static ref CONTRACT_ADDRESS: RevmAddress = + RevmAddress::from_slice(&hex::decode(HISTORY_STORAGE_ADDRESS_STR).unwrap(),); + }; + let tx_env = TxEnv { + caller: *SYSTEM_ADDRESS, + transact_to: RevmTxKind::Call(*CONTRACT_ADDRESS), + gas_limit: 30_000_000, + data: revm::primitives::Bytes::copy_from_slice(header.parent_hash.as_bytes()), + ..Default::default() + }; + let mut block_env = block_env(header); + block_env.basefee = RevmU256::ZERO; + block_env.gas_limit = RevmU256::from(30_000_000); + + match state { + EvmState::Store(db) => { + let mut evm = Evm::builder() + .with_db(db) + .with_block_env(block_env) + .with_tx_env(tx_env) + .with_spec_id(spec_id) + .build(); + + let transaction_result = evm.transact()?; + let mut result_state = transaction_result.state; + result_state.remove(&*SYSTEM_ADDRESS); + result_state.remove(&evm.block().coinbase); + + evm.context.evm.db.commit(result_state); + + Ok(transaction_result.result.into()) + } + EvmState::Execution(db) => { + let mut evm = Evm::builder() + .with_db(db) + .with_block_env(block_env) + .with_tx_env(tx_env) + .with_spec_id(spec_id) + .build(); + + // Not necessary to commit to DB + let transaction_result = evm.transact()?; + Ok(transaction_result.result.into()) + } + } +} + pub fn block_env(header: &BlockHeader) -> BlockEnv { BlockEnv { number: RevmU256::from(header.number), diff --git a/test_data/genesis-execution-api.json b/test_data/genesis-execution-api.json index 951e53525d..797a20fd6d 100644 --- a/test_data/genesis-execution-api.json +++ b/test_data/genesis-execution-api.json @@ -29,6 +29,10 @@ "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000", "coinbase": "0x0000000000000000000000000000000000000000", "alloc": { + "0F792be4B0c0cb4DAE440Ef133E90C0eCD48CCCC": { + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500", + "balance": "0x0" + }, "000f3df6d732807ef1319fb7b8bb8522d0beac02": { "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500", "balance": "0x2a" diff --git a/test_data/genesis-hive.json b/test_data/genesis-hive.json index 8340e0b755..ed313dd384 100644 --- a/test_data/genesis-hive.json +++ b/test_data/genesis-hive.json @@ -31,6 +31,10 @@ "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500", "nonce": "0x1" }, + "0F792be4B0c0cb4DAE440Ef133E90C0eCD48CCCC": { + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500", + "balance": "0" + }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b": { "balance": "0x5af3107a4000" } diff --git a/test_data/genesis-kurtosis.json b/test_data/genesis-kurtosis.json index ce30c61b0d..f2c73b7ac7 100644 --- a/test_data/genesis-kurtosis.json +++ b/test_data/genesis-kurtosis.json @@ -841,6 +841,10 @@ "nonce": "1", "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500" }, + "0F792be4B0c0cb4DAE440Ef133E90C0eCD48CCCC": { + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500", + "balance": "0" + }, "0x8943545177806ED17B9F23F0a21ee5948eCaa776": { "balance": "1000000000000000000000000000" }, diff --git a/test_data/genesis-l1.json b/test_data/genesis-l1.json index ff44978f17..93818d8512 100644 --- a/test_data/genesis-l1.json +++ b/test_data/genesis-l1.json @@ -19,6 +19,10 @@ "pragueTime": 1718232101 }, "alloc": { + "0F792be4B0c0cb4DAE440Ef133E90C0eCD48CCCC": { + "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500", + "balance": "0" + }, "0x4e59b44847b379578588920cA78FbF26c0B4956C": { "balance": "0", "code": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3" From bcc7829f3d38c1693f9bbd20b5c5d4a71f292f5b Mon Sep 17 00:00:00 2001 From: Julian Ventura Date: Wed, 5 Feb 2025 15:48:27 -0300 Subject: [PATCH 2/6] Fix implementation --- crates/blockchain/payload.rs | 64 ++++++++++++++++++---------- crates/vm/vm.rs | 30 ++++++------- test_data/genesis-execution-api.json | 3 +- test_data/genesis-hive.json | 4 -- test_data/genesis-kurtosis.json | 4 -- test_data/genesis-l1.json | 5 ++- 6 files changed, 61 insertions(+), 49 deletions(-) diff --git a/crates/blockchain/payload.rs b/crates/blockchain/payload.rs index d5508333d2..e77ce78707 100644 --- a/crates/blockchain/payload.rs +++ b/crates/blockchain/payload.rs @@ -8,26 +8,23 @@ use ethrex_core::{ types::{ calculate_base_fee_per_blob_gas, calculate_base_fee_per_gas, compute_receipts_root, compute_transactions_root, compute_withdrawals_root, BlobsBundle, Block, BlockBody, - BlockHash, BlockHeader, BlockNumber, ChainConfig, Fork, MempoolTransaction, Receipt, - Transaction, Withdrawal, DEFAULT_OMMERS_HASH, EMPTY_KECCACK_HASH, + BlockHash, BlockHeader, BlockNumber, ChainConfig, MempoolTransaction, Receipt, Transaction, + Withdrawal, DEFAULT_OMMERS_HASH, EMPTY_KECCACK_HASH, }, Address, Bloom, Bytes, H256, U256, }; #[cfg(not(feature = "levm"))] -use { - ethrex_core::types::Account, - ethrex_vm::{ - beacon_root_contract_call, execute_tx, get_state_transitions, process_withdrawals, spec_id, - SpecId, - }, +use ethrex_vm::{ + beacon_root_contract_call, execute_tx, get_state_transitions, process_block_hash_history, + process_withdrawals, spec_id, SpecId, }; #[cfg(feature = "levm")] use { - ethrex_core::types::GWEI_TO_WEI, + ethrex_core::types::{Fork, GWEI_TO_WEI}, ethrex_levm::{db::CacheDB, vm::EVMConfig, Account, AccountInfo}, ethrex_vm::{ beacon_root_contract_call_levm, db::StoreWrapper, execute_tx_levm, - get_state_transitions_levm, + get_state_transitions_levm, process_block_hash_history_levm, }, std::sync::Arc, }; @@ -251,16 +248,18 @@ pub fn build_payload( debug!("Building payload"); let mut evm_state = evm_state(store.clone(), payload.header.parent_hash); let mut context = PayloadBuildContext::new(payload, &mut evm_state)?; - apply_withdrawals(&mut context)?; + apply_system_operations(&mut context)?; fill_transactions(&mut context)?; finalize_payload(&mut context)?; Ok((context.blobs_bundle, context.block_value)) } -pub fn apply_withdrawals(context: &mut PayloadBuildContext) -> Result<(), EvmError> { +// This function applies system level operations: +// - Call beacon root contract, and obtain the new state root +// - Call block hash process contract, and store parent block hash +pub fn apply_system_operations(context: &mut PayloadBuildContext) -> Result<(), EvmError> { #[cfg(feature = "levm")] { - // Apply withdrawals & call beacon root contract, and obtain the new state root let fork = context .chain_config()? .fork(context.payload.header.timestamp); @@ -270,6 +269,7 @@ pub fn apply_withdrawals(context: &mut PayloadBuildContext) -> Result<(), EvmErr .unwrap_or(EVMConfig::canonical_values(fork)); let config = EVMConfig::new(fork, blob_schedule); + let mut new_state: HashMap<_, _> = HashMap::new(); if context.payload.header.parent_beacon_block_root.is_some() && fork >= Fork::Cancun { let store_wrapper = Arc::new(StoreWrapper { store: context.evm_state.database().unwrap().clone(), @@ -281,27 +281,45 @@ pub fn apply_withdrawals(context: &mut PayloadBuildContext) -> Result<(), EvmErr config, )?; - let mut new_state = report.new_state.clone(); + new_state.extend(report.new_state.clone()); + } - // Now original_value is going to be the same as the current_value, for the next transaction. - // It should have only one value but it is convenient to keep on using our CacheDB structure - for account in new_state.values_mut() { - for storage_slot in account.storage.values_mut() { - storage_slot.original_value = storage_slot.current_value; - } - } + if fork >= Fork::Prague { + let store_wrapper = Arc::new(StoreWrapper { + store: context.evm_state.database().unwrap().clone(), + block_hash: context.payload.header.parent_hash, + }); + let report = process_block_hash_history_levm( + store_wrapper.clone(), + &context.payload.header, + config, + )?; - context.block_cache.extend(new_state); + new_state.extend(report.new_state.clone()); } + + // Now original_value is going to be the same as the current_value, for the next transaction. + // It should have only one value but it is convenient to keep on using our CacheDB structure + for account in new_state.values_mut() { + for storage_slot in account.storage.values_mut() { + storage_slot.original_value = storage_slot.current_value; + } + } + + context.block_cache.extend(new_state); + Ok(()) } #[cfg(not(feature = "levm"))] { - // Apply withdrawals & call beacon root contract, and obtain the new state root let spec_id = spec_id(&context.chain_config()?, context.payload.header.timestamp); if context.payload.header.parent_beacon_block_root.is_some() && spec_id >= SpecId::CANCUN { beacon_root_contract_call(context.evm_state, &context.payload.header, spec_id)?; } + + if spec_id >= SpecId::PRAGUE { + process_block_hash_history(context.evm_state, &context.payload.header, spec_id)?; + } let withdrawals = context.payload.body.withdrawals.clone().unwrap_or_default(); process_withdrawals(context.evm_state, &withdrawals)?; Ok(()) diff --git a/crates/vm/vm.rs b/crates/vm/vm.rs index 3dae663bf7..42585f1141 100644 --- a/crates/vm/vm.rs +++ b/crates/vm/vm.rs @@ -44,7 +44,7 @@ pub const DEPOSIT_MAGIC_DATA: &[u8] = b"mint"; pub const SYSTEM_ADDRESS_STR: &str = "fffffffffffffffffffffffffffffffffffffffe"; pub const BEACON_ROOTS_ADDRESS_STR: &str = "000F3df6D732807Ef1319fB7B8bB8522d0Beac02"; -pub const HISTORY_STORAGE_ADDRESS_STR: &str = "0F792be4B0c0cb4DAE440Ef133E90C0eCD48CCCC"; +pub const HISTORY_STORAGE_ADDRESS_STR: &str = "0000F90827F1C53a10cb7A02335B175320002935"; /// State used when running the EVM. The state can be represented with a [StoreWrapper] database, or /// with a [ExecutionDB] in case we only want to store the necessary data for some particular @@ -163,7 +163,7 @@ cfg_if::cfg_if! { pub fn process_block_hash_history_levm( store_wrapper: Arc, block_header: &BlockHeader, - fork: Fork, + config: EVMConfig, ) -> Result { lazy_static! { static ref SYSTEM_ADDRESS: Address = @@ -185,7 +185,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(), - fork, + config, ..Default::default() }; @@ -309,18 +309,17 @@ cfg_if::cfg_if! { if #[cfg(not(feature = "l2"))] { if block_header.parent_beacon_block_root.is_some() && fork >= Fork::Cancun { //eip 4788: execute beacon_root_contract_call before block transactions - let report = beacon_root_contract_call_levm(store_wrapper.clone(), block_header, fork)?; - block_cache.extend(report.new_state); - } - - if fork >= Fork::Prague { - //eip 2935: stores parent block hash in system contract - let report = process_block_hash_history_levm(store_wrapper.clone(), block_header, fork)?; + let report = beacon_root_contract_call_levm(store_wrapper.clone(), block_header, config)?; block_cache.extend(report.new_state); } } } + if fork >= Fork::Prague { + //eip 2935: stores parent block hash in system contract + let report = process_block_hash_history_levm(store_wrapper.clone(), block_header, config)?; + block_cache.extend(report.new_state); + } // Account updates are initialized like this because of the beacon_root_contract_call, it is going to be empty if it wasn't called. let mut account_updates = get_state_transitions(state); @@ -438,13 +437,14 @@ cfg_if::cfg_if! { if block_header.parent_beacon_block_root.is_some() && spec_id >= SpecId::CANCUN { beacon_root_contract_call(state, block_header, spec_id)?; } - - //eip 2935: stores parent block hash in system contract - if spec_id >= SpecId::CANCUN { - process_block_hash_history(state, block_header, spec_id)?; - } } } + + //eip 2935: stores parent block hash in system contract + if spec_id >= SpecId::PRAGUE { + process_block_hash_history(state, block_header, spec_id)?; + } + let mut receipts = Vec::new(); let mut cumulative_gas_used = 0; diff --git a/test_data/genesis-execution-api.json b/test_data/genesis-execution-api.json index 797a20fd6d..22379f4dfe 100644 --- a/test_data/genesis-execution-api.json +++ b/test_data/genesis-execution-api.json @@ -31,7 +31,8 @@ "alloc": { "0F792be4B0c0cb4DAE440Ef133E90C0eCD48CCCC": { "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500", - "balance": "0x0" + "balance": "0x0", + "nonce": "0x1" }, "000f3df6d732807ef1319fb7b8bb8522d0beac02": { "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500", diff --git a/test_data/genesis-hive.json b/test_data/genesis-hive.json index ed313dd384..8340e0b755 100644 --- a/test_data/genesis-hive.json +++ b/test_data/genesis-hive.json @@ -31,10 +31,6 @@ "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500", "nonce": "0x1" }, - "0F792be4B0c0cb4DAE440Ef133E90C0eCD48CCCC": { - "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500", - "balance": "0" - }, "a94f5374fce5edbc8e2a8697c15331677e6ebf0b": { "balance": "0x5af3107a4000" } diff --git a/test_data/genesis-kurtosis.json b/test_data/genesis-kurtosis.json index f2c73b7ac7..ce30c61b0d 100644 --- a/test_data/genesis-kurtosis.json +++ b/test_data/genesis-kurtosis.json @@ -841,10 +841,6 @@ "nonce": "1", "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500" }, - "0F792be4B0c0cb4DAE440Ef133E90C0eCD48CCCC": { - "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500", - "balance": "0" - }, "0x8943545177806ED17B9F23F0a21ee5948eCaa776": { "balance": "1000000000000000000000000000" }, diff --git a/test_data/genesis-l1.json b/test_data/genesis-l1.json index 93818d8512..c415a9258b 100644 --- a/test_data/genesis-l1.json +++ b/test_data/genesis-l1.json @@ -19,9 +19,10 @@ "pragueTime": 1718232101 }, "alloc": { - "0F792be4B0c0cb4DAE440Ef133E90C0eCD48CCCC": { + "0x0F792be4B0c0cb4DAE440Ef133E90C0eCD48CCCC": { "code": "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500", - "balance": "0" + "balance": "0", + "nonce": "0x1" }, "0x4e59b44847b379578588920cA78FbF26c0B4956C": { "balance": "0", From ea88d94000d6f7451c7df88bd799b4955410c112 Mon Sep 17 00:00:00 2001 From: Julian Ventura Date: Thu, 6 Feb 2025 16:19:04 -0300 Subject: [PATCH 3/6] Enable Prague EIP-2935 EF tests --- cmd/ef_tests/blockchain/tests/prague.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/cmd/ef_tests/blockchain/tests/prague.rs b/cmd/ef_tests/blockchain/tests/prague.rs index db0522d6ed..6c5cce0661 100644 --- a/cmd/ef_tests/blockchain/tests/prague.rs +++ b/cmd/ef_tests/blockchain/tests/prague.rs @@ -20,10 +20,8 @@ fn parse_and_execute(path: &Path) -> datatest_stable::Result<()> { Ok(()) } -// TODO: Delete main function and uncomment the following line to allow prague tests to be parsed - -// datatest_stable::harness!(parse_and_execute, "vectors/prague/", r".*/.*/.*\.json"); - -fn main() { - //Do nothing -} +datatest_stable::harness!( + parse_and_execute, + "vectors/prague/eip2935_historical_block_hashes_from_state", + r".*/.*\.json" +); From 365477e682b39731e72334ab8711f2bb2ef50cc0 Mon Sep 17 00:00:00 2001 From: Julian Ventura Date: Tue, 11 Feb 2025 15:32:24 -0300 Subject: [PATCH 4/6] Move system contract addresses constants to file --- crates/vm/backends/constants.rs | 3 +++ crates/vm/backends/levm.rs | 10 +++------- crates/vm/backends/mod.rs | 1 + crates/vm/backends/revm.rs | 15 +++++---------- 4 files changed, 12 insertions(+), 17 deletions(-) create mode 100644 crates/vm/backends/constants.rs diff --git a/crates/vm/backends/constants.rs b/crates/vm/backends/constants.rs new file mode 100644 index 0000000000..2e98c6d227 --- /dev/null +++ b/crates/vm/backends/constants.rs @@ -0,0 +1,3 @@ +pub const SYSTEM_ADDRESS_STR: &str = "fffffffffffffffffffffffffffffffffffffffe"; +pub const BEACON_ROOTS_ADDRESS_STR: &str = "000F3df6D732807Ef1319fB7B8bB8522d0Beac02"; +pub const HISTORY_STORAGE_ADDRESS_STR: &str = "0000F90827F1C53a10cb7A02335B175320002935"; diff --git a/crates/vm/backends/levm.rs b/crates/vm/backends/levm.rs index 9944f05f6e..e264c8305d 100644 --- a/crates/vm/backends/levm.rs +++ b/crates/vm/backends/levm.rs @@ -1,7 +1,7 @@ +use super::constants::{BEACON_ROOTS_ADDRESS_STR, HISTORY_STORAGE_ADDRESS_STR, SYSTEM_ADDRESS_STR}; use crate::db::StoreWrapper; use crate::EvmError; use crate::EvmState; -#[cfg(not(feature = "l2"))] use ethrex_core::types::Fork; use ethrex_core::{ types::{ @@ -21,10 +21,6 @@ use lazy_static::lazy_static; use revm_primitives::Bytes; use std::{collections::HashMap, sync::Arc}; -pub const SYSTEM_ADDRESS_STR: &str = "fffffffffffffffffffffffffffffffffffffffe"; -pub const BEACON_ROOTS_ADDRESS_STR: &str = "000F3df6D732807Ef1319fB7B8bB8522d0Beac02"; -pub const HISTORY_STORAGE_ADDRESS_STR: &str = "0000F90827F1C53a10cb7A02335B175320002935"; - /// Executes all transactions in a block and returns their receipts. pub fn execute_block( block: &Block, @@ -269,9 +265,9 @@ pub fn beacon_root_contract_call_levm( ) -> Result { lazy_static! { static ref SYSTEM_ADDRESS: Address = - Address::from_slice(&hex::decode("fffffffffffffffffffffffffffffffffffffffe").unwrap()); + Address::from_slice(&hex::decode(SYSTEM_ADDRESS_STR).unwrap()); static ref CONTRACT_ADDRESS: Address = - Address::from_slice(&hex::decode("000F3df6D732807Ef1319fB7B8bB8522d0Beac02").unwrap(),); + Address::from_slice(&hex::decode(BEACON_ROOTS_ADDRESS_STR).unwrap()); }; // This is OK let beacon_root = match block_header.parent_beacon_block_root { diff --git a/crates/vm/backends/mod.rs b/crates/vm/backends/mod.rs index e89fe5e38e..a5955c779b 100644 --- a/crates/vm/backends/mod.rs +++ b/crates/vm/backends/mod.rs @@ -1,3 +1,4 @@ +mod constants; pub mod levm; pub mod revm; diff --git a/crates/vm/backends/revm.rs b/crates/vm/backends/revm.rs index 2ca0bad4bb..091264d5cf 100644 --- a/crates/vm/backends/revm.rs +++ b/crates/vm/backends/revm.rs @@ -1,3 +1,4 @@ +use super::constants::{BEACON_ROOTS_ADDRESS_STR, HISTORY_STORAGE_ADDRESS_STR, SYSTEM_ADDRESS_STR}; use crate::spec_id; use crate::EvmError; use crate::EvmState; @@ -29,10 +30,6 @@ use std::cmp::min; #[cfg(feature = "l2")] use crate::mods; -pub const SYSTEM_ADDRESS_STR: &str = "fffffffffffffffffffffffffffffffffffffffe"; -pub const BEACON_ROOTS_ADDRESS_STR: &str = "000F3df6D732807Ef1319fB7B8bB8522d0Beac02"; -pub const HISTORY_STORAGE_ADDRESS_STR: &str = "0000F90827F1C53a10cb7A02335B175320002935"; - /// Executes all transactions in a block and returns their receipts. pub fn execute_block(block: &Block, state: &mut EvmState) -> Result, EvmError> { let block_header = &block.header; @@ -447,12 +444,10 @@ pub fn beacon_root_contract_call( spec_id: SpecId, ) -> Result { lazy_static! { - static ref SYSTEM_ADDRESS: RevmAddress = RevmAddress::from_slice( - &hex::decode("fffffffffffffffffffffffffffffffffffffffe").unwrap() - ); - static ref CONTRACT_ADDRESS: RevmAddress = RevmAddress::from_slice( - &hex::decode("000F3df6D732807Ef1319fB7B8bB8522d0Beac02").unwrap(), - ); + static ref SYSTEM_ADDRESS: RevmAddress = + RevmAddress::from_slice(&hex::decode(SYSTEM_ADDRESS_STR).unwrap()); + static ref CONTRACT_ADDRESS: RevmAddress = + RevmAddress::from_slice(&hex::decode(BEACON_ROOTS_ADDRESS_STR).unwrap()); }; let beacon_root = match header.parent_beacon_block_root { None => { From dbdb48c2efee293265eaace53da2e6a0eb148a69 Mon Sep 17 00:00:00 2001 From: Julian Ventura Date: Tue, 11 Feb 2025 16:03:51 -0300 Subject: [PATCH 5/6] Remove unnecesary clones --- crates/blockchain/payload.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/blockchain/payload.rs b/crates/blockchain/payload.rs index 5766733740..82b2f52aca 100644 --- a/crates/blockchain/payload.rs +++ b/crates/blockchain/payload.rs @@ -323,12 +323,12 @@ pub fn apply_system_operations(context: &mut PayloadBuildContext) -> Result<(), block_hash: context.payload.header.parent_hash, }); let report = backends::levm::beacon_root_contract_call_levm( - store_wrapper.clone(), + store_wrapper, &context.payload.header, config, )?; - new_state.extend(report.new_state.clone()); + new_state.extend(report.new_state); } if fork >= Fork::Prague { @@ -337,12 +337,12 @@ pub fn apply_system_operations(context: &mut PayloadBuildContext) -> Result<(), block_hash: context.payload.header.parent_hash, }); let report = backends::levm::process_block_hash_history( - store_wrapper.clone(), + store_wrapper, &context.payload.header, config, )?; - new_state.extend(report.new_state.clone()); + new_state.extend(report.new_state); } // Now original_value is going to be the same as the current_value, for the next transaction. From 18b3f8484a57759c608f8768e6e81165037df1b2 Mon Sep 17 00:00:00 2001 From: Julian Ventura Date: Tue, 11 Feb 2025 16:12:40 -0300 Subject: [PATCH 6/6] Only call system contracts if L2 is not being used --- crates/vm/backends/levm.rs | 13 +++++++------ crates/vm/backends/revm.rs | 10 +++++----- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/crates/vm/backends/levm.rs b/crates/vm/backends/levm.rs index e264c8305d..7472658f39 100644 --- a/crates/vm/backends/levm.rs +++ b/crates/vm/backends/levm.rs @@ -2,6 +2,7 @@ use super::constants::{BEACON_ROOTS_ADDRESS_STR, HISTORY_STORAGE_ADDRESS_STR, SY use crate::db::StoreWrapper; use crate::EvmError; use crate::EvmState; +#[cfg(not(feature = "l2"))] use ethrex_core::types::Fork; use ethrex_core::{ types::{ @@ -47,13 +48,13 @@ pub fn execute_block( let report = beacon_root_contract_call_levm(store_wrapper.clone(), block_header, config)?; block_cache.extend(report.new_state); } - } - } - if fork >= Fork::Prague { - //eip 2935: stores parent block hash in system contract - let report = process_block_hash_history(store_wrapper.clone(), block_header, config)?; - block_cache.extend(report.new_state); + if fork >= Fork::Prague { + //eip 2935: stores parent block hash in system contract + let report = process_block_hash_history(store_wrapper.clone(), block_header, config)?; + block_cache.extend(report.new_state); + } + } } // Account updates are initialized like this because of the beacon_root_contract_call, it is going to be empty if it wasn't called. diff --git a/crates/vm/backends/revm.rs b/crates/vm/backends/revm.rs index 091264d5cf..ace6b0097a 100644 --- a/crates/vm/backends/revm.rs +++ b/crates/vm/backends/revm.rs @@ -41,12 +41,12 @@ pub fn execute_block(block: &Block, state: &mut EvmState) -> Result if block_header.parent_beacon_block_root.is_some() && spec_id >= SpecId::CANCUN { beacon_root_contract_call(state, block_header, spec_id)?; } - } - } - //eip 2935: stores parent block hash in system contract - if spec_id >= SpecId::PRAGUE { - process_block_hash_history(state, block_header, spec_id)?; + //eip 2935: stores parent block hash in system contract + if spec_id >= SpecId::PRAGUE { + process_block_hash_history(state, block_header, spec_id)?; + } + } } let mut receipts = Vec::new();