use primitives::{Address, StorageKey, StorageValue, KECCAK_EMPTY, PRECOMPILE3, U256};
use state::{EvmState, TransientStorage};
pub trait JournalEntryTr {
fn account_warmed(address: Address) -> Self;
fn account_destroyed(
address: Address,
target: Address,
destroyed_status: SelfdestructionRevertStatus,
had_balance: U256,
) -> Self;
fn account_touched(address: Address) -> Self;
fn balance_transfer(from: Address, to: Address, balance: U256) -> Self;
fn balance_changed(address: Address, old_balance: U256) -> Self;
fn nonce_changed(address: Address, previous_nonce: u64) -> Self;
fn nonce_bumped(address: Address) -> Self;
fn account_created(address: Address, is_created_globally: bool) -> Self;
fn storage_changed(address: Address, key: StorageKey, had_value: StorageValue) -> Self;
fn storage_warmed(address: Address, key: StorageKey) -> Self;
fn transient_storage_changed(
address: Address,
key: StorageKey,
had_value: StorageValue,
) -> Self;
fn code_changed(address: Address) -> Self;
fn revert(
self,
state: &mut EvmState,
transient_storage: Option<&mut TransientStorage>,
is_spurious_dragon_enabled: bool,
);
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum SelfdestructionRevertStatus {
GloballySelfdestroyed,
LocallySelfdestroyed,
RepeatedSelfdestruction,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum JournalEntry {
AccountWarmed {
address: Address,
},
AccountDestroyed {
had_balance: U256,
address: Address,
target: Address,
destroyed_status: SelfdestructionRevertStatus,
},
AccountTouched {
address: Address,
},
BalanceChange {
old_balance: U256,
address: Address,
},
BalanceTransfer {
balance: U256,
from: Address,
to: Address,
},
NonceChange {
address: Address,
previous_nonce: u64,
},
NonceBump {
address: Address,
},
AccountCreated {
address: Address,
is_created_globally: bool,
},
StorageChanged {
key: StorageKey,
had_value: StorageValue,
address: Address,
},
StorageWarmed {
key: StorageKey,
address: Address,
},
TransientStorageChange {
key: StorageKey,
had_value: StorageValue,
address: Address,
},
CodeChange {
address: Address,
},
}
impl JournalEntryTr for JournalEntry {
fn account_warmed(address: Address) -> Self {
JournalEntry::AccountWarmed { address }
}
fn account_destroyed(
address: Address,
target: Address,
destroyed_status: SelfdestructionRevertStatus,
had_balance: StorageValue,
) -> Self {
JournalEntry::AccountDestroyed {
address,
target,
destroyed_status,
had_balance,
}
}
fn account_touched(address: Address) -> Self {
JournalEntry::AccountTouched { address }
}
fn balance_changed(address: Address, old_balance: U256) -> Self {
JournalEntry::BalanceChange {
address,
old_balance,
}
}
fn balance_transfer(from: Address, to: Address, balance: U256) -> Self {
JournalEntry::BalanceTransfer { from, to, balance }
}
fn account_created(address: Address, is_created_globally: bool) -> Self {
JournalEntry::AccountCreated {
address,
is_created_globally,
}
}
fn storage_changed(address: Address, key: StorageKey, had_value: StorageValue) -> Self {
JournalEntry::StorageChanged {
address,
key,
had_value,
}
}
fn nonce_changed(address: Address, previous_nonce: u64) -> Self {
JournalEntry::NonceChange {
address,
previous_nonce,
}
}
fn nonce_bumped(address: Address) -> Self {
JournalEntry::NonceBump { address }
}
fn storage_warmed(address: Address, key: StorageKey) -> Self {
JournalEntry::StorageWarmed { address, key }
}
fn transient_storage_changed(
address: Address,
key: StorageKey,
had_value: StorageValue,
) -> Self {
JournalEntry::TransientStorageChange {
address,
key,
had_value,
}
}
fn code_changed(address: Address) -> Self {
JournalEntry::CodeChange { address }
}
fn revert(
self,
state: &mut EvmState,
transient_storage: Option<&mut TransientStorage>,
is_spurious_dragon_enabled: bool,
) {
match self {
JournalEntry::AccountWarmed { address } => {
state.get_mut(&address).unwrap().mark_cold();
}
JournalEntry::AccountTouched { address } => {
if is_spurious_dragon_enabled && address == PRECOMPILE3 {
return;
}
state.get_mut(&address).unwrap().unmark_touch();
}
JournalEntry::AccountDestroyed {
address,
target,
destroyed_status,
had_balance,
} => {
let account = state.get_mut(&address).unwrap();
match destroyed_status {
SelfdestructionRevertStatus::GloballySelfdestroyed => {
account.unmark_selfdestruct();
account.unmark_selfdestructed_locally();
}
SelfdestructionRevertStatus::LocallySelfdestroyed => {
account.unmark_selfdestructed_locally();
}
SelfdestructionRevertStatus::RepeatedSelfdestruction => (),
}
account.info.balance += had_balance;
if address != target {
let target = state.get_mut(&target).unwrap();
target.info.balance -= had_balance;
}
}
JournalEntry::BalanceChange {
address,
old_balance,
} => {
let account = state.get_mut(&address).unwrap();
account.info.balance = old_balance;
}
JournalEntry::BalanceTransfer { from, to, balance } => {
let from = state.get_mut(&from).unwrap();
from.info.balance += balance;
let to = state.get_mut(&to).unwrap();
to.info.balance -= balance;
}
JournalEntry::NonceChange {
address,
previous_nonce,
} => {
state.get_mut(&address).unwrap().info.nonce = previous_nonce;
}
JournalEntry::NonceBump { address } => {
let nonce = &mut state.get_mut(&address).unwrap().info.nonce;
*nonce = nonce.saturating_sub(1);
}
JournalEntry::AccountCreated {
address,
is_created_globally,
} => {
let account = &mut state.get_mut(&address).unwrap();
account.unmark_created_locally();
if is_created_globally {
account.unmark_created();
}
account.info.nonce = 0;
}
JournalEntry::StorageWarmed { address, key } => {
state
.get_mut(&address)
.unwrap()
.storage
.get_mut(&key)
.unwrap()
.mark_cold();
}
JournalEntry::StorageChanged {
address,
key,
had_value,
} => {
state
.get_mut(&address)
.unwrap()
.storage
.get_mut(&key)
.unwrap()
.present_value = had_value;
}
JournalEntry::TransientStorageChange {
address,
key,
had_value,
} => {
let Some(transient_storage) = transient_storage else {
return;
};
let tkey = (address, key);
if had_value.is_zero() {
transient_storage.remove(&tkey);
} else {
transient_storage.insert(tkey, had_value);
}
}
JournalEntry::CodeChange { address } => {
let acc = state.get_mut(&address).unwrap();
acc.info.code_hash = KECCAK_EMPTY;
acc.info.code = None;
}
}
}
}