1#[cfg(feature = "account-ext")]
4use crate::AccountExtension;
5use crate::{
6 bal::{writes::BalWrites, BalAccountInfo, BalAccountLookup, BalError, BlockAccessIndex},
7 Account, AccountInfo, EvmStorage,
8};
9use alloy_eip7928::{
10 AccountChanges as AlloyAccountChanges, BalanceChange as AlloyBalanceChange,
11 CodeChange as AlloyCodeChange, NonceChange as AlloyNonceChange,
12 SlotChanges as AlloySlotChanges, StorageChange as AlloyStorageChange,
13};
14use bytecode::{Bytecode, BytecodeDecodeError};
15use core::ops::{Deref, DerefMut};
16use primitives::{Address, StorageKey, StorageValue, B256, U256};
17use std::{
18 collections::{btree_map::Entry, BTreeMap},
19 vec::Vec,
20};
21
22#[derive(Debug, Default, Clone, PartialEq, Eq)]
24#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
25pub struct AccountBal {
26 pub account_info: AccountInfoBal,
28 pub storage: StorageBal,
30}
31
32impl Deref for AccountBal {
33 type Target = AccountInfoBal;
34
35 fn deref(&self) -> &Self::Target {
36 &self.account_info
37 }
38}
39
40impl DerefMut for AccountBal {
41 fn deref_mut(&mut self) -> &mut Self::Target {
42 &mut self.account_info
43 }
44}
45
46impl AccountBal {
47 pub fn populate_account_info(
49 &self,
50 bal_index: BlockAccessIndex,
51 account: &mut AccountInfo,
52 ) -> bool {
53 self.account_info.populate_account_info(bal_index, account)
54 }
55
56 #[inline]
58 pub fn update(&mut self, bal_index: BlockAccessIndex, account: &Account) {
59 if account.is_selfdestructed_locally() {
60 let empty_info = AccountInfo::default();
61 self.account_info
62 .update(bal_index, &account.original_info(), &empty_info);
63 self.storage
65 .update_selfdestruct(bal_index, &account.storage);
66 return;
67 }
68
69 self.account_info
70 .update(bal_index, &account.original_info(), &account.info);
71
72 self.storage.update(bal_index, &account.storage);
73 }
74
75 #[inline]
84 pub fn try_from_alloy(
85 alloy_account: AlloyAccountChanges,
86 ) -> Result<(Address, Self), BytecodeDecodeError> {
87 Ok((
88 alloy_account.address,
89 AccountBal {
90 account_info: AccountInfoBal {
91 nonce: BalWrites::from(alloy_account.nonce_changes),
92 balance: BalWrites::from(alloy_account.balance_changes),
93 code: BalWrites::try_from(alloy_account.code_changes)?,
94 #[cfg(feature = "account-ext")]
95 extension: BalWrites::default(),
96 },
97 storage: StorageBal::from_iter(
98 alloy_account
99 .storage_changes
100 .into_iter()
101 .chain(
102 alloy_account
103 .storage_reads
104 .into_iter()
105 .map(|key| AlloySlotChanges::new(key, Default::default())),
106 )
107 .map(|slot| (slot.slot, BalWrites::from(slot.changes))),
108 ),
109 },
110 ))
111 }
112
113 #[inline]
122 pub fn clone_from_alloy(
123 alloy_account: &AlloyAccountChanges,
124 ) -> Result<(Address, Self), BytecodeDecodeError> {
125 Ok((
126 alloy_account.address,
127 AccountBal {
128 account_info: AccountInfoBal {
129 nonce: BalWrites::from(alloy_account.nonce_changes.as_slice()),
130 balance: BalWrites::from(alloy_account.balance_changes.as_slice()),
131 code: BalWrites::try_from(alloy_account.code_changes.as_slice())?,
132 #[cfg(feature = "account-ext")]
133 extension: BalWrites::default(),
134 },
135 storage: StorageBal::from_iter(
136 alloy_account
137 .storage_changes
138 .iter()
139 .map(|slot| (slot.slot, BalWrites::from(slot.changes.as_slice())))
140 .chain(
141 alloy_account
142 .storage_reads
143 .iter()
144 .map(|key| (*key, BalWrites::default())),
145 ),
146 ),
147 },
148 ))
149 }
150
151 #[inline]
162 pub fn into_alloy_account(self, address: Address) -> AlloyAccountChanges {
163 let storage_len = self.storage.storage.len();
164 let mut storage_reads = Vec::with_capacity(storage_len);
165 let mut storage_changes = Vec::with_capacity(storage_len);
166 for (key, value) in self.storage.storage {
167 if value.writes.is_empty() {
168 storage_reads.push(key);
169 } else {
170 let mut changes = value
171 .writes
172 .into_iter()
173 .map(|(index, value)| AlloyStorageChange::new(index, value))
174 .collect::<Vec<_>>();
175 changes.sort_unstable_by_key(|change| change.block_access_index);
176
177 storage_changes.push(AlloySlotChanges::new(key, changes));
178 }
179 }
180
181 let mut balance_changes = self
182 .account_info
183 .balance
184 .writes
185 .into_iter()
186 .map(|(index, value)| AlloyBalanceChange::new(index, value))
187 .collect::<Vec<_>>();
188 balance_changes.sort_unstable_by_key(|change| change.block_access_index);
189
190 let mut nonce_changes = self
191 .account_info
192 .nonce
193 .writes
194 .into_iter()
195 .map(|(index, value)| AlloyNonceChange::new(index, value))
196 .collect::<Vec<_>>();
197 nonce_changes.sort_unstable_by_key(|change| change.block_access_index);
198
199 let mut code_changes = self
200 .account_info
201 .code
202 .writes
203 .into_iter()
204 .map(|(index, (_, value))| AlloyCodeChange::new(index, value.original_bytes()))
205 .collect::<Vec<_>>();
206 code_changes.sort_unstable_by_key(|change| change.block_access_index);
207
208 AlloyAccountChanges {
209 address,
210 storage_changes,
211 storage_reads,
212 balance_changes,
213 nonce_changes,
214 code_changes,
215 }
216 }
217}
218
219#[derive(Debug, Default, Clone, PartialEq, Eq)]
221#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
222pub struct AccountInfoBal {
223 pub nonce: BalWrites<u64>,
225 pub balance: BalWrites<U256>,
227 pub code: BalWrites<(B256, Bytecode)>,
229 #[cfg(feature = "account-ext")]
231 #[cfg_attr(
232 feature = "serde",
233 serde(default, skip_serializing_if = "BalWrites::is_empty")
234 )]
235 pub extension: BalWrites<AccountExtension>,
236}
237
238impl AccountInfoBal {
239 pub fn populate_account_info(
241 &self,
242 bal_index: BlockAccessIndex,
243 account: &mut AccountInfo,
244 ) -> bool {
245 let mut changed = false;
246 if let Some(nonce) = self.nonce.get(bal_index) {
247 account.nonce = nonce;
248 changed = true;
249 }
250 if let Some(balance) = self.balance.get(bal_index) {
251 account.balance = balance;
252 changed = true;
253 }
254 if let Some(code) = self.code.get(bal_index) {
255 account.code_hash = code.0;
256 account.code = Some(code.1);
257 changed = true;
258 }
259 #[cfg(feature = "account-ext")]
260 if let Some(extension) = self.extension.get(bal_index) {
261 account.extension = extension;
262 changed = true;
263 }
264 changed
265 }
266
267 pub fn account_info_lookup(&self, bal_index: BlockAccessIndex) -> BalAccountLookup {
274 let code = self.code.get(bal_index);
275 let info = BalAccountInfo {
276 balance: self.balance.get(bal_index),
277 nonce: self.nonce.get(bal_index),
278 code_hash: code.as_ref().map(|(hash, _)| *hash),
279 };
280 let (Some(balance), Some(nonce), Some((code_hash, code))) =
281 (info.balance, info.nonce, code)
282 else {
283 return BalAccountLookup::Partial(info);
284 };
285 #[cfg(feature = "account-ext")]
286 let Some(extension) = self.extension.get(bal_index) else {
287 return BalAccountLookup::Partial(info);
288 };
289 let account = AccountInfo::new(balance, nonce, code_hash, code);
290 #[cfg(feature = "account-ext")]
291 let account = account.with_extension(extension);
292 BalAccountLookup::Complete(account)
293 }
294
295 #[inline]
297 pub fn update(
298 &mut self,
299 index: BlockAccessIndex,
300 original: &AccountInfo,
301 present: &AccountInfo,
302 ) {
303 self.nonce.update(index, &original.nonce, present.nonce);
304 self.balance
305 .update(index, &original.balance, present.balance);
306 if original.code_hash != present.code_hash {
307 self.code.update_with_key(
308 index,
309 &original.code_hash,
310 (present.code_hash, present.code.clone().unwrap_or_default()),
311 |i| &i.0,
312 );
313 }
314 #[cfg(feature = "account-ext")]
315 self.extension
316 .update(index, &original.extension, present.extension.clone());
317 }
318
319 #[inline]
321 pub fn extend(&mut self, bal_account: AccountInfoBal) {
322 self.nonce.extend(bal_account.nonce);
323 self.balance.extend(bal_account.balance);
324 self.code.extend(bal_account.code);
325 #[cfg(feature = "account-ext")]
326 self.extension.extend(bal_account.extension);
327 }
328
329 #[inline]
331 pub fn balance_update(
332 &mut self,
333 bal_index: BlockAccessIndex,
334 original_balance: &U256,
335 balance: U256,
336 ) {
337 self.balance.update(bal_index, original_balance, balance);
338 }
339
340 #[inline]
342 pub fn nonce_update(&mut self, bal_index: BlockAccessIndex, original_nonce: &u64, nonce: u64) {
343 self.nonce.update(bal_index, original_nonce, nonce);
344 }
345
346 #[inline]
348 pub fn code_update(
349 &mut self,
350 bal_index: BlockAccessIndex,
351 original_code_hash: &B256,
352 code_hash: B256,
353 code: Bytecode,
354 ) {
355 self.code
356 .update_with_key(bal_index, original_code_hash, (code_hash, code), |i| &i.0);
357 }
358}
359
360#[derive(Debug, Default, Clone, PartialEq, Eq)]
362#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
363pub struct StorageBal {
364 pub storage: BTreeMap<StorageKey, BalWrites<StorageValue>>,
366}
367
368impl StorageBal {
369 #[inline]
371 pub fn get(
372 &self,
373 address: &Address,
374 key: StorageKey,
375 bal_index: BlockAccessIndex,
376 ) -> Result<Option<StorageValue>, BalError> {
377 Ok(self.get_bal_writes(address, key)?.get(bal_index))
378 }
379
380 #[inline]
384 pub fn get_bal_writes(
385 &self,
386 address: &Address,
387 key: StorageKey,
388 ) -> Result<&BalWrites<StorageValue>, BalError> {
389 self.storage.get(&key).ok_or(BalError::SlotNotFound {
390 address: *address,
391 slot: key,
392 })
393 }
394
395 #[inline]
397 pub fn extend(&mut self, storage: StorageBal) {
398 for (key, value) in storage.storage {
399 match self.storage.entry(key) {
400 Entry::Occupied(mut entry) => {
401 entry.get_mut().extend(value);
402 }
403 Entry::Vacant(entry) => {
404 entry.insert(value);
405 }
406 }
407 }
408 }
409
410 #[inline]
412 pub fn update(&mut self, bal_index: BlockAccessIndex, storage: &EvmStorage) {
413 for (key, value) in storage {
414 self.storage.entry(*key).or_default().update(
415 bal_index,
416 &value.original_value,
417 value.present_value,
418 );
419 }
420 }
421
422 #[inline]
426 pub fn update_selfdestruct(&mut self, bal_index: BlockAccessIndex, storage: &EvmStorage) {
427 for (key, value) in storage {
428 self.storage.entry(*key).or_default().update(
429 bal_index,
430 &value.original_value,
431 StorageValue::ZERO,
432 );
433 }
434 }
435
436 #[inline]
440 pub fn update_reads(&mut self, storage: impl Iterator<Item = StorageKey>) {
441 for key in storage {
442 self.storage.entry(key).or_default();
443 }
444 }
445
446 pub fn extend_iter(
448 &mut self,
449 storage: impl Iterator<Item = (StorageKey, BalWrites<StorageValue>)>,
450 ) {
451 for (key, value) in storage {
452 self.storage.insert(key, value);
453 }
454 }
455
456 pub fn into_vecs(self) -> (Vec<StorageKey>, Vec<(StorageKey, BalWrites<StorageValue>)>) {
458 let mut reads = Vec::new();
459 let mut writes = Vec::new();
460
461 for (key, value) in self.storage {
462 if value.writes.is_empty() {
463 reads.push(key);
464 } else {
465 writes.push((key, value));
466 }
467 }
468
469 (reads, writes)
470 }
471}
472
473impl FromIterator<(StorageKey, BalWrites<StorageValue>)> for StorageBal {
474 fn from_iter<I: IntoIterator<Item = (StorageKey, BalWrites<StorageValue>)>>(iter: I) -> Self {
475 Self {
476 storage: iter.into_iter().collect(),
477 }
478 }
479}