From cd19eec9cb2c1805b07fc1823a748b483c39c177 Mon Sep 17 00:00:00 2001 From: Iaroslav Mazur Date: Fri, 29 Dec 2023 23:29:03 +0100 Subject: [PATCH] BREAKING CHANGE: deprecate SELFDESTRUCT --- crates/interpreter/src/gas/calc.rs | 26 ---- crates/interpreter/src/gas/constants.rs | 1 - crates/interpreter/src/host.rs | 8 +- crates/interpreter/src/host/dummy.rs | 7 +- crates/interpreter/src/inner_models.rs | 10 -- crates/interpreter/src/instruction_result.rs | 7 +- crates/interpreter/src/instructions/host.rs | 5 - crates/interpreter/src/instructions/opcode.rs | 5 +- crates/primitives/src/result.rs | 1 - crates/primitives/src/state.rs | 21 +-- crates/revm/src/db/in_memory_db.rs | 11 +- crates/revm/src/db/states/account_status.rs | 103 ++---------- crates/revm/src/db/states/bundle_account.rs | 146 ------------------ crates/revm/src/db/states/bundle_state.rs | 109 ++----------- crates/revm/src/db/states/cache.rs | 9 +- crates/revm/src/db/states/cache_account.rs | 47 +----- crates/revm/src/db/states/changes.rs | 4 +- crates/revm/src/db/states/reverts.rs | 79 +--------- crates/revm/src/db/states/state.rs | 128 +-------------- .../revm/src/db/states/transition_account.rs | 38 ++--- crates/revm/src/evm_impl.rs | 14 +- crates/revm/src/inspector.rs | 10 +- crates/revm/src/inspector/customprinter.rs | 9 +- crates/revm/src/journaled_state.rs | 110 +------------ 24 files changed, 59 insertions(+), 849 deletions(-) diff --git a/crates/interpreter/src/gas/calc.rs b/crates/interpreter/src/gas/calc.rs index 332d84ab..6a55c39f 100644 --- a/crates/interpreter/src/gas/calc.rs +++ b/crates/interpreter/src/gas/calc.rs @@ -1,5 +1,4 @@ use super::constants::*; -use crate::inner_models::SelfDestructResult; use crate::primitives::{Address, Spec, SpecId::*, U256}; use alloc::vec::Vec; @@ -237,31 +236,6 @@ pub fn sstore_cost( } } -pub fn selfdestruct_cost(res: SelfDestructResult) -> u64 { - // EIP-161: State trie clearing (invariant-preserving alternative) - let should_charge_topup = if SPEC::enabled(SPURIOUS_DRAGON) { - res.had_value && !res.target_exists - } else { - !res.target_exists - }; - - // EIP-150: Gas cost changes for IO-heavy operations - let selfdestruct_gas_topup = if SPEC::enabled(TANGERINE) && should_charge_topup { - 25000 - } else { - 0 - }; - - // EIP-150: Gas cost changes for IO-heavy operations - let selfdestruct_gas = if SPEC::enabled(TANGERINE) { 5000 } else { 0 }; - - let mut gas = selfdestruct_gas + selfdestruct_gas_topup; - if SPEC::enabled(BERLIN) && res.is_cold { - gas += COLD_ACCOUNT_ACCESS_COST - } - gas -} - pub fn call_cost( transfers_value: bool, is_new: bool, diff --git a/crates/interpreter/src/gas/constants.rs b/crates/interpreter/src/gas/constants.rs index b8bd7d05..161f5b47 100644 --- a/crates/interpreter/src/gas/constants.rs +++ b/crates/interpreter/src/gas/constants.rs @@ -5,7 +5,6 @@ pub const LOW: u64 = 5; pub const MID: u64 = 8; pub const HIGH: u64 = 10; pub const JUMPDEST: u64 = 1; -pub const SELFDESTRUCT: i64 = 24000; pub const CREATE: u64 = 32000; pub const CALLVALUE: u64 = 9000; pub const NEWACCOUNT: u64 = 25000; diff --git a/crates/interpreter/src/host.rs b/crates/interpreter/src/host.rs index 101afd2d..7c8fdb95 100644 --- a/crates/interpreter/src/host.rs +++ b/crates/interpreter/src/host.rs @@ -1,7 +1,4 @@ -use crate::{ - primitives::{Address, Bytecode, Bytes, Env, B256, U256}, - SelfDestructResult, -}; +use crate::primitives::{Address, Bytecode, Bytes, Env, B256, U256}; use alloc::vec::Vec; mod dummy; @@ -51,9 +48,6 @@ pub trait Host { /// Emit a log owned by `address` with given `topics` and `data`. fn log(&mut self, address: Address, topics: Vec, data: Bytes); - /// Mark `address` to be deleted, with funds transferred to `target`. - fn selfdestruct(&mut self, address: Address, target: Address) -> Option; - /// Get asset balance of address and if account is cold loaded. fn balanceof(&mut self, asset_id: B256, address: Address) -> Option<(U256, bool)>; diff --git a/crates/interpreter/src/host/dummy.rs b/crates/interpreter/src/host/dummy.rs index 37ef86a0..b6872a2f 100644 --- a/crates/interpreter/src/host/dummy.rs +++ b/crates/interpreter/src/host/dummy.rs @@ -1,7 +1,7 @@ use crate::primitives::{hash_map::Entry, Bytecode, Bytes, HashMap, U256}; use crate::{ primitives::{Address, Env, Log, B256, KECCAK_EMPTY}, - Host, SelfDestructResult, + Host, }; use alloc::vec::Vec; @@ -114,11 +114,6 @@ impl Host for DummyHost { }) } - #[inline] - fn selfdestruct(&mut self, _address: Address, _target: Address) -> Option { - panic!("Selfdestruct is not supported for this host") - } - #[inline] fn balanceof(&mut self, _asset_id: B256, _address: Address) -> Option<(U256, bool)> { Some((U256::ZERO, false)) diff --git a/crates/interpreter/src/inner_models.rs b/crates/interpreter/src/inner_models.rs index a5d3bcd1..392c17d6 100644 --- a/crates/interpreter/src/inner_models.rs +++ b/crates/interpreter/src/inner_models.rs @@ -110,13 +110,3 @@ pub struct Transfer { /// The transfer value. pub value: U256, } - -/// Result of a call that resulted in a self destruct. -#[derive(Default, Clone, Debug, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct SelfDestructResult { - pub had_value: bool, - pub target_exists: bool, - pub is_cold: bool, - pub previously_destroyed: bool, -} diff --git a/crates/interpreter/src/instruction_result.rs b/crates/interpreter/src/instruction_result.rs index 08038f0f..e59650ad 100644 --- a/crates/interpreter/src/instruction_result.rs +++ b/crates/interpreter/src/instruction_result.rs @@ -9,7 +9,6 @@ pub enum InstructionResult { Continue = 0x00, Stop, Return, - SelfDestruct, // revert codes Revert = 0x10, // revert opcode @@ -149,7 +148,6 @@ impl From for SuccessOrHalt { InstructionResult::Continue => Self::InternalContinue, // used only in interpreter loop InstructionResult::Stop => Self::Success(Eval::Stop), InstructionResult::Return => Self::Success(Eval::Return), - InstructionResult::SelfDestruct => Self::Success(Eval::SelfDestruct), InstructionResult::Revert => Self::Revert, InstructionResult::CallOrCreate => Self::InternalCallOrCreate, // used only in interpreter loop InstructionResult::CallTooDeep => Self::Halt(HaltReason::CallTooDeep), // not gonna happen for first call @@ -203,10 +201,7 @@ impl From for SuccessOrHalt { #[macro_export] macro_rules! return_ok { () => { - InstructionResult::Continue - | InstructionResult::Stop - | InstructionResult::Return - | InstructionResult::SelfDestruct + InstructionResult::Continue | InstructionResult::Stop | InstructionResult::Return }; } diff --git a/crates/interpreter/src/instructions/host.rs b/crates/interpreter/src/instructions/host.rs index 4723df02..aee43f13 100644 --- a/crates/interpreter/src/instructions/host.rs +++ b/crates/interpreter/src/instructions/host.rs @@ -214,11 +214,6 @@ pub fn log(interpreter: &mut Interpreter, host: &mut H) host.log(interpreter.contract.address, topics, data); } -/// DEPRECATED: the SELFDESTRUCT opcode is not available in the SabVM -pub fn selfdestruct(interpreter: &mut Interpreter, _host: &mut H) { - interpreter.instruction_result = InstructionResult::NotActivated; -} - pub fn create( interpreter: &mut Interpreter, host: &mut H, diff --git a/crates/interpreter/src/instructions/opcode.rs b/crates/interpreter/src/instructions/opcode.rs index b93cc7d6..0cbc132a 100644 --- a/crates/interpreter/src/instructions/opcode.rs +++ b/crates/interpreter/src/instructions/opcode.rs @@ -368,8 +368,7 @@ opcodes! { // 0xFB // 0xFC 0xFD => REVERT => control::revert::, - 0xFE => INVALID => control::invalid, - 0xFF => SELFDESTRUCT => host::selfdestruct::, + 0xFF => INVALID => control::invalid, } /// An EVM opcode. @@ -846,8 +845,8 @@ const fn opcode_gas_info(opcode: u8, spec: SpecId) -> OpInfo { 0xFB => OpInfo::none(), 0xFC => OpInfo::none(), REVERT => OpInfo::gas_block_end(0), + 0xFE => OpInfo::none(), INVALID => OpInfo::gas_block_end(0), - SELFDESTRUCT => OpInfo::gas_block_end(0), } } diff --git a/crates/primitives/src/result.rs b/crates/primitives/src/result.rs index 9b42e057..b4f7eba0 100644 --- a/crates/primitives/src/result.rs +++ b/crates/primitives/src/result.rs @@ -358,7 +358,6 @@ impl fmt::Display for InvalidHeaderReason { pub enum Eval { Stop, Return, - SelfDestruct, } /// Indicates that the EVM has experienced an exceptional halt. This causes execution to diff --git a/crates/primitives/src/state.rs b/crates/primitives/src/state.rs index 3ffa3698..b61d64f4 100644 --- a/crates/primitives/src/state.rs +++ b/crates/primitives/src/state.rs @@ -35,13 +35,11 @@ bitflags! { /// When account is newly created we will not access database /// to fetch storage values const Created = 0b00000001; - /// If account is marked for self destruction. - const SelfDestructed = 0b00000010; /// Only when account is marked as touched we will save it to database. - const Touched = 0b00000100; + const Touched = 0b00000010; /// used only for pre spurious dragon hardforks where existing and empty were two separate states. /// it became same state after EIP-161: State trie clearing - const LoadedAsNotExisting = 0b0001000; + const LoadedAsNotExisting = 0b00000100; } } @@ -61,21 +59,6 @@ impl Account { } } - /// Mark account as self destructed. - pub fn mark_selfdestruct(&mut self) { - self.status |= AccountStatus::SelfDestructed; - } - - /// Unmark account as self destructed. - pub fn unmark_selfdestruct(&mut self) { - self.status -= AccountStatus::SelfDestructed; - } - - /// Is account marked for self destruct. - pub fn is_selfdestructed(&self) -> bool { - self.status.contains(AccountStatus::SelfDestructed) - } - /// Mark account as touched pub fn mark_touch(&mut self) { self.status |= AccountStatus::Touched; diff --git a/crates/revm/src/db/in_memory_db.rs b/crates/revm/src/db/in_memory_db.rs index 840867d0..686ce2b1 100644 --- a/crates/revm/src/db/in_memory_db.rs +++ b/crates/revm/src/db/in_memory_db.rs @@ -131,13 +131,6 @@ impl DatabaseCommit for CacheDB { if !account.is_touched() { continue; } - if account.is_selfdestructed() { - let db_account = self.accounts.entry(address).or_default(); - db_account.storage.clear(); - db_account.account_state = AccountState::NotExisting; - db_account.info = AccountInfo::default(); - continue; - } let is_newly_created = account.is_created(); self.insert_contract(&mut account.info); @@ -291,7 +284,7 @@ impl DatabaseRef for CacheDB { #[derive(Debug, Clone, Default)] pub struct DbAccount { pub info: AccountInfo, - /// If account is selfdestructed or newly created, storage will be cleared. + /// If account is newly created, storage will be cleared. pub account_state: AccountState, /// storage slots pub storage: HashMap, @@ -337,7 +330,7 @@ pub enum AccountState { NotExisting, /// EVM touched this account. For newer hardfork this means it can be cleared/removed from state. Touched, - /// EVM cleared storage of this account, mostly by selfdestruct, we don't ask database for storage slots + /// EVM cleared storage of this account, we don't ask database for storage slots /// and assume they are U256::ZERO StorageCleared, /// EVM didn't interacted with this account diff --git a/crates/revm/src/db/states/account_status.rs b/crates/revm/src/db/states/account_status.rs index aaf0b5b4..2b1eb20a 100644 --- a/crates/revm/src/db/states/account_status.rs +++ b/crates/revm/src/db/states/account_status.rs @@ -1,5 +1,5 @@ -/// After account get loaded from database it can be in a lot of different states -/// while we execute multiple transaction and even blocks over account that is in memory. +/// After account gets loaded from database it can be in a lot of different states +/// while we execute multiple transactions and even blocks over account that is in memory. /// This structure models all possible states that account can be in. #[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash)] pub enum AccountStatus { @@ -9,9 +9,6 @@ pub enum AccountStatus { LoadedEmptyEIP161, InMemoryChange, Changed, - Destroyed, - DestroyedChanged, - DestroyedAgain, } impl AccountStatus { @@ -25,26 +22,11 @@ impl AccountStatus { ) } - /// Account was destroyed by calling SELFDESTRUCT. - /// This means that full account and storage are inside memory. - pub fn was_destroyed(&self) -> bool { - matches!( - self, - AccountStatus::Destroyed - | AccountStatus::DestroyedChanged - | AccountStatus::DestroyedAgain - ) - } - /// This means storage is known, it can be newly created or storage got destroyed. pub fn is_storage_known(&self) -> bool { matches!( self, - AccountStatus::LoadedNotExisting - | AccountStatus::InMemoryChange - | AccountStatus::Destroyed - | AccountStatus::DestroyedChanged - | AccountStatus::DestroyedAgain + AccountStatus::LoadedNotExisting | AccountStatus::InMemoryChange ) } @@ -58,10 +40,6 @@ impl AccountStatus { /// Returns the next account status on creation. pub fn on_created(&self) -> AccountStatus { match self { - // if account was destroyed previously just copy new info to it. - AccountStatus::DestroyedAgain - | AccountStatus::Destroyed - | AccountStatus::DestroyedChanged => AccountStatus::DestroyedChanged, // if account is loaded from db. AccountStatus::LoadedNotExisting // Loaded empty eip161 to creates is not possible as CREATE2 was added after EIP-161 @@ -86,14 +64,13 @@ impl AccountStatus { match self { // Account can be touched but not existing. The status should remain the same. AccountStatus::LoadedNotExisting => AccountStatus::LoadedNotExisting, - // Account can be created empty and only then touched. - AccountStatus::InMemoryChange - | AccountStatus::Destroyed - | AccountStatus::LoadedEmptyEIP161 => AccountStatus::Destroyed, - // Transition to destroy the account. - AccountStatus::DestroyedAgain | AccountStatus::DestroyedChanged => { - AccountStatus::DestroyedAgain + + //TODO: see how the below should be adapted to the no-selfdestruct workflow + // // Account can be created empty and only then touched. + AccountStatus::InMemoryChange | AccountStatus::LoadedEmptyEIP161 => { + AccountStatus::LoadedNotExisting } + // Account statuses considered unreachable. AccountStatus::Loaded | AccountStatus::Changed => { unreachable!("Wrong state transition, touch empty is not possible from {self:?}"); @@ -107,19 +84,9 @@ impl AccountStatus { /// # Panics /// /// If current status is [AccountStatus::Loaded] or [AccountStatus::Changed]. - pub fn on_touched_created_pre_eip161(&self, had_no_info: bool) -> Option { + pub fn on_touched_created_pre_eip161(&self) -> Option { match self { AccountStatus::LoadedEmptyEIP161 => None, - AccountStatus::DestroyedChanged => { - if had_no_info { - None - } else { - Some(AccountStatus::DestroyedChanged) - } - } - AccountStatus::Destroyed | AccountStatus::DestroyedAgain => { - Some(AccountStatus::DestroyedChanged) - } AccountStatus::InMemoryChange | AccountStatus::LoadedNotExisting => { Some(AccountStatus::InMemoryChange) } @@ -154,30 +121,6 @@ impl AccountStatus { // Any checks for empty accounts are done outside of this fn. AccountStatus::Changed => AccountStatus::Changed, AccountStatus::InMemoryChange => AccountStatus::InMemoryChange, - AccountStatus::DestroyedChanged => AccountStatus::DestroyedChanged, - - // If account is destroyed and then changed this means this is - // balance transfer. - AccountStatus::Destroyed | AccountStatus::DestroyedAgain => { - AccountStatus::DestroyedChanged - } - } - } - - /// Returns the next account status on selfdestruct. - pub fn on_selfdestructed(&self) -> AccountStatus { - match self { - // Non existing account can't be destroyed. - AccountStatus::LoadedNotExisting => AccountStatus::LoadedNotExisting, - // If account is created and selfdestructed in the same block, mark it as destroyed again. - // Note: there is no big difference between Destroyed and DestroyedAgain in this case, - // but was added for clarity. - AccountStatus::DestroyedChanged - | AccountStatus::DestroyedAgain - | AccountStatus::Destroyed => AccountStatus::DestroyedAgain, - - // Transition to destroyed status. - _ => AccountStatus::Destroyed, } } @@ -194,17 +137,12 @@ impl AccountStatus { /// Otherwise, if both are destroyed or other is destroyed: /// set other status to extended account. pub fn transition(&mut self, other: Self) { - *self = match (self.was_destroyed(), other.was_destroyed()) { - (true, false) => Self::DestroyedChanged, - (false, false) if *self == Self::InMemoryChange => Self::InMemoryChange, - _ => other, - }; + *self = other; } } #[cfg(test)] mod test { - use super::*; #[test] @@ -215,38 +153,19 @@ mod test { assert!(AccountStatus::LoadedNotExisting.is_not_modified()); assert!(!AccountStatus::Changed.is_not_modified()); assert!(!AccountStatus::InMemoryChange.is_not_modified()); - assert!(!AccountStatus::Destroyed.is_not_modified()); - assert!(!AccountStatus::DestroyedChanged.is_not_modified()); - assert!(!AccountStatus::DestroyedAgain.is_not_modified()); // we know full storage assert!(!AccountStatus::LoadedEmptyEIP161.is_storage_known()); assert!(AccountStatus::LoadedNotExisting.is_storage_known()); assert!(AccountStatus::InMemoryChange.is_storage_known()); - assert!(AccountStatus::Destroyed.is_storage_known()); - assert!(AccountStatus::DestroyedChanged.is_storage_known()); - assert!(AccountStatus::DestroyedAgain.is_storage_known()); assert!(!AccountStatus::Loaded.is_storage_known()); assert!(!AccountStatus::Changed.is_storage_known()); - // account was destroyed - assert!(!AccountStatus::LoadedEmptyEIP161.was_destroyed()); - assert!(!AccountStatus::LoadedNotExisting.was_destroyed()); - assert!(!AccountStatus::InMemoryChange.was_destroyed()); - assert!(AccountStatus::Destroyed.was_destroyed()); - assert!(AccountStatus::DestroyedChanged.was_destroyed()); - assert!(AccountStatus::DestroyedAgain.was_destroyed()); - assert!(!AccountStatus::Loaded.was_destroyed()); - assert!(!AccountStatus::Changed.was_destroyed()); - // account modified but not destroyed assert!(AccountStatus::Changed.is_modified_and_not_destroyed()); assert!(AccountStatus::InMemoryChange.is_modified_and_not_destroyed()); assert!(!AccountStatus::Loaded.is_modified_and_not_destroyed()); assert!(!AccountStatus::LoadedEmptyEIP161.is_modified_and_not_destroyed()); assert!(!AccountStatus::LoadedNotExisting.is_modified_and_not_destroyed()); - assert!(!AccountStatus::Destroyed.is_modified_and_not_destroyed()); - assert!(!AccountStatus::DestroyedChanged.is_modified_and_not_destroyed()); - assert!(!AccountStatus::DestroyedAgain.is_modified_and_not_destroyed()); } } diff --git a/crates/revm/src/db/states/bundle_account.rs b/crates/revm/src/db/states/bundle_account.rs index 5955cba7..7a5d7d48 100644 --- a/crates/revm/src/db/states/bundle_account.rs +++ b/crates/revm/src/db/states/bundle_account.rs @@ -12,8 +12,6 @@ use revm_precompile::HashMap; /// /// Original account info is needed to know if there was a change. /// Same thing for storage with original value. -/// -/// On selfdestruct storage original value is ignored. #[derive(Clone, Debug, PartialEq, Eq)] pub struct BundleAccount { pub info: Option, @@ -69,11 +67,6 @@ impl BundleAccount { self.info.clone() } - /// Was this account destroyed. - pub fn was_destroyed(&self) -> bool { - self.status.was_destroyed() - } - /// Return true of account info was changed. pub fn is_info_changed(&self) -> bool { self.info != self.original_info @@ -215,145 +208,6 @@ impl BundleAccount { // Do nothing for now. None } - AccountStatus::Destroyed => { - // clear this storage and move it to the Revert. - let this_storage = self.storage.drain().collect(); - let ret = match self.status { - AccountStatus::InMemoryChange | AccountStatus::Changed | AccountStatus::Loaded | AccountStatus::LoadedEmptyEIP161 => { - Some(AccountRevert::new_selfdestructed(self.status, info_revert, this_storage)) - } - AccountStatus::LoadedNotExisting => { - // Do nothing as we have LoadedNotExisting -> Destroyed (It is noop) - None - } - _ => unreachable!("Invalid transition to Destroyed account from: {self:?} to {updated_info:?} {updated_status:?}"), - }; - - if ret.is_some() { - self.status = AccountStatus::Destroyed; - self.info = None; - } - - // set present to destroyed. - ret - } - AccountStatus::DestroyedChanged => { - // Previous block created account or changed. - // (It was destroyed on previous block or one before). - - // check common pre destroy paths. - // If common path is there it will drain the storage. - if let Some(revert_state) = AccountRevert::new_selfdestructed_from_bundle( - info_revert.clone(), - self, - &updated_storage, - ) { - // set to destroyed and revert state. - self.status = AccountStatus::DestroyedChanged; - self.info = updated_info; - self.storage = updated_storage; - - Some(revert_state) - } else { - let ret = match self.status { - AccountStatus::Destroyed | AccountStatus::LoadedNotExisting => { - // from destroyed state new account is made - Some(AccountRevert { - account: AccountInfoRevert::DeleteIt, - storage: previous_storage_from_update(&updated_storage), - previous_status: self.status, - wipe_storage: false, - }) - } - AccountStatus::DestroyedChanged => { - // Account was destroyed in this transition. So we should clear present storage - // and insert it inside revert. - - let previous_storage = if transition.storage_was_destroyed { - let mut storage = core::mem::take(&mut self.storage) - .into_iter() - .map(|t| (t.0, RevertToSlot::Some(t.1.present_value))) - .collect::>(); - for (key, _) in &updated_storage { - // as it is not existing inside Destroyed storage this means - // that previous values must be zero - storage.entry(*key).or_insert(RevertToSlot::Destroyed); - } - storage - } else { - previous_storage_from_update(&updated_storage) - }; - - Some(AccountRevert { - account: info_revert, - storage: previous_storage, - previous_status: AccountStatus::DestroyedChanged, - wipe_storage: false, - }) - } - AccountStatus::DestroyedAgain => { - Some(AccountRevert::new_selfdestructed_again( - // destroyed again will set empty account. - AccountStatus::DestroyedAgain, - AccountInfoRevert::DeleteIt, - HashMap::default(), - updated_storage.clone(), - )) - } - _ => unreachable!("Invalid state transfer to DestroyedNew from {self:?}"), - }; - self.status = AccountStatus::DestroyedChanged; - self.info = updated_info; - // extends current storage. - extend_storage(&mut self.storage, updated_storage); - - ret - } - } - AccountStatus::DestroyedAgain => { - // Previous block created account - // (It was destroyed on previous block or one before). - - // check common pre destroy paths. - // This will drain the storage if it is common transition. - let ret = if let Some(revert_state) = AccountRevert::new_selfdestructed_from_bundle( - info_revert, - self, - &HashMap::default(), - ) { - Some(revert_state) - } else { - match self.status { - AccountStatus::Destroyed - | AccountStatus::DestroyedAgain - | AccountStatus::LoadedNotExisting => { - // From destroyed to destroyed again. is noop - // - // DestroyedAgain to DestroyedAgain is noop - // - // From LoadedNotExisting to DestroyedAgain - // is noop as account is destroyed again - None - } - AccountStatus::DestroyedChanged => { - // From destroyed changed to destroyed again. - Some(AccountRevert::new_selfdestructed_again( - // destroyed again will set empty account. - AccountStatus::DestroyedChanged, - AccountInfoRevert::RevertTo(self.info.clone().unwrap_or_default()), - self.storage.drain().collect(), - HashMap::default(), - )) - } - _ => unreachable!("Invalid state to DestroyedAgain from {self:?}"), - } - }; - // set to destroyed and revert state. - self.status = AccountStatus::DestroyedAgain; - self.info = None; - self.storage.clear(); - ret - } }; account_revert.and_then(|acc| if acc.is_empty() { None } else { Some(acc) }) diff --git a/crates/revm/src/db/states/bundle_state.rs b/crates/revm/src/db/states/bundle_state.rs index 6617c42d..06388b52 100644 --- a/crates/revm/src/db/states/bundle_state.rs +++ b/crates/revm/src/db/states/bundle_state.rs @@ -454,7 +454,6 @@ impl BundleState { for (address, account) in self.state { // append account info if it is changed. - let was_destroyed = account.was_destroyed(); if is_value_known.is_not_known() || account.is_info_changed() { let info = account.info.map(AccountInfo::without_code); accounts.push((address, info)); @@ -467,27 +466,19 @@ impl BundleState { let mut account_storage_changed = Vec::with_capacity(account.storage.len()); for (key, slot) in account.storage { - // If storage was destroyed that means that storage was wiped. - // In that case we need to check if present storage value is different then ZERO. - let destroyed_and_not_zero = was_destroyed && slot.present_value != U256::ZERO; + // Check if original values was changed, so we can update it. + let changed = slot.is_changed(); //TODO: check if this is correct - // If account is not destroyed check if original values was changed, - // so we can update it. - let not_destroyed_and_changed = !was_destroyed && slot.is_changed(); - - if is_value_known.is_not_known() - || destroyed_and_not_zero - || not_destroyed_and_changed - { + if is_value_known.is_not_known() || changed { account_storage_changed.push((key, slot.present_value)); } } - if !account_storage_changed.is_empty() || was_destroyed { + if !account_storage_changed.is_empty() { // append storage changes to account. storage.push(PlainStorageChangeset { address, - wipe_storage: was_destroyed, + wipe_storage: false, storage: account_storage_changed, }); } @@ -541,11 +532,6 @@ impl BundleState { .entry(key) .or_insert(RevertToSlot::Some(value.present_value)); } - - // nullify `other` wipe as primary database wipe is done in `this`. - if this_account.was_destroyed() { - revert.wipe_storage = false; - } } } @@ -559,20 +545,15 @@ impl BundleState { let this = entry.get_mut(); self.state_size -= this.size_hint(); - // if other was destroyed. replace `this` storage with - // the `other one. - if other_account.was_destroyed() { - this.storage = other_account.storage; - } else { - // otherwise extend this storage with other - for (key, storage_slot) in other_account.storage { - // update present value or insert storage slot. - this.storage - .entry(key) - .or_insert(storage_slot) - .present_value = storage_slot.present_value; - } + // extend this storage with other + for (key, storage_slot) in other_account.storage { + // update present value or insert storage slot. + this.storage + .entry(key) + .or_insert(storage_slot) + .present_value = storage_slot.present_value; } + this.info = other_account.info; this.status.transition(other_account.status); @@ -873,70 +854,6 @@ mod tests { assert_eq!(reverted, BundleState::default()); } - #[test] - fn extend_on_destroyed_values() { - let base_bundle1 = test_bundle1(); - let base_bundle2 = test_bundle2(); - - // test1 - // bundle1 has Destroyed - // bundle2 has Changed - // end should be DestroyedChanged. - let mut b1 = base_bundle1.clone(); - let mut b2 = base_bundle2.clone(); - b1.state.get_mut(&account1()).unwrap().status = AccountStatus::Destroyed; - b2.state.get_mut(&account1()).unwrap().status = AccountStatus::Changed; - b1.extend(b2); - assert_eq!( - b1.state.get_mut(&account1()).unwrap().status, - AccountStatus::DestroyedChanged - ); - - // test2 - // bundle1 has Changed - // bundle2 has Destroyed - // end should be Destroyed - let mut b1 = base_bundle1.clone(); - let mut b2 = base_bundle2.clone(); - b1.state.get_mut(&account1()).unwrap().status = AccountStatus::Changed; - b2.state.get_mut(&account1()).unwrap().status = AccountStatus::Destroyed; - b2.reverts[0][0].1.wipe_storage = true; - b1.extend(b2); - assert_eq!( - b1.state.get_mut(&account1()).unwrap().status, - AccountStatus::Destroyed - ); - - // test2 extension - // revert of b2 should contains plain state of b1. - let mut revert1 = base_bundle2.reverts[0][0].clone(); - revert1.1.wipe_storage = true; - revert1 - .1 - .storage - .insert(slot2(), RevertToSlot::Some(U256::from(15))); - - assert_eq!( - b1.reverts.as_ref(), - vec![base_bundle1.reverts[0].clone(), vec![revert1]], - ); - - // test3 - // bundle1 has InMemoryChange - // bundle2 has Change - // end should be InMemoryChange. - - let mut b1 = base_bundle1.clone(); - let mut b2 = base_bundle2.clone(); - b1.state.get_mut(&account1()).unwrap().status = AccountStatus::InMemoryChange; - b2.state.get_mut(&account1()).unwrap().status = AccountStatus::Changed; - b1.extend(b2); - assert_eq!( - b1.state.get_mut(&account1()).unwrap().status, - AccountStatus::InMemoryChange - ); - } - #[test] fn test_sanity_path() { sanity_path(test_bundle1(), test_bundle2()); diff --git a/crates/revm/src/db/states/cache.rs b/crates/revm/src/db/states/cache.rs index a3232029..18c0a1e2 100644 --- a/crates/revm/src/db/states/cache.rs +++ b/crates/revm/src/db/states/cache.rs @@ -115,12 +115,6 @@ impl CacheState { .get_mut(&address) .expect("All accounts should be present inside cache"); - // If it is marked as selfdestructed inside revm - // we need to changed state to destroyed. - if account.is_selfdestructed() { - return this_account.selfdestruct(); - } - // Note: it can happen that created contract get selfdestructed in same block // that is why is_created is checked after selfdestructed // @@ -130,10 +124,11 @@ impl CacheState { // by just setting storage inside CRATE constructor. Overlap of those contracts // is not possible because CREATE2 is introduced later. if account.is_created() { + //TODO: does it make sense to still have this w/o the selfdestruct being implemented? return Some(this_account.newly_created(account.info, account.storage)); } - // Account is touched, but not selfdestructed or newly created. + // Account is touched, but not newly created. // Account can be touched and not changed. // And when empty account is touched it needs to be removed from database. // EIP-161 state clear diff --git a/crates/revm/src/db/states/cache_account.rs b/crates/revm/src/db/states/cache_account.rs index 72c2e70d..75fe51e4 100644 --- a/crates/revm/src/db/states/cache_account.rs +++ b/crates/revm/src/db/states/cache_account.rs @@ -64,14 +64,6 @@ impl CacheAccount { } } - /// Create account that is destroyed. - pub fn new_destroyed() -> Self { - Self { - account: None, - status: AccountStatus::Destroyed, - } - } - /// Create changed account pub fn new_changed(info: AccountInfo, storage: PlainStorage) -> Self { Self { @@ -86,7 +78,6 @@ impl CacheAccount { self.status, AccountStatus::Changed | AccountStatus::InMemoryChange - | AccountStatus::DestroyedChanged | AccountStatus::Loaded | AccountStatus::LoadedEmptyEIP161 ) @@ -116,12 +107,7 @@ impl CacheAccount { ) -> Option { let previous_status = self.status; - let had_no_info = self - .account - .as_ref() - .map(|a| a.info.is_empty()) - .unwrap_or_default(); - self.status = self.status.on_touched_created_pre_eip161(had_no_info)?; + self.status = self.status.on_touched_created_pre_eip161()?; let plain_storage = storage.iter().map(|(k, v)| (*k, v.present_value)).collect(); let previous_info = self.account.take().map(|a| a.info); @@ -150,12 +136,7 @@ impl CacheAccount { // Set account state to Destroyed as we need to clear the storage if it exist. self.status = self.status.on_touched_empty_post_eip161(); - if matches!( - previous_status, - AccountStatus::LoadedNotExisting - | AccountStatus::Destroyed - | AccountStatus::DestroyedAgain - ) { + if matches!(previous_status, AccountStatus::LoadedNotExisting) { None } else { Some(TransitionAccount { @@ -169,30 +150,6 @@ impl CacheAccount { } } - /// Consume self and make account as destroyed. - /// - /// Set account as None and set status to Destroyer or DestroyedAgain. - pub fn selfdestruct(&mut self) -> Option { - // account should be None after selfdestruct so we can take it. - let previous_info = self.account.take().map(|a| a.info); - let previous_status = self.status; - - self.status = self.status.on_selfdestructed(); - - if previous_status == AccountStatus::LoadedNotExisting { - None - } else { - Some(TransitionAccount { - info: None, - status: self.status, - previous_info, - previous_status, - storage: HashMap::new(), - storage_was_destroyed: true, - }) - } - } - /// Newly created account. pub fn newly_created( &mut self, diff --git a/crates/revm/src/db/states/changes.rs b/crates/revm/src/db/states/changes.rs index 4a559e69..bfd2e333 100644 --- a/crates/revm/src/db/states/changes.rs +++ b/crates/revm/src/db/states/changes.rs @@ -25,7 +25,7 @@ pub struct PlainStorageChangeset { /// Address of account pub address: Address, /// Wipe storage, - pub wipe_storage: bool, + pub wipe_storage: bool, //TODO: remove this field, given that selfdestruct isn't supported? /// Storage key value pairs. pub storage: Vec<(U256, U256)>, } @@ -38,7 +38,7 @@ pub struct PlainStorageRevert { /// Is storage wiped in this revert. Wiped flag is set on /// first known selfdestruct and would require clearing the /// state of this storage from database (And moving it to revert). - pub wiped: bool, + pub wiped: bool, //TODO: remove this field, given that selfdestruct isn't supported? /// Contains the storage key and old values of that storage. /// Reverts are **not** sorted. pub storage_revert: Vec<(U256, RevertToSlot)>, diff --git a/crates/revm/src/db/states/reverts.rs b/crates/revm/src/db/states/reverts.rs index 513101de..a80eeea1 100644 --- a/crates/revm/src/db/states/reverts.rs +++ b/crates/revm/src/db/states/reverts.rs @@ -1,7 +1,4 @@ -use super::{ - changes::PlainStorageRevert, AccountStatus, BundleAccount, PlainStateReverts, - StorageWithOriginalValues, -}; +use super::{changes::PlainStorageRevert, AccountStatus, PlainStateReverts}; use alloc::vec::Vec; use core::ops::{Deref, DerefMut}; use revm_interpreter::primitives::{AccountInfo, Address, HashMap, U256}; @@ -94,80 +91,6 @@ impl AccountRevert { 1 + self.storage.len() } - /// Very similar to new_selfdestructed but it will add additional zeros (RevertToSlot::Destroyed) - /// for the storage that are set if account is again created. - pub fn new_selfdestructed_again( - status: AccountStatus, - account: AccountInfoRevert, - mut previous_storage: StorageWithOriginalValues, - updated_storage: StorageWithOriginalValues, - ) -> Self { - // Take present storage values as the storages that we are going to revert to. - // As those values got destroyed. - let mut previous_storage: HashMap = previous_storage - .drain() - .map(|(key, value)| (key, RevertToSlot::Some(value.present_value))) - .collect(); - for (key, _) in updated_storage { - previous_storage - .entry(key) - .or_insert(RevertToSlot::Destroyed); - } - AccountRevert { - account, - storage: previous_storage, - previous_status: status, - wipe_storage: false, - } - } - - /// Create revert for states that were before selfdestruct. - pub fn new_selfdestructed_from_bundle( - account_info_revert: AccountInfoRevert, - bundle_account: &mut BundleAccount, - updated_storage: &StorageWithOriginalValues, - ) -> Option { - match bundle_account.status { - AccountStatus::InMemoryChange - | AccountStatus::Changed - | AccountStatus::LoadedEmptyEIP161 - | AccountStatus::Loaded => { - let mut ret = AccountRevert::new_selfdestructed_again( - bundle_account.status, - account_info_revert, - bundle_account.storage.drain().collect(), - updated_storage.clone(), - ); - ret.wipe_storage = true; - Some(ret) - } - _ => None, - } - } - - /// Create new selfdestruct revert. - pub fn new_selfdestructed( - status: AccountStatus, - account: AccountInfoRevert, - mut storage: StorageWithOriginalValues, - ) -> Self { - // Zero all present storage values and save present values to AccountRevert. - let previous_storage = storage - .iter_mut() - .map(|(key, value)| { - // take previous value and set ZERO as storage got destroyed. - (*key, RevertToSlot::Some(value.present_value)) - }) - .collect(); - - Self { - account, - storage: previous_storage, - previous_status: status, - wipe_storage: true, - } - } - /// Returns `true` if there is nothing to revert, /// by checking that: /// * both account info and storage have been left untouched diff --git a/crates/revm/src/db/states/state.rs b/crates/revm/src/db/states/state.rs index df6fa7de..71816d58 100644 --- a/crates/revm/src/db/states/state.rs +++ b/crates/revm/src/db/states/state.rs @@ -612,18 +612,9 @@ mod tests { nonce: 1, ..Default::default() }; + // A transaction in block 1 creates a new account. state.apply_transition(Vec::from([ - ( - new_account_address, - TransitionAccount { - status: AccountStatus::InMemoryChange, - info: Some(new_account_created_info.clone()), - previous_status: AccountStatus::LoadedNotExisting, - previous_info: None, - ..Default::default() - }, - ), ( existing_account_address, TransitionAccount { @@ -655,16 +646,6 @@ mod tests { // Another transaction in block 1 destroys new account. state.apply_transition(Vec::from([ - ( - new_account_address, - TransitionAccount { - status: AccountStatus::Destroyed, - info: None, - previous_status: AccountStatus::InMemoryChange, - previous_info: Some(new_account_created_info), - ..Default::default() - }, - ), ( existing_account_address, TransitionAccount { @@ -703,111 +684,4 @@ mod tests { // therefore there is nothing to revert assert_eq!(bundle_state.reverts.as_ref(), Vec::from([Vec::from([])])); } - - /// Checks that the behavior of selfdestruct within the block is correct. - #[test] - fn selfdestruct_state_and_reverts() { - let mut state = State::builder().with_bundle_update().build(); - - // Existing account. - let existing_account_address = Address::from_slice(&[0x1; 20]); - let existing_account_info = AccountInfo { - nonce: 1, - ..Default::default() - }; - - let (slot1, slot2) = (U256::from(1), U256::from(2)); - - // Existing account is destroyed. - state.apply_transition(Vec::from([( - existing_account_address, - TransitionAccount { - status: AccountStatus::Destroyed, - info: None, - previous_status: AccountStatus::Loaded, - previous_info: Some(existing_account_info.clone()), - storage: HashMap::default(), - storage_was_destroyed: true, - }, - )])); - - // Existing account is re-created and slot 0x01 is changed. - state.apply_transition(Vec::from([( - existing_account_address, - TransitionAccount { - status: AccountStatus::DestroyedChanged, - info: Some(existing_account_info.clone()), - previous_status: AccountStatus::Destroyed, - previous_info: None, - storage: HashMap::from([( - slot1, - StorageSlot::new_changed(U256::ZERO, U256::from(1)), - )]), - storage_was_destroyed: false, - }, - )])); - - // Slot 0x01 is changed, but existing account is destroyed again. - state.apply_transition(Vec::from([( - existing_account_address, - TransitionAccount { - status: AccountStatus::DestroyedAgain, - info: None, - previous_status: AccountStatus::DestroyedChanged, - previous_info: Some(existing_account_info.clone()), - // storage change should be ignored - storage: HashMap::default(), - storage_was_destroyed: true, - }, - )])); - - // Existing account is re-created and slot 0x02 is changed. - state.apply_transition(Vec::from([( - existing_account_address, - TransitionAccount { - status: AccountStatus::DestroyedChanged, - info: Some(existing_account_info.clone()), - previous_status: AccountStatus::DestroyedAgain, - previous_info: None, - storage: HashMap::from([( - slot2, - StorageSlot::new_changed(U256::ZERO, U256::from(2)), - )]), - storage_was_destroyed: false, - }, - )])); - - state.merge_transitions(BundleRetention::Reverts); - - let bundle_state = state.take_bundle(); - - assert_eq!( - bundle_state.state, - HashMap::from([( - existing_account_address, - BundleAccount { - info: Some(existing_account_info.clone()), - original_info: Some(existing_account_info.clone()), - storage: HashMap::from([( - slot2, - StorageSlot::new_changed(U256::ZERO, U256::from(2)) - )]), - status: AccountStatus::DestroyedChanged, - } - )]) - ); - - assert_eq!( - bundle_state.reverts.as_ref(), - Vec::from([Vec::from([( - existing_account_address, - AccountRevert { - account: AccountInfoRevert::DoNothing, - previous_status: AccountStatus::Loaded, - storage: HashMap::from([(slot2, RevertToSlot::Destroyed)]), - wipe_storage: true, - } - )])]) - ) - } } diff --git a/crates/revm/src/db/states/transition_account.rs b/crates/revm/src/db/states/transition_account.rs index b964bf54..d98d6488 100644 --- a/crates/revm/src/db/states/transition_account.rs +++ b/crates/revm/src/db/states/transition_account.rs @@ -88,30 +88,20 @@ impl TransitionAccount { self.info = other.info.clone(); self.status = other.status; - // if transition is from some to destroyed drop the storage. - // This need to be done here as it is one increment of the state. - if matches!( - other.status, - AccountStatus::Destroyed | AccountStatus::DestroyedAgain - ) { - self.storage = other.storage; - self.storage_was_destroyed = true; - } else { - // update changed values to this transition. - for (key, slot) in other.storage.into_iter() { - match self.storage.entry(key) { - hash_map::Entry::Vacant(entry) => { - entry.insert(slot); - } - hash_map::Entry::Occupied(mut entry) => { - let value = entry.get_mut(); - // if new value is same as original value. Remove storage entry. - if value.original_value() == slot.present_value() { - entry.remove(); - } else { - // if value is different, update transition present value; - value.present_value = slot.present_value; - } + // Update changed values to this transition. + for (key, slot) in other.storage.into_iter() { + match self.storage.entry(key) { + hash_map::Entry::Vacant(entry) => { + entry.insert(slot); + } + hash_map::Entry::Occupied(mut entry) => { + let value = entry.get_mut(); + // if new value is same as original value. Remove storage entry. + if value.original_value() == slot.present_value() { + entry.remove(); + } else { + // if value is different, update transition present value; + value.present_value = slot.present_value; } } } diff --git a/crates/revm/src/evm_impl.rs b/crates/revm/src/evm_impl.rs index 067c5f72..29f506cd 100644 --- a/crates/revm/src/evm_impl.rs +++ b/crates/revm/src/evm_impl.rs @@ -6,7 +6,7 @@ use crate::{ gas::initial_tx_gas, opcode::{make_boxed_instruction_table, make_instruction_table, InstructionTables}, CallContext, CallInputs, CallScheme, CreateInputs, Host, Interpreter, InterpreterAction, - InterpreterResult, SelfDestructResult, SharedMemory, Transfer, + InterpreterResult, SharedMemory, Transfer, }, journaled_state::JournaledState, precompile::Precompiles, @@ -647,18 +647,6 @@ impl<'a, SPEC: Spec + 'static, DB: Database> Host for EVMImpl<'a, SPEC, DB> { self.context.journaled_state.log(log); } - fn selfdestruct(&mut self, address: Address, target: Address) -> Option { - if let Some(inspector) = self.inspector.as_mut() { - let acc = self.context.journaled_state.state.get(&address).unwrap(); - inspector.selfdestruct(address, target, acc.info.get_base_balance()); - } - self.context - .journaled_state - .selfdestruct(address, target, self.context.db) - .map_err(|e| self.context.error = Some(e)) - .ok() - } - fn balanceof(&mut self, _asset_id: B256, _address: Address) -> Option<(U256, bool)> { // let journal = &mut self.data.journaled_state; // let error = &mut self.data.error; diff --git a/crates/revm/src/inspector.rs b/crates/revm/src/inspector.rs index 0f9435fa..c363f70e 100644 --- a/crates/revm/src/inspector.rs +++ b/crates/revm/src/inspector.rs @@ -2,7 +2,7 @@ use core::ops::Range; use crate::{ interpreter::{CallInputs, CreateInputs, Interpreter}, - primitives::{db::Database, Address, Bytes, B256, U256}, + primitives::{db::Database, Address, Bytes, B256}, EvmContext, }; use auto_impl::auto_impl; @@ -135,12 +135,4 @@ pub trait Inspector { let _ = context; (result, address) } - - /// Called when a contract has been self-destructed with funds transferred to target. - #[inline] - fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) { - let _ = contract; - let _ = target; - let _ = value; - } } diff --git a/crates/revm/src/inspector/customprinter.rs b/crates/revm/src/inspector/customprinter.rs index dfe08669..e324dbea 100644 --- a/crates/revm/src/inspector/customprinter.rs +++ b/crates/revm/src/inspector/customprinter.rs @@ -6,7 +6,7 @@ use core::ops::Range; use crate::{ inspectors::GasInspector, interpreter::{opcode, CallInputs, CreateInputs, Interpreter, InterpreterResult}, - primitives::{Address, U256}, + primitives::Address, Database, EvmContext, Inspector, }; @@ -98,13 +98,6 @@ impl Inspector for CustomPrintTracer { ); None } - - fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) { - println!( - "SELFDESTRUCT: contract: {:?}, refund target: {:?}, value {:?}", - contract, target, value - ); - } } #[cfg(test)] diff --git a/crates/revm/src/journaled_state.rs b/crates/revm/src/journaled_state.rs index b055ef9a..4389d5d0 100644 --- a/crates/revm/src/journaled_state.rs +++ b/crates/revm/src/journaled_state.rs @@ -1,4 +1,4 @@ -use crate::interpreter::{InstructionResult, SelfDestructResult}; +use crate::interpreter::InstructionResult; use crate::primitives::{ db::Database, hash_map::Entry, Account, Address, Bytecode, HashMap, Log, Spec, SpecId::*, State, StorageSlot, TransientStorage, B160, B256, KECCAK_EMPTY, PRECOMPILE3, U256, @@ -300,29 +300,6 @@ impl JournaledState { // remove touched status state.get_mut(&address).unwrap().unmark_touch(); } - JournalEntry::AccountDestroyed { - address, - target, - was_destroyed, - had_balance, - } => { - let account = state.get_mut(&address).unwrap(); - // set previous state of selfdestructed flag, as there could be multiple - // selfdestructs in one transaction. - if was_destroyed { - // flag is still selfdestructed - account.mark_selfdestruct(); - } else { - // flag that is not selfdestructed - account.unmark_selfdestruct(); - } - account.info.increase_base_balance(had_balance); - - if address != target { - let target = state.get_mut(&target).unwrap(); - target.info.decrease_base_balance(had_balance); - } - } JournalEntry::BalanceTransfer { from, to, balance } => { // we don't need to check overflow and underflow when adding and subtracting the balance. let from = state.get_mut(&from).unwrap(); @@ -417,82 +394,6 @@ impl JournaledState { self.journal.truncate(checkpoint.journal_i); } - /// DEPRECATED: this opcode is not available in the SabVM - /// - /// Performans selfdestruct action. - /// Transfers balance from address to target. Check if target exist/is_cold - /// - /// Note: balance will be lost if address and target are the same BUT when - /// current spec enables Cancun, this happens only when the account associated to address - /// is created in the same tx - /// - /// references: - /// * - /// * - /// * - #[inline] - pub fn selfdestruct( - &mut self, - address: Address, - target: Address, - db: &mut DB, - ) -> Result { - let (is_cold, target_exists) = self.load_account_exist(target, db)?; - - let acc = if address != target { - // Both accounts are loaded before this point, `address` as we execute its contract. - // and `target` at the beginning of the function. - let [acc, target_account] = self.state.get_many_mut([&address, &target]).unwrap(); - Self::touch_account(self.journal.last_mut().unwrap(), &target, target_account); - target_account - .info - .increase_base_balance(acc.info.get_base_balance()); - acc - } else { - self.state.get_mut(&address).unwrap() - }; - - let balance = acc.info.get_base_balance(); - let previously_destroyed = acc.is_selfdestructed(); - let is_cancun_enabled = SpecId::enabled(self.spec, CANCUN); - - // EIP-6780 (Cancun hard-fork): selfdestruct only if contract is created in the same tx - let journal_entry = if acc.is_created() || !is_cancun_enabled { - acc.mark_selfdestruct(); - acc.info.set_base_balance(U256::ZERO); - Some(JournalEntry::AccountDestroyed { - address, - target, - was_destroyed: previously_destroyed, - had_balance: balance, - }) - } else if address != target { - acc.info.set_base_balance(U256::ZERO); - Some(JournalEntry::BalanceTransfer { - from: address, - to: target, - balance, - }) - } else { - // State is not changed: - // * if we are after Cancun upgrade and - // * Selfdestruct account that is created in the same transaction and - // * Specify the target is same as selfdestructed account. The balance stays unchanged. - None - }; - - if let Some(entry) = journal_entry { - self.journal.last_mut().unwrap().push(entry); - }; - - Ok(SelfDestructResult { - had_value: balance != U256::ZERO, - is_cold, - target_exists, - previously_destroyed, - }) - } - /// Initial load of account. This load will not be tracked inside journal #[inline] pub fn initial_account_load( @@ -751,15 +652,6 @@ pub enum JournalEntry { /// Action: We will add Account to state. /// Revert: we will remove account from state. AccountLoaded { address: Address }, - /// Mark account to be destroyed and journal balance to be reverted - /// Action: Mark account and transfer the balance - /// Revert: Unmark the account and transfer balance back - AccountDestroyed { - address: Address, - target: Address, - was_destroyed: bool, // if account had already been destroyed before this journal entry - had_balance: U256, - }, /// Loading account does not mean that account will need to be added to MerkleTree (touched). /// Only when account is called (to execute contract or transfer balance) only then account is made touched. /// Action: Mark account touched