1use std::collections::{hash_map::Entry::Vacant, HashMap};
2
3use alloy::primitives::{Address, U256};
4use revm::state::AccountInfo;
5use tracing::{debug, trace, warn};
6
7#[derive(Clone, Default, Debug)]
16pub struct Account {
17 pub info: AccountInfo,
18 pub permanent_storage: HashMap<U256, U256>,
19 pub temp_storage: HashMap<U256, U256>,
20 pub mocked: bool,
21}
22
23#[derive(Default, Clone, PartialEq, Eq, Debug)]
24pub struct StateUpdate {
25 pub storage: Option<HashMap<U256, U256>>,
26 pub balance: Option<U256>,
27}
28#[derive(Clone, Default, Debug)]
29pub struct AccountStorage {
31 accounts: HashMap<Address, Account>,
32}
33
34impl AccountStorage {
35 pub fn new() -> Self {
36 Self::default()
37 }
38
39 pub fn clear(&mut self) {
41 self.accounts.clear();
42 }
43
44 pub fn init_account(
59 &mut self,
60 address: Address,
61 info: AccountInfo,
62 permanent_storage: Option<HashMap<U256, U256>>,
63 mocked: bool,
64 ) {
65 if let Vacant(e) = self.accounts.entry(address) {
66 e.insert(Account {
67 info,
68 permanent_storage: permanent_storage.unwrap_or_default(),
69 temp_storage: HashMap::new(),
70 mocked,
71 });
72 debug!(
73 "Inserted a {} account {:x?}",
74 if mocked { "mocked" } else { "non-mocked" },
75 address
76 );
77 } else {
78 trace!("Skipped init for already-existing account {:x?}", address);
79 }
80 }
81
82 pub fn overwrite_account(
97 &mut self,
98 address: Address,
99 info: AccountInfo,
100 permanent_storage: Option<HashMap<U256, U256>>,
101 mocked: bool,
102 ) {
103 self.accounts.insert(
104 address,
105 Account {
106 info,
107 permanent_storage: permanent_storage.unwrap_or_default(),
108 temp_storage: HashMap::new(),
109 mocked,
110 },
111 );
112 debug!(
113 "Overwrote a {} account {:x?}",
114 if mocked { "mocked" } else { "non-mocked" },
115 address
116 );
117 }
118
119 pub fn update_account(&mut self, address: &Address, update: &StateUpdate) {
137 if let Some(account) = self.accounts.get_mut(address) {
138 if let Some(new_balance) = update.balance {
139 account.info.balance = new_balance;
140 }
141 if let Some(new_storage) = &update.storage {
142 for (index, value) in new_storage {
143 account
144 .permanent_storage
145 .insert(*index, *value);
146 }
147 }
148 } else {
149 warn!(?address, "Tried to update account {:x?} that was not initialized", address);
150 }
151 }
152
153 pub fn get_account_info(&self, address: &Address) -> Option<&AccountInfo> {
167 self.accounts
168 .get(address)
169 .map(|acc| &acc.info)
170 }
171
172 pub fn account_present(&self, address: &Address) -> bool {
183 self.accounts.contains_key(address)
184 }
185
186 pub fn set_temp_storage(&mut self, address: Address, index: U256, value: U256) {
198 if let Some(acc) = self.accounts.get_mut(&address) {
199 acc.temp_storage.insert(index, value);
200 } else {
201 warn!("Trying to set storage on unitialized account {:x?}.", address);
202 }
203 }
204
205 pub fn get_storage(&self, address: &Address, index: &U256) -> Option<U256> {
221 if let Some(acc) = self.accounts.get(address) {
222 if let Some(s) = acc.temp_storage.get(index) {
223 Some(*s)
224 } else {
225 acc.permanent_storage
226 .get(index)
227 .copied()
228 }
229 } else {
230 None
231 }
232 }
233
234 pub fn get_permanent_storage(&self, address: &Address, index: &U256) -> Option<U256> {
244 if let Some(acc) = self.accounts.get(address) {
245 acc.permanent_storage
246 .get(index)
247 .copied()
248 } else {
249 None
250 }
251 }
252
253 pub fn clear_temp_storage(&mut self) {
257 self.accounts
258 .values_mut()
259 .for_each(|acc| acc.temp_storage.clear());
260 }
261
262 pub fn is_mocked_account(&self, address: &Address) -> Option<bool> {
268 self.accounts
269 .get(address)
270 .map(|acc| acc.mocked)
271 }
272}
273
274#[cfg(test)]
275mod tests {
276 use std::{error::Error, str::FromStr};
277
278 use revm::primitives::KECCAK_EMPTY;
279
280 use super::*;
281 use crate::evm::account_storage::{Account, AccountStorage};
282
283 #[test]
284 fn test_insert_account() -> Result<(), Box<dyn Error>> {
285 let mut account_storage = AccountStorage::default();
286 let expected_nonce = 100;
287 let expected_balance = U256::from(500);
288 let acc_address = Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc")?;
289 let info: AccountInfo = AccountInfo {
290 nonce: expected_nonce,
291 balance: expected_balance,
292 code: None,
293 code_hash: KECCAK_EMPTY,
294 };
295 let mut storage_new = HashMap::new();
296 let expected_storage_value = U256::from_str("5").unwrap();
297 storage_new.insert(U256::from_str("1").unwrap(), expected_storage_value);
298
299 account_storage.init_account(acc_address, info, Some(storage_new), false);
300
301 let acc = account_storage
302 .get_account_info(&acc_address)
303 .unwrap();
304 let storage_value = account_storage
305 .get_storage(&acc_address, &U256::from_str("1").unwrap())
306 .unwrap();
307 assert_eq!(acc.nonce, expected_nonce, "Nonce should match expected value");
308 assert_eq!(acc.balance, expected_balance, "Balance should match expected value");
309 assert_eq!(acc.code_hash, KECCAK_EMPTY, "Code hash should match expected value");
310 assert_eq!(
311 storage_value, expected_storage_value,
312 "Storage value should match expected value"
313 );
314 Ok(())
315 }
316
317 #[test]
318 fn test_update_account_info() -> Result<(), Box<dyn Error>> {
319 let mut account_storage = AccountStorage::default();
320 let acc_address = Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc")?;
321 let info: AccountInfo = AccountInfo {
322 nonce: 100,
323 balance: U256::from(500),
324 code: None,
325 code_hash: KECCAK_EMPTY,
326 };
327 let mut original_storage = HashMap::new();
328 let storage_index = U256::from_str("1").unwrap();
329 original_storage.insert(storage_index, U256::from_str("5").unwrap());
330 account_storage.accounts.insert(
331 acc_address,
332 Account {
333 info,
334 permanent_storage: original_storage,
335 temp_storage: HashMap::new(),
336 mocked: false,
337 },
338 );
339 let updated_balance = U256::from(100);
340 let updated_storage_value = U256::from_str("999").unwrap();
341 let mut updated_storage = HashMap::new();
342 updated_storage.insert(storage_index, updated_storage_value);
343 let state_update =
344 StateUpdate { balance: Some(updated_balance), storage: Some(updated_storage) };
345
346 account_storage.update_account(&acc_address, &state_update);
347
348 assert_eq!(
349 account_storage
350 .get_account_info(&acc_address)
351 .unwrap()
352 .balance,
353 updated_balance,
354 "Account balance should be updated"
355 );
356 assert_eq!(
357 account_storage
358 .get_storage(&acc_address, &storage_index)
359 .unwrap(),
360 updated_storage_value,
361 "Storage value should be updated"
362 );
363 Ok(())
364 }
365
366 #[test]
367 fn test_get_account_info() {
368 let mut account_storage = AccountStorage::default();
369 let address_1 = Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc").unwrap();
370 let address_2 = Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dd").unwrap();
371 let account_info_1 = AccountInfo::default();
372 let account_info_2 = AccountInfo { nonce: 500, ..Default::default() };
373 account_storage.init_account(address_1, account_info_1, None, false);
374 account_storage.init_account(address_2, account_info_2, None, false);
375
376 let existing_account = account_storage.get_account_info(&address_1);
377 let address_3 = Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9de").unwrap();
378 let non_existing_account = account_storage.get_account_info(&address_3);
379
380 assert_eq!(
381 existing_account.unwrap().nonce,
382 AccountInfo::default().nonce,
383 "Existing account's nonce should match the expected value"
384 );
385 assert_eq!(non_existing_account, None, "Non-existing account should return None");
386 }
387
388 #[test]
389 fn test_account_present() {
390 let mut account_storage = AccountStorage::default();
391 let existing_account =
392 Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc").unwrap();
393 let address_2 = Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dd").unwrap();
394 let non_existing_account =
395 Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9de").unwrap();
396 account_storage
397 .accounts
398 .insert(existing_account, Account::default());
399 account_storage
400 .accounts
401 .insert(address_2, Account::default());
402
403 assert!(
404 account_storage.account_present(&existing_account),
405 "Existing account should be present in the AccountStorage"
406 );
407 assert!(
408 !account_storage.account_present(&non_existing_account),
409 "Non-existing account should not be present in the AccountStorage"
410 );
411 }
412
413 #[test]
414 fn test_set_get_storage() {
415 let mut account_storage = AccountStorage::default();
417 let address = Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc").unwrap();
419 let non_existing_address =
420 Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dd").unwrap();
421 let account = Account::default();
422 account_storage
423 .accounts
424 .insert(address, account);
425 let index = U256::from_str("1").unwrap();
426 let value = U256::from_str("1").unwrap();
427 let non_existing_index = U256::from_str("2").unwrap();
428 let non_existing_value = U256::from_str("2").unwrap();
429 account_storage.set_temp_storage(
430 non_existing_address,
431 non_existing_index,
432 non_existing_value,
433 );
434 account_storage.set_temp_storage(address, index, value);
435
436 let storage = account_storage.get_storage(&address, &index);
437 let empty_storage = account_storage.get_storage(&non_existing_address, &non_existing_index);
438
439 assert_eq!(storage, Some(value), "Storage value should match the value that was set");
440 assert_eq!(empty_storage, None, "Storage value should be None for a non-existing account");
441 }
442
443 #[test]
444 fn test_get_storage() {
445 let mut account_storage = AccountStorage::default();
446 let existing_address =
447 Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc").unwrap();
448 let non_existent_address =
449 Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dd").unwrap();
450 let index = U256::from(42);
451 let value = U256::from(100);
452 let non_existent_index = U256::from(999);
453 let mut account = Account::default();
454 account
455 .temp_storage
456 .insert(index, value);
457 account_storage
458 .accounts
459 .insert(existing_address, account);
460
461 assert_eq!(
462 account_storage.get_storage(&existing_address, &index),
463 Some(value), "If the storage features the address and index the value at that position should be retunred."
464 );
465
466 assert_eq!(
468 account_storage.get_storage(&non_existent_address, &index),
469 None,
470 "If the storage does not feature the address None should be returned."
471 );
472
473 assert_eq!(
475 account_storage.get_storage(&existing_address, &non_existent_index),
476 None,
477 "If the storage does not feature the index None should be returned."
478 );
479 }
480
481 #[test]
482 fn test_get_storage_priority() {
483 let mut account_storage = AccountStorage::default();
484 let address = Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc").unwrap();
485 let index = U256::from(69);
486 let temp_value = U256::from(100);
487 let permanent_value = U256::from(200);
488 let mut account = Account::default();
489 account
490 .temp_storage
491 .insert(index, temp_value);
492 account
493 .permanent_storage
494 .insert(index, permanent_value);
495 account_storage
496 .accounts
497 .insert(address, account);
498
499 assert_eq!(
500 account_storage.get_storage(&address, &index),
501 Some(temp_value),
502 "Temp storage value should take priority over permanent storage value"
503 );
504 }
505
506 #[test]
507 fn test_is_mocked_account() {
508 let mut account_storage = AccountStorage::default();
509 let mocked_account_address =
510 Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc").unwrap();
511 let not_mocked_account_address =
512 Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dd").unwrap();
513 let unknown_address =
514 Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9de").unwrap();
515 let mocked_account = Account { mocked: true, ..Default::default() };
516 let not_mocked_account = Account { mocked: false, ..Default::default() };
517 account_storage
518 .accounts
519 .insert(mocked_account_address, mocked_account);
520 account_storage
521 .accounts
522 .insert(not_mocked_account_address, not_mocked_account);
523
524 assert_eq!(account_storage.is_mocked_account(&mocked_account_address), Some(true));
525 assert_eq!(account_storage.is_mocked_account(¬_mocked_account_address), Some(false));
526 assert_eq!(account_storage.is_mocked_account(&unknown_address), None);
527 }
528
529 #[test]
530 fn test_clear_temp_storage() {
531 let mut account_storage = AccountStorage::default();
532 let address_1 = Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc").unwrap();
533 let address_2 = Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dd").unwrap();
534 let mut account_1 = Account::default();
535 account_1
536 .temp_storage
537 .insert(U256::from(1), U256::from(10));
538 let mut account_2 = Account::default();
539 account_2
540 .temp_storage
541 .insert(U256::from(2), U256::from(20));
542 account_storage
543 .accounts
544 .insert(address_1, account_1);
545 account_storage
546 .accounts
547 .insert(address_2, account_2);
548
549 account_storage.clear_temp_storage();
550
551 let account_1_temp_storage = account_storage.accounts[&address_1]
552 .temp_storage
553 .len();
554 let account_2_temp_storage = account_storage.accounts[&address_2]
555 .temp_storage
556 .len();
557 assert_eq!(account_1_temp_storage, 0, "Temporary storage of account 1 should be cleared");
558 assert_eq!(account_2_temp_storage, 0, "Temporary storage of account 2 should be cleared");
559 }
560
561 #[test]
562 fn test_get_permanent_storage() {
563 let mut account_storage = AccountStorage::default();
564 let address = Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dc").unwrap();
565 let non_existing_address =
566 Address::from_str("0xb4e16d0168e52d35cacd2c6185b44281ec28c9dd").unwrap();
567 let index = U256::from_str("123").unwrap();
568 let value = U256::from_str("456").unwrap();
569 let mut account = Account::default();
570 account
571 .permanent_storage
572 .insert(index, value);
573 account_storage
574 .accounts
575 .insert(address, account);
576
577 let result = account_storage.get_permanent_storage(&address, &index);
578 let not_existing_result =
579 account_storage.get_permanent_storage(&non_existing_address, &index);
580 let empty_index = U256::from_str("789").unwrap();
581 let no_storage = account_storage.get_permanent_storage(&address, &empty_index);
582
583 assert_eq!(
584 result,
585 Some(value),
586 "Expected value for existing account with permanent storage"
587 );
588 assert_eq!(not_existing_result, None, "Expected None for non-existing account");
589 assert_eq!(
590 no_storage, None,
591 "Expected None for existing account without permanent storage"
592 );
593 }
594}