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;
16use primitives::{HashMap, StorageKey, StorageValue};
17
18#[derive(Debug, Clone, PartialEq, Eq, Default)]
20#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
21pub struct Account {
22 pub info: AccountInfo,
24 pub transaction_id: usize,
26 pub storage: EvmStorage,
28 pub status: AccountStatus,
30}
31
32impl Account {
33 pub fn new_not_existing(transaction_id: usize) -> Self {
35 Self {
36 info: AccountInfo::default(),
37 storage: HashMap::default(),
38 transaction_id,
39 status: AccountStatus::LoadedAsNotExisting,
40 }
41 }
42
43 #[inline]
45 pub fn state_clear_aware_is_empty(&self, spec: SpecId) -> bool {
46 if SpecId::is_enabled_in(spec, SpecId::SPURIOUS_DRAGON) {
47 self.is_empty()
48 } else {
49 self.is_loaded_as_not_existing_not_touched()
50 }
51 }
52
53 #[inline]
55 pub fn mark_selfdestruct(&mut self) {
56 self.status |= AccountStatus::SelfDestructed;
57 }
58
59 #[inline]
61 pub fn unmark_selfdestruct(&mut self) {
62 self.status -= AccountStatus::SelfDestructed;
63 }
64
65 #[inline]
67 pub fn is_selfdestructed(&self) -> bool {
68 self.status.contains(AccountStatus::SelfDestructed)
69 }
70
71 #[inline]
73 pub fn mark_touch(&mut self) {
74 self.status |= AccountStatus::Touched;
75 }
76
77 #[inline]
79 pub fn unmark_touch(&mut self) {
80 self.status -= AccountStatus::Touched;
81 }
82
83 #[inline]
85 pub fn is_touched(&self) -> bool {
86 self.status.contains(AccountStatus::Touched)
87 }
88
89 #[inline]
91 pub fn mark_created(&mut self) {
92 self.status |= AccountStatus::Created;
93 }
94
95 #[inline]
97 pub fn unmark_created(&mut self) {
98 self.status -= AccountStatus::Created;
99 }
100
101 #[inline]
103 pub fn mark_cold(&mut self) {
104 self.status |= AccountStatus::Cold;
105 }
106
107 #[inline]
109 pub fn is_cold_transaction_id(&self, transaction_id: usize) -> bool {
110 self.transaction_id != transaction_id || self.status.contains(AccountStatus::Cold)
111 }
112
113 #[inline]
115 pub fn mark_warm_with_transaction_id(&mut self, transaction_id: usize) -> bool {
116 let is_cold = self.is_cold_transaction_id(transaction_id);
117 self.status -= AccountStatus::Cold;
118 self.transaction_id = transaction_id;
119 is_cold
120 }
121
122 #[inline]
124 pub fn is_created_locally(&self) -> bool {
125 self.status.contains(AccountStatus::CreatedLocal)
126 }
127
128 #[inline]
130 pub fn is_selfdestructed_locally(&self) -> bool {
131 self.status.contains(AccountStatus::SelfDestructedLocal)
132 }
133
134 #[inline]
136 pub fn selfdestruct(&mut self) {
137 self.storage.clear();
138 self.info = AccountInfo::default();
139 }
140
141 #[inline]
145 pub fn mark_created_locally(&mut self) -> bool {
146 self.status |= AccountStatus::CreatedLocal;
147 let is_created_globaly = !self.status.contains(AccountStatus::Created);
148 self.status |= AccountStatus::Created;
149 is_created_globaly
150 }
151
152 #[inline]
154 pub fn unmark_created_locally(&mut self) {
155 self.status -= AccountStatus::CreatedLocal;
156 }
157
158 #[inline]
160 pub fn mark_selfdestructed_locally(&mut self) -> bool {
161 self.status |= AccountStatus::SelfDestructedLocal;
162 let is_global_selfdestructed = !self.status.contains(AccountStatus::SelfDestructed);
163 self.status |= AccountStatus::SelfDestructed;
164 is_global_selfdestructed
165 }
166
167 #[inline]
169 pub fn unmark_selfdestructed_locally(&mut self) {
170 self.status -= AccountStatus::SelfDestructedLocal;
171 }
172
173 pub fn is_loaded_as_not_existing(&self) -> bool {
178 self.status.contains(AccountStatus::LoadedAsNotExisting)
179 }
180
181 pub fn is_loaded_as_not_existing_not_touched(&self) -> bool {
183 self.is_loaded_as_not_existing() && !self.is_touched()
184 }
185
186 pub fn is_created(&self) -> bool {
188 self.status.contains(AccountStatus::Created)
189 }
190
191 pub fn is_empty(&self) -> bool {
193 self.info.is_empty()
194 }
195
196 pub fn changed_storage_slots(&self) -> impl Iterator<Item = (&StorageKey, &EvmStorageSlot)> {
200 self.storage.iter().filter(|(_, slot)| slot.is_changed())
201 }
202
203 pub fn with_info(mut self, info: AccountInfo) -> Self {
205 self.info = info;
206 self
207 }
208
209 pub fn with_storage<I>(mut self, storage_iter: I) -> Self
211 where
212 I: Iterator<Item = (StorageKey, EvmStorageSlot)>,
213 {
214 for (key, slot) in storage_iter {
215 self.storage.insert(key, slot);
216 }
217 self
218 }
219
220 pub fn with_selfdestruct_mark(mut self) -> Self {
222 self.mark_selfdestruct();
223 self
224 }
225
226 pub fn with_touched_mark(mut self) -> Self {
228 self.mark_touch();
229 self
230 }
231
232 pub fn with_created_mark(mut self) -> Self {
234 self.mark_created();
235 self
236 }
237
238 pub fn with_cold_mark(mut self) -> Self {
240 self.mark_cold();
241 self
242 }
243
244 pub fn with_warm_mark(mut self, transaction_id: usize) -> (Self, bool) {
247 let was_cold = self.mark_warm_with_transaction_id(transaction_id);
248 (self, was_cold)
249 }
250
251 pub fn with_warm(mut self, transaction_id: usize) -> Self {
253 self.mark_warm_with_transaction_id(transaction_id);
254 self
255 }
256}
257
258impl From<AccountInfo> for Account {
259 fn from(info: AccountInfo) -> Self {
260 Self {
261 info,
262 storage: HashMap::default(),
263 transaction_id: 0,
264 status: AccountStatus::empty(),
265 }
266 }
267}
268
269bitflags! {
271 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
303 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
304 #[cfg_attr(feature = "serde", serde(transparent))]
305 pub struct AccountStatus: u8 {
306 const Created = 0b00000001;
309 const CreatedLocal = 0b10000000;
311 const SelfDestructed = 0b00000010;
313 const SelfDestructedLocal = 0b01000000;
315 const Touched = 0b00000100;
319 const LoadedAsNotExisting = 0b00001000;
322 const Cold = 0b00010000;
325 }
326}
327
328impl Default for AccountStatus {
329 fn default() -> Self {
330 AccountStatus::empty()
331 }
332}
333
334#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
336#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
337pub struct EvmStorageSlot {
338 pub original_value: StorageValue,
340 pub present_value: StorageValue,
342 pub transaction_id: usize,
344 pub is_cold: bool,
346}
347
348impl EvmStorageSlot {
349 pub fn new(original: StorageValue, transaction_id: usize) -> Self {
351 Self {
352 original_value: original,
353 present_value: original,
354 transaction_id,
355 is_cold: false,
356 }
357 }
358
359 pub fn new_changed(
361 original_value: StorageValue,
362 present_value: StorageValue,
363 transaction_id: usize,
364 ) -> Self {
365 Self {
366 original_value,
367 present_value,
368 transaction_id,
369 is_cold: false,
370 }
371 }
372 pub fn is_changed(&self) -> bool {
374 self.original_value != self.present_value
375 }
376
377 #[inline]
379 pub fn original_value(&self) -> StorageValue {
380 self.original_value
381 }
382
383 #[inline]
385 pub fn present_value(&self) -> StorageValue {
386 self.present_value
387 }
388
389 #[inline]
391 pub fn mark_cold(&mut self) {
392 self.is_cold = true;
393 }
394
395 #[inline]
397 pub fn is_cold_transaction_id(&self, transaction_id: usize) -> bool {
398 self.transaction_id != transaction_id || self.is_cold
399 }
400
401 #[inline]
406 pub fn mark_warm_with_transaction_id(&mut self, transaction_id: usize) -> bool {
407 let is_cold = self.is_cold_transaction_id(transaction_id);
408 self.transaction_id = transaction_id;
409 self.is_cold = false;
410 is_cold
411 }
412}
413
414#[cfg(test)]
415mod tests {
416 use super::*;
417 use crate::EvmStorageSlot;
418 use primitives::{StorageKey, KECCAK_EMPTY, U256};
419
420 #[test]
421 fn account_is_empty_balance() {
422 let mut account = Account::default();
423 assert!(account.is_empty());
424
425 account.info.balance = U256::from(1);
426 assert!(!account.is_empty());
427
428 account.info.balance = U256::ZERO;
429 assert!(account.is_empty());
430 }
431
432 #[test]
433 fn account_is_empty_nonce() {
434 let mut account = Account::default();
435 assert!(account.is_empty());
436
437 account.info.nonce = 1;
438 assert!(!account.is_empty());
439
440 account.info.nonce = 0;
441 assert!(account.is_empty());
442 }
443
444 #[test]
445 fn account_is_empty_code_hash() {
446 let mut account = Account::default();
447 assert!(account.is_empty());
448
449 account.info.code_hash = [1; 32].into();
450 assert!(!account.is_empty());
451
452 account.info.code_hash = [0; 32].into();
453 assert!(account.is_empty());
454
455 account.info.code_hash = KECCAK_EMPTY;
456 assert!(account.is_empty());
457 }
458
459 #[test]
460 fn account_state() {
461 let mut account = Account::default();
462
463 assert!(!account.is_touched());
464 assert!(!account.is_selfdestructed());
465
466 account.mark_touch();
467 assert!(account.is_touched());
468 assert!(!account.is_selfdestructed());
469
470 account.mark_selfdestruct();
471 assert!(account.is_touched());
472 assert!(account.is_selfdestructed());
473
474 account.unmark_selfdestruct();
475 assert!(account.is_touched());
476 assert!(!account.is_selfdestructed());
477 }
478
479 #[test]
480 fn account_is_cold() {
481 let mut account = Account::default();
482
483 assert!(!account.status.contains(crate::AccountStatus::Cold));
485
486 assert!(!account.mark_warm_with_transaction_id(0));
488
489 account.mark_cold();
491
492 assert!(account.status.contains(crate::AccountStatus::Cold));
494
495 assert!(account.mark_warm_with_transaction_id(0));
497 }
498
499 #[test]
500 fn test_account_with_info() {
501 let info = AccountInfo::default();
502 let account = Account::default().with_info(info.clone());
503
504 assert_eq!(account.info, info);
505 assert_eq!(account.storage, HashMap::default());
506 assert_eq!(account.status, AccountStatus::empty());
507 }
508
509 #[test]
510 fn test_account_with_storage() {
511 let mut storage = HashMap::<StorageKey, EvmStorageSlot>::default();
512 let key1 = StorageKey::from(1);
513 let key2 = StorageKey::from(2);
514 let slot1 = EvmStorageSlot::new(StorageValue::from(10), 0);
515 let slot2 = EvmStorageSlot::new(StorageValue::from(20), 0);
516
517 storage.insert(key1, slot1.clone());
518 storage.insert(key2, slot2.clone());
519
520 let account = Account::default().with_storage(storage.clone().into_iter());
521
522 assert_eq!(account.storage.len(), 2);
523 assert_eq!(account.storage.get(&key1), Some(&slot1));
524 assert_eq!(account.storage.get(&key2), Some(&slot2));
525 }
526
527 #[test]
528 fn test_account_with_selfdestruct_mark() {
529 let account = Account::default().with_selfdestruct_mark();
530
531 assert!(account.is_selfdestructed());
532 assert!(!account.is_touched());
533 assert!(!account.is_created());
534 }
535
536 #[test]
537 fn test_account_with_touched_mark() {
538 let account = Account::default().with_touched_mark();
539
540 assert!(!account.is_selfdestructed());
541 assert!(account.is_touched());
542 assert!(!account.is_created());
543 }
544
545 #[test]
546 fn test_account_with_created_mark() {
547 let account = Account::default().with_created_mark();
548
549 assert!(!account.is_selfdestructed());
550 assert!(!account.is_touched());
551 assert!(account.is_created());
552 }
553
554 #[test]
555 fn test_account_with_cold_mark() {
556 let account = Account::default().with_cold_mark();
557
558 assert!(account.status.contains(AccountStatus::Cold));
559 }
560
561 #[test]
562 fn test_storage_mark_warm_with_transaction_id() {
563 let mut slot = EvmStorageSlot::new(U256::ZERO, 0);
564 slot.is_cold = true;
565 slot.transaction_id = 0;
566 assert!(slot.mark_warm_with_transaction_id(1));
567
568 slot.is_cold = false;
569 slot.transaction_id = 0;
570 assert!(slot.mark_warm_with_transaction_id(1));
571
572 slot.is_cold = true;
573 slot.transaction_id = 1;
574 assert!(slot.mark_warm_with_transaction_id(1));
575
576 slot.is_cold = false;
577 slot.transaction_id = 1;
578 assert!(!slot.mark_warm_with_transaction_id(1));
580 }
581
582 #[test]
583 fn test_account_with_warm_mark() {
584 let cold_account = Account::default().with_cold_mark();
586 assert!(cold_account.status.contains(AccountStatus::Cold));
587
588 let (warm_account, was_cold) = cold_account.with_warm_mark(0);
590
591 assert!(!warm_account.status.contains(AccountStatus::Cold));
593 assert!(was_cold);
594
595 let (still_warm_account, was_cold) = warm_account.with_warm_mark(0);
597 assert!(!still_warm_account.status.contains(AccountStatus::Cold));
598 assert!(!was_cold);
599 }
600
601 #[test]
602 fn test_account_with_warm() {
603 let cold_account = Account::default().with_cold_mark();
605 assert!(cold_account.status.contains(AccountStatus::Cold));
606
607 let warm_account = cold_account.with_warm(0);
609
610 assert!(!warm_account.status.contains(AccountStatus::Cold));
612 }
613
614 #[test]
615 fn test_account_builder_chaining() {
616 let info = AccountInfo {
617 nonce: 5,
618 ..AccountInfo::default()
619 };
620
621 let slot_key = StorageKey::from(42);
622 let slot_value = EvmStorageSlot::new(StorageValue::from(123), 0);
623 let mut storage = HashMap::<StorageKey, EvmStorageSlot>::default();
624 storage.insert(slot_key, slot_value.clone());
625
626 let account = Account::default()
628 .with_info(info.clone())
629 .with_storage(storage.into_iter())
630 .with_created_mark()
631 .with_touched_mark()
632 .with_cold_mark()
633 .with_warm(0);
634
635 assert_eq!(account.info, info);
637 assert_eq!(account.storage.get(&slot_key), Some(&slot_value));
638 assert!(account.is_created());
639 assert!(account.is_touched());
640 assert!(!account.status.contains(AccountStatus::Cold));
641 }
642
643 #[test]
644 fn test_account_is_cold_transaction_id() {
645 let mut account = Account::default();
646 assert!(!account.is_cold_transaction_id(0));
648
649 assert!(account.is_cold_transaction_id(1));
651 account.mark_cold();
652 assert!(account.is_cold_transaction_id(0));
653 assert!(account.is_cold_transaction_id(1));
654 }
655}