diff --git a/crates/vm/levm/src/opcode_handlers/system.rs b/crates/vm/levm/src/opcode_handlers/system.rs index 943813778d..a0738a003d 100644 --- a/crates/vm/levm/src/opcode_handlers/system.rs +++ b/crates/vm/levm/src/opcode_handlers/system.rs @@ -53,8 +53,12 @@ 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 (is_delegation, eip7702_gas_consumed, code_address, bytecode) = eip7702_get_code( + &mut self.cache, + &mut self.db, + &mut self.accrued_substate, + callee, + )?; let gas_left = current_call_frame .gas_limit @@ -132,8 +136,12 @@ 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 (is_delegation, eip7702_gas_consumed, code_address, bytecode) = eip7702_get_code( + &mut self.cache, + &mut self.db, + &mut self.accrued_substate, + code_address, + )?; let gas_left = current_call_frame .gas_limit @@ -239,8 +247,12 @@ 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 (is_delegation, eip7702_gas_consumed, code_address, bytecode) = eip7702_get_code( + &mut self.cache, + &mut self.db, + &mut self.accrued_substate, + code_address, + )?; let gas_left = current_call_frame .gas_limit @@ -314,8 +326,12 @@ 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 (is_delegation, eip7702_gas_consumed, _, bytecode) = eip7702_get_code( + &mut self.cache, + &mut self.db, + &mut self.accrued_substate, + code_address, + )?; let gas_left = current_call_frame .gas_limit diff --git a/crates/vm/levm/src/utils.rs b/crates/vm/levm/src/utils.rs index eaf2aface2..57e1f3907d 100644 --- a/crates/vm/levm/src/utils.rs +++ b/crates/vm/levm/src/utils.rs @@ -21,7 +21,7 @@ use crate::{ execute_precompile, is_precompile, SIZE_PRECOMPILES_CANCUN, SIZE_PRECOMPILES_PRAGUE, SIZE_PRECOMPILES_PRE_CANCUN, }, - vm::{AccessList, AuthorizationList, AuthorizationTuple}, + vm::{AccessList, AuthorizationList, AuthorizationTuple, Substate}, AccountInfo, TransientStorage, }; use bytes::Bytes; @@ -548,3 +548,57 @@ pub fn eip7702_recover_address( .map_err(|_| VMError::Internal(InternalError::ConversionError))?; Ok(Some(Address::from_slice(&authority_address_bytes))) } + +/// 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. +/// +/// 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( + cache: &mut CacheDB, + db: &Arc, + accrued_substate: &mut Substate, + address: Address, +) -> Result<(bool, u64, Address, Bytes), VMError> { + // Address is the delgated address + let account = get_account(cache, db, address); + let bytecode = account.info.bytecode.clone(); + + // 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 !has_delegation(&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)?; + + let access_cost = if accrued_substate.touched_accounts.contains(&auth_address) { + WARM_ADDRESS_ACCESS_COST + } else { + accrued_substate.touched_accounts.insert(auth_address); + COLD_ADDRESS_ACCESS_COST + }; + + let authorized_bytecode = get_account(cache, db, auth_address).info.bytecode; + + Ok((true, access_cost, auth_address, authorized_bytecode)) +} diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index 85d592581b..8cd09433a3 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -1220,58 +1220,4 @@ impl VM { get_valid_jump_destinations(&initial_call_frame.bytecode).unwrap_or_default(); Ok(refunded_gas) } - - /// 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. - /// - /// 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, - ) -> 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(); - - // 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 !has_delegation(&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)?; - - 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) - .info - .bytecode; - - Ok((true, access_cost, auth_address, authorized_bytecode)) - } }