From e94d12e580892db203c64faacdd8216ab4ca5db9 Mon Sep 17 00:00:00 2001 From: AshinGau Date: Thu, 23 Jul 2026 17:03:48 +0800 Subject: [PATCH] fix: publish EIP-7702 code changes --- crates/pevm/src/vm.rs | 13 ++-- crates/pevm/tests/eip7702.rs | 117 +++++++++++++++++++++++++++++++++++ 2 files changed, 125 insertions(+), 5 deletions(-) create mode 100644 crates/pevm/tests/eip7702.rs diff --git a/crates/pevm/src/vm.rs b/crates/pevm/src/vm.rs index ebf4a56d..ea175e87 100644 --- a/crates/pevm/src/vm.rs +++ b/crates/pevm/src/vm.rs @@ -596,11 +596,14 @@ impl<'a, S: Storage, C: PevmChain> Vm<'a, S, C> { let read_account = ctx.db().read_accounts.get(&account_location_hash); let has_code = !account.info.is_empty_code_hash(); - let is_new_code = has_code - && read_account.is_none_or(|(_, code_hash)| code_hash.is_none()); + let code_changed = has_code + && account.info.code.is_some() + && read_account.is_none_or(|(_, code_hash)| { + *code_hash != Some(account.info.code_hash) + }); // Write new account changes - if is_new_code + if code_changed || read_account.is_none() || read_account.is_some_and(|(basic, _)| { basic.nonce != account.info.nonce @@ -639,8 +642,8 @@ impl<'a, S: Storage, C: PevmChain> Vm<'a, S, C> { } } - // Write new contract - if is_new_code { + // Write code changes + if code_changed { write_set.push(( hash_deterministic(MemoryLocation::CodeHash(*address)), MemoryValue::CodeHash(account.info.code_hash), diff --git a/crates/pevm/tests/eip7702.rs b/crates/pevm/tests/eip7702.rs new file mode 100644 index 00000000..41b3fca4 --- /dev/null +++ b/crates/pevm/tests/eip7702.rs @@ -0,0 +1,117 @@ +//! EIP-7702 regression tests. + +use std::{num::NonZeroUsize, sync::Arc}; + +use pevm::{ + Bytecodes, ChainState, EvmAccount, EvmCode, InMemoryStorage, Pevm, chain::PevmEthereum, + execute_revm_sequential, +}; +use revm::{ + context::{ + BlockEnv, TransactionType, TxEnv, + transaction::{Authorization, RecoveredAuthority, RecoveredAuthorization}, + }, + context_interface::either::Either, + primitives::{Address, TxKind, U256, alloy_primitives::U160, hardfork::SpecId}, + state::Bytecode, +}; + +fn address(value: u64) -> Address { + Address::from(U160::from(value)) +} + +fn delegate_tx(sponsor: Address, authority: Address, target: Address, nonce: u64) -> TxEnv { + TxEnv { + tx_type: TransactionType::Eip7702.into(), + caller: sponsor, + gas_limit: 100_000, + gas_price: 1, + kind: TxKind::Call(sponsor), + nonce: 1, + chain_id: Some(1), + authorization_list: vec![Either::Right(RecoveredAuthorization::new_unchecked( + Authorization { + chain_id: U256::ZERO, + address: target, + nonce, + }, + RecoveredAuthority::Valid(authority), + ))], + ..TxEnv::default() + } +} + +#[test] +fn redelegation_uses_latest_code() { + let authority = address(1_000); + let target_x = address(1_001); + let target_y = address(1_002); + let sponsor_x = address(2_000); + let sponsor_y = address(2_001); + let caller = address(2_002); + + let mut accounts = [sponsor_x, sponsor_y, caller] + .into_iter() + .map(|address| { + ( + address, + EvmAccount { + balance: U256::MAX / U256::from(2), + nonce: 1, + ..EvmAccount::default() + }, + ) + }) + .collect::(); + accounts.insert(authority, EvmAccount::default()); + + let mut bytecodes = Bytecodes::default(); + for (target, value) in [(target_x, 1), (target_y, 2)] { + let bytecode = Bytecode::new_raw(vec![0x60, value, 0x60, 0x00, 0x55, 0x00].into()); + let code_hash = bytecode.hash_slow(); + let code = EvmCode::from(bytecode); + accounts.insert( + target, + EvmAccount { + nonce: 1, + code_hash: Some(code_hash), + code: Some(code.clone()), + ..EvmAccount::default() + }, + ); + bytecodes.insert(code_hash, code); + } + + let txs = vec![ + delegate_tx(sponsor_x, authority, target_x, 0), + delegate_tx(sponsor_y, authority, target_y, 1), + TxEnv { + caller, + gas_limit: 100_000, + gas_price: 1, + kind: TxKind::Call(authority), + nonce: 1, + ..TxEnv::default() + }, + ]; + + let chain = PevmEthereum::mainnet(); + let storage = InMemoryStorage::new(accounts, Arc::new(bytecodes), Default::default()); + assert_eq!( + execute_revm_sequential( + &chain, + &storage, + SpecId::PRAGUE, + BlockEnv::default(), + txs.clone(), + ), + Pevm::default().execute_revm_parallel( + &chain, + &storage, + SpecId::PRAGUE, + BlockEnv::default(), + txs, + NonZeroUsize::MIN, + ), + ); +}