use crate::{
bal::{writes::BalWrites, BalError, BalIndex},
Account, AccountInfo, EvmStorage,
};
use alloy_eip7928::{
AccountChanges as AlloyAccountChanges, BalanceChange as AlloyBalanceChange,
CodeChange as AlloyCodeChange, NonceChange as AlloyNonceChange,
SlotChanges as AlloySlotChanges, StorageChange as AlloyStorageChange,
};
use bytecode::{Bytecode, BytecodeDecodeError};
use core::ops::{Deref, DerefMut};
use primitives::{Address, StorageKey, StorageValue, B256, U256};
use std::{
collections::{btree_map::Entry, BTreeMap},
vec::Vec,
};
#[derive(Debug, Default, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AccountBal {
pub account_info: AccountInfoBal,
pub storage: StorageBal,
}
impl Deref for AccountBal {
type Target = AccountInfoBal;
fn deref(&self) -> &Self::Target {
&self.account_info
}
}
impl DerefMut for AccountBal {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.account_info
}
}
impl AccountBal {
pub fn populate_account_info(&self, bal_index: BalIndex, account: &mut AccountInfo) -> bool {
self.account_info.populate_account_info(bal_index, account)
}
#[inline]
pub fn update(&mut self, bal_index: BalIndex, account: &Account) {
if account.is_selfdestructed_locally() {
let empty_info = AccountInfo::default();
self.account_info
.update(bal_index, &account.original_info, &empty_info);
self.storage
.update_selfdestruct(bal_index, &account.storage);
return;
}
self.account_info
.update(bal_index, &account.original_info, &account.info);
self.storage.update(bal_index, &account.storage);
}
#[inline]
pub fn try_from_alloy(
alloy_account: AlloyAccountChanges,
) -> Result<(Address, Self), BytecodeDecodeError> {
Ok((
alloy_account.address,
AccountBal {
account_info: AccountInfoBal {
nonce: BalWrites::from(alloy_account.nonce_changes),
balance: BalWrites::from(alloy_account.balance_changes),
code: BalWrites::try_from(alloy_account.code_changes)?,
},
storage: StorageBal::from_iter(
alloy_account
.storage_changes
.into_iter()
.chain(
alloy_account
.storage_reads
.into_iter()
.map(|key| AlloySlotChanges::new(key, Default::default())),
)
.map(|slot| (slot.slot, BalWrites::from(slot.changes))),
),
},
))
}
#[inline]
pub fn into_alloy_account(self, address: Address) -> AlloyAccountChanges {
let storage_len = self.storage.storage.len();
let mut storage_reads = Vec::with_capacity(storage_len);
let mut storage_changes = Vec::with_capacity(storage_len);
for (key, value) in self.storage.storage {
if value.writes.is_empty() {
storage_reads.push(key);
} else {
storage_changes.push(AlloySlotChanges::new(
key,
value
.writes
.into_iter()
.map(|(index, value)| AlloyStorageChange::new(index, value))
.collect(),
));
}
}
AlloyAccountChanges {
address,
storage_changes,
storage_reads,
balance_changes: self
.account_info
.balance
.writes
.into_iter()
.map(|(index, value)| AlloyBalanceChange::new(index, value))
.collect(),
nonce_changes: self
.account_info
.nonce
.writes
.into_iter()
.map(|(index, value)| AlloyNonceChange::new(index, value))
.collect(),
code_changes: self
.account_info
.code
.writes
.into_iter()
.map(|(index, (_, value))| AlloyCodeChange::new(index, value.original_bytes()))
.collect(),
}
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AccountInfoBal {
pub nonce: BalWrites<u64>,
pub balance: BalWrites<U256>,
pub code: BalWrites<(B256, Bytecode)>,
}
impl AccountInfoBal {
pub fn populate_account_info(&self, bal_index: BalIndex, account: &mut AccountInfo) -> bool {
let mut changed = false;
if let Some(nonce) = self.nonce.get(bal_index) {
account.nonce = nonce;
changed = true;
}
if let Some(balance) = self.balance.get(bal_index) {
account.balance = balance;
changed = true;
}
if let Some(code) = self.code.get(bal_index) {
account.code_hash = code.0;
account.code = Some(code.1);
changed = true;
}
changed
}
#[inline]
pub fn update(&mut self, index: BalIndex, original: &AccountInfo, present: &AccountInfo) {
self.nonce.update(index, &original.nonce, present.nonce);
self.balance
.update(index, &original.balance, present.balance);
if original.code_hash != present.code_hash {
self.code.update_with_key(
index,
&original.code_hash,
(present.code_hash, present.code.clone().unwrap_or_default()),
|i| &i.0,
);
}
}
#[inline]
pub fn extend(&mut self, bal_account: AccountInfoBal) {
self.nonce.extend(bal_account.nonce);
self.balance.extend(bal_account.balance);
self.code.extend(bal_account.code);
}
#[inline]
pub fn balance_update(&mut self, bal_index: BalIndex, original_balance: &U256, balance: U256) {
self.balance.update(bal_index, original_balance, balance);
}
#[inline]
pub fn nonce_update(&mut self, bal_index: BalIndex, original_nonce: &u64, nonce: u64) {
self.nonce.update(bal_index, original_nonce, nonce);
}
#[inline]
pub fn code_update(
&mut self,
bal_index: BalIndex,
original_code_hash: &B256,
code_hash: B256,
code: Bytecode,
) {
self.code
.update_with_key(bal_index, original_code_hash, (code_hash, code), |i| &i.0);
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct StorageBal {
pub storage: BTreeMap<StorageKey, BalWrites<StorageValue>>,
}
impl StorageBal {
#[inline]
pub fn get(
&self,
key: StorageKey,
bal_index: BalIndex,
) -> Result<Option<StorageValue>, BalError> {
Ok(self.get_bal_writes(key)?.get(bal_index))
}
#[inline]
pub fn get_bal_writes(&self, key: StorageKey) -> Result<&BalWrites<StorageValue>, BalError> {
self.storage.get(&key).ok_or(BalError::SlotNotFound)
}
#[inline]
pub fn extend(&mut self, storage: StorageBal) {
for (key, value) in storage.storage {
match self.storage.entry(key) {
Entry::Occupied(mut entry) => {
entry.get_mut().extend(value);
}
Entry::Vacant(entry) => {
entry.insert(value);
}
}
}
}
#[inline]
pub fn update(&mut self, bal_index: BalIndex, storage: &EvmStorage) {
for (key, value) in storage {
self.storage.entry(*key).or_default().update(
bal_index,
&value.original_value,
value.present_value,
);
}
}
#[inline]
pub fn update_selfdestruct(&mut self, bal_index: BalIndex, storage: &EvmStorage) {
for (key, value) in storage {
self.storage.entry(*key).or_default().update(
bal_index,
&value.original_value,
StorageValue::ZERO,
);
}
}
#[inline]
pub fn update_reads(&mut self, storage: impl Iterator<Item = StorageKey>) {
for key in storage {
self.storage.entry(key).or_default();
}
}
pub fn extend_iter(
&mut self,
storage: impl Iterator<Item = (StorageKey, BalWrites<StorageValue>)>,
) {
for (key, value) in storage {
self.storage.insert(key, value);
}
}
pub fn into_vecs(self) -> (Vec<StorageKey>, Vec<(StorageKey, BalWrites<StorageValue>)>) {
let mut reads = Vec::new();
let mut writes = Vec::new();
for (key, value) in self.storage {
if value.writes.is_empty() {
reads.push(key);
} else {
writes.push((key, value));
}
}
(reads, writes)
}
}
impl FromIterator<(StorageKey, BalWrites<StorageValue>)> for StorageBal {
fn from_iter<I: IntoIterator<Item = (StorageKey, BalWrites<StorageValue>)>>(iter: I) -> Self {
Self {
storage: iter.into_iter().collect(),
}
}
}