use ethrex_common::H256;
use ethrex_common::constants::EMPTY_TRIE_HASH;
use ethrex_common::types::{AccountState, GenesisAccount};
use ethrex_common::utils::keccak;
use ethrex_common::{U256, constants::EMPTY_KECCAK_HASH, types::AccountInfo};
use rustc_hash::FxHashMap;
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct LevmAccount {
pub info: AccountInfo,
pub storage: FxHashMap<H256, U256>,
pub has_storage: bool,
pub status: AccountStatus,
pub exists: bool,
}
impl From<GenesisAccount> for LevmAccount {
fn from(genesis: GenesisAccount) -> Self {
let storage: FxHashMap<H256, U256> = genesis
.storage
.into_iter()
.map(|(key, value)| (H256::from(key.to_big_endian()), value))
.collect();
LevmAccount {
info: AccountInfo {
code_hash: keccak(genesis.code),
balance: genesis.balance,
nonce: genesis.nonce,
},
has_storage: !storage.is_empty(),
storage,
status: AccountStatus::Unmodified,
exists: true,
}
}
}
impl From<AccountState> for LevmAccount {
fn from(state: AccountState) -> Self {
let is_default = state == AccountState::default();
LevmAccount {
info: AccountInfo {
code_hash: state.code_hash,
balance: state.balance,
nonce: state.nonce,
},
storage: Default::default(),
status: AccountStatus::Unmodified,
has_storage: state.storage_root != *EMPTY_TRIE_HASH,
exists: !is_default,
}
}
}
impl LevmAccount {
pub fn mark_destroyed(&mut self) {
self.status = AccountStatus::Destroyed;
}
pub fn mark_modified(&mut self) {
if self.status == AccountStatus::Unmodified {
self.status = AccountStatus::Modified;
}
if self.status == AccountStatus::Destroyed {
self.status = AccountStatus::DestroyedModified;
}
self.exists = true;
}
pub fn has_nonce(&self) -> bool {
self.info.nonce != 0
}
pub fn has_code(&self) -> bool {
self.info.code_hash != *EMPTY_KECCAK_HASH
}
pub fn create_would_collide(&self) -> bool {
self.has_code() || self.has_nonce() || self.has_storage
}
pub fn is_empty(&self) -> bool {
self.info.is_empty()
}
pub fn is_unmodified(&self) -> bool {
matches!(self.status, AccountStatus::Unmodified)
}
#[inline]
pub fn clone_without_storage(&self) -> Self {
let Self {
info,
storage: _,
has_storage,
status,
exists,
} = self;
Self {
info: info.clone(),
storage: FxHashMap::default(),
has_storage: *has_storage,
status: status.clone(),
exists: *exists,
}
}
}
#[derive(Clone, Default, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum AccountStatus {
#[default]
Unmodified,
Modified,
Destroyed,
DestroyedModified,
}