1#![cfg_attr(not(test), warn(unused_crate_dependencies))]
3#![cfg_attr(not(feature = "std"), no_std)]
4
5mod account_info;
6mod types;
7pub use bytecode;
8
9pub use account_info::AccountInfo;
10pub use bytecode::Bytecode;
11pub use primitives;
12pub use types::{EvmState, EvmStorage, TransientStorage};
13
14use bitflags::bitflags;
15use primitives::{hardfork::SpecId, HashMap, StorageKey, StorageValue, U256};
16
17#[derive(Debug, Clone, PartialEq, Eq, Default)]
19#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20pub struct Account {
21 pub info: AccountInfo,
23 pub transaction_id: usize,
25 pub storage: EvmStorage,
27 pub status: AccountStatus,
29}
30
31impl Account {
32 pub fn new_not_existing(transaction_id: usize) -> Self {
34 Self {
35 info: AccountInfo::default(),
36 storage: HashMap::default(),
37 transaction_id,
38 status: AccountStatus::LoadedAsNotExisting,
39 }
40 }
41
42 #[inline]
48 pub fn caller_initial_modification(&mut self, new_balance: U256, is_call: bool) -> U256 {
49 self.mark_touch();
51
52 if is_call {
53 self.info.nonce = self.info.nonce.saturating_add(1);
55 }
56
57 core::mem::replace(&mut self.info.balance, new_balance)
58 }
59
60 #[inline]
62 pub fn state_clear_aware_is_empty(&self, spec: SpecId) -> bool {
63 if SpecId::is_enabled_in(spec, SpecId::SPURIOUS_DRAGON) {
64 self.is_empty()
65 } else {
66 self.is_loaded_as_not_existing_not_touched()
67 }
68 }
69
70 #[inline]
72 pub fn mark_selfdestruct(&mut self) {
73 self.status |= AccountStatus::SelfDestructed;
74 }
75
76 #[inline]
78 pub fn unmark_selfdestruct(&mut self) {
79 self.status -= AccountStatus::SelfDestructed;
80 }
81
82 #[inline]
84 pub fn is_selfdestructed(&self) -> bool {
85 self.status.contains(AccountStatus::SelfDestructed)
86 }
87
88 #[inline]
90 pub fn mark_touch(&mut self) {
91 self.status |= AccountStatus::Touched;
92 }
93
94 #[inline]
96 pub fn unmark_touch(&mut self) {
97 self.status -= AccountStatus::Touched;
98 }
99
100 #[inline]
102 pub fn is_touched(&self) -> bool {
103 self.status.contains(AccountStatus::Touched)
104 }
105
106 #[inline]
108 pub fn mark_created(&mut self) {
109 self.status |= AccountStatus::Created;
110 }
111
112 #[inline]
114 pub fn unmark_created(&mut self) {
115 self.status -= AccountStatus::Created;
116 }
117
118 #[inline]
120 pub fn mark_cold(&mut self) {
121 self.status |= AccountStatus::Cold;
122 }
123
124 #[inline]
126 pub fn is_cold_transaction_id(&self, transaction_id: usize) -> bool {
127 self.transaction_id != transaction_id || self.status.contains(AccountStatus::Cold)
128 }
129
130 #[inline]
132 pub fn mark_warm_with_transaction_id(&mut self, transaction_id: usize) -> bool {
133 let is_cold = self.is_cold_transaction_id(transaction_id);
134 self.status -= AccountStatus::Cold;
135 self.transaction_id = transaction_id;
136 is_cold
137 }
138
139 #[inline]
141 pub fn is_created_locally(&self) -> bool {
142 self.status.contains(AccountStatus::CreatedLocal)
143 }
144
145 #[inline]
147 pub fn is_selfdestructed_locally(&self) -> bool {
148 self.status.contains(AccountStatus::SelfDestructedLocal)
149 }
150
151 #[inline]
153 pub fn selfdestruct(&mut self) {
154 self.storage.clear();
155 self.info = AccountInfo::default();
156 }
157
158 #[inline]
162 pub fn mark_created_locally(&mut self) -> bool {
163 self.mark_local_and_global(AccountStatus::CreatedLocal, AccountStatus::Created)
164 }
165
166 #[inline]
168 pub fn unmark_created_locally(&mut self) {
169 self.status -= AccountStatus::CreatedLocal;
170 }
171
172 #[inline]
174 pub fn mark_selfdestructed_locally(&mut self) -> bool {
175 self.mark_local_and_global(
176 AccountStatus::SelfDestructedLocal,
177 AccountStatus::SelfDestructed,
178 )
179 }
180
181 #[inline]
182 fn mark_local_and_global(
183 &mut self,
184 local_flag: AccountStatus,
185 global_flag: AccountStatus,
186 ) -> bool {
187 self.status |= local_flag;
188 let is_global_first_time = !self.status.contains(global_flag);
189 self.status |= global_flag;
190 is_global_first_time
191 }
192
193 #[inline]
195 pub fn unmark_selfdestructed_locally(&mut self) {
196 self.status -= AccountStatus::SelfDestructedLocal;
197 }
198
199 pub fn is_loaded_as_not_existing(&self) -> bool {
204 self.status.contains(AccountStatus::LoadedAsNotExisting)
205 }
206
207 pub fn is_loaded_as_not_existing_not_touched(&self) -> bool {
209 self.is_loaded_as_not_existing() && !self.is_touched()
210 }
211
212 pub fn is_created(&self) -> bool {
214 self.status.contains(AccountStatus::Created)
215 }
216
217 pub fn is_empty(&self) -> bool {
219 self.info.is_empty()
220 }
221
222 pub fn changed_storage_slots(&self) -> impl Iterator<Item = (&StorageKey, &EvmStorageSlot)> {
226 self.storage.iter().filter(|(_, slot)| slot.is_changed())
227 }
228
229 pub fn with_info(mut self, info: AccountInfo) -> Self {
231 self.info = info;
232 self
233 }
234
235 pub fn with_storage<I>(mut self, storage_iter: I) -> Self
237 where
238 I: Iterator<Item = (StorageKey, EvmStorageSlot)>,
239 {
240 for (key, slot) in storage_iter {
241 self.storage.insert(key, slot);
242 }
243 self
244 }
245
246 pub fn with_selfdestruct_mark(mut self) -> Self {
248 self.mark_selfdestruct();
249 self
250 }
251
252 pub fn with_touched_mark(mut self) -> Self {
254 self.mark_touch();
255 self
256 }
257
258 pub fn with_created_mark(mut self) -> Self {
260 self.mark_created();
261 self
262 }
263
264 pub fn with_cold_mark(mut self) -> Self {
266 self.mark_cold();
267 self
268 }
269
270 pub fn with_warm_mark(mut self, transaction_id: usize) -> (Self, bool) {
273 let was_cold = self.mark_warm_with_transaction_id(transaction_id);
274 (self, was_cold)
275 }
276
277 pub fn with_warm(mut self, transaction_id: usize) -> Self {
279 self.mark_warm_with_transaction_id(transaction_id);
280 self
281 }
282}
283
284impl From<AccountInfo> for Account {
285 fn from(info: AccountInfo) -> Self {
286 Self {
287 info,
288 storage: HashMap::default(),
289 transaction_id: 0,
290 status: AccountStatus::empty(),
291 }
292 }
293}
294
295bitflags! {
297 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
329 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
330 #[cfg_attr(feature = "serde", serde(transparent))]
331 pub struct AccountStatus: u8 {
332 const Created = 0b00000001;
335 const CreatedLocal = 0b10000000;
337 const SelfDestructed = 0b00000010;
339 const SelfDestructedLocal = 0b01000000;
341 const Touched = 0b00000100;
345 const LoadedAsNotExisting = 0b00001000;
348 const Cold = 0b00010000;
351 }
352}
353
354impl AccountStatus {
355 #[inline]
357 pub fn is_touched(&self) -> bool {
358 self.contains(AccountStatus::Touched)
359 }
360}
361
362impl Default for AccountStatus {
363 fn default() -> Self {
364 AccountStatus::empty()
365 }
366}
367
368#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
370#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
371pub struct EvmStorageSlot {
372 pub original_value: StorageValue,
374 pub present_value: StorageValue,
376 pub transaction_id: usize,
378 pub is_cold: bool,
380}
381
382impl EvmStorageSlot {
383 pub fn new(original: StorageValue, transaction_id: usize) -> Self {
385 Self {
386 original_value: original,
387 present_value: original,
388 transaction_id,
389 is_cold: false,
390 }
391 }
392
393 pub fn new_changed(
395 original_value: StorageValue,
396 present_value: StorageValue,
397 transaction_id: usize,
398 ) -> Self {
399 Self {
400 original_value,
401 present_value,
402 transaction_id,
403 is_cold: false,
404 }
405 }
406 pub fn is_changed(&self) -> bool {
408 self.original_value != self.present_value
409 }
410
411 #[inline]
413 pub fn original_value(&self) -> StorageValue {
414 self.original_value
415 }
416
417 #[inline]
419 pub fn present_value(&self) -> StorageValue {
420 self.present_value
421 }
422
423 #[inline]
425 pub fn mark_cold(&mut self) {
426 self.is_cold = true;
427 }
428
429 #[inline]
431 pub fn is_cold_transaction_id(&self, transaction_id: usize) -> bool {
432 self.transaction_id != transaction_id || self.is_cold
433 }
434
435 #[inline]
440 pub fn mark_warm_with_transaction_id(&mut self, transaction_id: usize) -> bool {
441 let is_cold = self.is_cold_transaction_id(transaction_id);
442 self.transaction_id = transaction_id;
443 self.is_cold = false;
444 is_cold
445 }
446}
447
448#[cfg(test)]
449mod tests {
450 use super::*;
451 use crate::EvmStorageSlot;
452 use primitives::{StorageKey, KECCAK_EMPTY, U256};
453
454 #[test]
455 fn account_is_empty_balance() {
456 let mut account = Account::default();
457 assert!(account.is_empty());
458
459 account.info.balance = U256::from(1);
460 assert!(!account.is_empty());
461
462 account.info.balance = U256::ZERO;
463 assert!(account.is_empty());
464 }
465
466 #[test]
467 fn account_is_empty_nonce() {
468 let mut account = Account::default();
469 assert!(account.is_empty());
470
471 account.info.nonce = 1;
472 assert!(!account.is_empty());
473
474 account.info.nonce = 0;
475 assert!(account.is_empty());
476 }
477
478 #[test]
479 fn account_is_empty_code_hash() {
480 let mut account = Account::default();
481 assert!(account.is_empty());
482
483 account.info.code_hash = [1; 32].into();
484 assert!(!account.is_empty());
485
486 account.info.code_hash = [0; 32].into();
487 assert!(account.is_empty());
488
489 account.info.code_hash = KECCAK_EMPTY;
490 assert!(account.is_empty());
491 }
492
493 #[test]
494 fn account_state() {
495 let mut account = Account::default();
496
497 assert!(!account.is_touched());
498 assert!(!account.is_selfdestructed());
499
500 account.mark_touch();
501 assert!(account.is_touched());
502 assert!(!account.is_selfdestructed());
503
504 account.mark_selfdestruct();
505 assert!(account.is_touched());
506 assert!(account.is_selfdestructed());
507
508 account.unmark_selfdestruct();
509 assert!(account.is_touched());
510 assert!(!account.is_selfdestructed());
511 }
512
513 #[test]
514 fn account_is_cold() {
515 let mut account = Account::default();
516
517 assert!(!account.status.contains(crate::AccountStatus::Cold));
519
520 assert!(!account.mark_warm_with_transaction_id(0));
522
523 account.mark_cold();
525
526 assert!(account.status.contains(crate::AccountStatus::Cold));
528
529 assert!(account.mark_warm_with_transaction_id(0));
531 }
532
533 #[test]
534 fn test_account_with_info() {
535 let info = AccountInfo::default();
536 let account = Account::default().with_info(info.clone());
537
538 assert_eq!(account.info, info);
539 assert_eq!(account.storage, HashMap::default());
540 assert_eq!(account.status, AccountStatus::empty());
541 }
542
543 #[test]
544 fn test_account_with_storage() {
545 let mut storage = HashMap::<StorageKey, EvmStorageSlot>::default();
546 let key1 = StorageKey::from(1);
547 let key2 = StorageKey::from(2);
548 let slot1 = EvmStorageSlot::new(StorageValue::from(10), 0);
549 let slot2 = EvmStorageSlot::new(StorageValue::from(20), 0);
550
551 storage.insert(key1, slot1.clone());
552 storage.insert(key2, slot2.clone());
553
554 let account = Account::default().with_storage(storage.clone().into_iter());
555
556 assert_eq!(account.storage.len(), 2);
557 assert_eq!(account.storage.get(&key1), Some(&slot1));
558 assert_eq!(account.storage.get(&key2), Some(&slot2));
559 }
560
561 #[test]
562 fn test_account_with_selfdestruct_mark() {
563 let account = Account::default().with_selfdestruct_mark();
564
565 assert!(account.is_selfdestructed());
566 assert!(!account.is_touched());
567 assert!(!account.is_created());
568 }
569
570 #[test]
571 fn test_account_with_touched_mark() {
572 let account = Account::default().with_touched_mark();
573
574 assert!(!account.is_selfdestructed());
575 assert!(account.is_touched());
576 assert!(!account.is_created());
577 }
578
579 #[test]
580 fn test_account_with_created_mark() {
581 let account = Account::default().with_created_mark();
582
583 assert!(!account.is_selfdestructed());
584 assert!(!account.is_touched());
585 assert!(account.is_created());
586 }
587
588 #[test]
589 fn test_account_with_cold_mark() {
590 let account = Account::default().with_cold_mark();
591
592 assert!(account.status.contains(AccountStatus::Cold));
593 }
594
595 #[test]
596 fn test_storage_mark_warm_with_transaction_id() {
597 let mut slot = EvmStorageSlot::new(U256::ZERO, 0);
598 slot.is_cold = true;
599 slot.transaction_id = 0;
600 assert!(slot.mark_warm_with_transaction_id(1));
601
602 slot.is_cold = false;
603 slot.transaction_id = 0;
604 assert!(slot.mark_warm_with_transaction_id(1));
605
606 slot.is_cold = true;
607 slot.transaction_id = 1;
608 assert!(slot.mark_warm_with_transaction_id(1));
609
610 slot.is_cold = false;
611 slot.transaction_id = 1;
612 assert!(!slot.mark_warm_with_transaction_id(1));
614 }
615
616 #[test]
617 fn test_account_with_warm_mark() {
618 let cold_account = Account::default().with_cold_mark();
620 assert!(cold_account.status.contains(AccountStatus::Cold));
621
622 let (warm_account, was_cold) = cold_account.with_warm_mark(0);
624
625 assert!(!warm_account.status.contains(AccountStatus::Cold));
627 assert!(was_cold);
628
629 let (still_warm_account, was_cold) = warm_account.with_warm_mark(0);
631 assert!(!still_warm_account.status.contains(AccountStatus::Cold));
632 assert!(!was_cold);
633 }
634
635 #[test]
636 fn test_account_with_warm() {
637 let cold_account = Account::default().with_cold_mark();
639 assert!(cold_account.status.contains(AccountStatus::Cold));
640
641 let warm_account = cold_account.with_warm(0);
643
644 assert!(!warm_account.status.contains(AccountStatus::Cold));
646 }
647
648 #[test]
649 fn test_account_builder_chaining() {
650 let info = AccountInfo {
651 nonce: 5,
652 ..AccountInfo::default()
653 };
654
655 let slot_key = StorageKey::from(42);
656 let slot_value = EvmStorageSlot::new(StorageValue::from(123), 0);
657 let mut storage = HashMap::<StorageKey, EvmStorageSlot>::default();
658 storage.insert(slot_key, slot_value.clone());
659
660 let account = Account::default()
662 .with_info(info.clone())
663 .with_storage(storage.into_iter())
664 .with_created_mark()
665 .with_touched_mark()
666 .with_cold_mark()
667 .with_warm(0);
668
669 assert_eq!(account.info, info);
671 assert_eq!(account.storage.get(&slot_key), Some(&slot_value));
672 assert!(account.is_created());
673 assert!(account.is_touched());
674 assert!(!account.status.contains(AccountStatus::Cold));
675 }
676
677 #[test]
678 fn test_account_is_cold_transaction_id() {
679 let mut account = Account::default();
680 assert!(!account.is_cold_transaction_id(0));
682
683 assert!(account.is_cold_transaction_id(1));
685 account.mark_cold();
686 assert!(account.is_cold_transaction_id(0));
687 assert!(account.is_cold_transaction_id(1));
688 }
689}