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,
was_destroyed: bool,
had_balance: U256,
) -> Self;
fn account_touched(address: Address) -> Self;
fn balance_transfer(from: Address, to: Address, balance: U256) -> Self;
fn nonce_changed(address: Address) -> Self;
fn account_created(address: Address) -> 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: &mut TransientStorage,
is_spurious_dragon_enabled: bool,
);
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum JournalEntry {
AccountWarmed {
address: Address,
},
AccountDestroyed {
address: Address,
target: Address,
was_destroyed: bool,
had_balance: U256,
},
AccountTouched {
address: Address,
},
BalanceTransfer {
from: Address,
to: Address,
balance: U256,
},
NonceChange {
address: Address,
},
AccountCreated {
address: Address,
},
StorageChanged {
address: Address,
key: StorageKey,
had_value: StorageValue,
},
StorageWarmed {
address: Address,
key: StorageKey,
},
TransientStorageChange {
address: Address,
key: StorageKey,
had_value: StorageValue,
},
CodeChange {
address: Address,
},
}
impl JournalEntryTr for JournalEntry {
fn account_warmed(address: Address) -> Self {
JournalEntry::AccountWarmed { address }
}
fn account_destroyed(
address: Address,
target: Address,
was_destroyed: bool, had_balance: U256,
) -> Self {
JournalEntry::AccountDestroyed {
address,
target,
was_destroyed,
had_balance,
}
}
fn account_touched(address: Address) -> Self {
JournalEntry::AccountTouched { address }
}
fn balance_transfer(from: Address, to: Address, balance: U256) -> Self {
JournalEntry::BalanceTransfer { from, to, balance }
}
fn account_created(address: Address) -> Self {
JournalEntry::AccountCreated { address }
}
fn storage_changed(address: Address, key: StorageKey, had_value: StorageValue) -> Self {
JournalEntry::StorageChanged {
address,
key,
had_value,
}
}
fn nonce_changed(address: Address) -> Self {
JournalEntry::NonceChange { 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: &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,
was_destroyed,
had_balance,
} => {
let account = state.get_mut(&address).unwrap();
if was_destroyed {
account.mark_selfdestruct();
} else {
account.unmark_selfdestruct();
}
account.info.balance += had_balance;
if address != target {
let target = state.get_mut(&target).unwrap();
target.info.balance -= had_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 } => {
state.get_mut(&address).unwrap().info.nonce -= 1;
}
JournalEntry::AccountCreated { address } => {
let account = &mut state.get_mut(&address).unwrap();
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 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;
}
}
}
}