1#![cfg_attr(not(test), warn(unused_crate_dependencies))]
3#![cfg_attr(not(feature = "std"), no_std)]
4
5#[cfg(not(feature = "std"))]
6extern crate alloc as std;
7
8mod account_info;
9pub mod bal;
10mod types;
11
12pub use bytecode;
13
14pub use account_info::AccountInfo;
15pub use bytecode::Bytecode;
16pub use primitives;
17pub use types::{EvmState, EvmStorage, TransientStorage};
18
19use bitflags::bitflags;
20use primitives::{hardfork::SpecId, HashMap, OnceLock, StorageKey, StorageValue, U256};
21use std::boxed::Box;
22
23#[derive(Debug, Clone, PartialEq, Eq, Default)]
36#[cfg_attr(feature = "serde", derive(serde::Serialize))]
37pub struct Account {
38 pub info: AccountInfo,
40 pub original_info: Box<AccountInfo>,
42 pub transaction_id: usize,
44 pub storage: EvmStorage,
46 pub status: AccountStatus,
48}
49
50impl Account {
51 pub fn new_not_existing(transaction_id: usize) -> Self {
53 static DEFAULT: OnceLock<Account> = OnceLock::new();
54 let mut account = DEFAULT
55 .get_or_init(|| Self {
56 info: AccountInfo::default(),
57 storage: HashMap::default(),
58 transaction_id: 0,
59 status: AccountStatus::LoadedAsNotExisting,
60 original_info: Box::new(AccountInfo::default()),
61 })
62 .clone();
63 account.transaction_id = transaction_id;
64 account
65 }
66
67 #[inline]
73 pub fn caller_initial_modification(&mut self, new_balance: U256, is_call: bool) -> U256 {
74 self.mark_touch();
76
77 if is_call {
78 self.info.nonce = self.info.nonce.saturating_add(1);
80 }
81
82 core::mem::replace(&mut self.info.balance, new_balance)
83 }
84
85 #[inline]
87 pub fn state_clear_aware_is_empty(&self, spec: SpecId) -> bool {
88 if SpecId::is_enabled_in(spec, SpecId::SPURIOUS_DRAGON) {
89 self.is_empty()
90 } else {
91 self.is_loaded_as_not_existing_not_touched()
92 }
93 }
94
95 #[inline]
97 pub fn mark_selfdestruct(&mut self) {
98 self.status |= AccountStatus::SelfDestructed;
99 }
100
101 #[inline]
103 pub fn unmark_selfdestruct(&mut self) {
104 self.status -= AccountStatus::SelfDestructed;
105 }
106
107 #[inline]
109 pub fn is_selfdestructed(&self) -> bool {
110 self.status.contains(AccountStatus::SelfDestructed)
111 }
112
113 #[inline]
115 pub fn mark_touch(&mut self) {
116 self.status |= AccountStatus::Touched;
117 }
118
119 #[inline]
121 pub fn unmark_touch(&mut self) {
122 self.status -= AccountStatus::Touched;
123 }
124
125 #[inline]
127 pub fn is_touched(&self) -> bool {
128 self.status.contains(AccountStatus::Touched)
129 }
130
131 #[inline]
133 pub fn mark_created(&mut self) {
134 self.status |= AccountStatus::Created;
135 }
136
137 #[inline]
139 pub fn unmark_created(&mut self) {
140 self.status -= AccountStatus::Created;
141 }
142
143 #[inline]
145 pub fn mark_cold(&mut self) {
146 self.status |= AccountStatus::Cold;
147 }
148
149 #[inline]
151 pub fn is_cold_transaction_id(&self, transaction_id: usize) -> bool {
152 self.transaction_id != transaction_id || self.status.contains(AccountStatus::Cold)
153 }
154
155 #[inline]
157 pub fn mark_warm_with_transaction_id(&mut self, transaction_id: usize) -> bool {
158 let is_cold = self.is_cold_transaction_id(transaction_id);
159 self.status -= AccountStatus::Cold;
160 self.transaction_id = transaction_id;
161 is_cold
162 }
163
164 #[inline]
166 pub fn is_created_locally(&self) -> bool {
167 self.status.contains(AccountStatus::CreatedLocal)
168 }
169
170 #[inline]
172 pub fn is_selfdestructed_locally(&self) -> bool {
173 self.status.contains(AccountStatus::SelfDestructedLocal)
174 }
175
176 #[inline]
178 pub fn selfdestruct(&mut self) {
179 self.storage.clear();
180 self.info = AccountInfo::default();
181 }
182
183 #[inline]
187 pub fn mark_created_locally(&mut self) -> bool {
188 self.mark_local_and_global(AccountStatus::CreatedLocal, AccountStatus::Created)
189 }
190
191 #[inline]
193 pub fn unmark_created_locally(&mut self) {
194 self.status -= AccountStatus::CreatedLocal;
195 }
196
197 #[inline]
199 pub fn mark_selfdestructed_locally(&mut self) -> bool {
200 self.mark_local_and_global(
201 AccountStatus::SelfDestructedLocal,
202 AccountStatus::SelfDestructed,
203 )
204 }
205
206 #[inline]
207 fn mark_local_and_global(
208 &mut self,
209 local_flag: AccountStatus,
210 global_flag: AccountStatus,
211 ) -> bool {
212 self.status |= local_flag;
213 let is_global_first_time = !self.status.contains(global_flag);
214 self.status |= global_flag;
215 is_global_first_time
216 }
217
218 #[inline]
220 pub fn unmark_selfdestructed_locally(&mut self) {
221 self.status -= AccountStatus::SelfDestructedLocal;
222 }
223
224 pub fn is_loaded_as_not_existing(&self) -> bool {
229 self.status.contains(AccountStatus::LoadedAsNotExisting)
230 }
231
232 pub fn is_loaded_as_not_existing_not_touched(&self) -> bool {
234 self.is_loaded_as_not_existing() && !self.is_touched()
235 }
236
237 pub fn is_created(&self) -> bool {
239 self.status.contains(AccountStatus::Created)
240 }
241
242 pub fn is_empty(&self) -> bool {
244 self.info.is_empty()
245 }
246
247 pub fn changed_storage_slots(&self) -> impl Iterator<Item = (&StorageKey, &EvmStorageSlot)> {
251 self.storage.iter().filter(|(_, slot)| slot.is_changed())
252 }
253
254 pub fn with_info(mut self, info: AccountInfo) -> Self {
256 self.info = info;
257 self
258 }
259
260 pub fn with_storage<I>(mut self, storage_iter: I) -> Self
262 where
263 I: Iterator<Item = (StorageKey, EvmStorageSlot)>,
264 {
265 for (key, slot) in storage_iter {
266 self.storage.insert(key, slot);
267 }
268 self
269 }
270
271 pub fn with_selfdestruct_mark(mut self) -> Self {
273 self.mark_selfdestruct();
274 self
275 }
276
277 pub fn with_touched_mark(mut self) -> Self {
279 self.mark_touch();
280 self
281 }
282
283 pub fn with_created_mark(mut self) -> Self {
285 self.mark_created();
286 self
287 }
288
289 pub fn with_cold_mark(mut self) -> Self {
291 self.mark_cold();
292 self
293 }
294
295 pub fn with_warm_mark(mut self, transaction_id: usize) -> (Self, bool) {
298 let was_cold = self.mark_warm_with_transaction_id(transaction_id);
299 (self, was_cold)
300 }
301
302 pub fn with_warm(mut self, transaction_id: usize) -> Self {
304 self.mark_warm_with_transaction_id(transaction_id);
305 self
306 }
307}
308
309impl From<AccountInfo> for Account {
310 fn from(info: AccountInfo) -> Self {
311 let original_info = Box::new(info.clone());
312 Self {
313 info,
314 storage: HashMap::default(),
315 transaction_id: 0,
316 status: AccountStatus::empty(),
317 original_info,
318 }
319 }
320}
321
322#[cfg(feature = "serde")]
323mod serde_impl {
324 use super::*;
325 use serde::{Deserialize, Serialize};
326
327 #[derive(Serialize, Deserialize)]
328 struct AccountSerde {
329 info: AccountInfo,
330 original_info: Option<AccountInfo>,
331 storage: EvmStorage,
332 transaction_id: usize,
333 status: AccountStatus,
334 }
335
336 impl<'de> Deserialize<'de> for super::Account {
337 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
338 where
339 D: serde::Deserializer<'de>,
340 {
341 let AccountSerde {
342 info,
343 original_info,
344 storage,
345 transaction_id,
346 status,
347 } = Deserialize::deserialize(deserializer)?;
348
349 let original_info = original_info.unwrap_or_else(|| info.clone());
351
352 Ok(Account {
353 info,
354 original_info: Box::new(original_info),
355 storage,
356 transaction_id,
357 status,
358 })
359 }
360 }
361}
362
363bitflags! {
365 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
397 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
398 #[cfg_attr(feature = "serde", serde(transparent))]
399 pub struct AccountStatus: u8 {
400 const Created = 0b00000001;
403 const CreatedLocal = 0b10000000;
405 const SelfDestructed = 0b00000010;
407 const SelfDestructedLocal = 0b01000000;
409 const Touched = 0b00000100;
413 const LoadedAsNotExisting = 0b00001000;
416 const Cold = 0b00010000;
419 }
420}
421
422impl AccountStatus {
423 #[inline]
425 pub fn is_touched(&self) -> bool {
426 self.contains(AccountStatus::Touched)
427 }
428}
429
430impl Default for AccountStatus {
431 fn default() -> Self {
432 AccountStatus::empty()
433 }
434}
435
436#[derive(Debug, Clone, Default, PartialEq, Eq)]
438#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
439pub struct EvmStorageSlot {
440 pub original_value: StorageValue,
442 pub present_value: StorageValue,
444 pub transaction_id: usize,
446 pub is_cold: bool,
448}
449
450impl EvmStorageSlot {
451 pub fn new(original: StorageValue, transaction_id: usize) -> Self {
453 Self {
454 original_value: original,
455 present_value: original,
456 transaction_id,
457 is_cold: false,
458 }
459 }
460
461 pub fn new_changed(
463 original_value: StorageValue,
464 present_value: StorageValue,
465 transaction_id: usize,
466 ) -> Self {
467 Self {
468 original_value,
469 present_value,
470 transaction_id,
471 is_cold: false,
472 }
473 }
474 pub fn is_changed(&self) -> bool {
476 self.original_value != self.present_value
477 }
478
479 #[inline]
481 pub fn original_value(&self) -> StorageValue {
482 self.original_value
483 }
484
485 #[inline]
487 pub fn present_value(&self) -> StorageValue {
488 self.present_value
489 }
490
491 #[inline]
493 pub fn mark_cold(&mut self) {
494 self.is_cold = true;
495 }
496
497 #[inline]
499 pub fn is_cold_transaction_id(&self, transaction_id: usize) -> bool {
500 self.transaction_id != transaction_id || self.is_cold
501 }
502
503 #[inline]
508 pub fn mark_warm_with_transaction_id(&mut self, transaction_id: usize) -> bool {
509 let is_cold = self.is_cold_transaction_id(transaction_id);
510 if is_cold {
511 self.original_value = self.present_value;
513 }
514 self.transaction_id = transaction_id;
515 self.is_cold = false;
516 is_cold
517 }
518}
519
520#[cfg(test)]
521mod tests {
522 use super::*;
523 use crate::EvmStorageSlot;
524 use primitives::{StorageKey, KECCAK_EMPTY, U256};
525
526 #[test]
527 fn account_is_empty_balance() {
528 let mut account = Account::default();
529 assert!(account.is_empty());
530
531 account.info.balance = U256::from(1);
532 assert!(!account.is_empty());
533
534 account.info.balance = U256::ZERO;
535 assert!(account.is_empty());
536 }
537
538 #[test]
539 fn account_is_empty_nonce() {
540 let mut account = Account::default();
541 assert!(account.is_empty());
542
543 account.info.nonce = 1;
544 assert!(!account.is_empty());
545
546 account.info.nonce = 0;
547 assert!(account.is_empty());
548 }
549
550 #[test]
551 fn account_is_empty_code_hash() {
552 let mut account = Account::default();
553 assert!(account.is_empty());
554
555 account.info.code_hash = [1; 32].into();
556 assert!(!account.is_empty());
557
558 account.info.code_hash = [0; 32].into();
559 assert!(account.is_empty());
560
561 account.info.code_hash = KECCAK_EMPTY;
562 assert!(account.is_empty());
563 }
564
565 #[test]
566 fn account_state() {
567 let mut account = Account::default();
568
569 assert!(!account.is_touched());
570 assert!(!account.is_selfdestructed());
571
572 account.mark_touch();
573 assert!(account.is_touched());
574 assert!(!account.is_selfdestructed());
575
576 account.mark_selfdestruct();
577 assert!(account.is_touched());
578 assert!(account.is_selfdestructed());
579
580 account.unmark_selfdestruct();
581 assert!(account.is_touched());
582 assert!(!account.is_selfdestructed());
583 }
584
585 #[test]
586 fn account_is_cold() {
587 let mut account = Account::default();
588
589 assert!(!account.status.contains(crate::AccountStatus::Cold));
591
592 assert!(!account.mark_warm_with_transaction_id(0));
594
595 account.mark_cold();
597
598 assert!(account.status.contains(crate::AccountStatus::Cold));
600
601 assert!(account.mark_warm_with_transaction_id(0));
603 }
604
605 #[test]
606 fn test_account_with_info() {
607 let info = AccountInfo::default();
608 let account = Account::default().with_info(info.clone());
609
610 assert_eq!(account.info, info);
611 assert_eq!(account.storage, HashMap::default());
612 assert_eq!(account.status, AccountStatus::empty());
613 }
614
615 #[test]
616 fn test_account_with_storage() {
617 let mut storage = HashMap::<StorageKey, EvmStorageSlot>::default();
618 let key1 = StorageKey::from(1);
619 let key2 = StorageKey::from(2);
620 let slot1 = EvmStorageSlot::new(StorageValue::from(10), 0);
621 let slot2 = EvmStorageSlot::new(StorageValue::from(20), 0);
622
623 storage.insert(key1, slot1.clone());
624 storage.insert(key2, slot2.clone());
625
626 let account = Account::default().with_storage(storage.clone().into_iter());
627
628 assert_eq!(account.storage.len(), 2);
629 assert_eq!(account.storage.get(&key1), Some(&slot1));
630 assert_eq!(account.storage.get(&key2), Some(&slot2));
631 }
632
633 #[test]
634 fn test_account_with_selfdestruct_mark() {
635 let account = Account::default().with_selfdestruct_mark();
636
637 assert!(account.is_selfdestructed());
638 assert!(!account.is_touched());
639 assert!(!account.is_created());
640 }
641
642 #[test]
643 #[cfg(feature = "serde")]
644 fn test_account_serialize_deserialize() {
645 let account = Account::default().with_selfdestruct_mark();
646 let serialized = serde_json::to_string(&account).unwrap();
647 let deserialized: Account = serde_json::from_str(&serialized).unwrap();
648 assert_eq!(account, deserialized);
649 }
650
651 #[test]
652 #[cfg(feature = "serde")]
653 fn test_account_serialize_deserialize_without_original_info() {
654 let deserialize_without_original_info = r#"
655 {"info":{"balance":"0x0","nonce":0,"code_hash":"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470","storage_id":null,"code":{"LegacyAnalyzed":{"bytecode":"0x00","original_len":0,"jump_table":{"order":"bitvec::order::Lsb0","head":{"width":8,"index":0},"bits":0,"data":[]}}}},"transaction_id":0,"storage":{},"status":"SelfDestructed"}"#;
656
657 let account = Account::default().with_selfdestruct_mark();
658 let deserialized: Account =
659 serde_json::from_str(deserialize_without_original_info).unwrap();
660 assert_eq!(account, deserialized);
661 }
662
663 #[test]
664 fn test_account_with_touched_mark() {
665 let account = Account::default().with_touched_mark();
666
667 assert!(!account.is_selfdestructed());
668 assert!(account.is_touched());
669 assert!(!account.is_created());
670 }
671
672 #[test]
673 fn test_account_with_created_mark() {
674 let account = Account::default().with_created_mark();
675
676 assert!(!account.is_selfdestructed());
677 assert!(!account.is_touched());
678 assert!(account.is_created());
679 }
680
681 #[test]
682 fn test_account_with_cold_mark() {
683 let account = Account::default().with_cold_mark();
684
685 assert!(account.status.contains(AccountStatus::Cold));
686 }
687
688 #[test]
689 fn test_storage_mark_warm_with_transaction_id() {
690 let mut slot = EvmStorageSlot::new(U256::ZERO, 0);
691 slot.is_cold = true;
692 slot.transaction_id = 0;
693 assert!(slot.mark_warm_with_transaction_id(1));
694
695 slot.is_cold = false;
696 slot.transaction_id = 0;
697 assert!(slot.mark_warm_with_transaction_id(1));
698
699 slot.is_cold = true;
700 slot.transaction_id = 1;
701 assert!(slot.mark_warm_with_transaction_id(1));
702
703 slot.is_cold = false;
704 slot.transaction_id = 1;
705 assert!(!slot.mark_warm_with_transaction_id(1));
707 }
708
709 #[test]
710 fn test_account_with_warm_mark() {
711 let cold_account = Account::default().with_cold_mark();
713 assert!(cold_account.status.contains(AccountStatus::Cold));
714
715 let (warm_account, was_cold) = cold_account.with_warm_mark(0);
717
718 assert!(!warm_account.status.contains(AccountStatus::Cold));
720 assert!(was_cold);
721
722 let (still_warm_account, was_cold) = warm_account.with_warm_mark(0);
724 assert!(!still_warm_account.status.contains(AccountStatus::Cold));
725 assert!(!was_cold);
726 }
727
728 #[test]
729 fn test_account_with_warm() {
730 let cold_account = Account::default().with_cold_mark();
732 assert!(cold_account.status.contains(AccountStatus::Cold));
733
734 let warm_account = cold_account.with_warm(0);
736
737 assert!(!warm_account.status.contains(AccountStatus::Cold));
739 }
740
741 #[test]
742 fn test_account_builder_chaining() {
743 let info = AccountInfo {
744 nonce: 5,
745 ..AccountInfo::default()
746 };
747
748 let slot_key = StorageKey::from(42);
749 let slot_value = EvmStorageSlot::new(StorageValue::from(123), 0);
750 let mut storage = HashMap::<StorageKey, EvmStorageSlot>::default();
751 storage.insert(slot_key, slot_value.clone());
752
753 let account = Account::default()
755 .with_info(info.clone())
756 .with_storage(storage.into_iter())
757 .with_created_mark()
758 .with_touched_mark()
759 .with_cold_mark()
760 .with_warm(0);
761
762 assert_eq!(account.info, info);
764 assert_eq!(account.storage.get(&slot_key), Some(&slot_value));
765 assert!(account.is_created());
766 assert!(account.is_touched());
767 assert!(!account.status.contains(AccountStatus::Cold));
768 }
769
770 #[test]
771 fn test_account_is_cold_transaction_id() {
772 let mut account = Account::default();
773 assert!(!account.is_cold_transaction_id(0));
775
776 assert!(account.is_cold_transaction_id(1));
778 account.mark_cold();
779 assert!(account.is_cold_transaction_id(0));
780 assert!(account.is_cold_transaction_id(1));
781 }
782}