1#[cfg(feature = "account-ext")]
4use crate::AccountExtension;
5use crate::{
6 bal::{writes::BalWrites, 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 #[inline]
269 pub fn update(
270 &mut self,
271 index: BlockAccessIndex,
272 original: &AccountInfo,
273 present: &AccountInfo,
274 ) {
275 self.nonce.update(index, &original.nonce, present.nonce);
276 self.balance
277 .update(index, &original.balance, present.balance);
278 if original.code_hash != present.code_hash {
279 self.code.update_with_key(
280 index,
281 &original.code_hash,
282 (present.code_hash, present.code.clone().unwrap_or_default()),
283 |i| &i.0,
284 );
285 }
286 #[cfg(feature = "account-ext")]
287 self.extension
288 .update(index, &original.extension, present.extension.clone());
289 }
290
291 #[inline]
293 pub fn extend(&mut self, bal_account: AccountInfoBal) {
294 self.nonce.extend(bal_account.nonce);
295 self.balance.extend(bal_account.balance);
296 self.code.extend(bal_account.code);
297 #[cfg(feature = "account-ext")]
298 self.extension.extend(bal_account.extension);
299 }
300
301 #[inline]
303 pub fn balance_update(
304 &mut self,
305 bal_index: BlockAccessIndex,
306 original_balance: &U256,
307 balance: U256,
308 ) {
309 self.balance.update(bal_index, original_balance, balance);
310 }
311
312 #[inline]
314 pub fn nonce_update(&mut self, bal_index: BlockAccessIndex, original_nonce: &u64, nonce: u64) {
315 self.nonce.update(bal_index, original_nonce, nonce);
316 }
317
318 #[inline]
320 pub fn code_update(
321 &mut self,
322 bal_index: BlockAccessIndex,
323 original_code_hash: &B256,
324 code_hash: B256,
325 code: Bytecode,
326 ) {
327 self.code
328 .update_with_key(bal_index, original_code_hash, (code_hash, code), |i| &i.0);
329 }
330}
331
332#[derive(Debug, Default, Clone, PartialEq, Eq)]
334#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
335pub struct StorageBal {
336 pub storage: BTreeMap<StorageKey, BalWrites<StorageValue>>,
338}
339
340impl StorageBal {
341 #[inline]
343 pub fn get(
344 &self,
345 address: &Address,
346 key: StorageKey,
347 bal_index: BlockAccessIndex,
348 ) -> Result<Option<StorageValue>, BalError> {
349 Ok(self.get_bal_writes(address, key)?.get(bal_index))
350 }
351
352 #[inline]
356 pub fn get_bal_writes(
357 &self,
358 address: &Address,
359 key: StorageKey,
360 ) -> Result<&BalWrites<StorageValue>, BalError> {
361 self.storage.get(&key).ok_or(BalError::SlotNotFound {
362 address: *address,
363 slot: key,
364 })
365 }
366
367 #[inline]
369 pub fn extend(&mut self, storage: StorageBal) {
370 for (key, value) in storage.storage {
371 match self.storage.entry(key) {
372 Entry::Occupied(mut entry) => {
373 entry.get_mut().extend(value);
374 }
375 Entry::Vacant(entry) => {
376 entry.insert(value);
377 }
378 }
379 }
380 }
381
382 #[inline]
384 pub fn update(&mut self, bal_index: BlockAccessIndex, storage: &EvmStorage) {
385 for (key, value) in storage {
386 self.storage.entry(*key).or_default().update(
387 bal_index,
388 &value.original_value,
389 value.present_value,
390 );
391 }
392 }
393
394 #[inline]
398 pub fn update_selfdestruct(&mut self, bal_index: BlockAccessIndex, storage: &EvmStorage) {
399 for (key, value) in storage {
400 self.storage.entry(*key).or_default().update(
401 bal_index,
402 &value.original_value,
403 StorageValue::ZERO,
404 );
405 }
406 }
407
408 #[inline]
412 pub fn update_reads(&mut self, storage: impl Iterator<Item = StorageKey>) {
413 for key in storage {
414 self.storage.entry(key).or_default();
415 }
416 }
417
418 pub fn extend_iter(
420 &mut self,
421 storage: impl Iterator<Item = (StorageKey, BalWrites<StorageValue>)>,
422 ) {
423 for (key, value) in storage {
424 self.storage.insert(key, value);
425 }
426 }
427
428 pub fn into_vecs(self) -> (Vec<StorageKey>, Vec<(StorageKey, BalWrites<StorageValue>)>) {
430 let mut reads = Vec::new();
431 let mut writes = Vec::new();
432
433 for (key, value) in self.storage {
434 if value.writes.is_empty() {
435 reads.push(key);
436 } else {
437 writes.push((key, value));
438 }
439 }
440
441 (reads, writes)
442 }
443}
444
445impl FromIterator<(StorageKey, BalWrites<StorageValue>)> for StorageBal {
446 fn from_iter<I: IntoIterator<Item = (StorageKey, BalWrites<StorageValue>)>>(iter: I) -> Self {
447 Self {
448 storage: iter.into_iter().collect(),
449 }
450 }
451}