From c91c93096868d73f9f34960e7c357c61b215cd8e Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Thu, 9 Jan 2025 15:00:42 -0300 Subject: [PATCH 01/84] scaffolding: deserialize ef_test's EIP7702 txs --- cmd/ef_tests/levm/deserialize.rs | 18 ++++++++++++++++- cmd/ef_tests/levm/runner/levm_runner.rs | 25 +++++++++++++++++++++++- cmd/ef_tests/levm/types.rs | 26 +++++++++++++++++++++++-- crates/vm/levm/src/constants.rs | 6 ++++++ crates/vm/levm/src/environment.rs | 16 +-------------- crates/vm/levm/src/utils.rs | 1 + crates/vm/levm/src/vm.rs | 21 ++++++++++++++++++++ crates/vm/levm/tests/tests.rs | 8 ++++++++ crates/vm/vm.rs | 3 +++ 9 files changed, 105 insertions(+), 19 deletions(-) diff --git a/cmd/ef_tests/levm/deserialize.rs b/cmd/ef_tests/levm/deserialize.rs index 505ae696bf..df1d2cdbdf 100644 --- a/cmd/ef_tests/levm/deserialize.rs +++ b/cmd/ef_tests/levm/deserialize.rs @@ -1,4 +1,7 @@ -use crate::types::{EFTest, EFTestAccessListItem, EFTests, TransactionExpectedException}; +use crate::types::{ + EFTest, EFTestAccessListItem, EFTestAuthorizationListTuple, EFTests, + TransactionExpectedException, +}; use bytes::Bytes; use ethrex_core::{H256, U256}; use serde::{Deserialize, Deserializer}; @@ -194,6 +197,18 @@ where Ok(Some(final_access_lists)) } +pub fn deserialize_authorization_lists<'de, D>( + deserializer: D, +) -> Result>, D::Error> +where + D: serde::Deserializer<'de>, +{ + let authorization_list: Option> = + Option::>::deserialize(deserializer)?; + + Ok(authorization_list) +} + pub fn deserialize_u256_optional_safe<'de, D>(deserializer: D) -> Result, D::Error> where D: serde::Deserializer<'de>, @@ -322,6 +337,7 @@ impl<'de> Deserialize<'de> for EFTests { .get(data_id) .cloned() .unwrap_or_default(), + authorization_list: raw_tx.authorization_list.clone(), }; transactions.insert((data_id, gas_limit_id, value_id), tx); } diff --git a/cmd/ef_tests/levm/runner/levm_runner.rs b/cmd/ef_tests/levm/runner/levm_runner.rs index 27447b632d..564efb763b 100644 --- a/cmd/ef_tests/levm/runner/levm_runner.rs +++ b/cmd/ef_tests/levm/runner/levm_runner.rs @@ -11,7 +11,7 @@ use ethrex_core::{ use ethrex_levm::{ db::CacheDB, errors::{TransactionReport, TxValidationError, VMError}, - vm::VM, + vm::{AuthorizationTuple, VM}, Environment, }; use ethrex_storage::AccountUpdate; @@ -88,6 +88,28 @@ pub fn prepare_vm_for_tx(vector: &TestVector, test: &EFTest) -> Result + let auth_list = list + .iter() + .map(|auth_tuple| AuthorizationTuple { + chain_id: auth_tuple.chain_id, + address: auth_tuple.address, + nonce: auth_tuple.nonce, + y_parity: auth_tuple.v.as_u32() == 1, + r_signature: auth_tuple.r, + s_signature: auth_tuple.s, + // If the signer is not present, set it to Address::zero() + signer: auth_tuple.signer.unwrap_or_default(), + }) + .collect::>(); + + Some(auth_list) + } else { + None + }; + VM::new( tx.to.clone(), Environment { @@ -116,6 +138,7 @@ pub fn prepare_vm_for_tx(vector: &TestVector, test: &EFTest) -> Result, } +#[derive(Debug, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct EFTestAuthorizationListTuple { + #[serde(deserialize_with = "deserialize_u256_safe")] + pub chain_id: U256, + pub address: Address, + #[serde(deserialize_with = "deserialize_u64_safe")] + pub nonce: u64, + #[serde(deserialize_with = "deserialize_u256_safe")] + // yParity + pub v: U256, + #[serde(deserialize_with = "deserialize_u256_safe")] + pub r: U256, + #[serde(deserialize_with = "deserialize_u256_safe")] + pub s: U256, + pub signer: Option
, +} + #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub struct EFTestRawTransaction { @@ -312,6 +331,8 @@ pub struct EFTestRawTransaction { pub blob_versioned_hashes: Option>, #[serde(default, deserialize_with = "deserialize_access_lists")] pub access_lists: Option>>, + #[serde(default, deserialize_with = "deserialize_authorization_lists")] + pub authorization_list: Option>, } #[derive(Debug, Deserialize)] @@ -331,4 +352,5 @@ pub struct EFTestTransaction { pub max_fee_per_blob_gas: Option, pub blob_versioned_hashes: Vec, pub access_list: Vec, + pub authorization_list: Option>, } diff --git a/crates/vm/levm/src/constants.rs b/crates/vm/levm/src/constants.rs index a179002bfb..2eb5fc519a 100644 --- a/crates/vm/levm/src/constants.rs +++ b/crates/vm/levm/src/constants.rs @@ -50,3 +50,9 @@ pub const VALID_BLOB_PREFIXES: [u8; 2] = [0x01, 0x02]; // Block constants pub const LAST_AVAILABLE_BLOCK_LIMIT: U256 = U256([256, 0, 0, 0]); pub const MAX_BLOCK_GAS_LIMIT: U256 = U256([30_000_000, 0, 0, 0]); + +// EIP7702 - EOA Load Code +pub const MAGIC: u64 = 0x05; +pub const SET_CODE_TX_TYPE: u64 = 0x04; +pub const PER_AUTH_BASE_COST: U256 = U256([12500, 0, 0, 0]); +pub const PER_EMPTY_ACCOUNT_COST: U256 = U256([25000, 0, 0, 0]); diff --git a/crates/vm/levm/src/environment.rs b/crates/vm/levm/src/environment.rs index abfe127e0b..a4130c53ea 100644 --- a/crates/vm/levm/src/environment.rs +++ b/crates/vm/levm/src/environment.rs @@ -36,22 +36,8 @@ impl Environment { origin, refunded_gas: 0, gas_limit: u64::MAX, - spec_id: Default::default(), - block_number: Default::default(), - coinbase: Default::default(), - timestamp: Default::default(), - prev_randao: Default::default(), chain_id: U256::one(), - base_fee_per_gas: Default::default(), - gas_price: Default::default(), - block_excess_blob_gas: Default::default(), - block_blob_gas_used: Default::default(), - tx_blob_hashes: Default::default(), - tx_max_priority_fee_per_gas: Default::default(), - tx_max_fee_per_gas: Default::default(), - tx_max_fee_per_blob_gas: Default::default(), - block_gas_limit: Default::default(), - transient_storage: Default::default(), + ..Default::default() } } } diff --git a/crates/vm/levm/src/utils.rs b/crates/vm/levm/src/utils.rs index d0c32d8ebd..ffebb9e396 100644 --- a/crates/vm/levm/src/utils.rs +++ b/crates/vm/levm/src/utils.rs @@ -104,5 +104,6 @@ pub fn new_vm_with_ops_addr_bal_db( Arc::new(db), cache, Vec::new(), + None, ) } diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index de7053f3a9..c4edc44463 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -57,6 +57,10 @@ pub struct VM { pub cache: CacheDB, pub tx_kind: TxKind, pub access_list: AccessList, + // CHECK: check if we have to use an Option, if the AuthorizationList is not present in the tx. + // The node has to validate if the TxType is 0x4 and validate the AuthorizationList + // The Option is used with .is_some() and run the EIP7702 transaction. + pub authorization_list: Option, } pub fn address_to_word(address: Address) -> U256 { @@ -83,6 +87,19 @@ pub struct AccessListItem { type AccessList = Vec<(Address, Vec)>; +type AuthorizationList = Vec; +// TODO: We have to implement this in ethrex_core +#[derive(Debug, Clone, Default)] +pub struct AuthorizationTuple { + pub chain_id: U256, + pub address: Address, + pub nonce: u64, + pub y_parity: bool, + pub r_signature: U256, + pub s_signature: U256, + pub signer: Address, +} + pub fn get_valid_jump_destinations(code: &Bytes) -> Result, VMError> { let mut valid_jump_destinations = HashSet::new(); let mut pc = 0; @@ -128,6 +145,7 @@ impl VM { db: Arc, mut cache: CacheDB, access_list: AccessList, + authorization_list: Option, ) -> Result { // Maybe this decision should be made in an upper layer @@ -194,6 +212,7 @@ impl VM { cache, tx_kind: to, access_list, + authorization_list, }) } TxKind::Create => { @@ -236,6 +255,8 @@ impl VM { cache, tx_kind: TxKind::Create, access_list, + // CHECK: check if we can create a contract if we have an EIP7702 tx + authorization_list, }) } } diff --git a/crates/vm/levm/tests/tests.rs b/crates/vm/levm/tests/tests.rs index 028f5a44f7..3400cb914e 100644 --- a/crates/vm/levm/tests/tests.rs +++ b/crates/vm/levm/tests/tests.rs @@ -3890,6 +3890,7 @@ fn caller_op() { Arc::new(db), cache, Vec::new(), + Vec::new(), ) .unwrap(); @@ -3933,6 +3934,7 @@ fn origin_op() { Arc::new(db), cache, Vec::new(), + Vec::new(), ) .unwrap(); @@ -4003,6 +4005,7 @@ fn address_op() { Arc::new(db), cache, Vec::new(), + Vec::new(), ) .unwrap(); @@ -4050,6 +4053,7 @@ fn selfbalance_op() { Arc::new(db), cache, Vec::new(), + Vec::new(), ) .unwrap(); @@ -4094,6 +4098,7 @@ fn callvalue_op() { Arc::new(db), cache, Vec::new(), + Vec::new(), ) .unwrap(); @@ -4137,6 +4142,7 @@ fn codesize_op() { Arc::new(db), cache, Vec::new(), + Vec::new(), ) .unwrap(); @@ -4179,6 +4185,7 @@ fn gasprice_op() { Arc::new(db), cache, Vec::new(), + Vec::new(), ) .unwrap(); @@ -4237,6 +4244,7 @@ fn codecopy_op() { Arc::new(db), cache, Vec::new(), + Vec::new(), ) .unwrap(); diff --git a/crates/vm/vm.rs b/crates/vm/vm.rs index b9ad2f08ec..2b469927c4 100644 --- a/crates/vm/vm.rs +++ b/crates/vm/vm.rs @@ -261,6 +261,9 @@ cfg_if::cfg_if! { db, block_cache, tx.access_list(), + // TODO: Here we should pass the tx.authorization_list + // We have to implement the EIP7702 tx in ethrex_core + None )?; vm.transact() From da0e92b61c8f9268e1da6f60b6da2ca423d1262d Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Thu, 9 Jan 2025 18:05:31 -0300 Subject: [PATCH 02/84] feat: add checks for tx_type 4 --- crates/vm/levm/src/errors.rs | 6 ++++++ crates/vm/levm/src/vm.rs | 25 +++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/crates/vm/levm/src/errors.rs b/crates/vm/levm/src/errors.rs index 38fc359bfe..c774e70390 100644 --- a/crates/vm/levm/src/errors.rs +++ b/crates/vm/levm/src/errors.rs @@ -112,6 +112,12 @@ pub enum TxValidationError { Type3TxBlobCountExceeded, #[error("Type3TxContractCreation")] Type3TxContractCreation, + #[error("Type 4 transactions are not supported before the Prague fork")] + Type4TxPreFork, + #[error("Type4TxAuthorizationListIsEmpty")] + Type4TxAuthorizationListIsEmpty, + #[error("Type4TxContractCreation")] + Type4TxContractCreation, #[error("Gas limit price product overflow")] GasLimitPriceProductOverflow, } diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index c4edc44463..6066bb4adb 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -862,6 +862,31 @@ impl VM { } } + // [EIP-7702]: https://eips.ethereum.org/EIPS/eip-7702 + // 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 { + return Err(VMError::TxValidation(TxValidationError::Type4TxPreFork)); + } + + // (17) TYPE_4_TX_LIST_EMPTY + // From the EIP docs: The transaction is considered invalid if the length of authorization_list is zero. + if auth_list.is_empty() { + return Err(VMError::TxValidation( + TxValidationError::Type4TxAuthorizationListIsEmpty, + )); + } + + // (18) TYPE_4_TX_CONTRACT_CREATION -- or null address + // From the EIP docs: a null destination is not valid. + if self.is_create() { + return Err(VMError::TxValidation( + TxValidationError::Type4TxContractCreation, + )); + } + } + if self.is_create() { // Assign bytecode to context and empty calldata initial_call_frame.assign_bytecode(initial_call_frame.calldata.clone()); From 07632f4364f747b24fe6918fb685edca1d0e3a36 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Thu, 9 Jan 2025 18:12:02 -0300 Subject: [PATCH 03/84] chore: lint --- crates/vm/levm/tests/tests.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/vm/levm/tests/tests.rs b/crates/vm/levm/tests/tests.rs index 3400cb914e..3ec9e6e34b 100644 --- a/crates/vm/levm/tests/tests.rs +++ b/crates/vm/levm/tests/tests.rs @@ -3890,7 +3890,7 @@ fn caller_op() { Arc::new(db), cache, Vec::new(), - Vec::new(), + None, ) .unwrap(); @@ -3934,7 +3934,7 @@ fn origin_op() { Arc::new(db), cache, Vec::new(), - Vec::new(), + None, ) .unwrap(); @@ -4005,7 +4005,7 @@ fn address_op() { Arc::new(db), cache, Vec::new(), - Vec::new(), + None, ) .unwrap(); @@ -4053,7 +4053,7 @@ fn selfbalance_op() { Arc::new(db), cache, Vec::new(), - Vec::new(), + None, ) .unwrap(); @@ -4098,7 +4098,7 @@ fn callvalue_op() { Arc::new(db), cache, Vec::new(), - Vec::new(), + None, ) .unwrap(); @@ -4142,7 +4142,7 @@ fn codesize_op() { Arc::new(db), cache, Vec::new(), - Vec::new(), + None, ) .unwrap(); @@ -4185,7 +4185,7 @@ fn gasprice_op() { Arc::new(db), cache, Vec::new(), - Vec::new(), + None, ) .unwrap(); @@ -4244,7 +4244,7 @@ fn codecopy_op() { Arc::new(db), cache, Vec::new(), - Vec::new(), + None, ) .unwrap(); From 21bb98eddff5945eb4475f7df1bb9a00d689dfcf Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Fri, 10 Jan 2025 13:35:59 -0300 Subject: [PATCH 04/84] wip: add behavior section --- cmd/ef_tests/levm/runner/levm_runner.rs | 2 +- cmd/ef_tests/levm/types.rs | 1 - crates/vm/levm/src/constants.rs | 6 +- crates/vm/levm/src/vm.rs | 162 +++++++++++++++++++++++- 4 files changed, 164 insertions(+), 7 deletions(-) diff --git a/cmd/ef_tests/levm/runner/levm_runner.rs b/cmd/ef_tests/levm/runner/levm_runner.rs index 564efb763b..5a057e3fb6 100644 --- a/cmd/ef_tests/levm/runner/levm_runner.rs +++ b/cmd/ef_tests/levm/runner/levm_runner.rs @@ -97,7 +97,7 @@ pub fn prepare_vm_for_tx(vector: &TestVector, test: &EFTest) -> Result 23 +pub const EIP7702_DELEGATED_CODE_LEN: usize = 23; pub const PER_AUTH_BASE_COST: U256 = U256([12500, 0, 0, 0]); pub const PER_EMPTY_ACCOUNT_COST: U256 = U256([25000, 0, 0, 0]); diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 6066bb4adb..c45ea93761 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -3,7 +3,7 @@ use crate::{ call_frame::CallFrame, constants::*, db::{ - cache::{self, remove_account}, + cache::{self, get_account_mut, remove_account}, CacheDB, Database, }, environment::Environment, @@ -23,14 +23,18 @@ use bytes::Bytes; use ethrex_core::{types::TxKind, Address, H256, U256}; use ethrex_rlp; use ethrex_rlp::encode::RLPEncode; +use k256::{ + elliptic_curve::{bigint::Encoding, Curve}, + Secp256k1, +}; use keccak_hash::keccak; +use libsecp256k1::{Message, RecoveryId, Signature}; use revm_primitives::SpecId; use sha3::{Digest, Keccak256}; use std::{ collections::{HashMap, HashSet}, sync::Arc, }; - pub type Storage = HashMap; #[derive(Debug, Clone, Default)] @@ -89,12 +93,12 @@ type AccessList = Vec<(Address, Vec)>; type AuthorizationList = Vec; // TODO: We have to implement this in ethrex_core -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone, Default, Copy)] pub struct AuthorizationTuple { pub chain_id: U256, pub address: Address, pub nonce: u64, - pub y_parity: bool, + pub v: U256, pub r_signature: U256, pub s_signature: U256, pub signer: Address, @@ -885,6 +889,8 @@ impl VM { TxValidationError::Type4TxContractCreation, )); } + + self.eip7702_set_access_code(initial_call_frame.calldata.clone())?; } if self.is_create() { @@ -1258,6 +1264,137 @@ impl VM { Ok(report) } + + pub fn eip7702_set_access_code(&mut self, calldata: Bytes) -> Result<(), VMError> { + // Set code for the origin_address + let origin_address = self.env.origin; + let origin_account = get_account_mut(&mut self.cache, &origin_address); + if let Some(account) = origin_account { + account.info.bytecode = calldata; + } else { + return Err(VMError::Internal(InternalError::AccountNotFound)); + } + + // Steps from the EIP7702: + // IMPORTANT: + // If any of the below steps fail, immediately stop processing that tuple and continue to the next tuple in the list. It will in the case of multiple tuples for the same authority, set the code using the address in the last valid occurrence. + // If transaction execution results in failure (any exceptional condition or code reverting), setting delegation designations is not rolled back. + + // TODO: avoid clone() + for auth_tuple in self.authorization_list.clone().unwrap_or_default() { + let chain_id_not_equals_this_chain_id = auth_tuple.chain_id != self.env.chain_id; + let chain_id_not_zero = !auth_tuple.chain_id.is_zero(); + + // 1. Verify the chain id is either 0 or the chain’s current ID. + if chain_id_not_zero || chain_id_not_equals_this_chain_id { + continue; + } + + // 2. Verify the nonce is less than 2**64 - 1. + if auth_tuple.nonce < u64::MAX { + continue; + } + + // 3. authority = ecrecover(keccak(MAGIC || rlp([chain_id, address, nonce])), y_parity, r, s] + // s value must be less than or equal to secp256k1n/2, as specified in EIP-2. + let order_bytes = Secp256k1::ORDER.to_be_bytes(); + let n = U256::from_big_endian(&order_bytes); + if auth_tuple.s_signature <= n / 2 { + continue; + } + + let mut bytes = Vec::new(); + let mut rlp_buf = Vec::new(); + (auth_tuple.chain_id, auth_tuple.address, auth_tuple.nonce).encode(&mut rlp_buf); + + bytes.push(MAGIC); + bytes.extend_from_slice(&rlp_buf); + // TODO: remove unwrap + let message = Message::parse_slice(keccak(bytes).as_bytes()).unwrap(); + + let mut bytes = Vec::new(); + + bytes.extend_from_slice(&auth_tuple.r_signature.to_little_endian()); + bytes.extend_from_slice(&auth_tuple.s_signature.to_little_endian()); + + // TODO: remove unwrap + let signature = Signature::parse_standard_slice(&bytes).unwrap(); + + // TODO: remove as conversion and unwrap + let recovery_id = RecoveryId::parse(auth_tuple.v.as_u32() as u8).unwrap(); + + // TODO: remove unwrap + let authority = libsecp256k1::recover(&message, &signature, &recovery_id).unwrap(); + + let hash = keccak(&authority.serialize()[1..]); + // Get the last 20 bytes of the hash + let authority_address_bytes: [u8; 20] = + hash.as_ref().get(12..32).unwrap().try_into().unwrap(); + let authority_address = Address::from_slice(&authority_address_bytes); + + // 4. Add authority to accessed_addresses (as defined in EIP-2929. + self.accrued_substate + .touched_accounts + .insert(authority_address); + + // 5. Verify the code of authority is either empty or already delegated. + // CHECK: what do we do with this check? do we continue if it was already delegated? + + // What happens if it's not cached? + let authority_account = get_account_mut(&mut self.cache, &authority_address).ok_or( + VMError::Internal(InternalError::AccountShouldHaveBeenCached), + )?; + + if was_delegated(&authority_account.info)? { + continue; + } + + // 6. Verify the nonce of authority is equal to nonce. In case authority does not exist in the trie, verify that nonce is equal to 0. + // If it doesn't has nonce, it means it's zero, + // if it has nonce, the account.info.nonce should equal auth_tuple.nonce + if authority_account.has_nonce() { + if authority_account.info.nonce != auth_tuple.nonce { + continue; + } + } + + // If account is not empty exist -> exists + // 7. Add PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST gas to the global refund counter if authority exists in the trie. + if !authority_account.is_empty() { + // Should never throw an error + let refunded_gas_if_exists: u64 = (PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST) + .try_into() + .map_err(|_| VMError::Internal(InternalError::ConversionError))?; + self.env.refunded_gas += refunded_gas_if_exists; + } + + // 8. Set the code of authority to be 0xef0100 || address. This is a delegation designation. + let mut delegation_bytes = Vec::new(); + delegation_bytes.extend_from_slice(&SET_CODE_DELEGATION_BYTES); + delegation_bytes.extend_from_slice(auth_tuple.address.as_bytes()); + + // As a special case, if address is 0x0000000000000000000000000000000000000000 do not write the designation. + // Clear the account’s code and reset the account’s code hash to the empty hash. + if auth_tuple.address != Address::zero() { + // Write Designation + authority_account.info.bytecode = delegation_bytes.into(); + } else { + // auth_tuple.address is Address::zero() + // Do not write Designation and Write account's bytecode to empty + let origin_account = get_account_mut(&mut self.cache, &origin_address); + if let Some(account) = origin_account { + account.info.bytecode = Bytes::new() + } else { + return Err(VMError::Internal(InternalError::AccountNotFound)); + } + } + + // 9. Increase the nonce of authority by one. + self.increment_account_nonce(authority_address) + .map_err(|_| VMError::TxValidation(TxValidationError::NonceIsMax))?; + } + Ok(()) + } } fn get_n_value(op: Opcode, base_opcode: Opcode) -> Result { @@ -1293,3 +1430,20 @@ pub fn get_account(cache: &mut CacheDB, db: &Arc, address: Address } } } + +pub fn was_delegated(account_info: &AccountInfo) -> Result { + let mut was_delegated = false; + if account_info.has_code() { + if account_info.bytecode.len() == EIP7702_DELEGATED_CODE_LEN { + let first_3_bytes = account_info + .bytecode + .get(..3) + .ok_or(VMError::Internal(InternalError::SlicingError))?; + + if first_3_bytes == SET_CODE_DELEGATION_BYTES { + was_delegated = true; + } + } + } + Ok(was_delegated) +} From 8298c3d559b1a26719320f0c0f398d5d2ca839c3 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Mon, 13 Jan 2025 12:44:50 -0300 Subject: [PATCH 05/84] should be reverted: bump-up revm version so we can compare results against it --- Cargo.lock | 273 ++++++++---------- cmd/ef_tests/levm/Cargo.toml | 2 +- cmd/ef_tests/levm/runner/revm_runner.rs | 30 +- crates/vm/Cargo.toml | 6 +- crates/vm/levm/Cargo.toml | 2 +- .../vm/levm/bench/revm_comparison/Cargo.toml | 2 +- crates/vm/levm/rust-toolchain.toml | 2 +- crates/vm/levm/src/vm.rs | 30 +- crates/vm/vm.rs | 15 +- 9 files changed, 180 insertions(+), 182 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 19013b1ee2..4d1a237485 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -102,52 +102,66 @@ checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" [[package]] name = "alloy-consensus" -version = "0.4.2" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "705687d5bfd019fee57cf9e206b27b30a9a9617535d5590a02b171e813208f8e" +checksum = "f4138dc275554afa6f18c4217262ac9388790b2fc393c2dfe03c51d357abf013" dependencies = [ "alloy-eips", - "alloy-primitives 0.8.14", + "alloy-primitives 0.8.18", "alloy-rlp", "alloy-serde", + "alloy-trie", "auto_impl", "c-kzg", "derive_more 1.0.0", "serde", ] +[[package]] +name = "alloy-consensus-any" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa04e1882c31288ce1028fdf31b6ea94cfa9eafa2e497f903ded631c8c6a42c" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives 0.8.18", + "alloy-rlp", +] + [[package]] name = "alloy-eip2930" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41" dependencies = [ - "alloy-primitives 0.8.14", + "alloy-primitives 0.8.18", "alloy-rlp", "serde", ] [[package]] name = "alloy-eip7702" -version = "0.1.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea59dc42102bc9a1905dc57901edc6dd48b9f38115df86c7d252acba70d71d04" +checksum = "cabf647eb4650c91a9d38cb6f972bb320009e7e9d61765fb688a86f1563b33e8" dependencies = [ - "alloy-primitives 0.8.14", + "alloy-primitives 0.8.18", "alloy-rlp", + "derive_more 1.0.0", "k256", "serde", ] [[package]] name = "alloy-eips" -version = "0.4.2" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ffb906284a1e1f63c4607da2068c8197458a352d0b3e9796e67353d72a9be85" +checksum = "52dd5869ed09e399003e0e0ec6903d981b2a92e74c5d37e6b40890bad2517526" dependencies = [ "alloy-eip2930", "alloy-eip7702", - "alloy-primitives 0.8.14", + "alloy-primitives 0.8.18", "alloy-rlp", "alloy-serde", "c-kzg", @@ -159,11 +173,11 @@ dependencies = [ [[package]] name = "alloy-json-abi" -version = "0.8.14" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac4b22b3e51cac09fd2adfcc73b55f447b4df669f983c13f7894ec82b607c63f" +checksum = "731ea743b3d843bc657e120fb1d1e9cc94f5dab8107e35a82125a63e6420a102" dependencies = [ - "alloy-primitives 0.8.14", + "alloy-primitives 0.8.18", "alloy-sol-type-parser", "serde", "serde_json", @@ -171,13 +185,13 @@ dependencies = [ [[package]] name = "alloy-network-primitives" -version = "0.4.2" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801492711d4392b2ccf5fc0bc69e299fa1aab15167d74dcaa9aab96a54f684bd" +checksum = "f31c3c6b71340a1d076831823f09cb6e02de01de5c6630a9631bdb36f947ff80" dependencies = [ "alloy-consensus", "alloy-eips", - "alloy-primitives 0.8.14", + "alloy-primitives 0.8.18", "alloy-serde", "serde", ] @@ -206,9 +220,9 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "0.8.14" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9db948902dfbae96a73c2fbf1f7abec62af034ab883e4c777c3fd29702bd6e2c" +checksum = "788bb18e8f61d5d9340b52143f27771daf7e1dccbaf2741621d2493f9debf52e" dependencies = [ "alloy-rlp", "bytes", @@ -217,7 +231,6 @@ dependencies = [ "derive_more 1.0.0", "foldhash", "hashbrown 0.15.2", - "hex-literal", "indexmap 2.6.0", "itoa", "k256", @@ -226,7 +239,7 @@ dependencies = [ "proptest", "rand 0.8.5", "ruint", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "serde", "sha3", "tiny-keccak", @@ -256,44 +269,45 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "0.4.2" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413f4aa3ccf2c3e4234a047c5fa4727916d7daf25a89f9b765df0ba09784fd87" +checksum = "0938bc615c02421bd86c1733ca7205cc3d99a122d9f9bff05726bd604b76a5c2" dependencies = [ "alloy-consensus", + "alloy-consensus-any", "alloy-eips", "alloy-network-primitives", - "alloy-primitives 0.8.14", + "alloy-primitives 0.8.18", "alloy-rlp", "alloy-serde", - "alloy-sol-types 0.8.14", - "derive_more 1.0.0", + "alloy-sol-types 0.8.18", "itertools 0.13.0", "serde", "serde_json", + "thiserror 2.0.9", ] [[package]] name = "alloy-rpc-types-trace" -version = "0.4.2" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "017cad3e5793c5613588c1f9732bcbad77e820ba7d0feaba3527749f856fdbc5" +checksum = "cd38207e056cc7d1372367fbb4560ddf9107cbd20731743f641246bf0dede149" dependencies = [ - "alloy-primitives 0.8.14", + "alloy-primitives 0.8.18", "alloy-rpc-types-eth", "alloy-serde", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror 2.0.9", ] [[package]] name = "alloy-serde" -version = "0.4.2" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dff0ab1cdd43ca001e324dc27ee0e8606bd2161d6623c63e0e0b8c4dfc13600" +checksum = "ae0465c71d4dced7525f408d84873aeebb71faf807d22d74c4a426430ccd9b55" dependencies = [ - "alloy-primitives 0.8.14", + "alloy-primitives 0.8.18", "serde", "serde_json", ] @@ -314,12 +328,12 @@ dependencies = [ [[package]] name = "alloy-sol-macro" -version = "0.8.14" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bfd7853b65a2b4f49629ec975fee274faf6dff15ab8894c620943398ef283c0" +checksum = "a07b74d48661ab2e4b50bb5950d74dbff5e61dd8ed03bb822281b706d54ebacb" dependencies = [ - "alloy-sol-macro-expander 0.8.14", - "alloy-sol-macro-input 0.8.14", + "alloy-sol-macro-expander 0.8.18", + "alloy-sol-macro-input 0.8.18", "proc-macro-error2", "proc-macro2", "quote", @@ -346,11 +360,11 @@ dependencies = [ [[package]] name = "alloy-sol-macro-expander" -version = "0.8.14" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82ec42f342d9a9261699f8078e57a7a4fda8aaa73c1a212ed3987080e6a9cd13" +checksum = "19cc9c7f20b90f9be1a8f71a3d8e283a43745137b0837b1a1cb13159d37cad72" dependencies = [ - "alloy-sol-macro-input 0.8.14", + "alloy-sol-macro-input 0.8.18", "const-hex", "heck 0.5.0", "indexmap 2.6.0", @@ -358,7 +372,7 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.89", - "syn-solidity 0.8.14", + "syn-solidity 0.8.18", "tiny-keccak", ] @@ -379,9 +393,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-input" -version = "0.8.14" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2c50e6a62ee2b4f7ab3c6d0366e5770a21cad426e109c2f40335a1b3aff3df" +checksum = "713b7e6dfe1cb2f55c80fb05fd22ed085a1b4e48217611365ed0ae598a74c6ac" dependencies = [ "const-hex", "dunce", @@ -389,14 +403,14 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.89", - "syn-solidity 0.8.14", + "syn-solidity 0.8.18", ] [[package]] name = "alloy-sol-type-parser" -version = "0.8.14" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac17c6e89a50fb4a758012e4b409d9a0ba575228e69b539fe37d7a1bd507ca4a" +checksum = "1eda2711ab2e1fb517fc6e2ffa9728c9a232e296d16810810e6957b781a1b8bc" dependencies = [ "serde", "winnow 0.6.20", @@ -416,17 +430,33 @@ dependencies = [ [[package]] name = "alloy-sol-types" -version = "0.8.14" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9dc0fffe397aa17628160e16b89f704098bf3c9d74d5d369ebc239575936de5" +checksum = "e3b478bc9c0c4737a04cd976accde4df7eba0bdc0d90ad6ff43d58bc93cf79c1" dependencies = [ "alloy-json-abi", - "alloy-primitives 0.8.14", - "alloy-sol-macro 0.8.14", + "alloy-primitives 0.8.18", + "alloy-sol-macro 0.8.18", "const-hex", "serde", ] +[[package]] +name = "alloy-trie" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6917c79e837aa7b77b7a6dae9f89cbe15313ac161c4d3cfaf8909ef21f3d22d8" +dependencies = [ + "alloy-primitives 0.8.18", + "alloy-rlp", + "arrayvec", + "derive_more 1.0.0", + "nybbles", + "serde", + "smallvec", + "tracing", +] + [[package]] name = "android-tzdata" version = "0.1.1" @@ -769,6 +799,9 @@ name = "arrayvec" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +dependencies = [ + "serde", +] [[package]] name = "async-trait" @@ -2276,7 +2309,7 @@ dependencies = [ "hex", "itertools 0.13.0", "keccak-hash", - "revm 14.0.3", + "revm", "serde", "serde_json", "spinoff", @@ -2885,7 +2918,7 @@ dependencies = [ "lambdaworks-math", "libsecp256k1", "num-bigint 0.4.6", - "revm-primitives 10.0.0", + "revm-primitives", "ripemd", "serde", "serde_json", @@ -3086,9 +3119,9 @@ dependencies = [ "ethrex-trie", "hex", "lazy_static", - "revm 14.0.3", + "revm", "revm-inspectors", - "revm-primitives 10.0.0", + "revm-primitives", "serde", "thiserror 2.0.9", "tracing", @@ -3271,9 +3304,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" +checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" [[package]] name = "foreign-types" @@ -5249,6 +5282,17 @@ dependencies = [ "cc", ] +[[package]] +name = "nybbles" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8983bb634df7248924ee0c4c3a749609b5abcb082c28fffe3254b3eb3602b307" +dependencies = [ + "const-hex", + "serde", + "smallvec", +] + [[package]] name = "objc" version = "0.2.7" @@ -6202,7 +6246,7 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "rustls", "socket2", "thiserror 2.0.9", @@ -6220,7 +6264,7 @@ dependencies = [ "getrandom", "rand 0.8.5", "ring 0.17.8", - "rustc-hash 2.0.0", + "rustc-hash 2.1.0", "rustls", "rustls-pki-types", "slab", @@ -6570,94 +6614,51 @@ dependencies = [ [[package]] name = "revm" -version = "9.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a2c336f9921588e50871c00024feb51a521eca50ce6d01494bb9c50f837c8ed" -dependencies = [ - "auto_impl", - "cfg-if", - "dyn-clone", - "revm-interpreter 5.0.0", - "revm-precompile 7.0.0", - "serde", - "serde_json", -] - -[[package]] -name = "revm" -version = "14.0.3" +version = "19.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "641702b12847f9ed418d552f4fcabe536d867a2c980e96b6e7e25d7b992f929f" +checksum = "8b829dc9d6e62c5a540dfdceb0c4d2217e445bf5f6f5ed3866817e7a9637c019" dependencies = [ "auto_impl", "cfg-if", "dyn-clone", - "revm-interpreter 10.0.3", - "revm-precompile 11.0.3", + "revm-interpreter", + "revm-precompile", "serde", "serde_json", ] [[package]] name = "revm-inspectors" -version = "0.8.1" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43c44af0bf801f48d25f7baf25cf72aff4c02d610f83b428175228162fef0246" +checksum = "dc873bc873e12a1723493e1a35804fa79b673a0bfb1c19cfee659d46def8be42" dependencies = [ - "alloy-primitives 0.8.14", + "alloy-primitives 0.8.18", "alloy-rpc-types-eth", "alloy-rpc-types-trace", - "alloy-sol-types 0.8.14", + "alloy-sol-types 0.8.18", "anstyle", "colorchoice", - "revm 14.0.3", + "revm", "serde_json", - "thiserror 1.0.69", -] - -[[package]] -name = "revm-interpreter" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a58182c7454179826f9dad2ca577661963092ce9d0fd0c9d682c1e9215a72e70" -dependencies = [ - "revm-primitives 4.0.0", - "serde", + "thiserror 2.0.9", ] [[package]] name = "revm-interpreter" -version = "10.0.3" +version = "15.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5e14002afae20b5bf1566f22316122f42f57517000e559c55b25bf7a49cba2" +checksum = "e5ff76b50b5a9fa861fbc236fc82ce1afdf58861f65012aea807d679e54630d6" dependencies = [ - "revm-primitives 10.0.0", + "revm-primitives", "serde", ] [[package]] name = "revm-precompile" -version = "7.0.0" +version = "16.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc8af9aa737eef0509a50d9f3cc1a631557a00ef2e70a3aa8a75d9ee0ed275bb" -dependencies = [ - "aurora-engine-modexp", - "blst", - "c-kzg", - "k256", - "once_cell", - "revm-primitives 4.0.0", - "ripemd", - "secp256k1", - "sha2 0.10.8", - "substrate-bn", -] - -[[package]] -name = "revm-precompile" -version = "11.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3198c06247e8d4ad0d1312591edf049b0de4ddffa9fecb625c318fd67db8639b" +checksum = "6542fb37650dfdbf4b9186769e49c4a8bc1901a3280b2ebf32f915b6c8850f36" dependencies = [ "aurora-engine-modexp", "blst", @@ -6665,7 +6666,7 @@ dependencies = [ "cfg-if", "k256", "once_cell", - "revm-primitives 10.0.0", + "revm-primitives", "ripemd", "secp256k1", "sha2 0.10.8", @@ -6674,34 +6675,13 @@ dependencies = [ [[package]] name = "revm-primitives" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9bf5d465e64b697da6a111cb19e798b5b2ebb18e5faf2ad48e9e8d47c64add2" -dependencies = [ - "alloy-primitives 0.7.7", - "auto_impl", - "bitflags 2.6.0", - "bitvec", - "c-kzg", - "cfg-if", - "derive_more 0.99.18", - "dyn-clone", - "enumn", - "hashbrown 0.14.5", - "hex", - "once_cell", - "serde", -] - -[[package]] -name = "revm-primitives" -version = "10.0.0" +version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f1525851a03aff9a9d6a1d018b414d76252d6802ab54695b27093ecd7e7a101" +checksum = "48faea1ecf2c9f80d9b043bbde0db9da616431faed84c4cfa3dd7393005598e6" dependencies = [ "alloy-eip2930", "alloy-eip7702", - "alloy-primitives 0.8.14", + "alloy-primitives 0.8.18", "auto_impl", "bitflags 2.6.0", "bitvec", @@ -6720,7 +6700,7 @@ dependencies = [ "bytes", "ethrex-levm", "hex", - "revm 9.0.0", + "revm", ] [[package]] @@ -7139,9 +7119,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.0.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" +checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" [[package]] name = "rustc-hex" @@ -7726,6 +7706,9 @@ name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +dependencies = [ + "serde", +] [[package]] name = "snap" @@ -8354,9 +8337,9 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "0.8.14" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0523f59468a2696391f2a772edc089342aacd53c3caa2ac3264e598edf119b" +checksum = "31e89d8bf2768d277f40573c83a02a099e96d96dd3104e13ea676194e61ac4b0" dependencies = [ "paste", "proc-macro2", diff --git a/cmd/ef_tests/levm/Cargo.toml b/cmd/ef_tests/levm/Cargo.toml index 073ed7ade4..f8dae29ffb 100644 --- a/cmd/ef_tests/levm/Cargo.toml +++ b/cmd/ef_tests/levm/Cargo.toml @@ -21,7 +21,7 @@ thiserror.workspace = true clap = { version = "4.3", features = ["derive"] } clap_complete = "4.5.17" itertools = "0.13.0" -revm = { version = "14.0.3", features = [ +revm = { version = "19.2.0", features = [ "serde", "std", "serde-json", diff --git a/cmd/ef_tests/levm/runner/revm_runner.rs b/cmd/ef_tests/levm/runner/revm_runner.rs index a0bce7438b..5eb62ce88d 100644 --- a/cmd/ef_tests/levm/runner/revm_runner.rs +++ b/cmd/ef_tests/levm/runner/revm_runner.rs @@ -19,8 +19,9 @@ use revm::{ db::State, inspectors::TracerEip3155 as RevmTracerEip3155, primitives::{ - AccessListItem, BlobExcessGasAndPrice, BlockEnv as RevmBlockEnv, EVMError as REVMError, - ExecutionResult as RevmExecutionResult, TxEnv as RevmTxEnv, TxKind as RevmTxKind, B256, + AccessListItem, Authorization, BlobExcessGasAndPrice, BlockEnv as RevmBlockEnv, + EVMError as REVMError, ExecutionResult as RevmExecutionResult, SignedAuthorization, + TxEnv as RevmTxEnv, TxKind as RevmTxKind, B256, }, Evm as Revm, }; @@ -113,7 +114,7 @@ pub fn prepare_revm_for_tx<'state>( blob_excess_gas_and_price: test .env .current_excess_blob_gas - .map(|gas| BlobExcessGasAndPrice::new(gas.as_u64())), + .map(|gas| BlobExcessGasAndPrice::new(gas.as_u64(), true)), }; let tx = &test .transactions @@ -136,6 +137,27 @@ pub fn prepare_revm_for_tx<'state>( }) .collect(); + let revm_authorization_list: Vec = tx + .authorization_list + .clone() + .unwrap_or_default() + .iter() + .map(|auth_t| { + SignedAuthorization::new_unchecked( + Authorization { + chain_id: RevmU256::from_le_bytes(auth_t.chain_id.to_little_endian()), + address: RevmAddress(auth_t.address.0.into()), + nonce: auth_t.nonce, + }, + auth_t.v.as_u32() as u8, + RevmU256::from_le_bytes(auth_t.r.to_little_endian()), + RevmU256::from_le_bytes(auth_t.s.to_little_endian()), + ) + }) + .collect(); + + let authorization_list = Some(revm_authorization_list.into()); + let tx_env = RevmTxEnv { caller: tx.sender.0.into(), gas_limit: tx.gas_limit, @@ -160,7 +182,7 @@ pub fn prepare_revm_for_tx<'state>( max_fee_per_blob_gas: tx .max_fee_per_blob_gas .map(|fee| RevmU256::from_limbs(fee.0)), - authorization_list: None, + authorization_list, }; let evm_builder = Revm::builder() diff --git a/crates/vm/Cargo.toml b/crates/vm/Cargo.toml index b183689baf..024794c801 100644 --- a/crates/vm/Cargo.toml +++ b/crates/vm/Cargo.toml @@ -9,7 +9,7 @@ ethrex-storage = { path = "../storage/store", default-features = false } ethrex-levm = { path = "./levm", optional = true } ethrex-trie = { path = "../storage/trie", default-features = false } ethrex-rlp = { path = "../common/rlp", default-features = false } -revm = { version = "14.0.3", features = [ +revm = { version = "19.2.0", features = [ "serde", "std", "serde-json", @@ -18,8 +18,8 @@ revm = { version = "14.0.3", features = [ ], default-features = false } # These dependencies must be kept up to date with the corresponding revm version, otherwise errors may pop up because of trait implementation mismatches -revm-inspectors = { version = "0.8.1" } -revm-primitives = { version = "10.0.0", features = [ +revm-inspectors = { version = "0.14.1" } +revm-primitives = { version = "15.1.0", features = [ "std", ], default-features = false } bytes.workspace = true diff --git a/crates/vm/levm/Cargo.toml b/crates/vm/levm/Cargo.toml index f592f2e5a2..6ac9a5c44b 100644 --- a/crates/vm/levm/Cargo.toml +++ b/crates/vm/levm/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace = true [dependencies] ethrex-core.workspace = true ethrex-rlp.workspace = true -revm-primitives = { version = "10.0.0", features = [ +revm-primitives = { version = "15.1.0", features = [ "std", ], default-features = false } diff --git a/crates/vm/levm/bench/revm_comparison/Cargo.toml b/crates/vm/levm/bench/revm_comparison/Cargo.toml index 59e2c04312..d4e415771b 100644 --- a/crates/vm/levm/bench/revm_comparison/Cargo.toml +++ b/crates/vm/levm/bench/revm_comparison/Cargo.toml @@ -10,7 +10,7 @@ path = "src/lib.rs" [dependencies] ethrex-levm = { path = "../../" } hex = "0.4.3" -revm = "9.0.0" +revm = "19.2.0" bytes = "1.8.0" [[bin]] diff --git a/crates/vm/levm/rust-toolchain.toml b/crates/vm/levm/rust-toolchain.toml index 1de01fa45c..2e2b8c8521 100644 --- a/crates/vm/levm/rust-toolchain.toml +++ b/crates/vm/levm/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.81.0" +channel = "1.82.0" diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index c45ea93761..90ece66a77 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -27,7 +27,7 @@ use k256::{ elliptic_curve::{bigint::Encoding, Curve}, Secp256k1, }; -use keccak_hash::keccak; +use keccak_hash::{keccak, keccak256}; use libsecp256k1::{Message, RecoveryId, Signature}; use revm_primitives::SpecId; use sha3::{Digest, Keccak256}; @@ -890,7 +890,7 @@ impl VM { )); } - self.eip7702_set_access_code(initial_call_frame.calldata.clone())?; + self.eip7702_set_access_code(initial_call_frame.code_address)?; } if self.is_create() { @@ -1265,16 +1265,7 @@ impl VM { Ok(report) } - pub fn eip7702_set_access_code(&mut self, calldata: Bytes) -> Result<(), VMError> { - // Set code for the origin_address - let origin_address = self.env.origin; - let origin_account = get_account_mut(&mut self.cache, &origin_address); - if let Some(account) = origin_account { - account.info.bytecode = calldata; - } else { - return Err(VMError::Internal(InternalError::AccountNotFound)); - } - + pub fn eip7702_set_access_code(&mut self, code_address: Address) -> Result<(), VMError> { // Steps from the EIP7702: // IMPORTANT: // If any of the below steps fail, immediately stop processing that tuple and continue to the next tuple in the list. It will in the case of multiple tuples for the same authority, set the code using the address in the last valid occurrence. @@ -1310,7 +1301,8 @@ impl VM { bytes.push(MAGIC); bytes.extend_from_slice(&rlp_buf); // TODO: remove unwrap - let message = Message::parse_slice(keccak(bytes).as_bytes()).unwrap(); + keccak256(&mut bytes); + let message = Message::parse_slice(&bytes).unwrap(); let mut bytes = Vec::new(); @@ -1326,10 +1318,11 @@ impl VM { // TODO: remove unwrap let authority = libsecp256k1::recover(&message, &signature, &recovery_id).unwrap(); - let hash = keccak(&authority.serialize()[1..]); + let mut public_key = authority.serialize(); + keccak256(&mut public_key[1..]); // Get the last 20 bytes of the hash let authority_address_bytes: [u8; 20] = - hash.as_ref().get(12..32).unwrap().try_into().unwrap(); + public_key.get(12..32).unwrap().try_into().unwrap(); let authority_address = Address::from_slice(&authority_address_bytes); // 4. Add authority to accessed_addresses (as defined in EIP-2929. @@ -1381,12 +1374,7 @@ impl VM { } else { // auth_tuple.address is Address::zero() // Do not write Designation and Write account's bytecode to empty - let origin_account = get_account_mut(&mut self.cache, &origin_address); - if let Some(account) = origin_account { - account.info.bytecode = Bytes::new() - } else { - return Err(VMError::Internal(InternalError::AccountNotFound)); - } + todo!() } // 9. Increase the nonce of authority by one. diff --git a/crates/vm/vm.rs b/crates/vm/vm.rs index 2b469927c4..5cd3c3df87 100644 --- a/crates/vm/vm.rs +++ b/crates/vm/vm.rs @@ -313,7 +313,7 @@ pub fn execute_tx( state: &mut EvmState, spec_id: SpecId, ) -> Result { - let block_env = block_env(header); + let block_env = block_env(header, is_prague(spec_id)); let tx_env = tx_env(tx); run_evm(tx_env, block_env, state, spec_id) } @@ -325,7 +325,7 @@ pub fn simulate_tx_from_generic( state: &mut EvmState, spec_id: SpecId, ) -> Result { - let block_env = block_env(header); + let block_env = block_env(header, is_prague(spec_id)); let tx_env = tx_env_from_generic(tx, header.base_fee_per_gas.unwrap_or(INITIAL_BASE_FEE)); run_without_commit(tx_env, block_env, state, spec_id) } @@ -403,7 +403,7 @@ pub fn create_access_list( spec_id: SpecId, ) -> Result<(ExecutionResult, AccessList), EvmError> { let mut tx_env = tx_env_from_generic(tx, header.base_fee_per_gas.unwrap_or(INITIAL_BASE_FEE)); - let block_env = block_env(header); + let block_env = block_env(header, is_prague(spec_id)); // Run tx with access list inspector let (execution_result, access_list) = @@ -712,7 +712,7 @@ pub fn beacon_root_contract_call( data: revm::primitives::Bytes::copy_from_slice(beacon_root.as_bytes()), ..Default::default() }; - let mut block_env = block_env(header); + let mut block_env = block_env(header, is_prague(spec_id)); block_env.basefee = RevmU256::ZERO; block_env.gas_limit = RevmU256::from(30_000_000); @@ -749,7 +749,7 @@ pub fn beacon_root_contract_call( } } -pub fn block_env(header: &BlockHeader) -> BlockEnv { +pub fn block_env(header: &BlockHeader, is_prague: bool) -> BlockEnv { BlockEnv { number: RevmU256::from(header.number), coinbase: RevmAddress(header.coinbase.0.into()), @@ -760,6 +760,7 @@ pub fn block_env(header: &BlockHeader) -> BlockEnv { prevrandao: Some(header.prev_randao.as_fixed_bytes().into()), blob_excess_gas_and_price: Some(BlobExcessGasAndPrice::new( header.excess_blob_gas.unwrap_or_default(), + is_prague, )), } } @@ -937,3 +938,7 @@ fn calculate_gas_price(tx: &GenericTransaction, basefee: u64) -> Uint<256, 4> { )) } } + +pub fn is_prague(spec_id: SpecId) -> bool { + spec_id >= SpecId::PRAGUE +} From 96f8a069b22cd59cc2c32ff3253640c7a88e6314 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Mon, 13 Jan 2025 14:49:05 -0300 Subject: [PATCH 06/84] dbg: can't use Message::parse_slice --- crates/vm/levm/src/vm.rs | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 90ece66a77..869b234357 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -4,7 +4,7 @@ use crate::{ constants::*, db::{ cache::{self, get_account_mut, remove_account}, - CacheDB, Database, + CacheDB, Database, Db, }, environment::Environment, errors::{ @@ -36,6 +36,7 @@ use std::{ sync::Arc, }; pub type Storage = HashMap; +use std::str::FromStr; #[derive(Debug, Clone, Default)] // TODO: https://github.com/lambdaclass/ethrex/issues/604 @@ -1271,28 +1272,32 @@ impl VM { // If any of the below steps fail, immediately stop processing that tuple and continue to the next tuple in the list. It will in the case of multiple tuples for the same authority, set the code using the address in the last valid occurrence. // If transaction execution results in failure (any exceptional condition or code reverting), setting delegation designations is not rolled back. + dbg!("authorization_list:", &self.authorization_list); // TODO: avoid clone() for auth_tuple in self.authorization_list.clone().unwrap_or_default() { let chain_id_not_equals_this_chain_id = auth_tuple.chain_id != self.env.chain_id; let chain_id_not_zero = !auth_tuple.chain_id.is_zero(); // 1. Verify the chain id is either 0 or the chain’s current ID. - if chain_id_not_zero || chain_id_not_equals_this_chain_id { + if chain_id_not_zero && chain_id_not_equals_this_chain_id { continue; } + dbg!("EIP-7702-1"); // 2. Verify the nonce is less than 2**64 - 1. - if auth_tuple.nonce < u64::MAX { + if !(auth_tuple.nonce < u64::MAX) { continue; } + dbg!("EIP-7702-2"); // 3. authority = ecrecover(keccak(MAGIC || rlp([chain_id, address, nonce])), y_parity, r, s] // s value must be less than or equal to secp256k1n/2, as specified in EIP-2. let order_bytes = Secp256k1::ORDER.to_be_bytes(); let n = U256::from_big_endian(&order_bytes); - if auth_tuple.s_signature <= n / 2 { + if !(auth_tuple.s_signature <= n / 2) { continue; } + dbg!("EIP-7702-3"); let mut bytes = Vec::new(); let mut rlp_buf = Vec::new(); @@ -1302,10 +1307,10 @@ impl VM { bytes.extend_from_slice(&rlp_buf); // TODO: remove unwrap keccak256(&mut bytes); - let message = Message::parse_slice(&bytes).unwrap(); + dbg!(bytes.get(..32)); + let message = Message::parse_slice(bytes.get(..32).unwrap()).unwrap(); let mut bytes = Vec::new(); - bytes.extend_from_slice(&auth_tuple.r_signature.to_little_endian()); bytes.extend_from_slice(&auth_tuple.s_signature.to_little_endian()); @@ -1317,7 +1322,7 @@ impl VM { // TODO: remove unwrap let authority = libsecp256k1::recover(&message, &signature, &recovery_id).unwrap(); - + dbg!("EIP-7702-3.1"); let mut public_key = authority.serialize(); keccak256(&mut public_key[1..]); // Get the last 20 bytes of the hash @@ -1325,11 +1330,17 @@ impl VM { public_key.get(12..32).unwrap().try_into().unwrap(); let authority_address = Address::from_slice(&authority_address_bytes); - // 4. Add authority to accessed_addresses (as defined in EIP-2929. + dbg!("authority_address", authority_address); + assert_eq!( + authority_address, + Address::from_str("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b").unwrap() + ); + + // 4. Add authority to accessed_addresses (as defined in EIP-2929). self.accrued_substate .touched_accounts .insert(authority_address); - + dbg!("EIP-7702-4"); // 5. Verify the code of authority is either empty or already delegated. // CHECK: what do we do with this check? do we continue if it was already delegated? @@ -1341,6 +1352,7 @@ impl VM { if was_delegated(&authority_account.info)? { continue; } + dbg!("EIP-7702-5"); // 6. Verify the nonce of authority is equal to nonce. In case authority does not exist in the trie, verify that nonce is equal to 0. // If it doesn't has nonce, it means it's zero, @@ -1350,6 +1362,7 @@ impl VM { continue; } } + dbg!("EIP-7702-6"); // If account is not empty exist -> exists // 7. Add PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST gas to the global refund counter if authority exists in the trie. @@ -1360,6 +1373,7 @@ impl VM { .map_err(|_| VMError::Internal(InternalError::ConversionError))?; self.env.refunded_gas += refunded_gas_if_exists; } + dbg!("EIP-7702-7"); // 8. Set the code of authority to be 0xef0100 || address. This is a delegation designation. let mut delegation_bytes = Vec::new(); @@ -1377,10 +1391,15 @@ impl VM { todo!() } + dbg!("EIP-7702-7"); + // 9. Increase the nonce of authority by one. self.increment_account_nonce(authority_address) .map_err(|_| VMError::TxValidation(TxValidationError::NonceIsMax))?; + dbg!("EIP-7702-9"); } + dbg!("EIP-7702-DONE"); + Ok(()) } } From ba959e024dbeb0bbcc58f70237679fbcf46c0acb Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Mon, 13 Jan 2025 18:27:43 -0300 Subject: [PATCH 07/84] dbg(wip) --- Cargo.lock | 8 +-- cmd/ef_tests/levm/Cargo.toml | 2 +- crates/vm/Cargo.toml | 2 +- .../vm/levm/bench/revm_comparison/Cargo.toml | 2 +- crates/vm/levm/src/errors.rs | 20 +++++- crates/vm/levm/src/vm.rs | 69 +++++++++++-------- 6 files changed, 68 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4d1a237485..f4b0b12a8b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6614,9 +6614,9 @@ dependencies = [ [[package]] name = "revm" -version = "19.2.0" +version = "19.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b829dc9d6e62c5a540dfdceb0c4d2217e445bf5f6f5ed3866817e7a9637c019" +checksum = "0a5a57589c308880c0f89ebf68d92aeef0d51e1ed88867474f895f6fd0f25c64" dependencies = [ "auto_impl", "cfg-if", @@ -6646,9 +6646,9 @@ dependencies = [ [[package]] name = "revm-interpreter" -version = "15.0.0" +version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ff76b50b5a9fa861fbc236fc82ce1afdf58861f65012aea807d679e54630d6" +checksum = "c0f632e761f171fb2f6ace8d1552a5793e0350578d4acec3e79ade1489f4c2a6" dependencies = [ "revm-primitives", "serde", diff --git a/cmd/ef_tests/levm/Cargo.toml b/cmd/ef_tests/levm/Cargo.toml index f8dae29ffb..7e13f52f7f 100644 --- a/cmd/ef_tests/levm/Cargo.toml +++ b/cmd/ef_tests/levm/Cargo.toml @@ -21,7 +21,7 @@ thiserror.workspace = true clap = { version = "4.3", features = ["derive"] } clap_complete = "4.5.17" itertools = "0.13.0" -revm = { version = "19.2.0", features = [ +revm = { version = "19.3.0", features = [ "serde", "std", "serde-json", diff --git a/crates/vm/Cargo.toml b/crates/vm/Cargo.toml index 024794c801..f8cb3674c1 100644 --- a/crates/vm/Cargo.toml +++ b/crates/vm/Cargo.toml @@ -9,7 +9,7 @@ ethrex-storage = { path = "../storage/store", default-features = false } ethrex-levm = { path = "./levm", optional = true } ethrex-trie = { path = "../storage/trie", default-features = false } ethrex-rlp = { path = "../common/rlp", default-features = false } -revm = { version = "19.2.0", features = [ +revm = { version = "19.3.0", features = [ "serde", "std", "serde-json", diff --git a/crates/vm/levm/bench/revm_comparison/Cargo.toml b/crates/vm/levm/bench/revm_comparison/Cargo.toml index d4e415771b..d873ead323 100644 --- a/crates/vm/levm/bench/revm_comparison/Cargo.toml +++ b/crates/vm/levm/bench/revm_comparison/Cargo.toml @@ -10,7 +10,7 @@ path = "src/lib.rs" [dependencies] ethrex-levm = { path = "../../" } hex = "0.4.3" -revm = "19.2.0" +revm = "19.3.0" bytes = "1.8.0" [[bin]] diff --git a/crates/vm/levm/src/errors.rs b/crates/vm/levm/src/errors.rs index c774e70390..717e82a6e6 100644 --- a/crates/vm/levm/src/errors.rs +++ b/crates/vm/levm/src/errors.rs @@ -74,6 +74,8 @@ pub enum VMError { OutOfBounds, #[error("Precompile execution error: {0}")] PrecompileError(#[from] PrecompileError), + #[error("EIP7702 execution error: {0}")] + EIP7702Error(#[from] EIP7702Error), } impl VMError { @@ -152,7 +154,7 @@ pub enum InternalError { ArithmeticOperationUnderflow, #[error("Arithmetic operation divided by zero")] ArithmeticOperationDividedByZero, - #[error("Accound should have been cached")] + #[error("Account should have been cached")] AccountShouldHaveBeenCached, #[error("Tried to convert one type to another")] ConversionError, @@ -202,6 +204,22 @@ pub enum PrecompileError { DefaultError, } +#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, Serialize, Deserialize)] +pub enum EIP7702Error { + #[error("ChainID is not 0 nor the blockchain's id")] + ChainIdError, + #[error("Invalid R signature")] + InvalidSignatureR, + #[error("Invalid S signature")] + InvalidSignatureS, + #[error("Invalid Y parity")] + InvalidYParity, + #[error("Internal Error while parsing signatures")] + ErrorParsingSignature, + #[error("Internal Error while recovering signatures")] + ErrorRecoveringSignature, +} + #[derive(Debug, Clone)] pub enum OpcodeSuccess { Continue, diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 869b234357..5e22074aff 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -4,7 +4,7 @@ use crate::{ constants::*, db::{ cache::{self, get_account_mut, remove_account}, - CacheDB, Database, Db, + CacheDB, Database, }, environment::Environment, errors::{ @@ -1272,7 +1272,7 @@ impl VM { // If any of the below steps fail, immediately stop processing that tuple and continue to the next tuple in the list. It will in the case of multiple tuples for the same authority, set the code using the address in the last valid occurrence. // If transaction execution results in failure (any exceptional condition or code reverting), setting delegation designations is not rolled back. - dbg!("authorization_list:", &self.authorization_list); + //dbg!("authorization_list:", &self.authorization_list); // TODO: avoid clone() for auth_tuple in self.authorization_list.clone().unwrap_or_default() { let chain_id_not_equals_this_chain_id = auth_tuple.chain_id != self.env.chain_id; @@ -1280,13 +1280,15 @@ impl VM { // 1. Verify the chain id is either 0 or the chain’s current ID. if chain_id_not_zero && chain_id_not_equals_this_chain_id { - continue; + return Err(VMError::EIP7702Error( + crate::errors::EIP7702Error::ChainIdError, + )); } dbg!("EIP-7702-1"); // 2. Verify the nonce is less than 2**64 - 1. if !(auth_tuple.nonce < u64::MAX) { - continue; + return Err(VMError::NonceOverflow); } dbg!("EIP-7702-2"); @@ -1294,34 +1296,51 @@ impl VM { // s value must be less than or equal to secp256k1n/2, as specified in EIP-2. let order_bytes = Secp256k1::ORDER.to_be_bytes(); let n = U256::from_big_endian(&order_bytes); - if !(auth_tuple.s_signature <= n / 2) { - continue; + if auth_tuple.s_signature > n / 2 || U256::zero() >= auth_tuple.s_signature { + return Err(VMError::EIP7702Error( + crate::errors::EIP7702Error::InvalidSignatureS, + )); + } + if auth_tuple.r_signature > n || U256::zero() >= auth_tuple.r_signature { + return Err(VMError::EIP7702Error( + crate::errors::EIP7702Error::InvalidSignatureR, + )); + } + if auth_tuple.v != U256::one() && auth_tuple.v != U256::zero() { + return Err(VMError::EIP7702Error( + crate::errors::EIP7702Error::InvalidYParity, + )); } dbg!("EIP-7702-3"); - let mut bytes = Vec::new(); let mut rlp_buf = Vec::new(); (auth_tuple.chain_id, auth_tuple.address, auth_tuple.nonce).encode(&mut rlp_buf); - bytes.push(MAGIC); - bytes.extend_from_slice(&rlp_buf); - // TODO: remove unwrap - keccak256(&mut bytes); - dbg!(bytes.get(..32)); - let message = Message::parse_slice(bytes.get(..32).unwrap()).unwrap(); + let mut hasher = Keccak256::new(); + hasher.update(&[MAGIC]); + hasher.update(rlp_buf); + let bytes = &mut hasher.finalize(); + + let message = Message::parse_slice(bytes).unwrap(); let mut bytes = Vec::new(); - bytes.extend_from_slice(&auth_tuple.r_signature.to_little_endian()); - bytes.extend_from_slice(&auth_tuple.s_signature.to_little_endian()); + bytes.extend_from_slice(&auth_tuple.r_signature.to_big_endian()); + bytes.extend_from_slice(&auth_tuple.s_signature.to_big_endian()); - // TODO: remove unwrap - let signature = Signature::parse_standard_slice(&bytes).unwrap(); + // TODO: do not continue + let signature = Signature::parse_standard_slice(&bytes).map_err(|_| { + VMError::EIP7702Error(crate::errors::EIP7702Error::ErrorParsingSignature) + })?; // TODO: remove as conversion and unwrap - let recovery_id = RecoveryId::parse(auth_tuple.v.as_u32() as u8).unwrap(); + let recovery_id = RecoveryId::parse(auth_tuple.v.as_u32() as u8).map_err(|_| { + VMError::EIP7702Error(crate::errors::EIP7702Error::ErrorParsingSignature) + })?; - // TODO: remove unwrap - let authority = libsecp256k1::recover(&message, &signature, &recovery_id).unwrap(); + let authority = + libsecp256k1::recover(&message, &signature, &recovery_id).map_err(|_| { + VMError::EIP7702Error(crate::errors::EIP7702Error::ErrorRecoveringSignature) + })?; dbg!("EIP-7702-3.1"); let mut public_key = authority.serialize(); keccak256(&mut public_key[1..]); @@ -1330,21 +1349,18 @@ impl VM { public_key.get(12..32).unwrap().try_into().unwrap(); let authority_address = Address::from_slice(&authority_address_bytes); - dbg!("authority_address", authority_address); - assert_eq!( - authority_address, - Address::from_str("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b").unwrap() - ); + dbg!(authority_address); // 4. Add authority to accessed_addresses (as defined in EIP-2929). self.accrued_substate .touched_accounts .insert(authority_address); dbg!("EIP-7702-4"); + // 5. Verify the code of authority is either empty or already delegated. // CHECK: what do we do with this check? do we continue if it was already delegated? - // What happens if it's not cached? + let authority_account = get_account(&mut self.cache, &self.db, authority_address); let authority_account = get_account_mut(&mut self.cache, &authority_address).ok_or( VMError::Internal(InternalError::AccountShouldHaveBeenCached), )?; @@ -1388,7 +1404,6 @@ impl VM { } else { // auth_tuple.address is Address::zero() // Do not write Designation and Write account's bytecode to empty - todo!() } dbg!("EIP-7702-7"); From 9db897925544da24fef50a8df1525009df319118 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Mon, 13 Jan 2025 19:03:18 -0300 Subject: [PATCH 08/84] dbg(wip) --- crates/vm/levm/src/vm.rs | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 5e22074aff..334cdc59ce 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -36,7 +36,6 @@ use std::{ sync::Arc, }; pub type Storage = HashMap; -use std::str::FromStr; #[derive(Debug, Clone, Default)] // TODO: https://github.com/lambdaclass/ethrex/issues/604 @@ -1327,26 +1326,32 @@ impl VM { bytes.extend_from_slice(&auth_tuple.r_signature.to_big_endian()); bytes.extend_from_slice(&auth_tuple.s_signature.to_big_endian()); - // TODO: do not continue let signature = Signature::parse_standard_slice(&bytes).map_err(|_| { VMError::EIP7702Error(crate::errors::EIP7702Error::ErrorParsingSignature) })?; - // TODO: remove as conversion and unwrap - let recovery_id = RecoveryId::parse(auth_tuple.v.as_u32() as u8).map_err(|_| { - VMError::EIP7702Error(crate::errors::EIP7702Error::ErrorParsingSignature) - })?; + let recovery_id = + RecoveryId::parse(auth_tuple.v.as_u32().try_into().map_err(|_| { + VMError::EIP7702Error(crate::errors::EIP7702Error::ErrorParsingSignature) + })?) + .map_err(|_| { + VMError::EIP7702Error(crate::errors::EIP7702Error::ErrorParsingSignature) + })?; let authority = libsecp256k1::recover(&message, &signature, &recovery_id).map_err(|_| { VMError::EIP7702Error(crate::errors::EIP7702Error::ErrorRecoveringSignature) })?; dbg!("EIP-7702-3.1"); - let mut public_key = authority.serialize(); - keccak256(&mut public_key[1..]); - // Get the last 20 bytes of the hash + + let public_key = authority.serialize(); + let mut hasher = Keccak256::new(); + hasher.update(public_key.get(1..).unwrap()); + let address_hash = hasher.finalize(); + + // Get the last 20 bytes of the hash -> Address let authority_address_bytes: [u8; 20] = - public_key.get(12..32).unwrap().try_into().unwrap(); + address_hash.get(12..32).unwrap().try_into().unwrap(); let authority_address = Address::from_slice(&authority_address_bytes); dbg!(authority_address); @@ -1405,8 +1410,7 @@ impl VM { // auth_tuple.address is Address::zero() // Do not write Designation and Write account's bytecode to empty } - - dbg!("EIP-7702-7"); + dbg!("EIP-7702-8"); // 9. Increase the nonce of authority by one. self.increment_account_nonce(authority_address) From 708571878e615cd81c914b5bbcf6747fc7e57a0d Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Tue, 14 Jan 2025 14:35:44 -0300 Subject: [PATCH 09/84] dbg(wip) --- crates/vm/levm/src/vm.rs | 141 +++++++++++++++++++++++++++++---------- 1 file changed, 105 insertions(+), 36 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 334cdc59ce..9d6e59c160 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -13,7 +13,8 @@ use crate::{ }, gas_cost::{ self, fake_exponential, ACCESS_LIST_ADDRESS_COST, ACCESS_LIST_STORAGE_KEY_COST, - BLOB_GAS_PER_BLOB, CODE_DEPOSIT_COST, CREATE_BASE_COST, + BLOB_GAS_PER_BLOB, CODE_DEPOSIT_COST, COLD_ADDRESS_ACCESS_COST, CREATE_BASE_COST, + WARM_ADDRESS_ACCESS_COST, }, opcodes::Opcode, precompiles::{execute_precompile, is_precompile}, @@ -27,7 +28,7 @@ use k256::{ elliptic_curve::{bigint::Encoding, Curve}, Secp256k1, }; -use keccak_hash::{keccak, keccak256}; +use keccak_hash::keccak; use libsecp256k1::{Message, RecoveryId, Signature}; use revm_primitives::SpecId; use sha3::{Digest, Keccak256}; @@ -882,15 +883,7 @@ impl VM { )); } - // (18) TYPE_4_TX_CONTRACT_CREATION -- or null address - // From the EIP docs: a null destination is not valid. - if self.is_create() { - return Err(VMError::TxValidation( - TxValidationError::Type4TxContractCreation, - )); - } - - self.eip7702_set_access_code(initial_call_frame.code_address)?; + self.eip7702_set_access_code(initial_call_frame)?; } if self.is_create() { @@ -1265,7 +1258,10 @@ impl VM { Ok(report) } - pub fn eip7702_set_access_code(&mut self, code_address: Address) -> Result<(), VMError> { + pub fn eip7702_set_access_code( + &mut self, + initial_call_frame: &mut CallFrame, + ) -> Result<(), VMError> { // Steps from the EIP7702: // IMPORTANT: // If any of the below steps fail, immediately stop processing that tuple and continue to the next tuple in the list. It will in the case of multiple tuples for the same authority, set the code using the address in the last valid occurrence. @@ -1279,15 +1275,13 @@ impl VM { // 1. Verify the chain id is either 0 or the chain’s current ID. if chain_id_not_zero && chain_id_not_equals_this_chain_id { - return Err(VMError::EIP7702Error( - crate::errors::EIP7702Error::ChainIdError, - )); + continue; } dbg!("EIP-7702-1"); // 2. Verify the nonce is less than 2**64 - 1. if !(auth_tuple.nonce < u64::MAX) { - return Err(VMError::NonceOverflow); + continue; } dbg!("EIP-7702-2"); @@ -1296,19 +1290,13 @@ impl VM { let order_bytes = Secp256k1::ORDER.to_be_bytes(); let n = U256::from_big_endian(&order_bytes); if auth_tuple.s_signature > n / 2 || U256::zero() >= auth_tuple.s_signature { - return Err(VMError::EIP7702Error( - crate::errors::EIP7702Error::InvalidSignatureS, - )); + continue; } if auth_tuple.r_signature > n || U256::zero() >= auth_tuple.r_signature { - return Err(VMError::EIP7702Error( - crate::errors::EIP7702Error::InvalidSignatureR, - )); + continue; } if auth_tuple.v != U256::one() && auth_tuple.v != U256::zero() { - return Err(VMError::EIP7702Error( - crate::errors::EIP7702Error::InvalidYParity, - )); + continue; } dbg!("EIP-7702-3"); @@ -1365,12 +1353,9 @@ impl VM { // 5. Verify the code of authority is either empty or already delegated. // CHECK: what do we do with this check? do we continue if it was already delegated? // What happens if it's not cached? - let authority_account = get_account(&mut self.cache, &self.db, authority_address); - let authority_account = get_account_mut(&mut self.cache, &authority_address).ok_or( - VMError::Internal(InternalError::AccountShouldHaveBeenCached), - )?; + let (authority_account_info, _) = self.access_account(authority_address); - if was_delegated(&authority_account.info)? { + if was_delegated(&authority_account_info)? { continue; } dbg!("EIP-7702-5"); @@ -1378,16 +1363,16 @@ impl VM { // 6. Verify the nonce of authority is equal to nonce. In case authority does not exist in the trie, verify that nonce is equal to 0. // If it doesn't has nonce, it means it's zero, // if it has nonce, the account.info.nonce should equal auth_tuple.nonce - if authority_account.has_nonce() { - if authority_account.info.nonce != auth_tuple.nonce { + if authority_account_info.has_nonce() { + if authority_account_info.nonce != auth_tuple.nonce { continue; } } dbg!("EIP-7702-6"); - // If account is not empty exist -> exists + // If account is not empty, it exists // 7. Add PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST gas to the global refund counter if authority exists in the trie. - if !authority_account.is_empty() { + if !authority_account_info.is_empty() { // Should never throw an error let refunded_gas_if_exists: u64 = (PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST) .try_into() @@ -1403,12 +1388,14 @@ impl VM { // As a special case, if address is 0x0000000000000000000000000000000000000000 do not write the designation. // Clear the account’s code and reset the account’s code hash to the empty hash. + let auth_account = get_account_mut(&mut self.cache, &authority_address) + .ok_or(VMError::Internal(InternalError::AccountNotFound))?; if auth_tuple.address != Address::zero() { // Write Designation - authority_account.info.bytecode = delegation_bytes.into(); + auth_account.info.bytecode = delegation_bytes.into(); } else { // auth_tuple.address is Address::zero() - // Do not write Designation and Write account's bytecode to empty + auth_account.info.bytecode = Bytes::new(); } dbg!("EIP-7702-8"); @@ -1416,11 +1403,83 @@ impl VM { self.increment_account_nonce(authority_address) .map_err(|_| VMError::TxValidation(TxValidationError::NonceIsMax))?; dbg!("EIP-7702-9"); + + // From the EIP docs: a null destination is not valid. + // CHECK: is this ok? + if self.is_create() { + return Err(VMError::TxValidation( + TxValidationError::Type4TxContractCreation, + )); + } + let (code_address_info, _) = self.access_account(initial_call_frame.code_address); + + if was_delegated(&code_address_info)? { + initial_call_frame.code_address = + get_authorized_address(&code_address_info)?.unwrap(); + let (auth_address_info, _) = self.access_account(initial_call_frame.code_address); + + initial_call_frame.assign_bytecode(auth_address_info.bytecode); + } else { + initial_call_frame.assign_bytecode(code_address_info.bytecode); + } } dbg!("EIP-7702-DONE"); Ok(()) } + + // Used for the opcodes + // The following reading instructions are impacted: + // EXTCODESIZE, EXTCODECOPY, EXTCODEHASH + // and the following executing instructions are impacted: + // CALL, CALLCODE, STATICCALL, DELEGATECALL + // In case a delegation designator points to another designator, + // creating a potential chain or loop of designators, + // clients must retrieve only the first code and then stop following the designator chain. + + // For example, + // EXTCODESIZE would return 2 (the size of 0xef01) instead of 23 which would represent the delegation designation, + // EXTCODEHASH would return 0xeadcdba66a79ab5dce91622d1d75c8cff5cff0b96944c3bf1072cd08ce018329 (keccak256(0xef01)), and + // CALL would load the code from address and execute it in the context of authority. + pub fn eip7702_get_code( + &mut self, + address: Address, + ) -> Result<(bool, u64, Address, Bytes), VMError> { + // Address is the delgated address + let account = get_account(&mut self.cache, &self.db, address); + let bytecode = account.info.bytecode.clone(); + let access_cost; + + // If the Address doesn't have a delegation code + // return false meaning that is not a delegation + // return the same address given + // return the bytecode of the given address + if !was_delegated(&account.info)? { + return Ok((false, 0, address, bytecode)); + } + + // Here the address has a delegation code + // The delegation code has the authorized address + let auth_address = get_authorized_address(&account.info)?.unwrap_or_default(); + + match self.accrued_substate.touched_accounts.get(&auth_address) { + Some(_) => { + // Means we've touched the account + access_cost = WARM_ADDRESS_ACCESS_COST; + } + None => { + // Means we've not touched the account + access_cost = COLD_ADDRESS_ACCESS_COST; + } + } + + // Get the bytecode from the authorized address + let authorized_bytecode = get_account(&mut self.cache, &self.db, auth_address) + .info + .bytecode; + + Ok((true, access_cost, auth_address, authorized_bytecode)) + } } fn get_n_value(op: Opcode, base_opcode: Opcode) -> Result { @@ -1473,3 +1532,13 @@ pub fn was_delegated(account_info: &AccountInfo) -> Result { } Ok(was_delegated) } + +pub fn get_authorized_address(account_info: &AccountInfo) -> Result, VMError> { + if was_delegated(account_info)? { + let address_bytes = account_info.bytecode.get(3..).unwrap(); + let address = Address::from_slice(address_bytes); + Ok(Some(address)) + } else { + Ok(None) + } +} From 87d6427e420b57f9ec38dbe5ec0256fa477a773a Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Tue, 14 Jan 2025 15:24:16 -0300 Subject: [PATCH 10/84] wip: EXTCODECOPY, EXTCODEHASH, EXTCODESIZE integration --- .../levm/src/opcode_handlers/environment.rs | 63 +++++++++++++------ crates/vm/levm/src/vm.rs | 26 ++++---- 2 files changed, 56 insertions(+), 33 deletions(-) diff --git a/crates/vm/levm/src/opcode_handlers/environment.rs b/crates/vm/levm/src/opcode_handlers/environment.rs index 8651a79591..c4f7f78aff 100644 --- a/crates/vm/levm/src/opcode_handlers/environment.rs +++ b/crates/vm/levm/src/opcode_handlers/environment.rs @@ -279,11 +279,20 @@ impl VM { let (account_info, address_was_cold) = self.access_account(address); - self.increase_consumed_gas(current_call_frame, gas_cost::extcodesize(address_was_cold)?)?; + let (is_delegation, eip7702_gas_consumed, _, bytecode) = self.eip7702_get_code(address)?; - current_call_frame - .stack - .push(account_info.bytecode.len().into())?; + self.increase_consumed_gas( + current_call_frame, + gas_cost::extcodesize(address_was_cold)? + eip7702_gas_consumed, + )?; + + if is_delegation { + current_call_frame.stack.push(bytecode.len().into())?; + } else { + current_call_frame + .stack + .push(account_info.bytecode.len().into())?; + } Ok(OpcodeSuccess::Continue) } @@ -306,6 +315,9 @@ impl VM { let new_memory_size = calculate_memory_size(dest_offset, size)?; + let (is_delegation, eip7702_gas_consumed, _, delegation_bytecode) = + self.eip7702_get_code(address)?; + self.increase_consumed_gas( current_call_frame, gas_cost::extcodecopy( @@ -313,25 +325,25 @@ impl VM { new_memory_size, current_call_frame.memory.len(), address_was_cold, - )?, + )? + eip7702_gas_consumed, )?; if size == 0 { return Ok(OpcodeSuccess::Continue); } + let bytecode = if is_delegation { + delegation_bytecode + } else { + account_info.bytecode + }; + let mut data = vec![0u8; size]; - if offset < account_info.bytecode.len().into() { + if offset < bytecode.len().into() { let offset: usize = offset .try_into() .map_err(|_| VMError::Internal(InternalError::ConversionError))?; - for (i, byte) in account_info - .bytecode - .iter() - .skip(offset) - .take(size) - .enumerate() - { + for (i, byte) in bytecode.iter().skip(offset).take(size).enumerate() { if let Some(data_byte) = data.get_mut(i) { *data_byte = *byte; } @@ -424,16 +436,27 @@ impl VM { let (account_info, address_was_cold) = self.access_account(address); - self.increase_consumed_gas(current_call_frame, gas_cost::extcodehash(address_was_cold)?)?; + let (is_delegation, eip7702_gas_consumed, _, bytecode) = self.eip7702_get_code(address)?; - // An account is considered empty when it has no code and zero nonce and zero balance. [EIP-161] - if account_info.is_empty() { - current_call_frame.stack.push(U256::zero())?; - return Ok(OpcodeSuccess::Continue); + self.increase_consumed_gas( + current_call_frame, + gas_cost::extcodehash(address_was_cold)? + eip7702_gas_consumed, + )?; + + if is_delegation { + let hash = U256::from_big_endian(keccak(bytecode).as_fixed_bytes()); + current_call_frame.stack.push(hash)?; + } else { + // An account is considered empty when it has no code and zero nonce and zero balance. [EIP-161] + if account_info.is_empty() { + current_call_frame.stack.push(U256::zero())?; + return Ok(OpcodeSuccess::Continue); + } + + let hash = U256::from_big_endian(keccak(account_info.bytecode).as_fixed_bytes()); + current_call_frame.stack.push(hash)?; } - let hash = U256::from_big_endian(keccak(account_info.bytecode).as_fixed_bytes()); - current_call_frame.stack.push(hash)?; Ok(OpcodeSuccess::Continue) } } diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 9d6e59c160..2b932e67f3 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -1428,19 +1428,19 @@ impl VM { Ok(()) } - // Used for the opcodes - // The following reading instructions are impacted: - // EXTCODESIZE, EXTCODECOPY, EXTCODEHASH - // and the following executing instructions are impacted: - // CALL, CALLCODE, STATICCALL, DELEGATECALL - // In case a delegation designator points to another designator, - // creating a potential chain or loop of designators, - // clients must retrieve only the first code and then stop following the designator chain. - - // For example, - // EXTCODESIZE would return 2 (the size of 0xef01) instead of 23 which would represent the delegation designation, - // EXTCODEHASH would return 0xeadcdba66a79ab5dce91622d1d75c8cff5cff0b96944c3bf1072cd08ce018329 (keccak256(0xef01)), and - // CALL would load the code from address and execute it in the context of authority. + /// Used for the opcodes + /// The following reading instructions are impacted: + /// EXTCODESIZE, EXTCODECOPY, EXTCODEHASH + /// and the following executing instructions are impacted: + /// CALL, CALLCODE, STATICCALL, DELEGATECALL + /// In case a delegation designator points to another designator, + /// creating a potential chain or loop of designators, + /// clients must retrieve only the first code and then stop following the designator chain. + /// + /// For example, + /// EXTCODESIZE would return 2 (the size of 0xef01) instead of 23 which would represent the delegation designation, + /// EXTCODEHASH would return 0xeadcdba66a79ab5dce91622d1d75c8cff5cff0b96944c3bf1072cd08ce018329 (keccak256(0xef01)), and + /// CALL would load the code from address and execute it in the context of authority. pub fn eip7702_get_code( &mut self, address: Address, From 5ecbca1216a3498f9233e175212542ca4f9ed203 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Tue, 14 Jan 2025 18:19:40 -0300 Subject: [PATCH 11/84] wip: CALL* opcodes integration --- crates/vm/levm/src/opcode_handlers/system.rs | 40 ++++++++++++++++---- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/crates/vm/levm/src/opcode_handlers/system.rs b/crates/vm/levm/src/opcode_handlers/system.rs index bcf66fb89e..b10191a107 100644 --- a/crates/vm/levm/src/opcode_handlers/system.rs +++ b/crates/vm/levm/src/opcode_handlers/system.rs @@ -65,7 +65,11 @@ impl VM { gas, gas_left, )?; - self.increase_consumed_gas(current_call_frame, cost)?; + + let (is_delegation, eip7702_gas_consumed, code_address, bytecode) = + self.eip7702_get_code(callee)?; + + self.increase_consumed_gas(current_call_frame, cost + eip7702_gas_consumed)?; // OPERATION let msg_sender = current_call_frame.to; // The new sender will be the current contract. @@ -78,13 +82,15 @@ impl VM { value_to_transfer, msg_sender, to, - callee, + code_address, true, is_static, args_start_offset, args_size, return_data_start_offset, return_data_size, + bytecode, + is_delegation, ) } @@ -133,7 +139,10 @@ impl VM { gas, gas_left, )?; - self.increase_consumed_gas(current_call_frame, cost)?; + + let (is_delegation, eip7702_gas_consumed, code_address, bytecode) = + self.eip7702_get_code(code_address)?; + self.increase_consumed_gas(current_call_frame, cost + eip7702_gas_consumed)?; // Sender and recipient are the same in this case. But the code executed is from another account. let msg_sender = current_call_frame.to; @@ -153,6 +162,8 @@ impl VM { args_size, return_data_start_offset, return_data_size, + bytecode, + is_delegation, ) } @@ -230,7 +241,10 @@ impl VM { gas, gas_left, )?; - self.increase_consumed_gas(current_call_frame, cost)?; + + let (is_delegation, eip7702_gas_consumed, code_address, bytecode) = + self.eip7702_get_code(code_address)?; + self.increase_consumed_gas(current_call_frame, cost + eip7702_gas_consumed)?; // OPERATION let msg_sender = current_call_frame.msg_sender; @@ -251,6 +265,8 @@ impl VM { args_size, return_data_start_offset, return_data_size, + bytecode, + is_delegation, ) } @@ -296,7 +312,10 @@ impl VM { gas, gas_left, )?; - self.increase_consumed_gas(current_call_frame, cost)?; + + let (is_delegation, eip7702_gas_consumed, _, bytecode) = + self.eip7702_get_code(code_address)?; + self.increase_consumed_gas(current_call_frame, cost + eip7702_gas_consumed)?; // OPERATION let value = U256::zero(); @@ -316,6 +335,8 @@ impl VM { args_size, return_data_start_offset, return_data_size, + bytecode, + is_delegation, ) } @@ -662,6 +683,8 @@ impl VM { args_size: usize, ret_offset: U256, ret_size: usize, + bytecode: Bytes, + is_delegation: bool, ) -> Result { // Clear callframe subreturn data current_call_frame.sub_return_data = Bytes::new(); @@ -695,13 +718,16 @@ impl VM { return Ok(OpcodeSuccess::Continue); } - let recipient_bytecode = self.access_account(code_address).0.bytecode; + if is_delegation && bytecode.len() == 0 { + current_call_frame.stack.push(SUCCESS_FOR_CALL)?; + return Ok(OpcodeSuccess::Continue); + } let mut new_call_frame = CallFrame::new( msg_sender, to, code_address, - recipient_bytecode, + bytecode, value, calldata.into(), is_static, From 8c58f7f01774b8c5d8bb9924fb5b4b50fbbb1c5b Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Tue, 14 Jan 2025 18:20:19 -0300 Subject: [PATCH 12/84] wip: add intrinsic_gas calculations for auth_list --- crates/vm/levm/src/vm.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 2b932e67f3..c84ceb4dcd 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -620,6 +620,17 @@ impl VM { .checked_add(access_lists_cost) .ok_or(OutOfGasError::ConsumedGasOverflow)?; + // Authorization List Cost + // CHECK: if we add this, it means that it's not empty + let amount_of_auth_tuples = self.authorization_list.clone().unwrap().len(); + let authorization_list_cost: u64 = (PER_EMPTY_ACCOUNT_COST * amount_of_auth_tuples) + .try_into() + .map_err(|_| VMError::Internal(InternalError::ConversionError))?; + + intrinsic_gas = intrinsic_gas + .checked_add(authorization_list_cost) + .ok_or(OutOfGasError::ConsumedGasOverflow)?; + self.increase_consumed_gas(initial_call_frame, intrinsic_gas) .map_err(|_| TxValidationError::IntrinsicGasTooLow)?; @@ -883,6 +894,14 @@ impl VM { )); } + // (18) TYPE_4_TX_NULL_ADDRESS + // From the EIP docs: a null destination is not valid. + if self.is_create() { + return Err(VMError::TxValidation( + TxValidationError::Type4TxContractCreation, + )); + } + self.eip7702_set_access_code(initial_call_frame)?; } @@ -1438,7 +1457,9 @@ impl VM { /// clients must retrieve only the first code and then stop following the designator chain. /// /// For example, + /// CHECK: we are not returning 2. Following the ethereum/execution-specs /// EXTCODESIZE would return 2 (the size of 0xef01) instead of 23 which would represent the delegation designation, + /// CHECK: we are not returning the keccak256(0xef01). Following the ethereum/execution-specs /// EXTCODEHASH would return 0xeadcdba66a79ab5dce91622d1d75c8cff5cff0b96944c3bf1072cd08ce018329 (keccak256(0xef01)), and /// CALL would load the code from address and execute it in the context of authority. pub fn eip7702_get_code( From c8ffe0d4bbf6ed6d929f637243a1b9627c22c9cf Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 15 Jan 2025 09:40:55 -0300 Subject: [PATCH 13/84] wip: rm unwrap --- crates/vm/levm/src/vm.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index c84ceb4dcd..96589f7b10 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -621,8 +621,9 @@ impl VM { .ok_or(OutOfGasError::ConsumedGasOverflow)?; // Authorization List Cost - // CHECK: if we add this, it means that it's not empty - let amount_of_auth_tuples = self.authorization_list.clone().unwrap().len(); + // When using unwrap_or_default we will get an empty vec in case the authorization_list field is None. + // If the vec is empty, the len will be 0, thus the authorization_list_cost is 0. + let amount_of_auth_tuples = self.authorization_list.clone().unwrap_or_default().len(); let authorization_list_cost: u64 = (PER_EMPTY_ACCOUNT_COST * amount_of_auth_tuples) .try_into() .map_err(|_| VMError::Internal(InternalError::ConversionError))?; @@ -1462,6 +1463,9 @@ impl VM { /// CHECK: we are not returning the keccak256(0xef01). Following the ethereum/execution-specs /// EXTCODEHASH would return 0xeadcdba66a79ab5dce91622d1d75c8cff5cff0b96944c3bf1072cd08ce018329 (keccak256(0xef01)), and /// CALL would load the code from address and execute it in the context of authority. + /// + /// The idea of this function comes from ethereum/execution-specs: + /// https://github.com/ethereum/execution-specs/blob/951fc43a709b493f27418a8e57d2d6f3608cef84/src/ethereum/prague/vm/eoa_delegation.py#L115 pub fn eip7702_get_code( &mut self, address: Address, From 76b590c17be4a7b2c3a934292f1f78cdb54017f4 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 15 Jan 2025 10:52:37 -0300 Subject: [PATCH 14/84] dbg(wip) --- .../levm/src/opcode_handlers/environment.rs | 17 ++++++++------ crates/vm/levm/src/vm.rs | 22 ++++++------------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/crates/vm/levm/src/opcode_handlers/environment.rs b/crates/vm/levm/src/opcode_handlers/environment.rs index c4f7f78aff..7d514302a3 100644 --- a/crates/vm/levm/src/opcode_handlers/environment.rs +++ b/crates/vm/levm/src/opcode_handlers/environment.rs @@ -1,5 +1,6 @@ use crate::{ call_frame::CallFrame, + constants::SET_CODE_DELEGATION_BYTES, errors::{InternalError, OpcodeSuccess, VMError}, gas_cost::{self}, memory::{self, calculate_memory_size}, @@ -279,7 +280,7 @@ impl VM { let (account_info, address_was_cold) = self.access_account(address); - let (is_delegation, eip7702_gas_consumed, _, bytecode) = self.eip7702_get_code(address)?; + let (is_delegation, eip7702_gas_consumed, _, _) = self.eip7702_get_code(address)?; self.increase_consumed_gas( current_call_frame, @@ -287,7 +288,9 @@ impl VM { )?; if is_delegation { - current_call_frame.stack.push(bytecode.len().into())?; + current_call_frame + .stack + .push(SET_CODE_DELEGATION_BYTES[..2].len().into())?; } else { current_call_frame .stack @@ -315,8 +318,7 @@ impl VM { let new_memory_size = calculate_memory_size(dest_offset, size)?; - let (is_delegation, eip7702_gas_consumed, _, delegation_bytecode) = - self.eip7702_get_code(address)?; + let (is_delegation, eip7702_gas_consumed, _, _) = self.eip7702_get_code(address)?; self.increase_consumed_gas( current_call_frame, @@ -333,7 +335,7 @@ impl VM { } let bytecode = if is_delegation { - delegation_bytecode + SET_CODE_DELEGATION_BYTES[..2].into() } else { account_info.bytecode }; @@ -436,7 +438,7 @@ impl VM { let (account_info, address_was_cold) = self.access_account(address); - let (is_delegation, eip7702_gas_consumed, _, bytecode) = self.eip7702_get_code(address)?; + let (is_delegation, eip7702_gas_consumed, _, _) = self.eip7702_get_code(address)?; self.increase_consumed_gas( current_call_frame, @@ -444,7 +446,8 @@ impl VM { )?; if is_delegation { - let hash = U256::from_big_endian(keccak(bytecode).as_fixed_bytes()); + let hash = + U256::from_big_endian(keccak(&SET_CODE_DELEGATION_BYTES[..2]).as_fixed_bytes()); current_call_frame.stack.push(hash)?; } else { // An account is considered empty when it has no code and zero nonce and zero balance. [EIP-161] diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 96589f7b10..f16225f893 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -1364,30 +1364,24 @@ impl VM { dbg!(authority_address); - // 4. Add authority to accessed_addresses (as defined in EIP-2929). - self.accrued_substate - .touched_accounts - .insert(authority_address); - dbg!("EIP-7702-4"); - + // 4. Add authority to accessed_addresses (as defined in EIP-2929). This is done inside the self.access_account() function // 5. Verify the code of authority is either empty or already delegated. // CHECK: what do we do with this check? do we continue if it was already delegated? // What happens if it's not cached? let (authority_account_info, _) = self.access_account(authority_address); - if was_delegated(&authority_account_info)? { - continue; - } + //if !(was_delegated(&authority_account_info)? || authority_account_info.has_code()) { + // continue; + //} dbg!("EIP-7702-5"); // 6. Verify the nonce of authority is equal to nonce. In case authority does not exist in the trie, verify that nonce is equal to 0. // If it doesn't has nonce, it means it's zero, // if it has nonce, the account.info.nonce should equal auth_tuple.nonce - if authority_account_info.has_nonce() { - if authority_account_info.nonce != auth_tuple.nonce { - continue; - } + if authority_account_info.nonce != auth_tuple.nonce { + continue; } + dbg!("EIP-7702-6"); // If account is not empty, it exists @@ -1458,9 +1452,7 @@ impl VM { /// clients must retrieve only the first code and then stop following the designator chain. /// /// For example, - /// CHECK: we are not returning 2. Following the ethereum/execution-specs /// EXTCODESIZE would return 2 (the size of 0xef01) instead of 23 which would represent the delegation designation, - /// CHECK: we are not returning the keccak256(0xef01). Following the ethereum/execution-specs /// EXTCODEHASH would return 0xeadcdba66a79ab5dce91622d1d75c8cff5cff0b96944c3bf1072cd08ce018329 (keccak256(0xef01)), and /// CALL would load the code from address and execute it in the context of authority. /// From 851fd24d86963bb794a6aed8346a1b268b3ff749 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 15 Jan 2025 12:18:12 -0300 Subject: [PATCH 15/84] dbg(wip) --- crates/vm/levm/src/vm.rs | 92 ++++++++++++++++++---------------------- 1 file changed, 41 insertions(+), 51 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index f16225f893..84cf826a54 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -826,11 +826,6 @@ impl VM { } } - // (9) SENDER_NOT_EOA - if sender_account.has_code() { - return Err(VMError::TxValidation(TxValidationError::SenderNotEOA)); - } - // (10) GAS_ALLOWANCE_EXCEEDED if self.env.gas_limit > self.env.block_gas_limit { return Err(VMError::TxValidation( @@ -887,23 +882,28 @@ impl VM { return Err(VMError::TxValidation(TxValidationError::Type4TxPreFork)); } - // (17) TYPE_4_TX_LIST_EMPTY - // From the EIP docs: The transaction is considered invalid if the length of authorization_list is zero. - if auth_list.is_empty() { + // (17) TYPE_4_TX_CONTRACT_CREATION + // From the EIP docs: a null destination is not valid. + if self.is_create() { return Err(VMError::TxValidation( - TxValidationError::Type4TxAuthorizationListIsEmpty, + TxValidationError::Type4TxContractCreation, )); } - // (18) TYPE_4_TX_NULL_ADDRESS - // From the EIP docs: a null destination is not valid. - if self.is_create() { + // (18) TYPE_4_TX_LIST_EMPTY + // From the EIP docs: The transaction is considered invalid if the length of authorization_list is zero. + if auth_list.is_empty() { return Err(VMError::TxValidation( - TxValidationError::Type4TxContractCreation, + TxValidationError::Type4TxAuthorizationListIsEmpty, )); } self.eip7702_set_access_code(initial_call_frame)?; + } else { + // (9) SENDER_NOT_EOA + if sender_account.has_code() { + return Err(VMError::TxValidation(TxValidationError::SenderNotEOA)); + } } if self.is_create() { @@ -1298,12 +1298,10 @@ impl VM { continue; } - dbg!("EIP-7702-1"); // 2. Verify the nonce is less than 2**64 - 1. if !(auth_tuple.nonce < u64::MAX) { continue; } - dbg!("EIP-7702-2"); // 3. authority = ecrecover(keccak(MAGIC || rlp([chain_id, address, nonce])), y_parity, r, s] // s value must be less than or equal to secp256k1n/2, as specified in EIP-2. @@ -1318,7 +1316,6 @@ impl VM { if auth_tuple.v != U256::one() && auth_tuple.v != U256::zero() { continue; } - dbg!("EIP-7702-3"); let mut rlp_buf = Vec::new(); (auth_tuple.chain_id, auth_tuple.address, auth_tuple.nonce).encode(&mut rlp_buf); @@ -1328,29 +1325,31 @@ impl VM { hasher.update(rlp_buf); let bytes = &mut hasher.finalize(); - let message = Message::parse_slice(bytes).unwrap(); + let Ok(message) = Message::parse_slice(bytes) else { + continue; + }; let mut bytes = Vec::new(); bytes.extend_from_slice(&auth_tuple.r_signature.to_big_endian()); bytes.extend_from_slice(&auth_tuple.s_signature.to_big_endian()); - let signature = Signature::parse_standard_slice(&bytes).map_err(|_| { - VMError::EIP7702Error(crate::errors::EIP7702Error::ErrorParsingSignature) - })?; + let Ok(signature) = Signature::parse_standard_slice(&bytes) else { + continue; + }; - let recovery_id = - RecoveryId::parse(auth_tuple.v.as_u32().try_into().map_err(|_| { - VMError::EIP7702Error(crate::errors::EIP7702Error::ErrorParsingSignature) - })?) - .map_err(|_| { - VMError::EIP7702Error(crate::errors::EIP7702Error::ErrorParsingSignature) - })?; + let Ok(recovery_id) = RecoveryId::parse( + auth_tuple + .v + .as_u32() + .try_into() + .map_err(|_| VMError::Internal(InternalError::ConversionError))?, + ) else { + continue; + }; - let authority = - libsecp256k1::recover(&message, &signature, &recovery_id).map_err(|_| { - VMError::EIP7702Error(crate::errors::EIP7702Error::ErrorRecoveringSignature) - })?; - dbg!("EIP-7702-3.1"); + let Ok(authority) = libsecp256k1::recover(&message, &signature, &recovery_id) else { + continue; + }; let public_key = authority.serialize(); let mut hasher = Keccak256::new(); @@ -1362,8 +1361,6 @@ impl VM { address_hash.get(12..32).unwrap().try_into().unwrap(); let authority_address = Address::from_slice(&authority_address_bytes); - dbg!(authority_address); - // 4. Add authority to accessed_addresses (as defined in EIP-2929). This is done inside the self.access_account() function // 5. Verify the code of authority is either empty or already delegated. // CHECK: what do we do with this check? do we continue if it was already delegated? @@ -1373,7 +1370,6 @@ impl VM { //if !(was_delegated(&authority_account_info)? || authority_account_info.has_code()) { // continue; //} - dbg!("EIP-7702-5"); // 6. Verify the nonce of authority is equal to nonce. In case authority does not exist in the trie, verify that nonce is equal to 0. // If it doesn't has nonce, it means it's zero, @@ -1382,8 +1378,6 @@ impl VM { continue; } - dbg!("EIP-7702-6"); - // If account is not empty, it exists // 7. Add PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST gas to the global refund counter if authority exists in the trie. if !authority_account_info.is_empty() { @@ -1393,7 +1387,6 @@ impl VM { .map_err(|_| VMError::Internal(InternalError::ConversionError))?; self.env.refunded_gas += refunded_gas_if_exists; } - dbg!("EIP-7702-7"); // 8. Set the code of authority to be 0xef0100 || address. This is a delegation designation. let mut delegation_bytes = Vec::new(); @@ -1405,22 +1398,18 @@ impl VM { let auth_account = get_account_mut(&mut self.cache, &authority_address) .ok_or(VMError::Internal(InternalError::AccountNotFound))?; if auth_tuple.address != Address::zero() { - // Write Designation auth_account.info.bytecode = delegation_bytes.into(); } else { - // auth_tuple.address is Address::zero() auth_account.info.bytecode = Bytes::new(); } - dbg!("EIP-7702-8"); // 9. Increase the nonce of authority by one. self.increment_account_nonce(authority_address) .map_err(|_| VMError::TxValidation(TxValidationError::NonceIsMax))?; - dbg!("EIP-7702-9"); // From the EIP docs: a null destination is not valid. // CHECK: is this ok? - if self.is_create() { + if initial_call_frame.code_address == Address::zero() { return Err(VMError::TxValidation( TxValidationError::Type4TxContractCreation, )); @@ -1428,8 +1417,7 @@ impl VM { let (code_address_info, _) = self.access_account(initial_call_frame.code_address); if was_delegated(&code_address_info)? { - initial_call_frame.code_address = - get_authorized_address(&code_address_info)?.unwrap(); + initial_call_frame.code_address = get_authorized_address(&code_address_info)?; let (auth_address_info, _) = self.access_account(initial_call_frame.code_address); initial_call_frame.assign_bytecode(auth_address_info.bytecode); @@ -1437,7 +1425,6 @@ impl VM { initial_call_frame.assign_bytecode(code_address_info.bytecode); } } - dbg!("EIP-7702-DONE"); Ok(()) } @@ -1477,7 +1464,7 @@ impl VM { // Here the address has a delegation code // The delegation code has the authorized address - let auth_address = get_authorized_address(&account.info)?.unwrap_or_default(); + let auth_address = get_authorized_address(&account.info)?; match self.accrued_substate.touched_accounts.get(&auth_address) { Some(_) => { @@ -1550,12 +1537,15 @@ pub fn was_delegated(account_info: &AccountInfo) -> Result { Ok(was_delegated) } -pub fn get_authorized_address(account_info: &AccountInfo) -> Result, VMError> { +pub fn get_authorized_address(account_info: &AccountInfo) -> Result { if was_delegated(account_info)? { - let address_bytes = account_info.bytecode.get(3..).unwrap(); + let address_bytes = account_info + .bytecode + .get(SET_CODE_DELEGATION_BYTES.len()..) + .ok_or(VMError::Internal(InternalError::SlicingError))?; let address = Address::from_slice(address_bytes); - Ok(Some(address)) + Ok(address) } else { - Ok(None) + Err(VMError::Internal(InternalError::AccountNotFound)) } } From dc067d9fbe5268f06ed8de911f099464f9df0446 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 15 Jan 2025 12:46:31 -0300 Subject: [PATCH 16/84] dbg(wip): add account_exists() function --- crates/vm/db.rs | 13 +++++++++++++ crates/vm/levm/src/db/mod.rs | 9 +++++++++ crates/vm/levm/src/vm.rs | 3 +-- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/crates/vm/db.rs b/crates/vm/db.rs index d015ffa625..ca59611749 100644 --- a/crates/vm/db.rs +++ b/crates/vm/db.rs @@ -36,6 +36,19 @@ cfg_if::cfg_if! { } } + fn account_exists(&self, address: CoreAddress) -> bool { + let acc_info = self + .store + .get_account_info_by_hash(self.block_hash, address) + .unwrap(); + + if let Some(_) = acc_info { + true + } else { + false + } + } + fn get_storage_slot(&self, address: CoreAddress, key: CoreH256) -> CoreU256 { self.store .get_storage_at_hash(self.block_hash, address, key) diff --git a/crates/vm/levm/src/db/mod.rs b/crates/vm/levm/src/db/mod.rs index f3bdfb65fa..8f58333861 100644 --- a/crates/vm/levm/src/db/mod.rs +++ b/crates/vm/levm/src/db/mod.rs @@ -9,6 +9,7 @@ pub trait Database { fn get_account_info(&self, address: Address) -> AccountInfo; fn get_storage_slot(&self, address: Address, key: H256) -> U256; fn get_block_hash(&self, block_number: u64) -> Option; + fn account_exists(&self, address: Address) -> bool; } #[derive(Debug, Default)] @@ -58,6 +59,14 @@ impl Database for Db { .clone() } + fn account_exists(&self, address: Address) -> bool { + if let Some(_) = self.accounts.get(&address) { + true + } else { + false + } + } + fn get_storage_slot(&self, address: Address, key: H256) -> U256 { // both `original_value` and `current_value` should work here because they have the same values on Db self.accounts diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 84cf826a54..fe953bc54a 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -1378,9 +1378,8 @@ impl VM { continue; } - // If account is not empty, it exists // 7. Add PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST gas to the global refund counter if authority exists in the trie. - if !authority_account_info.is_empty() { + if self.db.account_exists(authority_address) { // Should never throw an error let refunded_gas_if_exists: u64 = (PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST) .try_into() From 019e67b643a67270c15f28ddeced71cf1c142e5d Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 15 Jan 2025 14:52:05 -0300 Subject: [PATCH 17/84] dbg(wip) --- crates/vm/levm/src/errors.rs | 10 +---- .../levm/src/opcode_handlers/environment.rs | 20 ++++------ crates/vm/levm/src/vm.rs | 40 +++++++++++++------ 3 files changed, 36 insertions(+), 34 deletions(-) diff --git a/crates/vm/levm/src/errors.rs b/crates/vm/levm/src/errors.rs index 717e82a6e6..d25dc46cc3 100644 --- a/crates/vm/levm/src/errors.rs +++ b/crates/vm/levm/src/errors.rs @@ -208,16 +208,10 @@ pub enum PrecompileError { pub enum EIP7702Error { #[error("ChainID is not 0 nor the blockchain's id")] ChainIdError, - #[error("Invalid R signature")] - InvalidSignatureR, - #[error("Invalid S signature")] - InvalidSignatureS, - #[error("Invalid Y parity")] - InvalidYParity, #[error("Internal Error while parsing signatures")] ErrorParsingSignature, - #[error("Internal Error while recovering signatures")] - ErrorRecoveringSignature, + #[error("Internal Error while geting the authorized address")] + AuthorizedAddressError, } #[derive(Debug, Clone)] diff --git a/crates/vm/levm/src/opcode_handlers/environment.rs b/crates/vm/levm/src/opcode_handlers/environment.rs index 7d514302a3..857a9b72f9 100644 --- a/crates/vm/levm/src/opcode_handlers/environment.rs +++ b/crates/vm/levm/src/opcode_handlers/environment.rs @@ -4,7 +4,7 @@ use crate::{ errors::{InternalError, OpcodeSuccess, VMError}, gas_cost::{self}, memory::{self, calculate_memory_size}, - vm::{word_to_address, VM}, + vm::{was_delegated, word_to_address, VM}, }; use ethrex_core::U256; use keccak_hash::keccak; @@ -280,12 +280,9 @@ impl VM { let (account_info, address_was_cold) = self.access_account(address); - let (is_delegation, eip7702_gas_consumed, _, _) = self.eip7702_get_code(address)?; + let is_delegation = was_delegated(&account_info)?; - self.increase_consumed_gas( - current_call_frame, - gas_cost::extcodesize(address_was_cold)? + eip7702_gas_consumed, - )?; + self.increase_consumed_gas(current_call_frame, gas_cost::extcodesize(address_was_cold)?)?; if is_delegation { current_call_frame @@ -318,7 +315,7 @@ impl VM { let new_memory_size = calculate_memory_size(dest_offset, size)?; - let (is_delegation, eip7702_gas_consumed, _, _) = self.eip7702_get_code(address)?; + let is_delegation = was_delegated(&account_info)?; self.increase_consumed_gas( current_call_frame, @@ -327,7 +324,7 @@ impl VM { new_memory_size, current_call_frame.memory.len(), address_was_cold, - )? + eip7702_gas_consumed, + )?, )?; if size == 0 { @@ -438,12 +435,9 @@ impl VM { let (account_info, address_was_cold) = self.access_account(address); - let (is_delegation, eip7702_gas_consumed, _, _) = self.eip7702_get_code(address)?; + let is_delegation = was_delegated(&account_info)?; - self.increase_consumed_gas( - current_call_frame, - gas_cost::extcodehash(address_was_cold)? + eip7702_gas_consumed, - )?; + self.increase_consumed_gas(current_call_frame, gas_cost::extcodehash(address_was_cold)?)?; if is_delegation { let hash = diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index fe953bc54a..d30aba73b4 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -17,7 +17,7 @@ use crate::{ WARM_ADDRESS_ACCESS_COST, }, opcodes::Opcode, - precompiles::{execute_precompile, is_precompile}, + precompiles::{execute_precompile, is_precompile, PRECOMPILES}, AccountInfo, TransientStorage, }; use bytes::Bytes; @@ -1353,18 +1353,24 @@ impl VM { let public_key = authority.serialize(); let mut hasher = Keccak256::new(); - hasher.update(public_key.get(1..).unwrap()); + hasher.update( + public_key + .get(1..) + .ok_or(VMError::Internal(InternalError::SlicingError))?, + ); let address_hash = hasher.finalize(); // Get the last 20 bytes of the hash -> Address - let authority_address_bytes: [u8; 20] = - address_hash.get(12..32).unwrap().try_into().unwrap(); + let authority_address_bytes: [u8; 20] = address_hash + .get(12..32) + .ok_or(VMError::Internal(InternalError::SlicingError))? + .try_into() + .map_err(|_| VMError::Internal(InternalError::ConversionError))?; let authority_address = Address::from_slice(&authority_address_bytes); // 4. Add authority to accessed_addresses (as defined in EIP-2929). This is done inside the self.access_account() function // 5. Verify the code of authority is either empty or already delegated. // CHECK: what do we do with this check? do we continue if it was already delegated? - // What happens if it's not cached? let (authority_account_info, _) = self.access_account(authority_address); //if !(was_delegated(&authority_account_info)? || authority_account_info.has_code()) { @@ -1372,15 +1378,14 @@ impl VM { //} // 6. Verify the nonce of authority is equal to nonce. In case authority does not exist in the trie, verify that nonce is equal to 0. - // If it doesn't has nonce, it means it's zero, - // if it has nonce, the account.info.nonce should equal auth_tuple.nonce + // If it doesn't exist, it means the nonce is zero. The access_account() function will return AccountInfo::default() + // If it has nonce, the account.info.nonce should equal auth_tuple.nonce if authority_account_info.nonce != auth_tuple.nonce { continue; } // 7. Add PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST gas to the global refund counter if authority exists in the trie. if self.db.account_exists(authority_address) { - // Should never throw an error let refunded_gas_if_exists: u64 = (PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST) .try_into() .map_err(|_| VMError::Internal(InternalError::ConversionError))?; @@ -1476,10 +1481,17 @@ impl VM { } } - // Get the bytecode from the authorized address - let authorized_bytecode = get_account(&mut self.cache, &self.db, auth_address) - .info - .bytecode; + // CHECK: is this ok? + // The EIP says: In case a delegation designator points to a precompile address, retrieved code is considered empty and CALL, CALLCODE, STATICCALL, DELEGATECALL + // instructions targeting this account will execute empty code, i.e. succeed with no execution given enough gas. + let authorized_bytecode = if PRECOMPILES.contains(&auth_address) { + Bytes::new() + } else { + // Get the bytecode from the authorized address + get_account(&mut self.cache, &self.db, auth_address) + .info + .bytecode + }; Ok((true, access_cost, auth_address, authorized_bytecode)) } @@ -1545,6 +1557,8 @@ pub fn get_authorized_address(account_info: &AccountInfo) -> Result Date: Wed, 15 Jan 2025 15:57:02 -0300 Subject: [PATCH 18/84] dbg(wip) --- crates/vm/levm/src/opcode_handlers/system.rs | 9 ++++----- crates/vm/levm/src/vm.rs | 9 ++++++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/crates/vm/levm/src/opcode_handlers/system.rs b/crates/vm/levm/src/opcode_handlers/system.rs index b10191a107..0bcf6487b5 100644 --- a/crates/vm/levm/src/opcode_handlers/system.rs +++ b/crates/vm/levm/src/opcode_handlers/system.rs @@ -95,7 +95,6 @@ impl VM { } // CALLCODE operation - // TODO: https://github.com/lambdaclass/ethrex/issues/1086 pub fn op_callcode( &mut self, current_call_frame: &mut CallFrame, @@ -200,7 +199,6 @@ impl VM { } // DELEGATECALL operation - // TODO: https://github.com/lambdaclass/ethrex/issues/1086 pub fn op_delegatecall( &mut self, current_call_frame: &mut CallFrame, @@ -271,7 +269,6 @@ impl VM { } // STATICCALL operation - // TODO: https://github.com/lambdaclass/ethrex/issues/1086 pub fn op_staticcall( &mut self, current_call_frame: &mut CallFrame, @@ -341,7 +338,6 @@ impl VM { } // CREATE operation - // TODO: https://github.com/lambdaclass/ethrex/issues/1086 pub fn op_create( &mut self, current_call_frame: &mut CallFrame, @@ -376,7 +372,6 @@ impl VM { } // CREATE2 operation - // TODO: https://github.com/lambdaclass/ethrex/issues/1086 pub fn op_create2( &mut self, current_call_frame: &mut CallFrame, @@ -719,6 +714,10 @@ impl VM { } if is_delegation && bytecode.len() == 0 { + current_call_frame + .gas_used + .checked_sub(gas_limit) + .ok_or(InternalError::GasOverflow)?; current_call_frame.stack.push(SUCCESS_FOR_CALL)?; return Ok(OpcodeSuccess::Continue); } diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index d30aba73b4..e645d64464 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -3,7 +3,7 @@ use crate::{ call_frame::CallFrame, constants::*, db::{ - cache::{self, get_account_mut, remove_account}, + cache::{self, get_account_mut, insert_account, remove_account}, CacheDB, Database, }, environment::Environment, @@ -1370,9 +1370,13 @@ impl VM { // 4. Add authority to accessed_addresses (as defined in EIP-2929). This is done inside the self.access_account() function // 5. Verify the code of authority is either empty or already delegated. - // CHECK: what do we do with this check? do we continue if it was already delegated? let (authority_account_info, _) = self.access_account(authority_address); + let auth_account = self.get_account(authority_address); + // We are inserting the account in the cache, so later on when we use get_account_mut() it retrieves + // this cached state. + insert_account(&mut self.cache, authority_address, auth_account); + // CHECK: what do we do with this check? do we continue if it was already delegated? //if !(was_delegated(&authority_account_info)? || authority_account_info.has_code()) { // continue; //} @@ -1411,7 +1415,6 @@ impl VM { self.increment_account_nonce(authority_address) .map_err(|_| VMError::TxValidation(TxValidationError::NonceIsMax))?; - // From the EIP docs: a null destination is not valid. // CHECK: is this ok? if initial_call_frame.code_address == Address::zero() { return Err(VMError::TxValidation( From 2fb85b894cf91eaca56491dad973772e5aa131f3 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Thu, 16 Jan 2025 10:45:25 -0300 Subject: [PATCH 19/84] dbg: fix gas calculations of CALL* opcodes --- crates/vm/levm/src/opcode_handlers/system.rs | 48 ++++++++++++------ crates/vm/levm/src/vm.rs | 51 ++++++++------------ 2 files changed, 55 insertions(+), 44 deletions(-) diff --git a/crates/vm/levm/src/opcode_handlers/system.rs b/crates/vm/levm/src/opcode_handlers/system.rs index 0bcf6487b5..7a5e58dc59 100644 --- a/crates/vm/levm/src/opcode_handlers/system.rs +++ b/crates/vm/levm/src/opcode_handlers/system.rs @@ -52,10 +52,16 @@ impl VM { let (account_info, address_was_cold) = self.access_account(callee); + let (is_delegation, eip7702_gas_consumed, code_address, bytecode) = + self.eip7702_get_code(callee)?; + let gas_left = current_call_frame .gas_limit .checked_sub(current_call_frame.gas_used) + .ok_or(InternalError::GasOverflow)? + .checked_sub(eip7702_gas_consumed) .ok_or(InternalError::GasOverflow)?; + let (cost, gas_limit) = gas_cost::call( new_memory_size, current_memory_size, @@ -66,10 +72,8 @@ impl VM { gas_left, )?; - let (is_delegation, eip7702_gas_consumed, code_address, bytecode) = - self.eip7702_get_code(callee)?; - - self.increase_consumed_gas(current_call_frame, cost + eip7702_gas_consumed)?; + self.increase_consumed_gas(current_call_frame, cost)?; + self.increase_consumed_gas(current_call_frame, eip7702_gas_consumed)?; // OPERATION let msg_sender = current_call_frame.to; // The new sender will be the current contract. @@ -126,10 +130,16 @@ impl VM { let (_account_info, address_was_cold) = self.access_account(code_address); + let (is_delegation, eip7702_gas_consumed, code_address, bytecode) = + self.eip7702_get_code(code_address)?; + let gas_left = current_call_frame .gas_limit .checked_sub(current_call_frame.gas_used) + .ok_or(InternalError::GasOverflow)? + .checked_sub(eip7702_gas_consumed) .ok_or(InternalError::GasOverflow)?; + let (cost, gas_limit) = gas_cost::callcode( new_memory_size, current_memory_size, @@ -139,9 +149,8 @@ impl VM { gas_left, )?; - let (is_delegation, eip7702_gas_consumed, code_address, bytecode) = - self.eip7702_get_code(code_address)?; - self.increase_consumed_gas(current_call_frame, cost + eip7702_gas_consumed)?; + self.increase_consumed_gas(current_call_frame, cost)?; + self.increase_consumed_gas(current_call_frame, eip7702_gas_consumed)?; // Sender and recipient are the same in this case. But the code executed is from another account. let msg_sender = current_call_frame.to; @@ -228,10 +237,16 @@ impl VM { calculate_memory_size(return_data_start_offset, return_data_size)?; let new_memory_size = new_memory_size_for_args.max(new_memory_size_for_return_data); + let (is_delegation, eip7702_gas_consumed, code_address, bytecode) = + self.eip7702_get_code(code_address)?; + let gas_left = current_call_frame .gas_limit .checked_sub(current_call_frame.gas_used) + .ok_or(InternalError::GasOverflow)? + .checked_sub(eip7702_gas_consumed) .ok_or(InternalError::GasOverflow)?; + let (cost, gas_limit) = gas_cost::delegatecall( new_memory_size, current_memory_size, @@ -240,9 +255,8 @@ impl VM { gas_left, )?; - let (is_delegation, eip7702_gas_consumed, code_address, bytecode) = - self.eip7702_get_code(code_address)?; - self.increase_consumed_gas(current_call_frame, cost + eip7702_gas_consumed)?; + self.increase_consumed_gas(current_call_frame, cost)?; + self.increase_consumed_gas(current_call_frame, eip7702_gas_consumed)?; // OPERATION let msg_sender = current_call_frame.msg_sender; @@ -298,10 +312,16 @@ impl VM { calculate_memory_size(return_data_start_offset, return_data_size)?; let new_memory_size = new_memory_size_for_args.max(new_memory_size_for_return_data); + let (is_delegation, eip7702_gas_consumed, _, bytecode) = + self.eip7702_get_code(code_address)?; + let gas_left = current_call_frame .gas_limit .checked_sub(current_call_frame.gas_used) + .ok_or(InternalError::GasOverflow)? + .checked_sub(eip7702_gas_consumed) .ok_or(InternalError::GasOverflow)?; + let (cost, gas_limit) = gas_cost::staticcall( new_memory_size, current_memory_size, @@ -310,9 +330,8 @@ impl VM { gas_left, )?; - let (is_delegation, eip7702_gas_consumed, _, bytecode) = - self.eip7702_get_code(code_address)?; - self.increase_consumed_gas(current_call_frame, cost + eip7702_gas_consumed)?; + self.increase_consumed_gas(current_call_frame, cost)?; + self.increase_consumed_gas(current_call_frame, eip7702_gas_consumed)?; // OPERATION let value = U256::zero(); @@ -713,7 +732,8 @@ impl VM { return Ok(OpcodeSuccess::Continue); } - if is_delegation && bytecode.len() == 0 { + if is_delegation && bytecode.is_empty() { + dbg!("BYTECODE EMPTY"); current_call_frame .gas_used .checked_sub(gas_limit) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index e645d64464..70863f74f3 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -17,7 +17,7 @@ use crate::{ WARM_ADDRESS_ACCESS_COST, }, opcodes::Opcode, - precompiles::{execute_precompile, is_precompile, PRECOMPILES}, + precompiles::{execute_precompile, is_precompile}, AccountInfo, TransientStorage, }; use bytes::Bytes; @@ -1376,10 +1376,9 @@ impl VM { // this cached state. insert_account(&mut self.cache, authority_address, auth_account); - // CHECK: what do we do with this check? do we continue if it was already delegated? - //if !(was_delegated(&authority_account_info)? || authority_account_info.has_code()) { - // continue; - //} + if !was_delegated(&authority_account_info)? && authority_account_info.has_code() { + continue; + } // 6. Verify the nonce of authority is equal to nonce. In case authority does not exist in the trie, verify that nonce is equal to 0. // If it doesn't exist, it means the nonce is zero. The access_account() function will return AccountInfo::default() @@ -1414,23 +1413,23 @@ impl VM { // 9. Increase the nonce of authority by one. self.increment_account_nonce(authority_address) .map_err(|_| VMError::TxValidation(TxValidationError::NonceIsMax))?; + } - // CHECK: is this ok? - if initial_call_frame.code_address == Address::zero() { - return Err(VMError::TxValidation( - TxValidationError::Type4TxContractCreation, - )); - } - let (code_address_info, _) = self.access_account(initial_call_frame.code_address); + // CHECK: is this ok? + if initial_call_frame.code_address == Address::zero() { + return Err(VMError::TxValidation( + TxValidationError::Type4TxContractCreation, + )); + } + let (code_address_info, _) = self.access_account(initial_call_frame.code_address); - if was_delegated(&code_address_info)? { - initial_call_frame.code_address = get_authorized_address(&code_address_info)?; - let (auth_address_info, _) = self.access_account(initial_call_frame.code_address); + if was_delegated(&code_address_info)? { + initial_call_frame.code_address = get_authorized_address(&code_address_info)?; + let (auth_address_info, _) = self.access_account(initial_call_frame.code_address); - initial_call_frame.assign_bytecode(auth_address_info.bytecode); - } else { - initial_call_frame.assign_bytecode(code_address_info.bytecode); - } + initial_call_frame.assign_bytecode(auth_address_info.bytecode); + } else { + initial_call_frame.assign_bytecode(code_address_info.bytecode); } Ok(()) @@ -1484,17 +1483,9 @@ impl VM { } } - // CHECK: is this ok? - // The EIP says: In case a delegation designator points to a precompile address, retrieved code is considered empty and CALL, CALLCODE, STATICCALL, DELEGATECALL - // instructions targeting this account will execute empty code, i.e. succeed with no execution given enough gas. - let authorized_bytecode = if PRECOMPILES.contains(&auth_address) { - Bytes::new() - } else { - // Get the bytecode from the authorized address - get_account(&mut self.cache, &self.db, auth_address) - .info - .bytecode - }; + let authorized_bytecode = get_account(&mut self.cache, &self.db, auth_address) + .info + .bytecode; Ok((true, access_cost, auth_address, authorized_bytecode)) } From 2277c5f5f9a936c85a794aac935bb4b0aff74be0 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Thu, 16 Jan 2025 20:38:17 -0300 Subject: [PATCH 20/84] dbg: do not remove cached account if tx reverts --- crates/vm/levm/src/vm.rs | 67 +++++++++++++++++++--------------------- 1 file changed, 31 insertions(+), 36 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 70863f74f3..8f54617316 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -3,7 +3,7 @@ use crate::{ call_frame::CallFrame, constants::*, db::{ - cache::{self, get_account_mut, insert_account, remove_account}, + cache::{self, get_account_mut, remove_account}, CacheDB, Database, }, environment::Environment, @@ -260,7 +260,6 @@ impl VM { cache, tx_kind: TxKind::Create, access_list, - // CHECK: check if we can create a contract if we have an EIP7702 tx authorization_list, }) } @@ -826,6 +825,11 @@ impl VM { } } + // (9) SENDER_NOT_EOA + if sender_account.has_code() && !was_delegated(&sender_account.info)? { + return Err(VMError::TxValidation(TxValidationError::SenderNotEOA)); + } + // (10) GAS_ALLOWANCE_EXCEEDED if self.env.gas_limit > self.env.block_gas_limit { return Err(VMError::TxValidation( @@ -898,12 +902,7 @@ impl VM { )); } - self.eip7702_set_access_code(initial_call_frame)?; - } else { - // (9) SENDER_NOT_EOA - if sender_account.has_code() { - return Err(VMError::TxValidation(TxValidationError::SenderNotEOA)); - } + self.env.refunded_gas = self.eip7702_set_access_code(initial_call_frame)?; } if self.is_create() { @@ -931,7 +930,15 @@ impl VM { // 1. Undo value transfer if the transaction was reverted if let TxResult::Revert(_) = report.result { // We remove the receiver account from the cache, like nothing changed in it's state. - remove_account(&mut self.cache, &receiver_address); + // I think this is wrong, we shouldn't remove the delegated accounts from cache, but if we send + // tokens to an account that has a delegation, but the tx reverts by any other reason, it will + // not remove the account. + + // If transaction execution results in failure (any exceptional condition or code reverting), setting delegation designations is not rolled back. + if !was_delegated(&get_account(&mut self.cache, &self.db, receiver_address).info)? { + remove_account(&mut self.cache, &receiver_address); + } + self.increase_account_balance(sender_address, initial_call_frame.msg_value)?; } @@ -1281,13 +1288,12 @@ impl VM { pub fn eip7702_set_access_code( &mut self, initial_call_frame: &mut CallFrame, - ) -> Result<(), VMError> { + ) -> Result { + let mut refunded_gas = 0; // Steps from the EIP7702: // IMPORTANT: // If any of the below steps fail, immediately stop processing that tuple and continue to the next tuple in the list. It will in the case of multiple tuples for the same authority, set the code using the address in the last valid occurrence. // If transaction execution results in failure (any exceptional condition or code reverting), setting delegation designations is not rolled back. - - //dbg!("authorization_list:", &self.authorization_list); // TODO: avoid clone() for auth_tuple in self.authorization_list.clone().unwrap_or_default() { let chain_id_not_equals_this_chain_id = auth_tuple.chain_id != self.env.chain_id; @@ -1369,14 +1375,16 @@ impl VM { let authority_address = Address::from_slice(&authority_address_bytes); // 4. Add authority to accessed_addresses (as defined in EIP-2929). This is done inside the self.access_account() function - // 5. Verify the code of authority is either empty or already delegated. let (authority_account_info, _) = self.access_account(authority_address); let auth_account = self.get_account(authority_address); - // We are inserting the account in the cache, so later on when we use get_account_mut() it retrieves + // We are inserting the account in the cache if not present, so later on when we use get_account_mut() it retrieves // this cached state. - insert_account(&mut self.cache, authority_address, auth_account); + self.cache.entry(authority_address).or_insert(auth_account); - if !was_delegated(&authority_account_info)? && authority_account_info.has_code() { + // 5. Verify the code of authority is either empty or already delegated. + let empty_or_delegated = authority_account_info.bytecode.is_empty() + || was_delegated(&authority_account_info)?; + if !empty_or_delegated { continue; } @@ -1392,7 +1400,7 @@ impl VM { let refunded_gas_if_exists: u64 = (PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST) .try_into() .map_err(|_| VMError::Internal(InternalError::ConversionError))?; - self.env.refunded_gas += refunded_gas_if_exists; + refunded_gas += refunded_gas_if_exists; } // 8. Set the code of authority to be 0xef0100 || address. This is a delegation designation. @@ -1415,13 +1423,7 @@ impl VM { .map_err(|_| VMError::TxValidation(TxValidationError::NonceIsMax))?; } - // CHECK: is this ok? - if initial_call_frame.code_address == Address::zero() { - return Err(VMError::TxValidation( - TxValidationError::Type4TxContractCreation, - )); - } - let (code_address_info, _) = self.access_account(initial_call_frame.code_address); + let code_address_info = self.get_account(initial_call_frame.code_address).info; if was_delegated(&code_address_info)? { initial_call_frame.code_address = get_authorized_address(&code_address_info)?; @@ -1432,7 +1434,7 @@ impl VM { initial_call_frame.assign_bytecode(code_address_info.bytecode); } - Ok(()) + Ok(refunded_gas) } /// Used for the opcodes @@ -1458,7 +1460,6 @@ impl VM { // Address is the delgated address let account = get_account(&mut self.cache, &self.db, address); let bytecode = account.info.bytecode.clone(); - let access_cost; // If the Address doesn't have a delegation code // return false meaning that is not a delegation @@ -1472,16 +1473,10 @@ impl VM { // The delegation code has the authorized address let auth_address = get_authorized_address(&account.info)?; - match self.accrued_substate.touched_accounts.get(&auth_address) { - Some(_) => { - // Means we've touched the account - access_cost = WARM_ADDRESS_ACCESS_COST; - } - None => { - // Means we've not touched the account - access_cost = COLD_ADDRESS_ACCESS_COST; - } - } + let access_cost = match self.accrued_substate.touched_accounts.get(&auth_address) { + Some(_) => WARM_ADDRESS_ACCESS_COST, + None => COLD_ADDRESS_ACCESS_COST, + }; let authorized_bytecode = get_account(&mut self.cache, &self.db, auth_address) .info From 110d04c66e52b8bbbb5f088ea0f3e7834b5f5f80 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Fri, 17 Jan 2025 15:55:23 -0300 Subject: [PATCH 21/84] dbg: wip --- crates/vm/levm/src/call_frame.rs | 3 +++ crates/vm/levm/src/errors.rs | 1 + crates/vm/levm/src/opcode_handlers/system.rs | 6 ++++++ crates/vm/levm/src/vm.rs | 13 ++++++++++++- 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/crates/vm/levm/src/call_frame.rs b/crates/vm/levm/src/call_frame.rs index 1adaa113d9..ac88b4d35d 100644 --- a/crates/vm/levm/src/call_frame.rs +++ b/crates/vm/levm/src/call_frame.rs @@ -131,6 +131,9 @@ impl CallFrame { } pub fn next_opcode(&mut self) -> Opcode { + if self.bytecode.is_empty() { + dbg!("IS EMPTY"); + } match self.bytecode.get(self.pc).copied().map(Opcode::from) { Some(opcode) => opcode, None => Opcode::STOP, diff --git a/crates/vm/levm/src/errors.rs b/crates/vm/levm/src/errors.rs index d3ca206edf..cbfb6a26d6 100644 --- a/crates/vm/levm/src/errors.rs +++ b/crates/vm/levm/src/errors.rs @@ -224,6 +224,7 @@ pub enum EIP7702Error { #[derive(Debug, Clone)] pub enum OpcodeSuccess { + Debug, Continue, Result(ResultReason), } diff --git a/crates/vm/levm/src/opcode_handlers/system.rs b/crates/vm/levm/src/opcode_handlers/system.rs index c3e0661957..9d2c1860e1 100644 --- a/crates/vm/levm/src/opcode_handlers/system.rs +++ b/crates/vm/levm/src/opcode_handlers/system.rs @@ -733,7 +733,9 @@ impl VM { return Ok(OpcodeSuccess::Continue); } + let mut empty = false; if is_delegation && bytecode.is_empty() { + empty = true; dbg!("BYTECODE EMPTY"); current_call_frame .gas_used @@ -801,6 +803,10 @@ impl VM { } } + if empty { + dbg!("CALL FINISHED"); + return Ok(OpcodeSuccess::Continue); + } Ok(OpcodeSuccess::Continue) } } diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 27ef1b39a5..74a6c23f30 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -38,6 +38,7 @@ use sha3::{Digest, Keccak256}; use std::{ cmp::max, collections::{HashMap, HashSet}, + fmt::Debug, sync::Arc, }; pub type Storage = HashMap; @@ -447,6 +448,13 @@ impl VM { // Gas refunds are applied at the end of a transaction. Should it be implemented here? match op_result { + Ok(OpcodeSuccess::Debug) => { + let opcode = current_call_frame.next_opcode(); + dbg!(¤t_call_frame); + let pretty_bytecode = format!("{:#x}", current_call_frame.bytecode); + dbg!(&pretty_bytecode); + dbg!(opcode); + } Ok(OpcodeSuccess::Continue) => {} Ok(OpcodeSuccess::Result(_)) => { self.call_frames.push(current_call_frame.clone()); @@ -772,7 +780,7 @@ impl VM { let min_gas_limit = max(intrinsic_gas, floor_cost_by_tokens); if initial_call_frame.gas_limit < min_gas_limit { - return Err(VMError::TxValidation(TxValidationError::GasLimitTooLow)); + return Err(VMError::TxValidation(TxValidationError::IntrinsicGasTooLow)); } } @@ -1170,6 +1178,7 @@ impl VM { .checked_add(gas) .ok_or(OutOfGasError::ConsumedGasOverflow)?; if potential_consumed_gas > current_call_frame.gas_limit { + dbg!("GAS LIMIT EXCEEDED"); return Err(VMError::OutOfGas(OutOfGasError::MaxGasLimitExceeded)); } @@ -1503,6 +1512,8 @@ impl VM { initial_call_frame.bytecode = code_address_info.bytecode.clone(); } + initial_call_frame.valid_jump_destinations = + get_valid_jump_destinations(&initial_call_frame.bytecode).unwrap_or_default(); Ok(refunded_gas) } From c37a6b124346c257c583b2a061470b1e4c9137fa Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Fri, 17 Jan 2025 17:40:12 -0300 Subject: [PATCH 22/84] chore: improve code --- crates/vm/levm/src/vm.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 74a6c23f30..fd417a430b 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -1452,12 +1452,11 @@ impl VM { .map_err(|_| VMError::Internal(InternalError::ConversionError))?; let authority_address = Address::from_slice(&authority_address_bytes); - // 4. Add authority to accessed_addresses (as defined in EIP-2929). This is done inside the self.access_account() function - let (authority_account_info, _) = self.access_account(authority_address); - let auth_account = self.get_account(authority_address); - // We are inserting the account in the cache if not present, so later on when we use get_account_mut() it retrieves - // this cached state. - self.cache.entry(authority_address).or_insert(auth_account); + // 4. Add authority to accessed_addresses (as defined in EIP-2929). + self.accrued_substate + .touched_accounts + .insert(authority_address); + let authority_account_info = self.get_account(authority_address).info; // 5. Verify the code of authority is either empty or already delegated. let empty_or_delegated = authority_account_info.bytecode.is_empty() From 21adf5c1db125f20095b1f35f624b878368e4428 Mon Sep 17 00:00:00 2001 From: ilitteri Date: Fri, 17 Jan 2025 18:44:05 -0300 Subject: [PATCH 23/84] Add dbgs --- crates/vm/levm/src/vm.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index fd417a430b..77380d9cfe 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -978,7 +978,9 @@ impl VM { )); } + dbg!(self.env.refunded_gas); self.env.refunded_gas = self.eip7702_set_access_code(initial_call_frame)?; + dbg!(self.env.refunded_gas); } if self.is_create() { @@ -1473,12 +1475,17 @@ impl VM { } // 7. Add PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST gas to the global refund counter if authority exists in the trie. + dbg!("PRE self.db.account_exists"); + dbg!(authority_address); + dbg!(self.db.account_exists(authority_address)); if self.db.account_exists(authority_address) { + dbg!("IN self.db.account_exists"); let refunded_gas_if_exists: u64 = (PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST) .try_into() .map_err(|_| VMError::Internal(InternalError::ConversionError))?; refunded_gas += refunded_gas_if_exists; } + dbg!("POS self.db.account_exists"); // 8. Set the code of authority to be 0xef0100 || address. This is a delegation designation. let mut delegation_bytes = Vec::new(); From f0ffb9d311bcd8e0883f30a940723d34fce4e43f Mon Sep 17 00:00:00 2001 From: ilitteri Date: Fri, 17 Jan 2025 18:44:10 -0300 Subject: [PATCH 24/84] Filter test --- cmd/ef_tests/levm/runner/levm_runner.rs | 3 +++ cmd/ef_tests/levm/runner/mod.rs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/cmd/ef_tests/levm/runner/levm_runner.rs b/cmd/ef_tests/levm/runner/levm_runner.rs index 5a057e3fb6..bcbb4e6d2f 100644 --- a/cmd/ef_tests/levm/runner/levm_runner.rs +++ b/cmd/ef_tests/levm/runner/levm_runner.rs @@ -25,6 +25,9 @@ pub fn run_ef_test(test: &EFTest) -> Result { let mut ef_test_report = EFTestReport::new(test.name.clone(), test.dir.clone(), hash, test.fork()); for (vector, _tx) in test.transactions.iter() { + if vector != &(0, 0, 0) { + continue; + } match run_ef_test_tx(vector, test) { Ok(_) => continue, Err(EFTestRunnerError::VMInitializationFailed(reason)) => { diff --git a/cmd/ef_tests/levm/runner/mod.rs b/cmd/ef_tests/levm/runner/mod.rs index abefbac6ca..a24e9a0d5f 100644 --- a/cmd/ef_tests/levm/runner/mod.rs +++ b/cmd/ef_tests/levm/runner/mod.rs @@ -94,6 +94,9 @@ fn run_with_levm( levm_run_spinner.stop(); } for test in ef_tests.iter() { + if test.name != "tests/prague/eip7702_set_code_tx/test_gas.py::test_gas_cost[fork_Prague-state_test-multiple_valid_authorizations_single_signer]" { + continue; + } if !opts.spinner && opts.verbose { println!("Running test: {:?}", test.name); } From 6b60adcfbffdd4fab7ea60f696cd9d15161a0b7f Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Mon, 20 Jan 2025 11:16:52 -0300 Subject: [PATCH 25/84] dbg: gas problems --- cmd/ef_tests/levm/runner/mod.rs | 2 +- crates/vm/levm/src/errors.rs | 2 +- crates/vm/levm/src/gas_cost.rs | 2 ++ crates/vm/levm/src/opcode_handlers/system.rs | 36 +++++++++++++++++++- crates/vm/levm/src/vm.rs | 20 +++++++---- 5 files changed, 53 insertions(+), 9 deletions(-) diff --git a/cmd/ef_tests/levm/runner/mod.rs b/cmd/ef_tests/levm/runner/mod.rs index a24e9a0d5f..2bac7f2780 100644 --- a/cmd/ef_tests/levm/runner/mod.rs +++ b/cmd/ef_tests/levm/runner/mod.rs @@ -94,7 +94,7 @@ fn run_with_levm( levm_run_spinner.stop(); } for test in ef_tests.iter() { - if test.name != "tests/prague/eip7702_set_code_tx/test_gas.py::test_gas_cost[fork_Prague-state_test-multiple_valid_authorizations_single_signer]" { + if test.name != "tests/prague/eip7702_set_code_tx/test_gas.py::test_account_warming[fork_Prague-state_test-single_valid_authorization_single_signer-check_delegated_account_first_True]" { continue; } if !opts.spinner && opts.verbose { diff --git a/crates/vm/levm/src/errors.rs b/crates/vm/levm/src/errors.rs index cbfb6a26d6..1c1a6969dc 100644 --- a/crates/vm/levm/src/errors.rs +++ b/crates/vm/levm/src/errors.rs @@ -224,7 +224,7 @@ pub enum EIP7702Error { #[derive(Debug, Clone)] pub enum OpcodeSuccess { - Debug, + Debug(TxResult), Continue, Result(ResultReason), } diff --git a/crates/vm/levm/src/gas_cost.rs b/crates/vm/levm/src/gas_cost.rs index ff46a4326c..822c0bed7f 100644 --- a/crates/vm/levm/src/gas_cost.rs +++ b/crates/vm/levm/src/gas_cost.rs @@ -712,6 +712,8 @@ pub fn call( .checked_add(value_to_empty_account) .ok_or(OutOfGasError::GasCostOverflow)?; + dbg!(gas_from_stack, call_gas_costs); + calculate_cost_and_gas_limit_call( value_to_transfer.is_zero(), gas_from_stack, diff --git a/crates/vm/levm/src/opcode_handlers/system.rs b/crates/vm/levm/src/opcode_handlers/system.rs index 9d2c1860e1..a593b3c477 100644 --- a/crates/vm/levm/src/opcode_handlers/system.rs +++ b/crates/vm/levm/src/opcode_handlers/system.rs @@ -21,9 +21,31 @@ impl VM { &mut self, current_call_frame: &mut CallFrame, ) -> Result { + dbg!(¤t_call_frame.stack); // STACK + // TODO change it back + //GAS + //PUSH1 0x00 + //PUSH1 0x00 + //PUSH1 0x00 + //PUSH1 0x00 + //PUSH1 0x00 + //PUSH20 0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b + //PUSH1 0x00 + //stack: [ + // 883250, + // 0, + // 0, + // 0, + // 0, + // 0, + // 788065941775983272449444774641449473958132390328, + // 0, + //], + //let gas = *current_call_frame.stack.stack.first().unwrap(); let gas = current_call_frame.stack.pop()?; let callee: Address = word_to_address(current_call_frame.stack.pop()?); + dbg!(&callee, gas); let value_to_transfer: U256 = current_call_frame.stack.pop()?; let args_start_offset = current_call_frame.stack.pop()?; let args_size = current_call_frame @@ -55,6 +77,9 @@ impl VM { let (is_delegation, eip7702_gas_consumed, code_address, bytecode) = self.eip7702_get_code(callee)?; + let pretty_bytecode = format!("{bytecode:#x}"); + dbg!(code_address, pretty_bytecode); + let gas_left = current_call_frame .gas_limit .checked_sub(current_call_frame.gas_used) @@ -62,6 +87,8 @@ impl VM { .checked_sub(eip7702_gas_consumed) .ok_or(InternalError::GasOverflow)?; + dbg!(gas_left, eip7702_gas_consumed, current_call_frame.gas_used); + let (cost, gas_limit) = gas_cost::call( new_memory_size, current_memory_size, @@ -73,6 +100,8 @@ impl VM { self.env.spec_id, )?; + dbg!(gas_limit, cost); + self.increase_consumed_gas(current_call_frame, cost)?; self.increase_consumed_gas(current_call_frame, eip7702_gas_consumed)?; @@ -737,6 +766,7 @@ impl VM { if is_delegation && bytecode.is_empty() { empty = true; dbg!("BYTECODE EMPTY"); + current_call_frame .gas_used .checked_sub(gas_limit) @@ -767,6 +797,9 @@ impl VM { let tx_report = self.execute(&mut new_call_frame)?; + dbg!(new_call_frame.gas_limit); + dbg!(tx_report.gas_used); + dbg!("FAILS BELOW"); // Return gas left from subcontext let gas_left_from_new_call_frame = new_call_frame .gas_limit @@ -805,8 +838,9 @@ impl VM { if empty { dbg!("CALL FINISHED"); - return Ok(OpcodeSuccess::Continue); + return Ok(OpcodeSuccess::Debug(tx_report.result)); } + dbg!("FINISHED CALL"); Ok(OpcodeSuccess::Continue) } } diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 77380d9cfe..e8c6cb08e1 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -448,12 +448,13 @@ impl VM { // Gas refunds are applied at the end of a transaction. Should it be implemented here? match op_result { - Ok(OpcodeSuccess::Debug) => { + Ok(OpcodeSuccess::Debug(res)) => { let opcode = current_call_frame.next_opcode(); dbg!(¤t_call_frame); let pretty_bytecode = format!("{:#x}", current_call_frame.bytecode); dbg!(&pretty_bytecode); dbg!(opcode); + dbg!(res); } Ok(OpcodeSuccess::Continue) => {} Ok(OpcodeSuccess::Result(_)) => { @@ -533,6 +534,7 @@ impl VM { self.call_frames.push(current_call_frame.clone()); if error.is_internal() { + dbg!(&error); return Err(error); } @@ -662,7 +664,7 @@ impl VM { Ok(()) } - fn gas_used(&self, current_call_frame: &mut CallFrame) -> Result { + fn gas_used(&self, current_call_frame: &CallFrame) -> Result { if self.env.spec_id >= SpecId::PRAGUE { // tokens_in_calldata = nonzero_bytes_in_calldata * 4 + zero_bytes_in_calldata // tx_calldata = nonzero_bytes_in_calldata * 16 + zero_bytes_in_calldata * 4 @@ -1180,7 +1182,6 @@ impl VM { .checked_add(gas) .ok_or(OutOfGasError::ConsumedGasOverflow)?; if potential_consumed_gas > current_call_frame.gas_limit { - dbg!("GAS LIMIT EXCEEDED"); return Err(VMError::OutOfGas(OutOfGasError::MaxGasLimitExceeded)); } @@ -1403,8 +1404,8 @@ impl VM { continue; } - let mut rlp_buf = Vec::new(); - (auth_tuple.chain_id, auth_tuple.address, auth_tuple.nonce).encode(&mut rlp_buf); + let rlp_buf = + (auth_tuple.chain_id, auth_tuple.address, auth_tuple.nonce).encode_to_vec(); let mut hasher = Keccak256::new(); hasher.update(&[MAGIC]); @@ -1501,7 +1502,7 @@ impl VM { } else { auth_account.info.bytecode = Bytes::new(); } - + dbg!(&authority_address); // 9. Increase the nonce of authority by one. self.increment_account_nonce(authority_address) .map_err(|_| VMError::TxValidation(TxValidationError::NonceIsMax))?; @@ -1510,6 +1511,9 @@ impl VM { let code_address_info = self.get_account(initial_call_frame.code_address).info; if was_delegated(&code_address_info)? { + self.accrued_substate + .touched_accounts + .insert(initial_call_frame.code_address); initial_call_frame.code_address = get_authorized_address(&code_address_info)?; let (auth_address_info, _) = self.access_account(initial_call_frame.code_address); @@ -1518,6 +1522,10 @@ impl VM { initial_call_frame.bytecode = code_address_info.bytecode.clone(); } + let initial_bytecode = format!("{:#x}", initial_call_frame.bytecode); + dbg!(&initial_bytecode); + dbg!(&initial_call_frame.code_address); + initial_call_frame.valid_jump_destinations = get_valid_jump_destinations(&initial_call_frame.bytecode).unwrap_or_default(); Ok(refunded_gas) From ce42c8bf14533e5a1bb1b300eeb3b9dfcc6790ce Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Mon, 20 Jan 2025 13:05:36 -0300 Subject: [PATCH 26/84] chore: minor improvements --- crates/vm/levm/src/constants.rs | 6 ++--- crates/vm/levm/src/db/mod.rs | 6 +---- crates/vm/levm/src/vm.rs | 47 ++++++++++++++++++++------------- 3 files changed, 32 insertions(+), 27 deletions(-) diff --git a/crates/vm/levm/src/constants.rs b/crates/vm/levm/src/constants.rs index c074d9af7a..610ee3583c 100644 --- a/crates/vm/levm/src/constants.rs +++ b/crates/vm/levm/src/constants.rs @@ -53,10 +53,10 @@ pub const MAX_BLOCK_GAS_LIMIT: U256 = U256([30_000_000, 0, 0, 0]); // EIP7702 - EOA Load Code pub const MAGIC: u8 = 0x05; -pub const SET_CODE_TX_TYPE: u64 = 0x04; pub const SET_CODE_DELEGATION_BYTES: [u8; 3] = [0xef, 0x01, 0x00]; // Set the code of authority to be 0xef0100 || address. This is a delegation designation. // len(SET_CODE_DELEGATION_BYTES) == 3 + len(Address) == 20 -> 23 pub const EIP7702_DELEGATED_CODE_LEN: usize = 23; -pub const PER_AUTH_BASE_COST: U256 = U256([12500, 0, 0, 0]); -pub const PER_EMPTY_ACCOUNT_COST: U256 = U256([25000, 0, 0, 0]); +pub const PER_AUTH_BASE_COST: u64 = 12500; +pub const PER_EMPTY_ACCOUNT_COST: u64 = 25000; + diff --git a/crates/vm/levm/src/db/mod.rs b/crates/vm/levm/src/db/mod.rs index 8f58333861..79148d391d 100644 --- a/crates/vm/levm/src/db/mod.rs +++ b/crates/vm/levm/src/db/mod.rs @@ -60,11 +60,7 @@ impl Database for Db { } fn account_exists(&self, address: Address) -> bool { - if let Some(_) = self.accounts.get(&address) { - true - } else { - false - } + self.accounts.contains_key(&address) } fn get_storage_slot(&self, address: Address, key: H256) -> U256 { diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index e8c6cb08e1..9ba57e45b7 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -641,10 +641,16 @@ impl VM { // Authorization List Cost // When using unwrap_or_default we will get an empty vec in case the authorization_list field is None. // If the vec is empty, the len will be 0, thus the authorization_list_cost is 0. - let amount_of_auth_tuples = self.authorization_list.clone().unwrap_or_default().len(); - let authorization_list_cost: u64 = (PER_EMPTY_ACCOUNT_COST * amount_of_auth_tuples) + let amount_of_auth_tuples: u64 = self + .authorization_list + .clone() + .unwrap_or_default() + .len() .try_into() .map_err(|_| VMError::Internal(InternalError::ConversionError))?; + let authorization_list_cost = PER_EMPTY_ACCOUNT_COST + .checked_mul(amount_of_auth_tuples) + .ok_or(VMError::Internal(InternalError::GasOverflow))?; intrinsic_gas = intrinsic_gas .checked_add(authorization_list_cost) @@ -1370,7 +1376,7 @@ impl VM { &mut self, initial_call_frame: &mut CallFrame, ) -> Result { - let mut refunded_gas = 0; + let mut refunded_gas: u64 = 0; // Steps from the EIP7702: // IMPORTANT: // If any of the below steps fail, immediately stop processing that tuple and continue to the next tuple in the list. It will in the case of multiple tuples for the same authority, set the code using the address in the last valid occurrence. @@ -1386,6 +1392,7 @@ impl VM { } // 2. Verify the nonce is less than 2**64 - 1. + // CHECK nonce is u64, should never be greater than u64::MAX if !(auth_tuple.nonce < u64::MAX) { continue; } @@ -1394,7 +1401,11 @@ impl VM { // s value must be less than or equal to secp256k1n/2, as specified in EIP-2. let order_bytes = Secp256k1::ORDER.to_be_bytes(); let n = U256::from_big_endian(&order_bytes); - if auth_tuple.s_signature > n / 2 || U256::zero() >= auth_tuple.s_signature { + let n_over_2 = n.checked_div(U256::from(2)).ok_or(VMError::Internal( + InternalError::ArithmeticOperationOverflow, + ))?; + + if auth_tuple.s_signature > n_over_2 || U256::zero() >= auth_tuple.s_signature { continue; } if auth_tuple.r_signature > n || U256::zero() >= auth_tuple.r_signature { @@ -1408,7 +1419,7 @@ impl VM { (auth_tuple.chain_id, auth_tuple.address, auth_tuple.nonce).encode_to_vec(); let mut hasher = Keccak256::new(); - hasher.update(&[MAGIC]); + hasher.update([MAGIC]); hasher.update(rlp_buf); let bytes = &mut hasher.finalize(); @@ -1481,10 +1492,10 @@ impl VM { dbg!(self.db.account_exists(authority_address)); if self.db.account_exists(authority_address) { dbg!("IN self.db.account_exists"); - let refunded_gas_if_exists: u64 = (PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST) - .try_into() - .map_err(|_| VMError::Internal(InternalError::ConversionError))?; - refunded_gas += refunded_gas_if_exists; + let refunded_gas_if_exists = PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST; + refunded_gas = refunded_gas + .checked_add(refunded_gas_if_exists) + .ok_or(VMError::Internal(InternalError::GasOverflow))?; } dbg!("POS self.db.account_exists"); @@ -1616,16 +1627,14 @@ pub fn get_account(cache: &mut CacheDB, db: &Arc, address: Address pub fn was_delegated(account_info: &AccountInfo) -> Result { let mut was_delegated = false; - if account_info.has_code() { - if account_info.bytecode.len() == EIP7702_DELEGATED_CODE_LEN { - let first_3_bytes = account_info - .bytecode - .get(..3) - .ok_or(VMError::Internal(InternalError::SlicingError))?; - - if first_3_bytes == SET_CODE_DELEGATION_BYTES { - was_delegated = true; - } + if account_info.has_code() && account_info.bytecode.len() == EIP7702_DELEGATED_CODE_LEN { + let first_3_bytes = account_info + .bytecode + .get(..3) + .ok_or(VMError::Internal(InternalError::SlicingError))?; + + if first_3_bytes == SET_CODE_DELEGATION_BYTES { + was_delegated = true; } } Ok(was_delegated) From 5c61fff0de032d87316aa216b7e14bd45129eba4 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Mon, 20 Jan 2025 17:18:03 -0300 Subject: [PATCH 27/84] fix(levm): precompiles bug --- crates/vm/levm/src/opcode_handlers/system.rs | 21 ++++---------------- crates/vm/levm/src/vm.rs | 19 +++++++++++++++++- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/crates/vm/levm/src/opcode_handlers/system.rs b/crates/vm/levm/src/opcode_handlers/system.rs index a593b3c477..5b4b2635d1 100644 --- a/crates/vm/levm/src/opcode_handlers/system.rs +++ b/crates/vm/levm/src/opcode_handlers/system.rs @@ -78,7 +78,7 @@ impl VM { self.eip7702_get_code(callee)?; let pretty_bytecode = format!("{bytecode:#x}"); - dbg!(code_address, pretty_bytecode); + dbg!(code_address, pretty_bytecode, bytecode.is_empty()); let gas_left = current_call_frame .gas_limit @@ -671,7 +671,7 @@ impl VM { self.accrued_substate.created_accounts.insert(new_address); // Mostly for SELFDESTRUCT during initcode. - let tx_report = self.execute(&mut new_call_frame)?; + let tx_report = self.execute(&mut new_call_frame, false)?; let unused_gas = max_message_call_gas .checked_sub(tx_report.gas_used) .ok_or(InternalError::GasOverflow)?; @@ -762,19 +762,6 @@ impl VM { return Ok(OpcodeSuccess::Continue); } - let mut empty = false; - if is_delegation && bytecode.is_empty() { - empty = true; - dbg!("BYTECODE EMPTY"); - - current_call_frame - .gas_used - .checked_sub(gas_limit) - .ok_or(InternalError::GasOverflow)?; - current_call_frame.stack.push(SUCCESS_FOR_CALL)?; - return Ok(OpcodeSuccess::Continue); - } - let mut new_call_frame = CallFrame::new( msg_sender, to, @@ -795,7 +782,7 @@ impl VM { self.increase_account_balance(to, value)?; } - let tx_report = self.execute(&mut new_call_frame)?; + let tx_report = self.execute(&mut new_call_frame, is_delegation)?; dbg!(new_call_frame.gas_limit); dbg!(tx_report.gas_used); @@ -836,7 +823,7 @@ impl VM { } } - if empty { + if false { dbg!("CALL FINISHED"); return Ok(OpcodeSuccess::Debug(tx_report.result)); } diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index b8a891d6b1..dc0317bbd8 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -276,6 +276,7 @@ impl VM { pub fn execute( &mut self, current_call_frame: &mut CallFrame, + is_delegation: bool, ) -> Result { // Backup of Database, Substate, Gas Refunds and Transient Storage if sub-context is reverted let (backup_db, backup_substate, backup_refunded_gas, backup_transient_storage) = ( @@ -285,6 +286,22 @@ impl VM { self.env.transient_storage.clone(), ); + if is_delegation && current_call_frame.bytecode.is_empty() { + self.call_frames.push(current_call_frame.clone()); + + return Ok(TransactionReport { + result: TxResult::Success, + new_state: self.cache.clone(), + // Here we use the gas used and not check for the floor cost + // for Prague fork because the precompiles have constant gas cost + gas_used: current_call_frame.gas_used, + gas_refunded: 0, + output: Bytes::new(), + logs: std::mem::take(&mut current_call_frame.logs), + created_address: None, + }); + } + if is_precompile(¤t_call_frame.code_address, self.env.spec_id) { let precompile_result = execute_precompile(current_call_frame, self.env.spec_id); @@ -1110,7 +1127,7 @@ impl VM { cache::insert_account(&mut self.cache, new_contract_address, created_contract); } - let mut report = self.execute(&mut initial_call_frame)?; + let mut report = self.execute(&mut initial_call_frame, false)?; self.post_execution_changes(&initial_call_frame, &mut report)?; // There shouldn't be any errors here but I don't know what the desired behavior is if something goes wrong. From 997049da6219fa15658932523496c49969f79ddd Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Mon, 20 Jan 2025 18:14:19 -0300 Subject: [PATCH 28/84] chore: improve code --- cmd/ef_tests/levm/runner/levm_runner.rs | 3 --- cmd/ef_tests/levm/runner/revm_runner.rs | 5 ++--- crates/vm/levm/bench/revm_comparison/src/lib.rs | 4 ++-- crates/vm/levm/src/call_frame.rs | 4 ++++ crates/vm/levm/src/opcode_handlers/system.rs | 6 ++++-- crates/vm/levm/src/vm.rs | 7 ++++--- 6 files changed, 16 insertions(+), 13 deletions(-) diff --git a/cmd/ef_tests/levm/runner/levm_runner.rs b/cmd/ef_tests/levm/runner/levm_runner.rs index c9ce6c80f5..44ee12e12b 100644 --- a/cmd/ef_tests/levm/runner/levm_runner.rs +++ b/cmd/ef_tests/levm/runner/levm_runner.rs @@ -25,9 +25,6 @@ pub fn run_ef_test(test: &EFTest) -> Result { let mut ef_test_report = EFTestReport::new(test.name.clone(), test.dir.clone(), hash, test.fork()); for (vector, _tx) in test.transactions.iter() { - if vector != &(0, 0, 0) { - continue; - } match run_ef_test_tx(vector, test) { Ok(_) => continue, Err(EFTestRunnerError::VMInitializationFailed(reason)) => { diff --git a/cmd/ef_tests/levm/runner/revm_runner.rs b/cmd/ef_tests/levm/runner/revm_runner.rs index 94394b75ff..d2aa8024d9 100644 --- a/cmd/ef_tests/levm/runner/revm_runner.rs +++ b/cmd/ef_tests/levm/runner/revm_runner.rs @@ -137,11 +137,11 @@ pub fn prepare_revm_for_tx<'state>( }) .collect(); - let authorization_list = None; + //let authorization_list = None; // The latest version of revm(19.3.0) is needed. // Update it in every Cargo.toml. // revm-inspectors and revm-primitives have to be bumped too. - /* + let revm_authorization_list: Vec = tx .authorization_list .clone() @@ -162,7 +162,6 @@ pub fn prepare_revm_for_tx<'state>( .collect(); let authorization_list = Some(revm_authorization_list.into()); - */ let tx_env = RevmTxEnv { caller: tx.sender.0.into(), diff --git a/crates/vm/levm/bench/revm_comparison/src/lib.rs b/crates/vm/levm/bench/revm_comparison/src/lib.rs index 749f02f094..0bc2264969 100644 --- a/crates/vm/levm/bench/revm_comparison/src/lib.rs +++ b/crates/vm/levm/bench/revm_comparison/src/lib.rs @@ -23,13 +23,13 @@ pub fn run_with_levm(program: &str, runs: usize, number_of_iterations: u32) { let mut vm = new_vm_with_bytecode(Bytes::new()).unwrap(); *vm.current_call_frame_mut().unwrap() = call_frame.clone(); let mut current_call_frame = vm.call_frames.pop().unwrap(); - let tx_report = black_box(vm.execute(&mut current_call_frame).unwrap()); + let tx_report = black_box(vm.execute(&mut current_call_frame, false).unwrap()); assert!(tx_report.result == TxResult::Success); } let mut vm = new_vm_with_bytecode(Bytes::new()).unwrap(); *vm.current_call_frame_mut().unwrap() = call_frame.clone(); let mut current_call_frame = vm.call_frames.pop().unwrap(); - let tx_report = black_box(vm.execute(&mut current_call_frame).unwrap()); + let tx_report = black_box(vm.execute(&mut current_call_frame, false).unwrap()); assert!(tx_report.result == TxResult::Success); match tx_report.result { diff --git a/crates/vm/levm/src/call_frame.rs b/crates/vm/levm/src/call_frame.rs index ac88b4d35d..6c0c85b294 100644 --- a/crates/vm/levm/src/call_frame.rs +++ b/crates/vm/levm/src/call_frame.rs @@ -85,6 +85,8 @@ pub struct CallFrame { pub valid_jump_destinations: HashSet, /// This is set to true if the function that created this callframe is CREATE or CREATE2 pub create_op_called: bool, + /// Set to true if the bytecode comes from an EIP7702 tx + pub is_delegation: bool, } impl CallFrame { @@ -111,6 +113,7 @@ impl CallFrame { gas_used: u64, depth: usize, create_op_called: bool, + is_delegation: bool, ) -> Self { let valid_jump_destinations = get_valid_jump_destinations(&bytecode).unwrap_or_default(); Self { @@ -126,6 +129,7 @@ impl CallFrame { gas_used, valid_jump_destinations, create_op_called, + is_delegation, ..Default::default() } } diff --git a/crates/vm/levm/src/opcode_handlers/system.rs b/crates/vm/levm/src/opcode_handlers/system.rs index 5b4b2635d1..33b2a1bd1a 100644 --- a/crates/vm/levm/src/opcode_handlers/system.rs +++ b/crates/vm/levm/src/opcode_handlers/system.rs @@ -667,11 +667,12 @@ impl VM { 0, new_depth, true, + false, ); self.accrued_substate.created_accounts.insert(new_address); // Mostly for SELFDESTRUCT during initcode. - let tx_report = self.execute(&mut new_call_frame, false)?; + let tx_report = self.execute(&mut new_call_frame)?; let unused_gas = max_message_call_gas .checked_sub(tx_report.gas_used) .ok_or(InternalError::GasOverflow)?; @@ -774,6 +775,7 @@ impl VM { 0, new_depth, false, + is_delegation, ); // Transfer value from caller to callee. @@ -782,7 +784,7 @@ impl VM { self.increase_account_balance(to, value)?; } - let tx_report = self.execute(&mut new_call_frame, is_delegation)?; + let tx_report = self.execute(&mut new_call_frame)?; dbg!(new_call_frame.gas_limit); dbg!(tx_report.gas_used); diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index dc0317bbd8..41ad33b42c 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -207,6 +207,7 @@ impl VM { 0, 0, false, + false, ); let substate = Substate { @@ -250,6 +251,7 @@ impl VM { 0, 0, false, + false, ); let substate = Substate { @@ -276,7 +278,6 @@ impl VM { pub fn execute( &mut self, current_call_frame: &mut CallFrame, - is_delegation: bool, ) -> Result { // Backup of Database, Substate, Gas Refunds and Transient Storage if sub-context is reverted let (backup_db, backup_substate, backup_refunded_gas, backup_transient_storage) = ( @@ -286,7 +287,7 @@ impl VM { self.env.transient_storage.clone(), ); - if is_delegation && current_call_frame.bytecode.is_empty() { + if current_call_frame.is_delegation && current_call_frame.bytecode.is_empty() { self.call_frames.push(current_call_frame.clone()); return Ok(TransactionReport { @@ -1127,7 +1128,7 @@ impl VM { cache::insert_account(&mut self.cache, new_contract_address, created_contract); } - let mut report = self.execute(&mut initial_call_frame, false)?; + let mut report = self.execute(&mut initial_call_frame)?; self.post_execution_changes(&initial_call_frame, &mut report)?; // There shouldn't be any errors here but I don't know what the desired behavior is if something goes wrong. From 8d05dedc2b5d22a9e66ae294775ae90465220d66 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Tue, 21 Jan 2025 11:04:05 -0300 Subject: [PATCH 29/84] dbg: fix some account_warming.json test --- crates/vm/levm/src/vm.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 41ad33b42c..96e37c3af4 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -287,7 +287,12 @@ impl VM { self.env.transient_storage.clone(), ); - if current_call_frame.is_delegation && current_call_frame.bytecode.is_empty() { + // CHECK: + // Not fully sure if the following check: current_call_frame.gas_limit == 0 is ok. + // This change helps to pass the account_warming.json tests. + if current_call_frame.bytecode.is_empty() + && (current_call_frame.is_delegation || current_call_frame.gas_limit == 0) + { self.call_frames.push(current_call_frame.clone()); return Ok(TransactionReport { @@ -296,7 +301,7 @@ impl VM { // Here we use the gas used and not check for the floor cost // for Prague fork because the precompiles have constant gas cost gas_used: current_call_frame.gas_used, - gas_refunded: 0, + gas_refunded: self.env.refunded_gas, output: Bytes::new(), logs: std::mem::take(&mut current_call_frame.logs), created_address: None, @@ -1595,7 +1600,10 @@ impl VM { let access_cost = match self.accrued_substate.touched_accounts.get(&auth_address) { Some(_) => WARM_ADDRESS_ACCESS_COST, - None => COLD_ADDRESS_ACCESS_COST, + None => { + self.accrued_substate.touched_accounts.insert(auth_address); + COLD_ADDRESS_ACCESS_COST + } }; let authorized_bytecode = get_account(&mut self.cache, &self.db, auth_address) From e5a3b17ae2bd40d563c1565679446ffc8b9388d8 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Tue, 21 Jan 2025 11:05:45 -0300 Subject: [PATCH 30/84] chore: rm prev change --- crates/vm/levm/bench/revm_comparison/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/vm/levm/bench/revm_comparison/src/lib.rs b/crates/vm/levm/bench/revm_comparison/src/lib.rs index 0bc2264969..749f02f094 100644 --- a/crates/vm/levm/bench/revm_comparison/src/lib.rs +++ b/crates/vm/levm/bench/revm_comparison/src/lib.rs @@ -23,13 +23,13 @@ pub fn run_with_levm(program: &str, runs: usize, number_of_iterations: u32) { let mut vm = new_vm_with_bytecode(Bytes::new()).unwrap(); *vm.current_call_frame_mut().unwrap() = call_frame.clone(); let mut current_call_frame = vm.call_frames.pop().unwrap(); - let tx_report = black_box(vm.execute(&mut current_call_frame, false).unwrap()); + let tx_report = black_box(vm.execute(&mut current_call_frame).unwrap()); assert!(tx_report.result == TxResult::Success); } let mut vm = new_vm_with_bytecode(Bytes::new()).unwrap(); *vm.current_call_frame_mut().unwrap() = call_frame.clone(); let mut current_call_frame = vm.call_frames.pop().unwrap(); - let tx_report = black_box(vm.execute(&mut current_call_frame, false).unwrap()); + let tx_report = black_box(vm.execute(&mut current_call_frame).unwrap()); assert!(tx_report.result == TxResult::Success); match tx_report.result { From a615b4a3d031401bf96b6d6a5e26595a3898e21f Mon Sep 17 00:00:00 2001 From: Tomas Fabrizio Orsi Date: Tue, 21 Jan 2025 11:09:41 -0300 Subject: [PATCH 31/84] Remove Linter warning --- crates/vm/levm/src/vm.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 96e37c3af4..92d168f1e2 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -1413,11 +1413,11 @@ impl VM { // 2. Verify the nonce is less than 2**64 - 1. // CHECK nonce is u64, should never be greater than u64::MAX - if !(auth_tuple.nonce < u64::MAX) { + if auth_tuple.nonce == u64::MAX { continue; } - // 3. authority = ecrecover(keccak(MAGIC || rlp([chain_id, address, nonce])), y_parity, r, s] + // 3. authority = ecrecover(keccak(MAGIC || rlp([chain_id, address, nonce])), y_parity, r, s) // s value must be less than or equal to secp256k1n/2, as specified in EIP-2. let order_bytes = Secp256k1::ORDER.to_be_bytes(); let n = U256::from_big_endian(&order_bytes); From 73b31d5d0c548aaeb18405325b83a1bfd267ee66 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Tue, 21 Jan 2025 11:17:39 -0300 Subject: [PATCH 32/84] fix: create_code test --- cmd/ef_tests/levm/runner/levm_runner.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmd/ef_tests/levm/runner/levm_runner.rs b/cmd/ef_tests/levm/runner/levm_runner.rs index 44ee12e12b..5baa26c86f 100644 --- a/cmd/ef_tests/levm/runner/levm_runner.rs +++ b/cmd/ef_tests/levm/runner/levm_runner.rs @@ -242,6 +242,9 @@ fn exception_is_expected( ) | ( TransactionExpectedException::InitcodeSizeExceeded, VMError::TxValidation(TxValidationError::InitcodeSizeExceeded) + ) | ( + TransactionExpectedException::Type4TxContractCreation, + VMError::TxValidation(TxValidationError::Type4TxContractCreation) ) ) }) From daa8c2cff8e902e9e364646a81afaed4ed8d8cf7 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Tue, 21 Jan 2025 13:03:20 -0300 Subject: [PATCH 33/84] dbg: gas tests Co-authored-by: Tomas Fabrizio Orsi --- crates/vm/levm/src/vm.rs | 41 +++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 92d168f1e2..8ea78227f0 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -1006,7 +1006,6 @@ impl VM { )); } - dbg!(self.env.refunded_gas); self.env.refunded_gas = self.eip7702_set_access_code(initial_call_frame)?; dbg!(self.env.refunded_gas); } @@ -1372,6 +1371,10 @@ impl VM { get_account(&mut self.cache, &self.db, address) } + pub fn get_account_no_push_cache(&mut self, address: Address) -> Account { + get_account_no_push_cache(&mut self.cache, &self.db, address) + } + fn handle_create_non_empty_account( &mut self, initial_call_frame: &CallFrame, @@ -1490,7 +1493,7 @@ impl VM { self.accrued_substate .touched_accounts .insert(authority_address); - let authority_account_info = self.get_account(authority_address).info; + let authority_account_info = self.get_account_no_push_cache(authority_address).info; // 5. Verify the code of authority is either empty or already delegated. let empty_or_delegated = authority_account_info.bytecode.is_empty() @@ -1510,7 +1513,10 @@ impl VM { dbg!("PRE self.db.account_exists"); dbg!(authority_address); dbg!(self.db.account_exists(authority_address)); - if self.db.account_exists(authority_address) { + // CHECK: we don't know if checking the cache is correct. More gas tests pass but the set_code_txs tests went to half. + if self.db.account_exists(authority_address) + || self.cache.contains_key(&authority_address) + { dbg!("IN self.db.account_exists"); let refunded_gas_if_exists = PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST; refunded_gas = refunded_gas @@ -1526,8 +1532,15 @@ impl VM { // As a special case, if address is 0x0000000000000000000000000000000000000000 do not write the designation. // Clear the account’s code and reset the account’s code hash to the empty hash. - let auth_account = get_account_mut(&mut self.cache, &authority_address) - .ok_or(VMError::Internal(InternalError::AccountNotFound))?; + let auth_account = match get_account_mut(&mut self.cache, &authority_address) { + Some(account_mut) => account_mut, + None => { + // This is to add the account to the cache + self.get_account(authority_address); + self.get_account_mut(authority_address)? + } + }; + if auth_tuple.address != Address::zero() { auth_account.info.bytecode = delegation_bytes.into(); } else { @@ -1648,6 +1661,24 @@ pub fn get_account(cache: &mut CacheDB, db: &Arc, address: Address } } +pub fn get_account_no_push_cache( + cache: &mut CacheDB, + db: &Arc, + address: Address, +) -> Account { + match cache::get_account(cache, &address) { + Some(acc) => acc.clone(), + None => { + let account_info = db.get_account_info(address); + let account = Account { + info: account_info, + storage: HashMap::new(), + }; + account + } + } +} + pub fn was_delegated(account_info: &AccountInfo) -> Result { let mut was_delegated = false; if account_info.has_code() && account_info.bytecode.len() == EIP7702_DELEGATED_CODE_LEN { From facb25ad51263809e5b2a5f1d79caa68edb68bde Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Tue, 21 Jan 2025 15:02:23 -0300 Subject: [PATCH 34/84] fix: revm ef_tests decoder --- cmd/ef_tests/levm/runner/revm_runner.rs | 37 ++++++++++++------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/cmd/ef_tests/levm/runner/revm_runner.rs b/cmd/ef_tests/levm/runner/revm_runner.rs index d2aa8024d9..492b48bbab 100644 --- a/cmd/ef_tests/levm/runner/revm_runner.rs +++ b/cmd/ef_tests/levm/runner/revm_runner.rs @@ -142,26 +142,23 @@ pub fn prepare_revm_for_tx<'state>( // Update it in every Cargo.toml. // revm-inspectors and revm-primitives have to be bumped too. - let revm_authorization_list: Vec = tx - .authorization_list - .clone() - .unwrap_or_default() - .iter() - .map(|auth_t| { - SignedAuthorization::new_unchecked( - Authorization { - chain_id: RevmU256::from_le_bytes(auth_t.chain_id.to_little_endian()), - address: RevmAddress(auth_t.address.0.into()), - nonce: auth_t.nonce, - }, - auth_t.v.as_u32() as u8, - RevmU256::from_le_bytes(auth_t.r.to_little_endian()), - RevmU256::from_le_bytes(auth_t.s.to_little_endian()), - ) - }) - .collect(); - - let authorization_list = Some(revm_authorization_list.into()); + let authorization_list = tx.authorization_list.clone().map(|list| { + list.iter() + .map(|auth_t| { + SignedAuthorization::new_unchecked( + Authorization { + chain_id: RevmU256::from_le_bytes(auth_t.chain_id.to_little_endian()), + address: RevmAddress(auth_t.address.0.into()), + nonce: auth_t.nonce, + }, + auth_t.v.as_u32() as u8, + RevmU256::from_le_bytes(auth_t.r.to_little_endian()), + RevmU256::from_le_bytes(auth_t.s.to_little_endian()), + ) + }) + .collect::>() + .into() + }); let tx_env = RevmTxEnv { caller: tx.sender.0.into(), From b62ac2091a67ae52e1cda5f08a4e36c843010661 Mon Sep 17 00:00:00 2001 From: Tomas Fabrizio Orsi Date: Tue, 21 Jan 2025 15:41:20 -0300 Subject: [PATCH 35/84] Add if branch for when there's delegation code inside the call --- crates/vm/levm/src/vm.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 8ea78227f0..bdd1671002 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -295,6 +295,22 @@ impl VM { { self.call_frames.push(current_call_frame.clone()); + return Ok(TransactionReport { + result: TxResult::Success, + new_state: self.cache.clone(), + // Here we use the gas used and not check for the floor cost + // for Prague fork because the precompiles have constant gas cost + gas_used: current_call_frame.gas_used, + gas_refunded: self.env.refunded_gas, + output: Bytes::new(), + logs: std::mem::take(&mut current_call_frame.logs), + created_address: None, + }); + } else if current_call_frame.is_delegation + && was_delegated_from_bytecode(¤t_call_frame.bytecode)? + { + self.call_frames.push(current_call_frame.clone()); + return Ok(TransactionReport { result: TxResult::Success, new_state: self.cache.clone(), From 8e3da10834d54e98a3b6fa44e2dc2160db104442 Mon Sep 17 00:00:00 2001 From: Tomas Fabrizio Orsi Date: Tue, 21 Jan 2025 15:43:03 -0300 Subject: [PATCH 36/84] Forgot funciton --- crates/vm/levm/src/vm.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index bdd1671002..a86df58758 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -1695,6 +1695,20 @@ pub fn get_account_no_push_cache( } } +pub fn was_delegated_from_bytecode(bytecode: &Bytes) -> Result { + let mut was_delegated = false; + if !bytecode.is_empty() && bytecode.len() == EIP7702_DELEGATED_CODE_LEN { + let first_3_bytes = bytecode + .get(..3) + .ok_or(VMError::Internal(InternalError::SlicingError))?; + + if first_3_bytes == SET_CODE_DELEGATION_BYTES { + was_delegated = true; + } + } + Ok(was_delegated) +} + pub fn was_delegated(account_info: &AccountInfo) -> Result { let mut was_delegated = false; if account_info.has_code() && account_info.bytecode.len() == EIP7702_DELEGATED_CODE_LEN { From cce01d00963aeeb3851c471e1aaebc6e19ce8952 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Tue, 21 Jan 2025 16:30:37 -0300 Subject: [PATCH 37/84] dbg: increase_balance after set_eip7702_code() is called --- crates/vm/levm/src/vm.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 8ea78227f0..01c7e4c266 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -39,6 +39,7 @@ use std::{ cmp::max, collections::{HashMap, HashSet}, fmt::Debug, + str::FromStr, sync::Arc, }; pub type Storage = HashMap; @@ -192,7 +193,9 @@ impl VM { TxKind::Call(address_to) => { default_touched_accounts.insert(address_to); - let bytecode = get_account(&mut cache, &db, address_to).info.bytecode; + let bytecode = get_account_no_push_cache(&mut cache, &db, address_to) + .info + .bytecode; // CALL tx let initial_call_frame = CallFrame::new( @@ -884,13 +887,6 @@ impl VM { self.decrease_account_balance(sender_address, up_front_cost) .map_err(|_| TxValidationError::InsufficientAccountFunds)?; - // Transfer value to receiver - let receiver_address = initial_call_frame.to; - // msg_value is already transferred into the created contract at creation. - if !self.is_create() { - self.increase_account_balance(receiver_address, initial_call_frame.msg_value)?; - } - // (4) INSUFFICIENT_MAX_FEE_PER_GAS if self.env.tx_max_fee_per_gas.unwrap_or(self.env.gas_price) < self.env.base_fee_per_gas { return Err(VMError::TxValidation( @@ -1015,6 +1011,10 @@ impl VM { initial_call_frame.bytecode = std::mem::take(&mut initial_call_frame.calldata); initial_call_frame.valid_jump_destinations = get_valid_jump_destinations(&initial_call_frame.bytecode).unwrap_or_default(); + } else { + // Transfer value to receiver + // It's here to avoid storing the "to" address in the cache before eip7702_set_access_code() step 7). + self.increase_account_balance(initial_call_frame.to, initial_call_frame.msg_value)?; } Ok(()) } @@ -1559,7 +1559,7 @@ impl VM { .touched_accounts .insert(initial_call_frame.code_address); initial_call_frame.code_address = get_authorized_address(&code_address_info)?; - let (auth_address_info, _) = self.access_account(initial_call_frame.code_address); + let auth_address_info = self.get_account(initial_call_frame.code_address).info; initial_call_frame.bytecode = auth_address_info.bytecode.clone(); } else { From 397119ca9630d90259c9f425967a77585caa8344 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Tue, 21 Jan 2025 16:58:07 -0300 Subject: [PATCH 38/84] dbg: refactor nested if inside execute() --- crates/vm/levm/src/vm.rs | 66 +++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 67015a1988..5db7df6f7e 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -293,38 +293,40 @@ impl VM { // CHECK: // Not fully sure if the following check: current_call_frame.gas_limit == 0 is ok. // This change helps to pass the account_warming.json tests. - if current_call_frame.bytecode.is_empty() - && (current_call_frame.is_delegation || current_call_frame.gas_limit == 0) - { - self.call_frames.push(current_call_frame.clone()); - - return Ok(TransactionReport { - result: TxResult::Success, - new_state: self.cache.clone(), - // Here we use the gas used and not check for the floor cost - // for Prague fork because the precompiles have constant gas cost - gas_used: current_call_frame.gas_used, - gas_refunded: self.env.refunded_gas, - output: Bytes::new(), - logs: std::mem::take(&mut current_call_frame.logs), - created_address: None, - }); - } else if current_call_frame.is_delegation - && was_delegated_from_bytecode(¤t_call_frame.bytecode)? - { - self.call_frames.push(current_call_frame.clone()); - - return Ok(TransactionReport { - result: TxResult::Success, - new_state: self.cache.clone(), - // Here we use the gas used and not check for the floor cost - // for Prague fork because the precompiles have constant gas cost - gas_used: current_call_frame.gas_used, - gas_refunded: self.env.refunded_gas, - output: Bytes::new(), - logs: std::mem::take(&mut current_call_frame.logs), - created_address: None, - }); + if current_call_frame.bytecode.is_empty() { + if current_call_frame.is_delegation || current_call_frame.gas_limit == 0 { + self.call_frames.push(current_call_frame.clone()); + + return Ok(TransactionReport { + result: TxResult::Success, + new_state: self.cache.clone(), + // Here we use the gas used and not check for the floor cost + // for Prague fork because the precompiles have constant gas cost + gas_used: current_call_frame.gas_used, + gas_refunded: self.env.refunded_gas, + output: Bytes::new(), + logs: std::mem::take(&mut current_call_frame.logs), + created_address: None, + }); + } + } else { + if current_call_frame.is_delegation + && was_delegated_from_bytecode(¤t_call_frame.bytecode)? + { + self.call_frames.push(current_call_frame.clone()); + + return Ok(TransactionReport { + result: TxResult::Success, + new_state: self.cache.clone(), + // Here we use the gas used and not check for the floor cost + // for Prague fork because the precompiles have constant gas cost + gas_used: current_call_frame.gas_used, + gas_refunded: self.env.refunded_gas, + output: Bytes::new(), + logs: std::mem::take(&mut current_call_frame.logs), + created_address: None, + }); + } } if is_precompile(¤t_call_frame.code_address, self.env.spec_id) { From 27aa8e091ca80e6a22d1bf5b9fba160fc4446520 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Tue, 21 Jan 2025 17:12:14 -0300 Subject: [PATCH 39/84] dbg: gas tests, temporary solution --- crates/vm/levm/src/opcode_handlers/system.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/crates/vm/levm/src/opcode_handlers/system.rs b/crates/vm/levm/src/opcode_handlers/system.rs index 33b2a1bd1a..3f71acd8ce 100644 --- a/crates/vm/levm/src/opcode_handlers/system.rs +++ b/crates/vm/levm/src/opcode_handlers/system.rs @@ -784,10 +784,13 @@ impl VM { self.increase_account_balance(to, value)?; } - let tx_report = self.execute(&mut new_call_frame)?; + let mut tx_report = self.execute(&mut new_call_frame)?; dbg!(new_call_frame.gas_limit); dbg!(tx_report.gas_used); + if tx_report.gas_used == 21000 { + tx_report.gas_used = 0; + } dbg!("FAILS BELOW"); // Return gas left from subcontext let gas_left_from_new_call_frame = new_call_frame From 555320947acb7106472f083b4996867bd0e357f8 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 22 Jan 2025 09:29:12 -0300 Subject: [PATCH 40/84] fix: eip7623 --- crates/vm/levm/src/vm.rs | 47 +++++----------------------------------- 1 file changed, 5 insertions(+), 42 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 5db7df6f7e..5b9b55f6bf 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -290,45 +290,6 @@ impl VM { self.env.transient_storage.clone(), ); - // CHECK: - // Not fully sure if the following check: current_call_frame.gas_limit == 0 is ok. - // This change helps to pass the account_warming.json tests. - if current_call_frame.bytecode.is_empty() { - if current_call_frame.is_delegation || current_call_frame.gas_limit == 0 { - self.call_frames.push(current_call_frame.clone()); - - return Ok(TransactionReport { - result: TxResult::Success, - new_state: self.cache.clone(), - // Here we use the gas used and not check for the floor cost - // for Prague fork because the precompiles have constant gas cost - gas_used: current_call_frame.gas_used, - gas_refunded: self.env.refunded_gas, - output: Bytes::new(), - logs: std::mem::take(&mut current_call_frame.logs), - created_address: None, - }); - } - } else { - if current_call_frame.is_delegation - && was_delegated_from_bytecode(¤t_call_frame.bytecode)? - { - self.call_frames.push(current_call_frame.clone()); - - return Ok(TransactionReport { - result: TxResult::Success, - new_state: self.cache.clone(), - // Here we use the gas used and not check for the floor cost - // for Prague fork because the precompiles have constant gas cost - gas_used: current_call_frame.gas_used, - gas_refunded: self.env.refunded_gas, - output: Bytes::new(), - logs: std::mem::take(&mut current_call_frame.logs), - created_address: None, - }); - } - } - if is_precompile(¤t_call_frame.code_address, self.env.spec_id) { let precompile_result = execute_precompile(current_call_frame, self.env.spec_id); @@ -551,7 +512,7 @@ impl VM { return Ok(TransactionReport { result: TxResult::Revert(error), new_state: HashMap::default(), - gas_used: self.gas_used(current_call_frame)?, + gas_used: current_call_frame.gas_used, gas_refunded: self.env.refunded_gas, output: std::mem::take(&mut current_call_frame.output), logs: std::mem::take(&mut current_call_frame.logs), @@ -564,7 +525,7 @@ impl VM { return Ok(TransactionReport { result: TxResult::Success, new_state: HashMap::default(), - gas_used: self.gas_used(current_call_frame)?, + gas_used: current_call_frame.gas_used, gas_refunded: self.env.refunded_gas, output: std::mem::take(&mut current_call_frame.output), logs: std::mem::take(&mut current_call_frame.logs), @@ -598,7 +559,7 @@ impl VM { return Ok(TransactionReport { result: TxResult::Revert(error), new_state: HashMap::default(), - gas_used: self.gas_used(current_call_frame)?, + gas_used: current_call_frame.gas_used, gas_refunded: self.env.refunded_gas, output: std::mem::take(&mut current_call_frame.output), // Bytes::new() if error is not RevertOpcode logs: std::mem::take(&mut current_call_frame.logs), @@ -1152,6 +1113,8 @@ impl VM { let mut report = self.execute(&mut initial_call_frame)?; + report.gas_used = self.gas_used(&initial_call_frame)?; + self.post_execution_changes(&initial_call_frame, &mut report)?; // There shouldn't be any errors here but I don't know what the desired behavior is if something goes wrong. From f49ca78861065a5ed346f3a8bb49e6abc177a95e Mon Sep 17 00:00:00 2001 From: Tomas Fabrizio Orsi Date: Wed, 22 Jan 2025 09:36:59 -0300 Subject: [PATCH 41/84] Remove debugging if --- crates/vm/levm/src/opcode_handlers/system.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/crates/vm/levm/src/opcode_handlers/system.rs b/crates/vm/levm/src/opcode_handlers/system.rs index 3f71acd8ce..bba340560c 100644 --- a/crates/vm/levm/src/opcode_handlers/system.rs +++ b/crates/vm/levm/src/opcode_handlers/system.rs @@ -788,9 +788,6 @@ impl VM { dbg!(new_call_frame.gas_limit); dbg!(tx_report.gas_used); - if tx_report.gas_used == 21000 { - tx_report.gas_used = 0; - } dbg!("FAILS BELOW"); // Return gas left from subcontext let gas_left_from_new_call_frame = new_call_frame From f6c7f440c7bbcd52703520ff306b54a4a7fc0c86 Mon Sep 17 00:00:00 2001 From: Tomas Fabrizio Orsi Date: Wed, 22 Jan 2025 09:52:03 -0300 Subject: [PATCH 42/84] Add comment explaining why this check --- crates/vm/levm/src/opcode_handlers/environment.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/crates/vm/levm/src/opcode_handlers/environment.rs b/crates/vm/levm/src/opcode_handlers/environment.rs index 857a9b72f9..f058cb6bb5 100644 --- a/crates/vm/levm/src/opcode_handlers/environment.rs +++ b/crates/vm/levm/src/opcode_handlers/environment.rs @@ -280,6 +280,7 @@ impl VM { let (account_info, address_was_cold) = self.access_account(address); + // https://eips.ethereum.org/EIPS/eip-7702#delegation-designation let is_delegation = was_delegated(&account_info)?; self.increase_consumed_gas(current_call_frame, gas_cost::extcodesize(address_was_cold)?)?; @@ -315,6 +316,7 @@ impl VM { let new_memory_size = calculate_memory_size(dest_offset, size)?; + // https://eips.ethereum.org/EIPS/eip-7702#delegation-designation let is_delegation = was_delegated(&account_info)?; self.increase_consumed_gas( @@ -435,6 +437,7 @@ impl VM { let (account_info, address_was_cold) = self.access_account(address); + // https://eips.ethereum.org/EIPS/eip-7702#delegation-designation let is_delegation = was_delegated(&account_info)?; self.increase_consumed_gas(current_call_frame, gas_cost::extcodehash(address_was_cold)?)?; From 12e4774e3a7aff97c6388df3782d152ac37a1b57 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 22 Jan 2025 10:02:01 -0300 Subject: [PATCH 43/84] dbg: wip --- crates/vm/levm/src/call_frame.rs | 5 ----- crates/vm/levm/src/opcode_handlers/system.rs | 13 ++++++++++--- crates/vm/levm/src/vm.rs | 2 -- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/vm/levm/src/call_frame.rs b/crates/vm/levm/src/call_frame.rs index 6c0c85b294..362b5ae949 100644 --- a/crates/vm/levm/src/call_frame.rs +++ b/crates/vm/levm/src/call_frame.rs @@ -113,7 +113,6 @@ impl CallFrame { gas_used: u64, depth: usize, create_op_called: bool, - is_delegation: bool, ) -> Self { let valid_jump_destinations = get_valid_jump_destinations(&bytecode).unwrap_or_default(); Self { @@ -129,15 +128,11 @@ impl CallFrame { gas_used, valid_jump_destinations, create_op_called, - is_delegation, ..Default::default() } } pub fn next_opcode(&mut self) -> Opcode { - if self.bytecode.is_empty() { - dbg!("IS EMPTY"); - } match self.bytecode.get(self.pc).copied().map(Opcode::from) { Some(opcode) => opcode, None => Opcode::STOP, diff --git a/crates/vm/levm/src/opcode_handlers/system.rs b/crates/vm/levm/src/opcode_handlers/system.rs index bba340560c..0bb02c5156 100644 --- a/crates/vm/levm/src/opcode_handlers/system.rs +++ b/crates/vm/levm/src/opcode_handlers/system.rs @@ -667,7 +667,6 @@ impl VM { 0, new_depth, true, - false, ); self.accrued_substate.created_accounts.insert(new_address); // Mostly for SELFDESTRUCT during initcode. @@ -763,6 +762,15 @@ impl VM { return Ok(OpcodeSuccess::Continue); } + if bytecode.is_empty() && is_delegation { + current_call_frame.gas_used = current_call_frame + .gas_used + .checked_sub(gas_limit) + .ok_or(InternalError::GasOverflow)?; + current_call_frame.stack.push(SUCCESS_FOR_CALL)?; + return Ok(OpcodeSuccess::Continue); + } + let mut new_call_frame = CallFrame::new( msg_sender, to, @@ -775,7 +783,6 @@ impl VM { 0, new_depth, false, - is_delegation, ); // Transfer value from caller to callee. @@ -784,7 +791,7 @@ impl VM { self.increase_account_balance(to, value)?; } - let mut tx_report = self.execute(&mut new_call_frame)?; + let tx_report = self.execute(&mut new_call_frame)?; dbg!(new_call_frame.gas_limit); dbg!(tx_report.gas_used); diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 5b9b55f6bf..1b1cff82b2 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -210,7 +210,6 @@ impl VM { 0, 0, false, - false, ); let substate = Substate { @@ -254,7 +253,6 @@ impl VM { 0, 0, false, - false, ); let substate = Substate { From 0e70b8f5904725c12c32e1979f60748263832754 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 22 Jan 2025 10:17:04 -0300 Subject: [PATCH 44/84] chore: rm dbg! statements --- crates/vm/levm/src/errors.rs | 1 - crates/vm/levm/src/gas_cost.rs | 2 -- crates/vm/levm/src/opcode_handlers/system.rs | 31 -------------------- crates/vm/levm/src/vm.rs | 18 +----------- 4 files changed, 1 insertion(+), 51 deletions(-) diff --git a/crates/vm/levm/src/errors.rs b/crates/vm/levm/src/errors.rs index 1c1a6969dc..d3ca206edf 100644 --- a/crates/vm/levm/src/errors.rs +++ b/crates/vm/levm/src/errors.rs @@ -224,7 +224,6 @@ pub enum EIP7702Error { #[derive(Debug, Clone)] pub enum OpcodeSuccess { - Debug(TxResult), Continue, Result(ResultReason), } diff --git a/crates/vm/levm/src/gas_cost.rs b/crates/vm/levm/src/gas_cost.rs index 54e7c17832..75d339d48d 100644 --- a/crates/vm/levm/src/gas_cost.rs +++ b/crates/vm/levm/src/gas_cost.rs @@ -713,8 +713,6 @@ pub fn call( .checked_add(value_to_empty_account) .ok_or(OutOfGasError::GasCostOverflow)?; - dbg!(gas_from_stack, call_gas_costs); - calculate_cost_and_gas_limit_call( value_to_transfer.is_zero(), gas_from_stack, diff --git a/crates/vm/levm/src/opcode_handlers/system.rs b/crates/vm/levm/src/opcode_handlers/system.rs index 0bb02c5156..96b88ca1f9 100644 --- a/crates/vm/levm/src/opcode_handlers/system.rs +++ b/crates/vm/levm/src/opcode_handlers/system.rs @@ -21,31 +21,8 @@ impl VM { &mut self, current_call_frame: &mut CallFrame, ) -> Result { - dbg!(¤t_call_frame.stack); - // STACK - // TODO change it back - //GAS - //PUSH1 0x00 - //PUSH1 0x00 - //PUSH1 0x00 - //PUSH1 0x00 - //PUSH1 0x00 - //PUSH20 0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b - //PUSH1 0x00 - //stack: [ - // 883250, - // 0, - // 0, - // 0, - // 0, - // 0, - // 788065941775983272449444774641449473958132390328, - // 0, - //], - //let gas = *current_call_frame.stack.stack.first().unwrap(); let gas = current_call_frame.stack.pop()?; let callee: Address = word_to_address(current_call_frame.stack.pop()?); - dbg!(&callee, gas); let value_to_transfer: U256 = current_call_frame.stack.pop()?; let args_start_offset = current_call_frame.stack.pop()?; let args_size = current_call_frame @@ -793,9 +770,6 @@ impl VM { let tx_report = self.execute(&mut new_call_frame)?; - dbg!(new_call_frame.gas_limit); - dbg!(tx_report.gas_used); - dbg!("FAILS BELOW"); // Return gas left from subcontext let gas_left_from_new_call_frame = new_call_frame .gas_limit @@ -832,11 +806,6 @@ impl VM { } } - if false { - dbg!("CALL FINISHED"); - return Ok(OpcodeSuccess::Debug(tx_report.result)); - } - dbg!("FINISHED CALL"); Ok(OpcodeSuccess::Continue) } } diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 1b1cff82b2..deb312947a 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -448,14 +448,6 @@ impl VM { // Gas refunds are applied at the end of a transaction. Should it be implemented here? match op_result { - Ok(OpcodeSuccess::Debug(res)) => { - let opcode = current_call_frame.next_opcode(); - dbg!(¤t_call_frame); - let pretty_bytecode = format!("{:#x}", current_call_frame.bytecode); - dbg!(&pretty_bytecode); - dbg!(opcode); - dbg!(res); - } Ok(OpcodeSuccess::Continue) => {} Ok(OpcodeSuccess::Result(_)) => { self.call_frames.push(current_call_frame.clone()); @@ -1489,20 +1481,15 @@ impl VM { } // 7. Add PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST gas to the global refund counter if authority exists in the trie. - dbg!("PRE self.db.account_exists"); - dbg!(authority_address); - dbg!(self.db.account_exists(authority_address)); // CHECK: we don't know if checking the cache is correct. More gas tests pass but the set_code_txs tests went to half. if self.db.account_exists(authority_address) || self.cache.contains_key(&authority_address) { - dbg!("IN self.db.account_exists"); let refunded_gas_if_exists = PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST; refunded_gas = refunded_gas .checked_add(refunded_gas_if_exists) .ok_or(VMError::Internal(InternalError::GasOverflow))?; } - dbg!("POS self.db.account_exists"); // 8. Set the code of authority to be 0xef0100 || address. This is a delegation designation. let mut delegation_bytes = Vec::new(); @@ -1545,10 +1532,6 @@ impl VM { initial_call_frame.bytecode = code_address_info.bytecode.clone(); } - let initial_bytecode = format!("{:#x}", initial_call_frame.bytecode); - dbg!(&initial_bytecode); - dbg!(&initial_call_frame.code_address); - initial_call_frame.valid_jump_destinations = get_valid_jump_destinations(&initial_call_frame.bytecode).unwrap_or_default(); Ok(refunded_gas) @@ -1593,6 +1576,7 @@ impl VM { let access_cost = match self.accrued_substate.touched_accounts.get(&auth_address) { Some(_) => WARM_ADDRESS_ACCESS_COST, None => { + dbg!(auth_address); self.accrued_substate.touched_accounts.insert(auth_address); COLD_ADDRESS_ACCESS_COST } From a17a1aa7c32407a316daa2f2830cf13aa12a9479 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 22 Jan 2025 10:26:17 -0300 Subject: [PATCH 45/84] dbg: touch the auth_address 'pointed' address Co-authored-by: Tomas Fabrizio Orsi --- crates/vm/levm/src/opcode_handlers/system.rs | 2 -- crates/vm/levm/src/vm.rs | 8 ++------ 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/crates/vm/levm/src/opcode_handlers/system.rs b/crates/vm/levm/src/opcode_handlers/system.rs index 96b88ca1f9..baa3b4bb48 100644 --- a/crates/vm/levm/src/opcode_handlers/system.rs +++ b/crates/vm/levm/src/opcode_handlers/system.rs @@ -77,8 +77,6 @@ impl VM { self.env.spec_id, )?; - dbg!(gas_limit, cost); - self.increase_consumed_gas(current_call_frame, cost)?; self.increase_consumed_gas(current_call_frame, eip7702_gas_consumed)?; diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index deb312947a..a26ae7f775 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -972,7 +972,6 @@ impl VM { } self.env.refunded_gas = self.eip7702_set_access_code(initial_call_frame)?; - dbg!(self.env.refunded_gas); } if self.is_create() { @@ -1518,14 +1517,11 @@ impl VM { .map_err(|_| VMError::TxValidation(TxValidationError::NonceIsMax))?; } - let code_address_info = self.get_account(initial_call_frame.code_address).info; + let (code_address_info, _) = self.access_account(initial_call_frame.code_address); if was_delegated(&code_address_info)? { - self.accrued_substate - .touched_accounts - .insert(initial_call_frame.code_address); initial_call_frame.code_address = get_authorized_address(&code_address_info)?; - let auth_address_info = self.get_account(initial_call_frame.code_address).info; + let (auth_address_info, _) = self.access_account(initial_call_frame.code_address); initial_call_frame.bytecode = auth_address_info.bytecode.clone(); } else { From 628b1706e346d69f1163ce70973cda955b74e169 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 22 Jan 2025 10:32:10 -0300 Subject: [PATCH 46/84] chore: rm dbg! statements --- crates/vm/levm/src/opcode_handlers/system.rs | 5 ----- crates/vm/levm/src/vm.rs | 5 +---- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/crates/vm/levm/src/opcode_handlers/system.rs b/crates/vm/levm/src/opcode_handlers/system.rs index baa3b4bb48..7997b9f2c4 100644 --- a/crates/vm/levm/src/opcode_handlers/system.rs +++ b/crates/vm/levm/src/opcode_handlers/system.rs @@ -54,9 +54,6 @@ impl VM { let (is_delegation, eip7702_gas_consumed, code_address, bytecode) = self.eip7702_get_code(callee)?; - let pretty_bytecode = format!("{bytecode:#x}"); - dbg!(code_address, pretty_bytecode, bytecode.is_empty()); - let gas_left = current_call_frame .gas_limit .checked_sub(current_call_frame.gas_used) @@ -64,8 +61,6 @@ impl VM { .checked_sub(eip7702_gas_consumed) .ok_or(InternalError::GasOverflow)?; - dbg!(gas_left, eip7702_gas_consumed, current_call_frame.gas_used); - let (cost, gas_limit) = gas_cost::call( new_memory_size, current_memory_size, diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index a26ae7f775..511598ef74 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -39,7 +39,6 @@ use std::{ cmp::max, collections::{HashMap, HashSet}, fmt::Debug, - str::FromStr, sync::Arc, }; pub type Storage = HashMap; @@ -526,7 +525,6 @@ impl VM { self.call_frames.push(current_call_frame.clone()); if error.is_internal() { - dbg!(&error); return Err(error); } @@ -1511,7 +1509,7 @@ impl VM { } else { auth_account.info.bytecode = Bytes::new(); } - dbg!(&authority_address); + // 9. Increase the nonce of authority by one. self.increment_account_nonce(authority_address) .map_err(|_| VMError::TxValidation(TxValidationError::NonceIsMax))?; @@ -1572,7 +1570,6 @@ impl VM { let access_cost = match self.accrued_substate.touched_accounts.get(&auth_address) { Some(_) => WARM_ADDRESS_ACCESS_COST, None => { - dbg!(auth_address); self.accrued_substate.touched_accounts.insert(auth_address); COLD_ADDRESS_ACCESS_COST } From 857ec75c5ece3641822509239cf75a4720d81bad Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 22 Jan 2025 10:54:41 -0300 Subject: [PATCH 47/84] dbg: fix all tests --- crates/vm/levm/src/vm.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 511598ef74..ba7a133938 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -3,7 +3,7 @@ use crate::{ call_frame::CallFrame, constants::*, db::{ - cache::{self, get_account_mut, remove_account}, + cache::{self, get_account_mut, insert_account, remove_account}, CacheDB, Database, }, environment::Environment, @@ -1007,8 +1007,13 @@ impl VM { // not remove the account. // If transaction execution results in failure (any exceptional condition or code reverting), setting delegation designations is not rolled back. - if !was_delegated(&get_account(&mut self.cache, &self.db, receiver_address).info)? { - remove_account(&mut self.cache, &receiver_address); + let existing_account = get_account(&mut self.cache, &self.db, receiver_address); + let mut new_account = Account::default(); + new_account.info = existing_account.info.clone(); + remove_account(&mut self.cache, &receiver_address); + if was_delegated(&existing_account.info)? { + insert_account(&mut self.cache, receiver_address, new_account); + self.decrease_account_balance(receiver_address, initial_call_frame.msg_value)?; } self.increase_account_balance(sender_address, initial_call_frame.msg_value)?; From e3dc3fea00850e9f48c680fb46297f8a80c60424 Mon Sep 17 00:00:00 2001 From: Tomas Fabrizio Orsi Date: Wed, 22 Jan 2025 11:04:24 -0300 Subject: [PATCH 48/84] Remove extra variable Co-authored-by: fborello-lambda --- crates/vm/levm/src/vm.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index ba7a133938..9b0e82a279 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -1007,12 +1007,15 @@ impl VM { // not remove the account. // If transaction execution results in failure (any exceptional condition or code reverting), setting delegation designations is not rolled back. - let existing_account = get_account(&mut self.cache, &self.db, receiver_address); - let mut new_account = Account::default(); - new_account.info = existing_account.info.clone(); + let existing_account = get_account(&mut self.cache, &self.db, receiver_address); //TO Account + + // let mut new_account = Account::default(); //TO Account + // new_account.info = existing_account.info.clone(); + remove_account(&mut self.cache, &receiver_address); + if was_delegated(&existing_account.info)? { - insert_account(&mut self.cache, receiver_address, new_account); + insert_account(&mut self.cache, receiver_address, existing_account); self.decrease_account_balance(receiver_address, initial_call_frame.msg_value)?; } From f20b07bb92cd09a02742618a8020ef36e55ac97e Mon Sep 17 00:00:00 2001 From: Tomas Fabrizio Orsi Date: Wed, 22 Jan 2025 11:16:20 -0300 Subject: [PATCH 49/84] Slight refactor + slight comments Co-authored-by: fborello-lambda --- crates/vm/levm/src/vm.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 9b0e82a279..768e426bdd 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -1006,17 +1006,22 @@ impl VM { // tokens to an account that has a delegation, but the tx reverts by any other reason, it will // not remove the account. - // If transaction execution results in failure (any exceptional condition or code reverting), setting delegation designations is not rolled back. let existing_account = get_account(&mut self.cache, &self.db, receiver_address); //TO Account - // let mut new_account = Account::default(); //TO Account - // new_account.info = existing_account.info.clone(); + // This is the case where the "to" address and the + // "signer" address are the same. We are setting the code + // and sending some balance to the "to"/"signer" + // address. + // See https://eips.ethereum.org/EIPS/eip-7702#behavior (last sentence). - remove_account(&mut self.cache, &receiver_address); + // If transaction execution results in failure (any + // exceptional condition or code reverting), setting + // delegation designations is not rolled back. if was_delegated(&existing_account.info)? { - insert_account(&mut self.cache, receiver_address, existing_account); self.decrease_account_balance(receiver_address, initial_call_frame.msg_value)?; + } else { + remove_account(&mut self.cache, &receiver_address); } self.increase_account_balance(sender_address, initial_call_frame.msg_value)?; From bc0eaf5ffaaa116dc5e72a1f4798876d8f9e1ba2 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 22 Jan 2025 11:28:21 -0300 Subject: [PATCH 50/84] chore: revert revm bump --- Cargo.lock | 236 ++++++++++++------ cmd/ef_tests/levm/Cargo.toml | 2 +- cmd/ef_tests/levm/runner/revm_runner.rs | 6 +- crates/vm/Cargo.toml | 4 +- crates/vm/levm/Cargo.toml | 2 +- .../vm/levm/bench/revm_comparison/Cargo.toml | 2 +- 6 files changed, 172 insertions(+), 80 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f2a87e12e..ba9bc7edfe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -102,15 +102,14 @@ checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" [[package]] name = "alloy-consensus" -version = "0.9.2" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4138dc275554afa6f18c4217262ac9388790b2fc393c2dfe03c51d357abf013" +checksum = "705687d5bfd019fee57cf9e206b27b30a9a9617535d5590a02b171e813208f8e" dependencies = [ "alloy-eips", "alloy-primitives 0.8.18", "alloy-rlp", "alloy-serde", - "alloy-trie", "auto_impl", "c-kzg", "derive_more 1.0.0", @@ -118,25 +117,25 @@ dependencies = [ ] [[package]] -name = "alloy-consensus-any" -version = "0.9.2" +name = "alloy-eip2930" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa04e1882c31288ce1028fdf31b6ea94cfa9eafa2e497f903ded631c8c6a42c" +checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41" dependencies = [ - "alloy-consensus", - "alloy-eips", "alloy-primitives 0.8.18", "alloy-rlp", + "serde", ] [[package]] -name = "alloy-eip2930" -version = "0.1.0" +name = "alloy-eip7702" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41" +checksum = "ea59dc42102bc9a1905dc57901edc6dd48b9f38115df86c7d252acba70d71d04" dependencies = [ "alloy-primitives 0.8.18", "alloy-rlp", + "k256", "serde", ] @@ -155,12 +154,12 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "0.9.2" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52dd5869ed09e399003e0e0ec6903d981b2a92e74c5d37e6b40890bad2517526" +checksum = "6ffb906284a1e1f63c4607da2068c8197458a352d0b3e9796e67353d72a9be85" dependencies = [ "alloy-eip2930", - "alloy-eip7702", + "alloy-eip7702 0.1.1", "alloy-primitives 0.8.18", "alloy-rlp", "alloy-serde", @@ -185,9 +184,9 @@ dependencies = [ [[package]] name = "alloy-network-primitives" -version = "0.9.2" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31c3c6b71340a1d076831823f09cb6e02de01de5c6630a9631bdb36f947ff80" +checksum = "801492711d4392b2ccf5fc0bc69e299fa1aab15167d74dcaa9aab96a54f684bd" dependencies = [ "alloy-consensus", "alloy-eips", @@ -269,43 +268,42 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "0.9.2" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0938bc615c02421bd86c1733ca7205cc3d99a122d9f9bff05726bd604b76a5c2" +checksum = "413f4aa3ccf2c3e4234a047c5fa4727916d7daf25a89f9b765df0ba09784fd87" dependencies = [ "alloy-consensus", - "alloy-consensus-any", "alloy-eips", "alloy-network-primitives", "alloy-primitives 0.8.18", "alloy-rlp", "alloy-serde", "alloy-sol-types 0.8.18", + "derive_more 1.0.0", "itertools 0.13.0", "serde", "serde_json", - "thiserror 2.0.9", ] [[package]] name = "alloy-rpc-types-trace" -version = "0.9.2" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd38207e056cc7d1372367fbb4560ddf9107cbd20731743f641246bf0dede149" +checksum = "017cad3e5793c5613588c1f9732bcbad77e820ba7d0feaba3527749f856fdbc5" dependencies = [ "alloy-primitives 0.8.18", "alloy-rpc-types-eth", "alloy-serde", "serde", "serde_json", - "thiserror 2.0.9", + "thiserror 1.0.69", ] [[package]] name = "alloy-serde" -version = "0.9.2" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae0465c71d4dced7525f408d84873aeebb71faf807d22d74c4a426430ccd9b55" +checksum = "9dff0ab1cdd43ca001e324dc27ee0e8606bd2161d6623c63e0e0b8c4dfc13600" dependencies = [ "alloy-primitives 0.8.18", "serde", @@ -441,22 +439,6 @@ dependencies = [ "serde", ] -[[package]] -name = "alloy-trie" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6917c79e837aa7b77b7a6dae9f89cbe15313ac161c4d3cfaf8909ef21f3d22d8" -dependencies = [ - "alloy-primitives 0.8.18", - "alloy-rlp", - "arrayvec", - "derive_more 1.0.0", - "nybbles", - "serde", - "smallvec", - "tracing", -] - [[package]] name = "android-tzdata" version = "0.1.1" @@ -799,9 +781,6 @@ name = "arrayvec" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" -dependencies = [ - "serde", -] [[package]] name = "async-trait" @@ -2322,7 +2301,7 @@ dependencies = [ "hex", "itertools 0.13.0", "keccak-hash", - "revm", + "revm 14.0.3", "serde", "serde_json", "spinoff", @@ -2933,7 +2912,7 @@ dependencies = [ "lambdaworks-math", "libsecp256k1", "num-bigint 0.4.6", - "revm-primitives", + "revm-primitives 10.0.0", "ripemd", "serde", "serde_json", @@ -3138,9 +3117,9 @@ dependencies = [ "ethrex-trie", "hex", "lazy_static", - "revm", + "revm 19.3.0", "revm-inspectors", - "revm-primitives", + "revm-primitives 10.0.0", "serde", "thiserror 2.0.9", "tracing", @@ -5301,17 +5280,6 @@ dependencies = [ "cc", ] -[[package]] -name = "nybbles" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8983bb634df7248924ee0c4c3a749609b5abcb082c28fffe3254b3eb3602b307" -dependencies = [ - "const-hex", - "serde", - "smallvec", -] - [[package]] name = "objc" version = "0.2.7" @@ -6631,6 +6599,36 @@ dependencies = [ "tower-service", ] +[[package]] +name = "revm" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a2c336f9921588e50871c00024feb51a521eca50ce6d01494bb9c50f837c8ed" +dependencies = [ + "auto_impl", + "cfg-if", + "dyn-clone", + "revm-interpreter 5.0.0", + "revm-precompile 7.0.0", + "serde", + "serde_json", +] + +[[package]] +name = "revm" +version = "14.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "641702b12847f9ed418d552f4fcabe536d867a2c980e96b6e7e25d7b992f929f" +dependencies = [ + "auto_impl", + "cfg-if", + "dyn-clone", + "revm-interpreter 10.0.3", + "revm-precompile 11.0.3", + "serde", + "serde_json", +] + [[package]] name = "revm" version = "19.3.0" @@ -6640,17 +6638,17 @@ dependencies = [ "auto_impl", "cfg-if", "dyn-clone", - "revm-interpreter", - "revm-precompile", + "revm-interpreter 15.1.0", + "revm-precompile 16.0.0", "serde", "serde_json", ] [[package]] name = "revm-inspectors" -version = "0.14.1" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc873bc873e12a1723493e1a35804fa79b673a0bfb1c19cfee659d46def8be42" +checksum = "43c44af0bf801f48d25f7baf25cf72aff4c02d610f83b428175228162fef0246" dependencies = [ "alloy-primitives 0.8.18", "alloy-rpc-types-eth", @@ -6658,9 +6656,29 @@ dependencies = [ "alloy-sol-types 0.8.18", "anstyle", "colorchoice", - "revm", + "revm 14.0.3", "serde_json", - "thiserror 2.0.9", + "thiserror 1.0.69", +] + +[[package]] +name = "revm-interpreter" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a58182c7454179826f9dad2ca577661963092ce9d0fd0c9d682c1e9215a72e70" +dependencies = [ + "revm-primitives 4.0.0", + "serde", +] + +[[package]] +name = "revm-interpreter" +version = "10.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e5e14002afae20b5bf1566f22316122f42f57517000e559c55b25bf7a49cba2" +dependencies = [ + "revm-primitives 10.0.0", + "serde", ] [[package]] @@ -6669,10 +6687,46 @@ version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0f632e761f171fb2f6ace8d1552a5793e0350578d4acec3e79ade1489f4c2a6" dependencies = [ - "revm-primitives", + "revm-primitives 15.1.0", "serde", ] +[[package]] +name = "revm-precompile" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc8af9aa737eef0509a50d9f3cc1a631557a00ef2e70a3aa8a75d9ee0ed275bb" +dependencies = [ + "aurora-engine-modexp", + "blst", + "c-kzg", + "k256", + "once_cell", + "revm-primitives 4.0.0", + "ripemd", + "secp256k1", + "sha2 0.10.8", + "substrate-bn", +] + +[[package]] +name = "revm-precompile" +version = "11.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3198c06247e8d4ad0d1312591edf049b0de4ddffa9fecb625c318fd67db8639b" +dependencies = [ + "aurora-engine-modexp", + "c-kzg", + "cfg-if", + "k256", + "once_cell", + "revm-primitives 10.0.0", + "ripemd", + "secp256k1", + "sha2 0.10.8", + "substrate-bn", +] + [[package]] name = "revm-precompile" version = "16.0.0" @@ -6685,13 +6739,54 @@ dependencies = [ "cfg-if", "k256", "once_cell", - "revm-primitives", + "revm-primitives 15.1.0", "ripemd", "secp256k1", "sha2 0.10.8", "substrate-bn", ] +[[package]] +name = "revm-primitives" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9bf5d465e64b697da6a111cb19e798b5b2ebb18e5faf2ad48e9e8d47c64add2" +dependencies = [ + "alloy-primitives 0.7.7", + "auto_impl", + "bitflags 2.6.0", + "bitvec", + "c-kzg", + "cfg-if", + "derive_more 0.99.18", + "dyn-clone", + "enumn", + "hashbrown 0.14.5", + "hex", + "once_cell", + "serde", +] + +[[package]] +name = "revm-primitives" +version = "10.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f1525851a03aff9a9d6a1d018b414d76252d6802ab54695b27093ecd7e7a101" +dependencies = [ + "alloy-eip2930", + "alloy-eip7702 0.1.1", + "alloy-primitives 0.8.18", + "auto_impl", + "bitflags 2.6.0", + "bitvec", + "c-kzg", + "cfg-if", + "dyn-clone", + "enumn", + "hex", + "serde", +] + [[package]] name = "revm-primitives" version = "15.1.0" @@ -6699,7 +6794,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48faea1ecf2c9f80d9b043bbde0db9da616431faed84c4cfa3dd7393005598e6" dependencies = [ "alloy-eip2930", - "alloy-eip7702", + "alloy-eip7702 0.5.0", "alloy-primitives 0.8.18", "auto_impl", "bitflags 2.6.0", @@ -6719,7 +6814,7 @@ dependencies = [ "bytes", "ethrex-levm", "hex", - "revm", + "revm 9.0.0", ] [[package]] @@ -7725,9 +7820,6 @@ name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" -dependencies = [ - "serde", -] [[package]] name = "snap" diff --git a/cmd/ef_tests/levm/Cargo.toml b/cmd/ef_tests/levm/Cargo.toml index 7e13f52f7f..073ed7ade4 100644 --- a/cmd/ef_tests/levm/Cargo.toml +++ b/cmd/ef_tests/levm/Cargo.toml @@ -21,7 +21,7 @@ thiserror.workspace = true clap = { version = "4.3", features = ["derive"] } clap_complete = "4.5.17" itertools = "0.13.0" -revm = { version = "19.3.0", features = [ +revm = { version = "14.0.3", features = [ "serde", "std", "serde-json", diff --git a/cmd/ef_tests/levm/runner/revm_runner.rs b/cmd/ef_tests/levm/runner/revm_runner.rs index 492b48bbab..9239f3cb49 100644 --- a/cmd/ef_tests/levm/runner/revm_runner.rs +++ b/cmd/ef_tests/levm/runner/revm_runner.rs @@ -137,11 +137,11 @@ pub fn prepare_revm_for_tx<'state>( }) .collect(); - //let authorization_list = None; + let authorization_list = None; // The latest version of revm(19.3.0) is needed. // Update it in every Cargo.toml. // revm-inspectors and revm-primitives have to be bumped too. - + /* let authorization_list = tx.authorization_list.clone().map(|list| { list.iter() .map(|auth_t| { @@ -159,7 +159,7 @@ pub fn prepare_revm_for_tx<'state>( .collect::>() .into() }); - + */ let tx_env = RevmTxEnv { caller: tx.sender.0.into(), gas_limit: tx.gas_limit, diff --git a/crates/vm/Cargo.toml b/crates/vm/Cargo.toml index f8cb3674c1..0bf78f5849 100644 --- a/crates/vm/Cargo.toml +++ b/crates/vm/Cargo.toml @@ -18,8 +18,8 @@ revm = { version = "19.3.0", features = [ ], default-features = false } # These dependencies must be kept up to date with the corresponding revm version, otherwise errors may pop up because of trait implementation mismatches -revm-inspectors = { version = "0.14.1" } -revm-primitives = { version = "15.1.0", features = [ +revm-inspectors = { version = "0.8.1" } +revm-primitives = { version = "10.0.0", features = [ "std", ], default-features = false } bytes.workspace = true diff --git a/crates/vm/levm/Cargo.toml b/crates/vm/levm/Cargo.toml index d0b3fabb4d..5b9c1b4eb3 100644 --- a/crates/vm/levm/Cargo.toml +++ b/crates/vm/levm/Cargo.toml @@ -6,7 +6,7 @@ edition.workspace = true [dependencies] ethrex-core.workspace = true ethrex-rlp.workspace = true -revm-primitives = { version = "15.1.0", features = [ +revm-primitives = { version = "10.0.0", features = [ "std", ], default-features = false } diff --git a/crates/vm/levm/bench/revm_comparison/Cargo.toml b/crates/vm/levm/bench/revm_comparison/Cargo.toml index d873ead323..59e2c04312 100644 --- a/crates/vm/levm/bench/revm_comparison/Cargo.toml +++ b/crates/vm/levm/bench/revm_comparison/Cargo.toml @@ -10,7 +10,7 @@ path = "src/lib.rs" [dependencies] ethrex-levm = { path = "../../" } hex = "0.4.3" -revm = "19.3.0" +revm = "9.0.0" bytes = "1.8.0" [[bin]] From 3c5b486f83fc33d43e4348deda710847ec317edd Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 22 Jan 2025 11:29:14 -0300 Subject: [PATCH 51/84] chore: revert revm bump --- Cargo.lock | 84 +++----------------------------------------- crates/vm/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 81 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ba9bc7edfe..e239748ed1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -139,19 +139,6 @@ dependencies = [ "serde", ] -[[package]] -name = "alloy-eip7702" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cabf647eb4650c91a9d38cb6f972bb320009e7e9d61765fb688a86f1563b33e8" -dependencies = [ - "alloy-primitives 0.8.18", - "alloy-rlp", - "derive_more 1.0.0", - "k256", - "serde", -] - [[package]] name = "alloy-eips" version = "0.4.2" @@ -159,7 +146,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ffb906284a1e1f63c4607da2068c8197458a352d0b3e9796e67353d72a9be85" dependencies = [ "alloy-eip2930", - "alloy-eip7702 0.1.1", + "alloy-eip7702", "alloy-primitives 0.8.18", "alloy-rlp", "alloy-serde", @@ -3117,7 +3104,7 @@ dependencies = [ "ethrex-trie", "hex", "lazy_static", - "revm 19.3.0", + "revm 14.0.3", "revm-inspectors", "revm-primitives 10.0.0", "serde", @@ -6629,21 +6616,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "revm" -version = "19.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a5a57589c308880c0f89ebf68d92aeef0d51e1ed88867474f895f6fd0f25c64" -dependencies = [ - "auto_impl", - "cfg-if", - "dyn-clone", - "revm-interpreter 15.1.0", - "revm-precompile 16.0.0", - "serde", - "serde_json", -] - [[package]] name = "revm-inspectors" version = "0.8.1" @@ -6681,16 +6653,6 @@ dependencies = [ "serde", ] -[[package]] -name = "revm-interpreter" -version = "15.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0f632e761f171fb2f6ace8d1552a5793e0350578d4acec3e79ade1489f4c2a6" -dependencies = [ - "revm-primitives 15.1.0", - "serde", -] - [[package]] name = "revm-precompile" version = "7.0.0" @@ -6714,24 +6676,6 @@ name = "revm-precompile" version = "11.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3198c06247e8d4ad0d1312591edf049b0de4ddffa9fecb625c318fd67db8639b" -dependencies = [ - "aurora-engine-modexp", - "c-kzg", - "cfg-if", - "k256", - "once_cell", - "revm-primitives 10.0.0", - "ripemd", - "secp256k1", - "sha2 0.10.8", - "substrate-bn", -] - -[[package]] -name = "revm-precompile" -version = "16.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6542fb37650dfdbf4b9186769e49c4a8bc1901a3280b2ebf32f915b6c8850f36" dependencies = [ "aurora-engine-modexp", "blst", @@ -6739,7 +6683,7 @@ dependencies = [ "cfg-if", "k256", "once_cell", - "revm-primitives 15.1.0", + "revm-primitives 10.0.0", "ripemd", "secp256k1", "sha2 0.10.8", @@ -6774,27 +6718,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f1525851a03aff9a9d6a1d018b414d76252d6802ab54695b27093ecd7e7a101" dependencies = [ "alloy-eip2930", - "alloy-eip7702 0.1.1", - "alloy-primitives 0.8.18", - "auto_impl", - "bitflags 2.6.0", - "bitvec", - "c-kzg", - "cfg-if", - "dyn-clone", - "enumn", - "hex", - "serde", -] - -[[package]] -name = "revm-primitives" -version = "15.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48faea1ecf2c9f80d9b043bbde0db9da616431faed84c4cfa3dd7393005598e6" -dependencies = [ - "alloy-eip2930", - "alloy-eip7702 0.5.0", + "alloy-eip7702", "alloy-primitives 0.8.18", "auto_impl", "bitflags 2.6.0", diff --git a/crates/vm/Cargo.toml b/crates/vm/Cargo.toml index 0bf78f5849..b183689baf 100644 --- a/crates/vm/Cargo.toml +++ b/crates/vm/Cargo.toml @@ -9,7 +9,7 @@ ethrex-storage = { path = "../storage/store", default-features = false } ethrex-levm = { path = "./levm", optional = true } ethrex-trie = { path = "../storage/trie", default-features = false } ethrex-rlp = { path = "../common/rlp", default-features = false } -revm = { version = "19.3.0", features = [ +revm = { version = "14.0.3", features = [ "serde", "std", "serde-json", From 4f2853a7ad6f26ba0146c13ab6506d4234dd6409 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 22 Jan 2025 11:29:57 -0300 Subject: [PATCH 52/84] chore: revert revm bump --- crates/vm/levm/rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/vm/levm/rust-toolchain.toml b/crates/vm/levm/rust-toolchain.toml index 2e2b8c8521..1de01fa45c 100644 --- a/crates/vm/levm/rust-toolchain.toml +++ b/crates/vm/levm/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.82.0" +channel = "1.81.0" From 5e7e2123f3f49234bced708cde51902ce119f69e Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 22 Jan 2025 11:31:27 -0300 Subject: [PATCH 53/84] chore: revert revm bump --- crates/vm/vm.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/crates/vm/vm.rs b/crates/vm/vm.rs index fb775393bf..f6649ea6a6 100644 --- a/crates/vm/vm.rs +++ b/crates/vm/vm.rs @@ -378,7 +378,7 @@ pub fn execute_tx( state: &mut EvmState, spec_id: SpecId, ) -> Result { - let block_env = block_env(header, is_prague(spec_id)); + let block_env = block_env(header); let tx_env = tx_env(tx); run_evm(tx_env, block_env, state, spec_id) } @@ -390,7 +390,7 @@ pub fn simulate_tx_from_generic( state: &mut EvmState, spec_id: SpecId, ) -> Result { - let block_env = block_env(header, is_prague(spec_id)); + let block_env = block_env(header); let tx_env = tx_env_from_generic(tx, header.base_fee_per_gas.unwrap_or(INITIAL_BASE_FEE)); run_without_commit(tx_env, block_env, state, spec_id) } @@ -468,7 +468,7 @@ pub fn create_access_list( spec_id: SpecId, ) -> Result<(ExecutionResult, AccessList), EvmError> { let mut tx_env = tx_env_from_generic(tx, header.base_fee_per_gas.unwrap_or(INITIAL_BASE_FEE)); - let block_env = block_env(header, is_prague(spec_id)); + let block_env = block_env(header); // Run tx with access list inspector let (execution_result, access_list) = @@ -777,7 +777,7 @@ pub fn beacon_root_contract_call( data: revm::primitives::Bytes::copy_from_slice(beacon_root.as_bytes()), ..Default::default() }; - let mut block_env = block_env(header, is_prague(spec_id)); + let mut block_env = block_env(header); block_env.basefee = RevmU256::ZERO; block_env.gas_limit = RevmU256::from(30_000_000); @@ -814,7 +814,7 @@ pub fn beacon_root_contract_call( } } -pub fn block_env(header: &BlockHeader, is_prague: bool) -> BlockEnv { +pub fn block_env(header: &BlockHeader) -> BlockEnv { BlockEnv { number: RevmU256::from(header.number), coinbase: RevmAddress(header.coinbase.0.into()), @@ -825,7 +825,6 @@ pub fn block_env(header: &BlockHeader, is_prague: bool) -> BlockEnv { prevrandao: Some(header.prev_randao.as_fixed_bytes().into()), blob_excess_gas_and_price: Some(BlobExcessGasAndPrice::new( header.excess_blob_gas.unwrap_or_default(), - is_prague, )), } } @@ -1004,6 +1003,7 @@ fn calculate_gas_price(tx: &GenericTransaction, basefee: u64) -> Uint<256, 4> { } } -pub fn is_prague(spec_id: SpecId) -> bool { - spec_id >= SpecId::PRAGUE -} +// USED for revm ^19.0.0 +//pub fn is_prague(spec_id: SpecId) -> bool { +// spec_id >= SpecId::PRAGUE +//} From d2e73b6adec16baa92aa37a92dda676c9a917fd1 Mon Sep 17 00:00:00 2001 From: Tomas Fabrizio Orsi Date: Wed, 22 Jan 2025 12:53:39 -0300 Subject: [PATCH 54/84] Apply clippy suggestion --- crates/vm/db.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/crates/vm/db.rs b/crates/vm/db.rs index ca59611749..cb9024673a 100644 --- a/crates/vm/db.rs +++ b/crates/vm/db.rs @@ -42,11 +42,7 @@ cfg_if::cfg_if! { .get_account_info_by_hash(self.block_hash, address) .unwrap(); - if let Some(_) = acc_info { - true - } else { - false - } + acc_info.is_some() } fn get_storage_slot(&self, address: CoreAddress, key: CoreH256) -> CoreU256 { From 0d4f2561209b26505e54c09981b1d8d53a4af16e Mon Sep 17 00:00:00 2001 From: Tomas Fabrizio Orsi Date: Wed, 22 Jan 2025 12:59:19 -0300 Subject: [PATCH 55/84] Remove unused fields --- crates/vm/levm/src/call_frame.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/vm/levm/src/call_frame.rs b/crates/vm/levm/src/call_frame.rs index 362b5ae949..1adaa113d9 100644 --- a/crates/vm/levm/src/call_frame.rs +++ b/crates/vm/levm/src/call_frame.rs @@ -85,8 +85,6 @@ pub struct CallFrame { pub valid_jump_destinations: HashSet, /// This is set to true if the function that created this callframe is CREATE or CREATE2 pub create_op_called: bool, - /// Set to true if the bytecode comes from an EIP7702 tx - pub is_delegation: bool, } impl CallFrame { From 9ee14e874a7e130dddfc60a6b990b60b991d351f Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 22 Jan 2025 13:38:25 -0300 Subject: [PATCH 56/84] chore: revert Cargo.lock changes --- Cargo.lock | 88 ++++++++++--------- cmd/ef_tests/levm/runner/revm_runner.rs | 2 +- .../vm/levm/bench/revm_comparison/Cargo.toml | 6 +- 3 files changed, 50 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e239748ed1..855281c0ab 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -107,7 +107,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "705687d5bfd019fee57cf9e206b27b30a9a9617535d5590a02b171e813208f8e" dependencies = [ "alloy-eips", - "alloy-primitives 0.8.18", + "alloy-primitives 0.8.14", "alloy-rlp", "alloy-serde", "auto_impl", @@ -122,7 +122,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41" dependencies = [ - "alloy-primitives 0.8.18", + "alloy-primitives 0.8.14", "alloy-rlp", "serde", ] @@ -133,7 +133,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea59dc42102bc9a1905dc57901edc6dd48b9f38115df86c7d252acba70d71d04" dependencies = [ - "alloy-primitives 0.8.18", + "alloy-primitives 0.8.14", "alloy-rlp", "k256", "serde", @@ -147,7 +147,7 @@ checksum = "6ffb906284a1e1f63c4607da2068c8197458a352d0b3e9796e67353d72a9be85" dependencies = [ "alloy-eip2930", "alloy-eip7702", - "alloy-primitives 0.8.18", + "alloy-primitives 0.8.14", "alloy-rlp", "alloy-serde", "c-kzg", @@ -159,11 +159,11 @@ dependencies = [ [[package]] name = "alloy-json-abi" -version = "0.8.18" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "731ea743b3d843bc657e120fb1d1e9cc94f5dab8107e35a82125a63e6420a102" +checksum = "ac4b22b3e51cac09fd2adfcc73b55f447b4df669f983c13f7894ec82b607c63f" dependencies = [ - "alloy-primitives 0.8.18", + "alloy-primitives 0.8.14", "alloy-sol-type-parser", "serde", "serde_json", @@ -177,7 +177,7 @@ checksum = "801492711d4392b2ccf5fc0bc69e299fa1aab15167d74dcaa9aab96a54f684bd" dependencies = [ "alloy-consensus", "alloy-eips", - "alloy-primitives 0.8.18", + "alloy-primitives 0.8.14", "alloy-serde", "serde", ] @@ -206,9 +206,9 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "0.8.18" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "788bb18e8f61d5d9340b52143f27771daf7e1dccbaf2741621d2493f9debf52e" +checksum = "9db948902dfbae96a73c2fbf1f7abec62af034ab883e4c777c3fd29702bd6e2c" dependencies = [ "alloy-rlp", "bytes", @@ -217,6 +217,7 @@ dependencies = [ "derive_more 1.0.0", "foldhash", "hashbrown 0.15.2", + "hex-literal", "indexmap 2.6.0", "itoa", "k256", @@ -225,7 +226,7 @@ dependencies = [ "proptest", "rand 0.8.5", "ruint", - "rustc-hash 2.1.0", + "rustc-hash 2.0.0", "serde", "sha3", "tiny-keccak", @@ -262,10 +263,10 @@ dependencies = [ "alloy-consensus", "alloy-eips", "alloy-network-primitives", - "alloy-primitives 0.8.18", + "alloy-primitives 0.8.14", "alloy-rlp", "alloy-serde", - "alloy-sol-types 0.8.18", + "alloy-sol-types 0.8.14", "derive_more 1.0.0", "itertools 0.13.0", "serde", @@ -278,7 +279,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "017cad3e5793c5613588c1f9732bcbad77e820ba7d0feaba3527749f856fdbc5" dependencies = [ - "alloy-primitives 0.8.18", + "alloy-primitives 0.8.14", "alloy-rpc-types-eth", "alloy-serde", "serde", @@ -292,7 +293,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9dff0ab1cdd43ca001e324dc27ee0e8606bd2161d6623c63e0e0b8c4dfc13600" dependencies = [ - "alloy-primitives 0.8.18", + "alloy-primitives 0.8.14", "serde", "serde_json", ] @@ -313,12 +314,12 @@ dependencies = [ [[package]] name = "alloy-sol-macro" -version = "0.8.18" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a07b74d48661ab2e4b50bb5950d74dbff5e61dd8ed03bb822281b706d54ebacb" +checksum = "3bfd7853b65a2b4f49629ec975fee274faf6dff15ab8894c620943398ef283c0" dependencies = [ - "alloy-sol-macro-expander 0.8.18", - "alloy-sol-macro-input 0.8.18", + "alloy-sol-macro-expander 0.8.14", + "alloy-sol-macro-input 0.8.14", "proc-macro-error2", "proc-macro2", "quote", @@ -345,11 +346,11 @@ dependencies = [ [[package]] name = "alloy-sol-macro-expander" -version = "0.8.18" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19cc9c7f20b90f9be1a8f71a3d8e283a43745137b0837b1a1cb13159d37cad72" +checksum = "82ec42f342d9a9261699f8078e57a7a4fda8aaa73c1a212ed3987080e6a9cd13" dependencies = [ - "alloy-sol-macro-input 0.8.18", + "alloy-sol-macro-input 0.8.14", "const-hex", "heck 0.5.0", "indexmap 2.6.0", @@ -357,7 +358,7 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.89", - "syn-solidity 0.8.18", + "syn-solidity 0.8.14", "tiny-keccak", ] @@ -378,9 +379,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-input" -version = "0.8.18" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713b7e6dfe1cb2f55c80fb05fd22ed085a1b4e48217611365ed0ae598a74c6ac" +checksum = "ed2c50e6a62ee2b4f7ab3c6d0366e5770a21cad426e109c2f40335a1b3aff3df" dependencies = [ "const-hex", "dunce", @@ -388,14 +389,14 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.89", - "syn-solidity 0.8.18", + "syn-solidity 0.8.14", ] [[package]] name = "alloy-sol-type-parser" -version = "0.8.18" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1eda2711ab2e1fb517fc6e2ffa9728c9a232e296d16810810e6957b781a1b8bc" +checksum = "ac17c6e89a50fb4a758012e4b409d9a0ba575228e69b539fe37d7a1bd507ca4a" dependencies = [ "serde", "winnow 0.6.20", @@ -415,13 +416,13 @@ dependencies = [ [[package]] name = "alloy-sol-types" -version = "0.8.18" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b478bc9c0c4737a04cd976accde4df7eba0bdc0d90ad6ff43d58bc93cf79c1" +checksum = "c9dc0fffe397aa17628160e16b89f704098bf3c9d74d5d369ebc239575936de5" dependencies = [ "alloy-json-abi", - "alloy-primitives 0.8.18", - "alloy-sol-macro 0.8.18", + "alloy-primitives 0.8.14", + "alloy-sol-macro 0.8.14", "const-hex", "serde", ] @@ -2826,6 +2827,7 @@ dependencies = [ "sha3", "thiserror 2.0.9", "tinyvec", + "tracing", ] [[package]] @@ -3289,9 +3291,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" -version = "0.1.4" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" [[package]] name = "foreign-types" @@ -6220,7 +6222,7 @@ dependencies = [ "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 2.1.0", + "rustc-hash 2.0.0", "rustls", "socket2", "thiserror 2.0.9", @@ -6238,7 +6240,7 @@ dependencies = [ "getrandom", "rand 0.8.5", "ring 0.17.8", - "rustc-hash 2.1.0", + "rustc-hash 2.0.0", "rustls", "rustls-pki-types", "slab", @@ -6622,10 +6624,10 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43c44af0bf801f48d25f7baf25cf72aff4c02d610f83b428175228162fef0246" dependencies = [ - "alloy-primitives 0.8.18", + "alloy-primitives 0.8.14", "alloy-rpc-types-eth", "alloy-rpc-types-trace", - "alloy-sol-types 0.8.18", + "alloy-sol-types 0.8.14", "anstyle", "colorchoice", "revm 14.0.3", @@ -6719,7 +6721,7 @@ checksum = "6f1525851a03aff9a9d6a1d018b414d76252d6802ab54695b27093ecd7e7a101" dependencies = [ "alloy-eip2930", "alloy-eip7702", - "alloy-primitives 0.8.18", + "alloy-primitives 0.8.14", "auto_impl", "bitflags 2.6.0", "bitvec", @@ -7157,9 +7159,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.1.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" [[package]] name = "rustc-hex" @@ -8372,9 +8374,9 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "0.8.18" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e89d8bf2768d277f40573c83a02a099e96d96dd3104e13ea676194e61ac4b0" +checksum = "da0523f59468a2696391f2a772edc089342aacd53c3caa2ac3264e598edf119b" dependencies = [ "paste", "proc-macro2", diff --git a/cmd/ef_tests/levm/runner/revm_runner.rs b/cmd/ef_tests/levm/runner/revm_runner.rs index 9239f3cb49..07b0385a8d 100644 --- a/cmd/ef_tests/levm/runner/revm_runner.rs +++ b/cmd/ef_tests/levm/runner/revm_runner.rs @@ -114,7 +114,7 @@ pub fn prepare_revm_for_tx<'state>( blob_excess_gas_and_price: test .env .current_excess_blob_gas - .map(|gas| BlobExcessGasAndPrice::new(gas.as_u64(), true)), + .map(|gas| BlobExcessGasAndPrice::new(gas.as_u64())), }; let tx = &test .transactions diff --git a/crates/vm/levm/bench/revm_comparison/Cargo.toml b/crates/vm/levm/bench/revm_comparison/Cargo.toml index 59e2c04312..03bae8f89b 100644 --- a/crates/vm/levm/bench/revm_comparison/Cargo.toml +++ b/crates/vm/levm/bench/revm_comparison/Cargo.toml @@ -9,9 +9,11 @@ path = "src/lib.rs" [dependencies] ethrex-levm = { path = "../../" } -hex = "0.4.3" + +hex.workspace = true +bytes.workspace = true + revm = "9.0.0" -bytes = "1.8.0" [[bin]] name = "levm_factorial" From 683be851747f496706c46f18dc92823a91d7652e Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 22 Jan 2025 13:45:43 -0300 Subject: [PATCH 57/84] chore: rm unneeded code --- Cargo.lock | 1 - cmd/ef_tests/levm/runner/revm_runner.rs | 5 ++--- crates/vm/levm/src/vm.rs | 2 +- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 855281c0ab..d466df48e7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2827,7 +2827,6 @@ dependencies = [ "sha3", "thiserror 2.0.9", "tinyvec", - "tracing", ] [[package]] diff --git a/cmd/ef_tests/levm/runner/revm_runner.rs b/cmd/ef_tests/levm/runner/revm_runner.rs index 07b0385a8d..db65e6b43f 100644 --- a/cmd/ef_tests/levm/runner/revm_runner.rs +++ b/cmd/ef_tests/levm/runner/revm_runner.rs @@ -19,9 +19,8 @@ use revm::{ db::State, inspectors::TracerEip3155 as RevmTracerEip3155, primitives::{ - AccessListItem, Authorization, BlobExcessGasAndPrice, BlockEnv as RevmBlockEnv, - EVMError as REVMError, ExecutionResult as RevmExecutionResult, SignedAuthorization, - TxEnv as RevmTxEnv, TxKind as RevmTxKind, B256, + AccessListItem, BlobExcessGasAndPrice, BlockEnv as RevmBlockEnv, EVMError as REVMError, + ExecutionResult as RevmExecutionResult, TxEnv as RevmTxEnv, TxKind as RevmTxKind, B256, }, Evm as Revm, }; diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 768e426bdd..70ab712604 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -3,7 +3,7 @@ use crate::{ call_frame::CallFrame, constants::*, db::{ - cache::{self, get_account_mut, insert_account, remove_account}, + cache::{self, get_account_mut, remove_account}, CacheDB, Database, }, environment::Environment, From 78e3aabe11b4cf595da097896e1bd944d16a115a Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 22 Jan 2025 14:29:25 -0300 Subject: [PATCH 58/84] chore: tidy-up --- crates/vm/levm/src/errors.rs | 10 +++------- crates/vm/levm/src/vm.rs | 25 +++++++------------------ 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/crates/vm/levm/src/errors.rs b/crates/vm/levm/src/errors.rs index d3ca206edf..c8592477ce 100644 --- a/crates/vm/levm/src/errors.rs +++ b/crates/vm/levm/src/errors.rs @@ -74,8 +74,6 @@ pub enum VMError { OutOfBounds, #[error("Precompile execution error: {0}")] PrecompileError(#[from] PrecompileError), - #[error("EIP7702 execution error: {0}")] - EIP7702Error(#[from] EIP7702Error), } impl VMError { @@ -192,6 +190,8 @@ pub enum InternalError { InvalidPrecompileAddress, #[error("Spec Id doesn't match to any fork")] InvalidSpecId, + #[error("EIP7702 error")] + EIP7702Internal(#[from] EIP7702Error), } #[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, Serialize, Deserialize)] @@ -214,11 +214,7 @@ pub enum PrecompileError { #[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, Serialize, Deserialize)] pub enum EIP7702Error { - #[error("ChainID is not 0 nor the blockchain's id")] - ChainIdError, - #[error("Internal Error while parsing signatures")] - ErrorParsingSignature, - #[error("Internal Error while geting the authorized address")] + #[error("Internal Error while getting the authorized address")] AuthorizedAddressError, } diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 70ab712604..8c661765d3 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -8,8 +8,8 @@ use crate::{ }, environment::Environment, errors::{ - InternalError, OpcodeSuccess, OutOfGasError, ResultReason, TransactionReport, TxResult, - TxValidationError, VMError, + EIP7702Error, InternalError, OpcodeSuccess, OutOfGasError, ResultReason, TransactionReport, + TxResult, TxValidationError, VMError, }, gas_cost::{ self, fake_exponential, ACCESS_LIST_ADDRESS_COST, ACCESS_LIST_STORAGE_KEY_COST, @@ -1648,20 +1648,6 @@ pub fn get_account_no_push_cache( } } -pub fn was_delegated_from_bytecode(bytecode: &Bytes) -> Result { - let mut was_delegated = false; - if !bytecode.is_empty() && bytecode.len() == EIP7702_DELEGATED_CODE_LEN { - let first_3_bytes = bytecode - .get(..3) - .ok_or(VMError::Internal(InternalError::SlicingError))?; - - if first_3_bytes == SET_CODE_DELEGATION_BYTES { - was_delegated = true; - } - } - Ok(was_delegated) -} - pub fn was_delegated(account_info: &AccountInfo) -> Result { let mut was_delegated = false; if account_info.has_code() && account_info.bytecode.len() == EIP7702_DELEGATED_CODE_LEN { @@ -1683,11 +1669,14 @@ pub fn get_authorized_address(account_info: &AccountInfo) -> Result Date: Wed, 22 Jan 2025 14:44:39 -0300 Subject: [PATCH 59/84] chore: tidy-up --- cmd/ef_tests/levm/runner/levm_runner.rs | 2 -- crates/vm/levm/src/vm.rs | 7 +++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/cmd/ef_tests/levm/runner/levm_runner.rs b/cmd/ef_tests/levm/runner/levm_runner.rs index 5baa26c86f..10fc4ebc07 100644 --- a/cmd/ef_tests/levm/runner/levm_runner.rs +++ b/cmd/ef_tests/levm/runner/levm_runner.rs @@ -98,8 +98,6 @@ pub fn prepare_vm_for_tx(vector: &TestVector, test: &EFTest) -> Result>() }); diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 8c661765d3..ec07e05427 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -104,7 +104,6 @@ pub struct AuthorizationTuple { pub v: U256, pub r_signature: U256, pub s_signature: U256, - pub signer: Address, } pub fn get_valid_jump_destinations(code: &Bytes) -> Result, VMError> { @@ -1396,7 +1395,7 @@ impl VM { } // 2. Verify the nonce is less than 2**64 - 1. - // CHECK nonce is u64, should never be greater than u64::MAX + // NOTE: nonce is a u64, is always less or equal to u64::MAX if auth_tuple.nonce == u64::MAX { continue; } @@ -1675,8 +1674,8 @@ pub fn get_authorized_address(account_info: &AccountInfo) -> Result Date: Wed, 22 Jan 2025 14:48:35 -0300 Subject: [PATCH 60/84] chore: linter --- crates/vm/levm/src/vm.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index ec07e05427..82b6a764ed 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -1638,11 +1638,10 @@ pub fn get_account_no_push_cache( Some(acc) => acc.clone(), None => { let account_info = db.get_account_info(address); - let account = Account { + Account { info: account_info, storage: HashMap::new(), - }; - account + } } } } From b26c65a204878e40685cf2f5e41789ecc02e44e3 Mon Sep 17 00:00:00 2001 From: Tomas Fabrizio Orsi Date: Wed, 22 Jan 2025 14:50:35 -0300 Subject: [PATCH 61/84] Add comment explaining needed toolchain and compiler versions --- cmd/ef_tests/levm/runner/revm_runner.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmd/ef_tests/levm/runner/revm_runner.rs b/cmd/ef_tests/levm/runner/revm_runner.rs index db65e6b43f..cfcce780c6 100644 --- a/cmd/ef_tests/levm/runner/revm_runner.rs +++ b/cmd/ef_tests/levm/runner/revm_runner.rs @@ -137,9 +137,14 @@ pub fn prepare_revm_for_tx<'state>( .collect(); let authorization_list = None; + + // WARNING: Do not delete the following. // The latest version of revm(19.3.0) is needed. // Update it in every Cargo.toml. // revm-inspectors and revm-primitives have to be bumped too. + // NOTE: + // - rust 1.82.X is needed + // - rust-toolchain 1.82.X is needed (this can be found in ethrex/crates/vm/levm/rust-toolchain.toml) /* let authorization_list = tx.authorization_list.clone().map(|list| { list.iter() From b87f213ac727e3d1f606dd88d00c0f17132e5298 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 22 Jan 2025 15:21:32 -0300 Subject: [PATCH 62/84] chore: comment --- crates/vm/levm/src/vm.rs | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 5bc596e15b..9bc9f2613c 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -1000,28 +1000,23 @@ impl VM { let sender_address = initial_call_frame.msg_sender; let receiver_address = initial_call_frame.to; - // 1. Undo value transfer if the transaction was reverted + // 1. Undo value transfer if the transaction has reverted if let TxResult::Revert(_) = report.result { - // We remove the receiver account from the cache, like nothing changed in it's state. - // I think this is wrong, we shouldn't remove the delegated accounts from cache, but if we send - // tokens to an account that has a delegation, but the tx reverts by any other reason, it will - // not remove the account. - let existing_account = get_account(&mut self.cache, &self.db, receiver_address); //TO Account - // This is the case where the "to" address and the - // "signer" address are the same. We are setting the code - // and sending some balance to the "to"/"signer" - // address. - // See https://eips.ethereum.org/EIPS/eip-7702#behavior (last sentence). - - // If transaction execution results in failure (any - // exceptional condition or code reverting), setting - // delegation designations is not rolled back. - if was_delegated(&existing_account.info)? { + // This is the case where the "to" address and the + // "signer" address are the same. We are setting the code + // and sending some balance to the "to"/"signer" + // address. + // See https://eips.ethereum.org/EIPS/eip-7702#behavior (last sentence). + + // If transaction execution results in failure (any + // exceptional condition or code reverting), setting + // delegation designations is not rolled back. self.decrease_account_balance(receiver_address, initial_call_frame.msg_value)?; } else { + // We remove the receiver account from the cache, like nothing changed in it's state. remove_account(&mut self.cache, &receiver_address); } From 11d68003097fcdc91ec11b28286d1149addb0415 Mon Sep 17 00:00:00 2001 From: Federico Borello <156438142+fborello-lambda@users.noreply.github.com> Date: Wed, 22 Jan 2025 15:22:33 -0300 Subject: [PATCH 63/84] Update crates/vm/levm/src/vm.rs Co-authored-by: Tomas Fabrizio Orsi --- crates/vm/levm/src/vm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 9bc9f2613c..004728f027 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -626,7 +626,7 @@ impl VM { .ok_or(OutOfGasError::ConsumedGasOverflow)?; // Authorization List Cost - // When using unwrap_or_default we will get an empty vec in case the authorization_list field is None. + // `unwrap_or_default` will return an empty vec when the `authorization_list` field is None. // If the vec is empty, the len will be 0, thus the authorization_list_cost is 0. let amount_of_auth_tuples: u64 = self .authorization_list From 94c3070502914d60e6bca48ff13fd2fcf135a47b Mon Sep 17 00:00:00 2001 From: Federico Borello <156438142+fborello-lambda@users.noreply.github.com> Date: Wed, 22 Jan 2025 15:22:43 -0300 Subject: [PATCH 64/84] Update crates/vm/levm/src/vm.rs Co-authored-by: Tomas Fabrizio Orsi --- crates/vm/levm/src/vm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 004728f027..028642f1f3 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -1392,7 +1392,7 @@ impl VM { } // 2. Verify the nonce is less than 2**64 - 1. - // NOTE: nonce is a u64, is always less or equal to u64::MAX + // NOTE: nonce is a u64, it's always less or equal to u64::MAX if auth_tuple.nonce == u64::MAX { continue; } From 3f37d1694706a78ce4a66d2ec5747fff3abb767d Mon Sep 17 00:00:00 2001 From: Federico Borello <156438142+fborello-lambda@users.noreply.github.com> Date: Wed, 22 Jan 2025 15:22:55 -0300 Subject: [PATCH 65/84] Update crates/vm/levm/src/vm.rs Co-authored-by: Tomas Fabrizio Orsi --- crates/vm/levm/src/vm.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 028642f1f3..7c801867c3 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -1508,6 +1508,7 @@ impl VM { Some(account_mut) => account_mut, None => { // This is to add the account to the cache + // NOTE: Refactor in the future self.get_account(authority_address); self.get_account_mut(authority_address)? } From 0b3d648272eae29a1bdfb0be7beca73419aae9f4 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 22 Jan 2025 15:27:16 -0300 Subject: [PATCH 66/84] chore: linter --- crates/vm/levm/src/constants.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/vm/levm/src/constants.rs b/crates/vm/levm/src/constants.rs index 610ee3583c..aa1e3f4ad4 100644 --- a/crates/vm/levm/src/constants.rs +++ b/crates/vm/levm/src/constants.rs @@ -59,4 +59,3 @@ pub const SET_CODE_DELEGATION_BYTES: [u8; 3] = [0xef, 0x01, 0x00]; pub const EIP7702_DELEGATED_CODE_LEN: usize = 23; pub const PER_AUTH_BASE_COST: u64 = 12500; pub const PER_EMPTY_ACCOUNT_COST: u64 = 25000; - From 18111d3f50a66898ef34f907bba34f9a3a479962 Mon Sep 17 00:00:00 2001 From: Tomas Fabrizio Orsi Date: Wed, 22 Jan 2025 15:28:36 -0300 Subject: [PATCH 67/84] refactor: Rename `was_delegated` to `has_delegation` --- .../levm/src/opcode_handlers/environment.rs | 8 +++---- crates/vm/levm/src/vm.rs | 22 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/crates/vm/levm/src/opcode_handlers/environment.rs b/crates/vm/levm/src/opcode_handlers/environment.rs index f058cb6bb5..d82ea00b5b 100644 --- a/crates/vm/levm/src/opcode_handlers/environment.rs +++ b/crates/vm/levm/src/opcode_handlers/environment.rs @@ -4,7 +4,7 @@ use crate::{ errors::{InternalError, OpcodeSuccess, VMError}, gas_cost::{self}, memory::{self, calculate_memory_size}, - vm::{was_delegated, word_to_address, VM}, + vm::{has_delegation, word_to_address, VM}, }; use ethrex_core::U256; use keccak_hash::keccak; @@ -281,7 +281,7 @@ impl VM { let (account_info, address_was_cold) = self.access_account(address); // https://eips.ethereum.org/EIPS/eip-7702#delegation-designation - let is_delegation = was_delegated(&account_info)?; + let is_delegation = has_delegation(&account_info)?; self.increase_consumed_gas(current_call_frame, gas_cost::extcodesize(address_was_cold)?)?; @@ -317,7 +317,7 @@ impl VM { let new_memory_size = calculate_memory_size(dest_offset, size)?; // https://eips.ethereum.org/EIPS/eip-7702#delegation-designation - let is_delegation = was_delegated(&account_info)?; + let is_delegation = has_delegation(&account_info)?; self.increase_consumed_gas( current_call_frame, @@ -438,7 +438,7 @@ impl VM { let (account_info, address_was_cold) = self.access_account(address); // https://eips.ethereum.org/EIPS/eip-7702#delegation-designation - let is_delegation = was_delegated(&account_info)?; + let is_delegation = has_delegation(&account_info)?; self.increase_consumed_gas(current_call_frame, gas_cost::extcodehash(address_was_cold)?)?; diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 7c801867c3..49ecd2420c 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -894,7 +894,7 @@ impl VM { } // (9) SENDER_NOT_EOA - if sender_account.has_code() && !was_delegated(&sender_account.info)? { + if sender_account.has_code() && !has_delegation(&sender_account.info)? { return Err(VMError::TxValidation(TxValidationError::SenderNotEOA)); } @@ -1004,7 +1004,7 @@ impl VM { if let TxResult::Revert(_) = report.result { let existing_account = get_account(&mut self.cache, &self.db, receiver_address); //TO Account - if was_delegated(&existing_account.info)? { + if has_delegation(&existing_account.info)? { // This is the case where the "to" address and the // "signer" address are the same. We are setting the code // and sending some balance to the "to"/"signer" @@ -1474,7 +1474,7 @@ impl VM { // 5. Verify the code of authority is either empty or already delegated. let empty_or_delegated = authority_account_info.bytecode.is_empty() - || was_delegated(&authority_account_info)?; + || has_delegation(&authority_account_info)?; if !empty_or_delegated { continue; } @@ -1527,7 +1527,7 @@ impl VM { let (code_address_info, _) = self.access_account(initial_call_frame.code_address); - if was_delegated(&code_address_info)? { + if has_delegation(&code_address_info)? { initial_call_frame.code_address = get_authorized_address(&code_address_info)?; let (auth_address_info, _) = self.access_account(initial_call_frame.code_address); @@ -1569,7 +1569,7 @@ impl VM { // return false meaning that is not a delegation // return the same address given // return the bytecode of the given address - if !was_delegated(&account.info)? { + if !has_delegation(&account.info)? { return Ok((false, 0, address, bytecode)); } @@ -1644,8 +1644,8 @@ pub fn get_account_no_push_cache( } } -pub fn was_delegated(account_info: &AccountInfo) -> Result { - let mut was_delegated = false; +pub fn has_delegation(account_info: &AccountInfo) -> Result { + let mut has_delegation = false; if account_info.has_code() && account_info.bytecode.len() == EIP7702_DELEGATED_CODE_LEN { let first_3_bytes = account_info .bytecode @@ -1653,20 +1653,20 @@ pub fn was_delegated(account_info: &AccountInfo) -> Result { .ok_or(VMError::Internal(InternalError::SlicingError))?; if first_3_bytes == SET_CODE_DELEGATION_BYTES { - was_delegated = true; + has_delegation = true; } } - Ok(was_delegated) + Ok(has_delegation) } pub fn get_authorized_address(account_info: &AccountInfo) -> Result { - if was_delegated(account_info)? { + if has_delegation(account_info)? { let address_bytes = account_info .bytecode .get(SET_CODE_DELEGATION_BYTES.len()..) .ok_or(VMError::Internal(InternalError::SlicingError))?; // It shouldn't panic when doing Address::from_slice() - // because the length is checked inside the was_delegated() function + // because the length is checked inside the has_delegation() function let address = Address::from_slice(address_bytes); Ok(address) } else { From 2c72ea5735a502358c89bec624380aa93d98d308 Mon Sep 17 00:00:00 2001 From: Federico Borello <156438142+fborello-lambda@users.noreply.github.com> Date: Wed, 22 Jan 2025 16:50:13 -0300 Subject: [PATCH 68/84] Update crates/vm/levm/src/errors.rs Co-authored-by: Ivan Litteri <67517699+ilitteri@users.noreply.github.com> --- crates/vm/levm/src/errors.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/vm/levm/src/errors.rs b/crates/vm/levm/src/errors.rs index c8592477ce..2e1b76470d 100644 --- a/crates/vm/levm/src/errors.rs +++ b/crates/vm/levm/src/errors.rs @@ -190,8 +190,8 @@ pub enum InternalError { InvalidPrecompileAddress, #[error("Spec Id doesn't match to any fork")] InvalidSpecId, - #[error("EIP7702 error")] - EIP7702Internal(#[from] EIP7702Error), + #[error("Account should had been delegated")] + AccountNotDelegated, } #[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, Serialize, Deserialize)] From f66c681d75998e77a93b4b8dda7164d51c44ff47 Mon Sep 17 00:00:00 2001 From: Federico Borello <156438142+fborello-lambda@users.noreply.github.com> Date: Wed, 22 Jan 2025 16:50:39 -0300 Subject: [PATCH 69/84] Update crates/vm/levm/src/opcode_handlers/environment.rs Co-authored-by: Ivan Litteri <67517699+ilitteri@users.noreply.github.com> --- crates/vm/levm/src/opcode_handlers/environment.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/crates/vm/levm/src/opcode_handlers/environment.rs b/crates/vm/levm/src/opcode_handlers/environment.rs index d82ea00b5b..fd855db926 100644 --- a/crates/vm/levm/src/opcode_handlers/environment.rs +++ b/crates/vm/levm/src/opcode_handlers/environment.rs @@ -285,15 +285,11 @@ impl VM { self.increase_consumed_gas(current_call_frame, gas_cost::extcodesize(address_was_cold)?)?; - if is_delegation { - current_call_frame - .stack - .push(SET_CODE_DELEGATION_BYTES[..2].len().into())?; + current_call_frame.stack.push(if is_delegation { + SET_CODE_DELEGATION_BYTES[..2].len().into() } else { - current_call_frame - .stack - .push(account_info.bytecode.len().into())?; - } + account_info.bytecode.len().into() + })?; Ok(OpcodeSuccess::Continue) } From c993e946bdbb03e2c999ab4070c33a3d58c5ce8e Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 22 Jan 2025 16:53:26 -0300 Subject: [PATCH 70/84] pr_comments: implement suggestions --- crates/vm/levm/src/errors.rs | 6 ------ crates/vm/levm/src/vm.rs | 8 +++----- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/crates/vm/levm/src/errors.rs b/crates/vm/levm/src/errors.rs index 2e1b76470d..17c47aa9b4 100644 --- a/crates/vm/levm/src/errors.rs +++ b/crates/vm/levm/src/errors.rs @@ -212,12 +212,6 @@ pub enum PrecompileError { BLS12381G2PointNotInCurve, } -#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error, Serialize, Deserialize)] -pub enum EIP7702Error { - #[error("Internal Error while getting the authorized address")] - AuthorizedAddressError, -} - #[derive(Debug, Clone)] pub enum OpcodeSuccess { Continue, diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 49ecd2420c..c4250ad48d 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -8,8 +8,8 @@ use crate::{ }, environment::Environment, errors::{ - EIP7702Error, InternalError, OpcodeSuccess, OutOfGasError, ResultReason, TransactionReport, - TxResult, TxValidationError, VMError, + InternalError, OpcodeSuccess, OutOfGasError, ResultReason, TransactionReport, TxResult, + TxValidationError, VMError, }, gas_cost::{ self, fake_exponential, ACCESS_LIST_ADDRESS_COST, ACCESS_LIST_STORAGE_KEY_COST, @@ -1671,8 +1671,6 @@ pub fn get_authorized_address(account_info: &AccountInfo) -> Result Date: Wed, 22 Jan 2025 16:54:25 -0300 Subject: [PATCH 71/84] Update crates/vm/levm/src/vm.rs Co-authored-by: Ivan Litteri <67517699+ilitteri@users.noreply.github.com> --- crates/vm/levm/src/vm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index c4250ad48d..f29b63427d 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -1392,7 +1392,7 @@ impl VM { } // 2. Verify the nonce is less than 2**64 - 1. - // NOTE: nonce is a u64, it's always less or equal to u64::MAX + // NOTE: nonce is a u64, it's always less than or equal to u64::MAX if auth_tuple.nonce == u64::MAX { continue; } From 050d9d6f8311b14fb0ef2614cb6854f927957ca2 Mon Sep 17 00:00:00 2001 From: Federico Borello <156438142+fborello-lambda@users.noreply.github.com> Date: Wed, 22 Jan 2025 17:16:36 -0300 Subject: [PATCH 72/84] Update crates/vm/levm/src/vm.rs Co-authored-by: Ivan Litteri <67517699+ilitteri@users.noreply.github.com> --- crates/vm/levm/src/vm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index f29b63427d..fb58094a5f 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -1489,7 +1489,7 @@ impl VM { // 7. Add PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST gas to the global refund counter if authority exists in the trie. // CHECK: we don't know if checking the cache is correct. More gas tests pass but the set_code_txs tests went to half. if self.db.account_exists(authority_address) - || self.cache.contains_key(&authority_address) + || cache::is_account_cached(&self.cache, &authority_address) { let refunded_gas_if_exists = PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST; refunded_gas = refunded_gas From b1dd292038b77b21abb0378125ca010edd355957 Mon Sep 17 00:00:00 2001 From: Federico Borello <156438142+fborello-lambda@users.noreply.github.com> Date: Wed, 22 Jan 2025 17:16:44 -0300 Subject: [PATCH 73/84] Update crates/vm/levm/src/vm.rs Co-authored-by: Ivan Litteri <67517699+ilitteri@users.noreply.github.com> --- crates/vm/levm/src/vm.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index fb58094a5f..c847a03c9a 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -1498,9 +1498,8 @@ impl VM { } // 8. Set the code of authority to be 0xef0100 || address. This is a delegation designation. - let mut delegation_bytes = Vec::new(); - delegation_bytes.extend_from_slice(&SET_CODE_DELEGATION_BYTES); - delegation_bytes.extend_from_slice(auth_tuple.address.as_bytes()); + let delegation_bytes = + [&SET_CODE_DELEGATION_BYTES[..], &authority_address_bytes].concat(); // As a special case, if address is 0x0000000000000000000000000000000000000000 do not write the designation. // Clear the account’s code and reset the account’s code hash to the empty hash. From 884e6698191d0f306e9e1e52f347cb50368c65e5 Mon Sep 17 00:00:00 2001 From: Federico Borello <156438142+fborello-lambda@users.noreply.github.com> Date: Wed, 22 Jan 2025 17:18:20 -0300 Subject: [PATCH 74/84] Update crates/vm/levm/src/vm.rs Co-authored-by: Ivan Litteri <67517699+ilitteri@users.noreply.github.com> --- crates/vm/levm/src/vm.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index c847a03c9a..7e26403e5b 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -1513,10 +1513,10 @@ impl VM { } }; - if auth_tuple.address != Address::zero() { - auth_account.info.bytecode = delegation_bytes.into(); + auth_account.info.bytecode = if auth_tuple.address != Address::zero() { + delegation_bytes.into() } else { - auth_account.info.bytecode = Bytes::new(); + Bytes::new() } // 9. Increase the nonce of authority by one. From 034f7de0642775b16c77be7d878d24b437786bea Mon Sep 17 00:00:00 2001 From: Federico Borello <156438142+fborello-lambda@users.noreply.github.com> Date: Wed, 22 Jan 2025 17:18:46 -0300 Subject: [PATCH 75/84] Update crates/vm/levm/src/vm.rs Co-authored-by: Ivan Litteri <67517699+ilitteri@users.noreply.github.com> --- crates/vm/levm/src/vm.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 7e26403e5b..95b0f4bf7e 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -1576,12 +1576,15 @@ impl VM { // The delegation code has the authorized address let auth_address = get_authorized_address(&account.info)?; - let access_cost = match self.accrued_substate.touched_accounts.get(&auth_address) { - Some(_) => WARM_ADDRESS_ACCESS_COST, - None => { - self.accrued_substate.touched_accounts.insert(auth_address); - COLD_ADDRESS_ACCESS_COST - } + let access_cost = if self + .accrued_substate + .touched_accounts + .contains(&auth_address) + { + WARM_ADDRESS_ACCESS_COST + } else { + self.accrued_substate.touched_accounts.insert(auth_address); + COLD_ADDRESS_ACCESS_COST }; let authorized_bytecode = get_account(&mut self.cache, &self.db, auth_address) From 1042d6fd67df6d514119ffad12f28b3803dacb2e Mon Sep 17 00:00:00 2001 From: Tomas Fabrizio Orsi Date: Wed, 22 Jan 2025 17:58:54 -0300 Subject: [PATCH 76/84] fix: Remove mutable reference from `get_account_no_push_cache`. Reported-by: Martin Fraga --- crates/vm/levm/src/vm.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index f29b63427d..1032c09e3b 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -1348,8 +1348,8 @@ impl VM { get_account(&mut self.cache, &self.db, address) } - pub fn get_account_no_push_cache(&mut self, address: Address) -> Account { - get_account_no_push_cache(&mut self.cache, &self.db, address) + pub fn get_account_no_push_cache(&self, address: Address) -> Account { + get_account_no_push_cache(&self.cache, &self.db, address) } fn handle_create_non_empty_account( @@ -1628,7 +1628,7 @@ pub fn get_account(cache: &mut CacheDB, db: &Arc, address: Address } pub fn get_account_no_push_cache( - cache: &mut CacheDB, + cache: &CacheDB, db: &Arc, address: Address, ) -> Account { From f0c3d7d6a7afcd8fa54184d4068933bb3f51127b Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 22 Jan 2025 18:01:29 -0300 Subject: [PATCH 77/84] pr_comments: implement suggestions --- crates/vm/levm/src/constants.rs | 9 ++ crates/vm/levm/src/vm.rs | 148 ++++++++++++++++---------------- 2 files changed, 85 insertions(+), 72 deletions(-) diff --git a/crates/vm/levm/src/constants.rs b/crates/vm/levm/src/constants.rs index aa1e3f4ad4..0d27ec1cad 100644 --- a/crates/vm/levm/src/constants.rs +++ b/crates/vm/levm/src/constants.rs @@ -1,4 +1,9 @@ use ethrex_core::{H256, U256}; +use k256::{ + elliptic_curve::{bigint::Encoding, Curve}, + Secp256k1, +}; +use std::sync::LazyLock; pub const WORD_SIZE_IN_BYTES: U256 = U256([32, 0, 0, 0]); pub const WORD_SIZE_IN_BYTES_USIZE: usize = 32; @@ -52,6 +57,10 @@ pub const LAST_AVAILABLE_BLOCK_LIMIT: U256 = U256([256, 0, 0, 0]); pub const MAX_BLOCK_GAS_LIMIT: U256 = U256([30_000_000, 0, 0, 0]); // EIP7702 - EOA Load Code +pub static SECP256K1_ORDER: LazyLock = + LazyLock::new(|| U256::from_big_endian(&Secp256k1::ORDER.to_be_bytes())); +pub static SECP256K1_ORDER_OVER2: LazyLock = + LazyLock::new(|| *SECP256K1_ORDER / U256::from(2)); pub const MAGIC: u8 = 0x05; pub const SET_CODE_DELEGATION_BYTES: [u8; 3] = [0xef, 0x01, 0x00]; // Set the code of authority to be 0xef0100 || address. This is a delegation designation. diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 95b0f4bf7e..8a442c1e13 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -27,10 +27,6 @@ use bytes::Bytes; use ethrex_core::{types::TxKind, Address, H256, U256}; use ethrex_rlp; use ethrex_rlp::encode::RLPEncode; -use k256::{ - elliptic_curve::{bigint::Encoding, Curve}, - Secp256k1, -}; use keccak_hash::keccak; use libsecp256k1::{Message, RecoveryId, Signature}; use revm_primitives::SpecId; @@ -1372,12 +1368,12 @@ impl VM { Ok(report) } + /// Sets the account code as the EIP7702 determines. pub fn eip7702_set_access_code( &mut self, initial_call_frame: &mut CallFrame, ) -> Result { let mut refunded_gas: u64 = 0; - // Steps from the EIP7702: // IMPORTANT: // If any of the below steps fail, immediately stop processing that tuple and continue to the next tuple in the list. It will in the case of multiple tuples for the same authority, set the code using the address in the last valid occurrence. // If transaction execution results in failure (any exceptional condition or code reverting), setting delegation designations is not rolled back. @@ -1399,73 +1395,12 @@ impl VM { // 3. authority = ecrecover(keccak(MAGIC || rlp([chain_id, address, nonce])), y_parity, r, s) // s value must be less than or equal to secp256k1n/2, as specified in EIP-2. - let order_bytes = Secp256k1::ORDER.to_be_bytes(); - let n = U256::from_big_endian(&order_bytes); - let n_over_2 = n.checked_div(U256::from(2)).ok_or(VMError::Internal( - InternalError::ArithmeticOperationOverflow, - ))?; - - if auth_tuple.s_signature > n_over_2 || U256::zero() >= auth_tuple.s_signature { - continue; - } - if auth_tuple.r_signature > n || U256::zero() >= auth_tuple.r_signature { - continue; - } - if auth_tuple.v != U256::one() && auth_tuple.v != U256::zero() { - continue; - } - - let rlp_buf = - (auth_tuple.chain_id, auth_tuple.address, auth_tuple.nonce).encode_to_vec(); - - let mut hasher = Keccak256::new(); - hasher.update([MAGIC]); - hasher.update(rlp_buf); - let bytes = &mut hasher.finalize(); - - let Ok(message) = Message::parse_slice(bytes) else { - continue; - }; - - let mut bytes = Vec::new(); - bytes.extend_from_slice(&auth_tuple.r_signature.to_big_endian()); - bytes.extend_from_slice(&auth_tuple.s_signature.to_big_endian()); - - let Ok(signature) = Signature::parse_standard_slice(&bytes) else { - continue; - }; - - let Ok(recovery_id) = RecoveryId::parse( - auth_tuple - .v - .as_u32() - .try_into() - .map_err(|_| VMError::Internal(InternalError::ConversionError))?, - ) else { - continue; - }; - - let Ok(authority) = libsecp256k1::recover(&message, &signature, &recovery_id) else { + let authority_address = if let Some(address) = eip7702_recover_address(&auth_tuple)? { + address + } else { continue; }; - let public_key = authority.serialize(); - let mut hasher = Keccak256::new(); - hasher.update( - public_key - .get(1..) - .ok_or(VMError::Internal(InternalError::SlicingError))?, - ); - let address_hash = hasher.finalize(); - - // Get the last 20 bytes of the hash -> Address - let authority_address_bytes: [u8; 20] = address_hash - .get(12..32) - .ok_or(VMError::Internal(InternalError::SlicingError))? - .try_into() - .map_err(|_| VMError::Internal(InternalError::ConversionError))?; - let authority_address = Address::from_slice(&authority_address_bytes); - // 4. Add authority to accessed_addresses (as defined in EIP-2929). self.accrued_substate .touched_accounts @@ -1498,8 +1433,11 @@ impl VM { } // 8. Set the code of authority to be 0xef0100 || address. This is a delegation designation. - let delegation_bytes = - [&SET_CODE_DELEGATION_BYTES[..], &authority_address_bytes].concat(); + let delegation_bytes = [ + &SET_CODE_DELEGATION_BYTES[..], + &auth_tuple.address.as_bytes(), + ] + .concat(); // As a special case, if address is 0x0000000000000000000000000000000000000000 do not write the designation. // Clear the account’s code and reset the account’s code hash to the empty hash. @@ -1517,7 +1455,7 @@ impl VM { delegation_bytes.into() } else { Bytes::new() - } + }; // 9. Increase the nonce of authority by one. self.increment_account_nonce(authority_address) @@ -1646,6 +1584,7 @@ pub fn get_account_no_push_cache( } } +/// Checks if account.info.bytecode has been delegated as the EIP7702 determines. pub fn has_delegation(account_info: &AccountInfo) -> Result { let mut has_delegation = false; if account_info.has_code() && account_info.bytecode.len() == EIP7702_DELEGATED_CODE_LEN { @@ -1661,6 +1600,7 @@ pub fn has_delegation(account_info: &AccountInfo) -> Result { Ok(has_delegation) } +/// Gets the address inside the account.info.bytecode if it has been delegated as the EIP7702 determines. pub fn get_authorized_address(account_info: &AccountInfo) -> Result { if has_delegation(account_info)? { let address_bytes = account_info @@ -1676,3 +1616,67 @@ pub fn get_authorized_address(account_info: &AccountInfo) -> Result Result, VMError> { + if auth_tuple.s_signature > *SECP256K1_ORDER_OVER2 || U256::zero() >= auth_tuple.s_signature { + return Ok(None); + } + if auth_tuple.r_signature > *SECP256K1_ORDER || U256::zero() >= auth_tuple.r_signature { + return Ok(None); + } + if auth_tuple.v != U256::one() && auth_tuple.v != U256::zero() { + return Ok(None); + } + + let rlp_buf = (auth_tuple.chain_id, auth_tuple.address, auth_tuple.nonce).encode_to_vec(); + + let mut hasher = Keccak256::new(); + hasher.update([MAGIC]); + hasher.update(rlp_buf); + let bytes = &mut hasher.finalize(); + + let Ok(message) = Message::parse_slice(bytes) else { + return Ok(None); + }; + + let bytes = [ + auth_tuple.r_signature.to_big_endian(), + auth_tuple.s_signature.to_big_endian(), + ] + .concat(); + + let Ok(signature) = Signature::parse_standard_slice(&bytes) else { + return Ok(None); + }; + + let Ok(recovery_id) = RecoveryId::parse( + auth_tuple + .v + .as_u32() + .try_into() + .map_err(|_| VMError::Internal(InternalError::ConversionError))?, + ) else { + return Ok(None); + }; + + let Ok(authority) = libsecp256k1::recover(&message, &signature, &recovery_id) else { + return Ok(None); + }; + + let public_key = authority.serialize(); + let mut hasher = Keccak256::new(); + hasher.update( + public_key + .get(1..) + .ok_or(VMError::Internal(InternalError::SlicingError))?, + ); + let address_hash = hasher.finalize(); + + // Get the last 20 bytes of the hash -> Address + let authority_address_bytes: [u8; 20] = address_hash + .get(12..32) + .ok_or(VMError::Internal(InternalError::SlicingError))? + .try_into() + .map_err(|_| VMError::Internal(InternalError::ConversionError))?; + Ok(Some(Address::from_slice(&authority_address_bytes))) +} From 9219dd9aa518de25ce5f8a33c8be76d0166af09f Mon Sep 17 00:00:00 2001 From: Tomas Fabrizio Orsi Date: Wed, 22 Jan 2025 18:05:38 -0300 Subject: [PATCH 78/84] fix: linter error --- crates/vm/levm/src/vm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 2e11be8463..ccd89170a4 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -187,7 +187,7 @@ impl VM { TxKind::Call(address_to) => { default_touched_accounts.insert(address_to); - let bytecode = get_account_no_push_cache(&mut cache, &db, address_to) + let bytecode = get_account_no_push_cache(&cache, &db, address_to) .info .bytecode; From 4194c7c88e3ab219e87f1d556db22700e989c370 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Wed, 22 Jan 2025 18:06:29 -0300 Subject: [PATCH 79/84] chore: linter --- crates/vm/levm/src/vm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index ccd89170a4..db6f232963 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -1435,7 +1435,7 @@ impl VM { // 8. Set the code of authority to be 0xef0100 || address. This is a delegation designation. let delegation_bytes = [ &SET_CODE_DELEGATION_BYTES[..], - &auth_tuple.address.as_bytes(), + auth_tuple.address.as_bytes(), ] .concat(); From 72845a01d163bbf68ca05f624c0d845e7c9edbcd Mon Sep 17 00:00:00 2001 From: Tomas Fabrizio Orsi Date: Wed, 22 Jan 2025 18:10:17 -0300 Subject: [PATCH 80/84] fix: performance? Check the cache BEFORE checking the db. --- crates/vm/levm/src/vm.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index db6f232963..3664edfd35 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -1423,8 +1423,8 @@ impl VM { // 7. Add PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST gas to the global refund counter if authority exists in the trie. // CHECK: we don't know if checking the cache is correct. More gas tests pass but the set_code_txs tests went to half. - if self.db.account_exists(authority_address) - || cache::is_account_cached(&self.cache, &authority_address) + if cache::is_account_cached(&self.cache, &authority_address) + || self.db.account_exists(authority_address) { let refunded_gas_if_exists = PER_EMPTY_ACCOUNT_COST - PER_AUTH_BASE_COST; refunded_gas = refunded_gas From a5af38986e8e009905105e6d74bd30167aa9e991 Mon Sep 17 00:00:00 2001 From: Federico Borello <156438142+fborello-lambda@users.noreply.github.com> Date: Thu, 23 Jan 2025 09:05:17 -0300 Subject: [PATCH 81/84] Update crates/vm/levm/src/vm.rs Co-authored-by: Ivan Litteri <67517699+ilitteri@users.noreply.github.com> --- crates/vm/levm/src/vm.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 3664edfd35..1306d0d4e0 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -1395,8 +1395,7 @@ impl VM { // 3. authority = ecrecover(keccak(MAGIC || rlp([chain_id, address, nonce])), y_parity, r, s) // s value must be less than or equal to secp256k1n/2, as specified in EIP-2. - let authority_address = if let Some(address) = eip7702_recover_address(&auth_tuple)? { - address + let Some(authority_address) = eip7702_recover_address(&auth_tuple)? { } else { continue; }; From a19397487df389c9e151ad9d5cb90732d755def4 Mon Sep 17 00:00:00 2001 From: fborello-lambda Date: Thu, 23 Jan 2025 09:13:19 -0300 Subject: [PATCH 82/84] chore: linter --- crates/vm/levm/src/vm.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 1306d0d4e0..70d538e4bf 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -1395,8 +1395,7 @@ impl VM { // 3. authority = ecrecover(keccak(MAGIC || rlp([chain_id, address, nonce])), y_parity, r, s) // s value must be less than or equal to secp256k1n/2, as specified in EIP-2. - let Some(authority_address) = eip7702_recover_address(&auth_tuple)? { - } else { + let Some(authority_address) = eip7702_recover_address(&auth_tuple)? else { continue; }; From 4849d060c1649d90dc27e1eb4abd3ee1e2989b9b Mon Sep 17 00:00:00 2001 From: Tomas Fabrizio Orsi Date: Thu, 23 Jan 2025 09:14:56 -0300 Subject: [PATCH 83/84] Remove one linter error --- crates/vm/levm/src/vm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 1306d0d4e0..8b5b8410f9 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -3,7 +3,7 @@ use crate::{ call_frame::CallFrame, constants::*, db::{ - cache::{self, get_account_mut, remove_account}, + cache::{self, remove_account}, CacheDB, Database, }, environment::Environment, From c9ab6ca07d3e78416f2af536f56724091ba8aee3 Mon Sep 17 00:00:00 2001 From: Tomas Fabrizio Orsi Date: Thu, 23 Jan 2025 09:17:45 -0300 Subject: [PATCH 84/84] Revert "Remove one linter error" This reverts commit 4849d060c1649d90dc27e1eb4abd3ee1e2989b9b. --- crates/vm/levm/src/vm.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index a999a476c6..70d538e4bf 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -3,7 +3,7 @@ use crate::{ call_frame::CallFrame, constants::*, db::{ - cache::{self, remove_account}, + cache::{self, get_account_mut, remove_account}, CacheDB, Database, }, environment::Environment,