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 core::hash::Hash;
16use primitives::hardfork::SpecId;
17use primitives::{HashMap, StorageKey, StorageValue};
18
19#[derive(Debug, Clone, PartialEq, Eq, Default)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22pub struct Account {
23 pub info: AccountInfo,
25 pub transaction_id: usize,
27 pub storage: EvmStorage,
29 pub status: AccountStatus,
31}
32
33impl Account {
34 pub fn new_not_existing(transaction_id: usize) -> Self {
36 Self {
37 info: AccountInfo::default(),
38 storage: HashMap::default(),
39 transaction_id,
40 status: AccountStatus::LoadedAsNotExisting,
41 }
42 }
43
44 #[inline]
46 pub fn state_clear_aware_is_empty(&self, spec: SpecId) -> bool {
47 if SpecId::is_enabled_in(spec, SpecId::SPURIOUS_DRAGON) {
48 self.is_empty()
49 } else {
50 self.is_loaded_as_not_existing_not_touched()
51 }
52 }
53
54 pub fn mark_selfdestruct(&mut self) {
56 self.status |= AccountStatus::SelfDestructed;
57 }
58
59 pub fn unmark_selfdestruct(&mut self) {
61 self.status -= AccountStatus::SelfDestructed;
62 }
63
64 pub fn is_selfdestructed(&self) -> bool {
66 self.status.contains(AccountStatus::SelfDestructed)
67 }
68
69 pub fn mark_touch(&mut self) {
71 self.status |= AccountStatus::Touched;
72 }
73
74 pub fn unmark_touch(&mut self) {
76 self.status -= AccountStatus::Touched;
77 }
78
79 pub fn is_touched(&self) -> bool {
81 self.status.contains(AccountStatus::Touched)
82 }
83
84 pub fn mark_created(&mut self) {
86 self.status |= AccountStatus::Created;
87 }
88
89 pub fn unmark_created(&mut self) {
91 self.status -= AccountStatus::Created;
92 }
93
94 pub fn mark_cold(&mut self) {
96 self.status |= AccountStatus::Cold;
97 }
98
99 pub fn mark_warm(&mut self) -> bool {
101 if self.status.contains(AccountStatus::Cold) {
102 self.status -= AccountStatus::Cold;
103 true
104 } else {
105 false
106 }
107 }
108
109 pub fn is_loaded_as_not_existing(&self) -> bool {
114 self.status.contains(AccountStatus::LoadedAsNotExisting)
115 }
116
117 pub fn is_loaded_as_not_existing_not_touched(&self) -> bool {
119 self.is_loaded_as_not_existing() && !self.is_touched()
120 }
121
122 pub fn is_created(&self) -> bool {
124 self.status.contains(AccountStatus::Created)
125 }
126
127 pub fn is_empty(&self) -> bool {
129 self.info.is_empty()
130 }
131
132 pub fn changed_storage_slots(&self) -> impl Iterator<Item = (&StorageKey, &EvmStorageSlot)> {
136 self.storage.iter().filter(|(_, slot)| slot.is_changed())
137 }
138
139 pub fn with_info(mut self, info: AccountInfo) -> Self {
141 self.info = info;
142 self
143 }
144
145 pub fn with_storage<I>(mut self, storage_iter: I) -> Self
147 where
148 I: Iterator<Item = (StorageKey, EvmStorageSlot)>,
149 {
150 for (key, slot) in storage_iter {
151 self.storage.insert(key, slot);
152 }
153 self
154 }
155
156 pub fn with_selfdestruct_mark(mut self) -> Self {
158 self.mark_selfdestruct();
159 self
160 }
161
162 pub fn with_touched_mark(mut self) -> Self {
164 self.mark_touch();
165 self
166 }
167
168 pub fn with_created_mark(mut self) -> Self {
170 self.mark_created();
171 self
172 }
173
174 pub fn with_cold_mark(mut self) -> Self {
176 self.mark_cold();
177 self
178 }
179
180 pub fn with_warm_mark(mut self) -> (Self, bool) {
183 let was_cold = self.mark_warm();
184 (self, was_cold)
185 }
186
187 pub fn with_warm(mut self) -> Self {
189 self.mark_warm();
190 self
191 }
192}
193
194impl From<AccountInfo> for Account {
195 fn from(info: AccountInfo) -> Self {
196 Self {
197 info,
198 storage: HashMap::default(),
199 transaction_id: 0,
200 status: AccountStatus::Loaded,
201 }
202 }
203}
204
205bitflags! {
207 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
209 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
210 #[cfg_attr(feature = "serde", serde(transparent))]
211 pub struct AccountStatus: u8 {
212 const Loaded = 0b00000000;
215 const Created = 0b00000001;
218 const SelfDestructed = 0b00000010;
220 const Touched = 0b00000100;
222 const LoadedAsNotExisting = 0b0001000;
225 const Cold = 0b0010000;
227 }
228}
229
230impl Default for AccountStatus {
231 fn default() -> Self {
232 Self::Loaded
233 }
234}
235
236#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
238#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
239pub struct EvmStorageSlot {
240 pub original_value: StorageValue,
242 pub present_value: StorageValue,
244 pub transaction_id: usize,
246 pub is_cold: bool,
248}
249
250impl EvmStorageSlot {
251 pub fn new(original: StorageValue, transaction_id: usize) -> Self {
253 Self {
254 original_value: original,
255 present_value: original,
256 transaction_id,
257 is_cold: false,
258 }
259 }
260
261 pub fn new_changed(
263 original_value: StorageValue,
264 present_value: StorageValue,
265 transaction_id: usize,
266 ) -> Self {
267 Self {
268 original_value,
269 present_value,
270 transaction_id,
271 is_cold: false,
272 }
273 }
274 pub fn is_changed(&self) -> bool {
276 self.original_value != self.present_value
277 }
278
279 #[inline]
281 pub fn original_value(&self) -> StorageValue {
282 self.original_value
283 }
284
285 #[inline]
287 pub fn present_value(&self) -> StorageValue {
288 self.present_value
289 }
290
291 #[inline]
293 pub fn mark_cold(&mut self) {
294 self.is_cold = true;
295 }
296
297 #[inline]
302 pub fn mark_warm_with_transaction_id(&mut self, transaction_id: usize) -> bool {
303 let same_id = self.transaction_id == transaction_id;
304 self.transaction_id = transaction_id;
305 let was_cold = core::mem::replace(&mut self.is_cold, false);
306
307 if same_id {
308 return was_cold;
310 }
311 true
312 }
313}
314
315#[cfg(test)]
316mod tests {
317 use super::*;
318 use crate::EvmStorageSlot;
319 use primitives::{StorageKey, KECCAK_EMPTY, U256};
320
321 #[test]
322 fn account_is_empty_balance() {
323 let mut account = Account::default();
324 assert!(account.is_empty());
325
326 account.info.balance = U256::from(1);
327 assert!(!account.is_empty());
328
329 account.info.balance = U256::ZERO;
330 assert!(account.is_empty());
331 }
332
333 #[test]
334 fn account_is_empty_nonce() {
335 let mut account = Account::default();
336 assert!(account.is_empty());
337
338 account.info.nonce = 1;
339 assert!(!account.is_empty());
340
341 account.info.nonce = 0;
342 assert!(account.is_empty());
343 }
344
345 #[test]
346 fn account_is_empty_code_hash() {
347 let mut account = Account::default();
348 assert!(account.is_empty());
349
350 account.info.code_hash = [1; 32].into();
351 assert!(!account.is_empty());
352
353 account.info.code_hash = [0; 32].into();
354 assert!(account.is_empty());
355
356 account.info.code_hash = KECCAK_EMPTY;
357 assert!(account.is_empty());
358 }
359
360 #[test]
361 fn account_state() {
362 let mut account = Account::default();
363
364 assert!(!account.is_touched());
365 assert!(!account.is_selfdestructed());
366
367 account.mark_touch();
368 assert!(account.is_touched());
369 assert!(!account.is_selfdestructed());
370
371 account.mark_selfdestruct();
372 assert!(account.is_touched());
373 assert!(account.is_selfdestructed());
374
375 account.unmark_selfdestruct();
376 assert!(account.is_touched());
377 assert!(!account.is_selfdestructed());
378 }
379
380 #[test]
381 fn account_is_cold() {
382 let mut account = Account::default();
383
384 assert!(!account.status.contains(crate::AccountStatus::Cold));
386
387 assert!(!account.mark_warm());
389
390 account.mark_cold();
392
393 assert!(account.status.contains(crate::AccountStatus::Cold));
395
396 assert!(account.mark_warm());
398 }
399
400 #[test]
401 fn test_account_with_info() {
402 let info = AccountInfo::default();
403 let account = Account::default().with_info(info.clone());
404
405 assert_eq!(account.info, info);
406 assert_eq!(account.storage, HashMap::default());
407 assert_eq!(account.status, AccountStatus::Loaded);
408 }
409
410 #[test]
411 fn test_account_with_storage() {
412 let mut storage = HashMap::new();
413 let key1 = StorageKey::from(1);
414 let key2 = StorageKey::from(2);
415 let slot1 = EvmStorageSlot::new(StorageValue::from(10), 0);
416 let slot2 = EvmStorageSlot::new(StorageValue::from(20), 0);
417
418 storage.insert(key1, slot1.clone());
419 storage.insert(key2, slot2.clone());
420
421 let account = Account::default().with_storage(storage.clone().into_iter());
422
423 assert_eq!(account.storage.len(), 2);
424 assert_eq!(account.storage.get(&key1), Some(&slot1));
425 assert_eq!(account.storage.get(&key2), Some(&slot2));
426 }
427
428 #[test]
429 fn test_account_with_selfdestruct_mark() {
430 let account = Account::default().with_selfdestruct_mark();
431
432 assert!(account.is_selfdestructed());
433 assert!(!account.is_touched());
434 assert!(!account.is_created());
435 }
436
437 #[test]
438 fn test_account_with_touched_mark() {
439 let account = Account::default().with_touched_mark();
440
441 assert!(!account.is_selfdestructed());
442 assert!(account.is_touched());
443 assert!(!account.is_created());
444 }
445
446 #[test]
447 fn test_account_with_created_mark() {
448 let account = Account::default().with_created_mark();
449
450 assert!(!account.is_selfdestructed());
451 assert!(!account.is_touched());
452 assert!(account.is_created());
453 }
454
455 #[test]
456 fn test_account_with_cold_mark() {
457 let account = Account::default().with_cold_mark();
458
459 assert!(account.status.contains(AccountStatus::Cold));
460 }
461
462 #[test]
463 fn test_storage_mark_warm_with_transaction_id() {
464 let mut slot = EvmStorageSlot::new(U256::ZERO, 0);
465 slot.is_cold = true;
466 slot.transaction_id = 0;
467 assert!(slot.mark_warm_with_transaction_id(1));
468
469 slot.is_cold = false;
470 slot.transaction_id = 0;
471 assert!(slot.mark_warm_with_transaction_id(1));
472
473 slot.is_cold = true;
474 slot.transaction_id = 1;
475 assert!(slot.mark_warm_with_transaction_id(1));
476
477 slot.is_cold = false;
478 slot.transaction_id = 1;
479 assert!(!slot.mark_warm_with_transaction_id(1));
481 }
482
483 #[test]
484 fn test_account_with_warm_mark() {
485 let cold_account = Account::default().with_cold_mark();
487 assert!(cold_account.status.contains(AccountStatus::Cold));
488
489 let (warm_account, was_cold) = cold_account.with_warm_mark();
491
492 assert!(!warm_account.status.contains(AccountStatus::Cold));
494 assert!(was_cold);
495
496 let (still_warm_account, was_cold) = warm_account.with_warm_mark();
498 assert!(!still_warm_account.status.contains(AccountStatus::Cold));
499 assert!(!was_cold);
500 }
501
502 #[test]
503 fn test_account_with_warm() {
504 let cold_account = Account::default().with_cold_mark();
506 assert!(cold_account.status.contains(AccountStatus::Cold));
507
508 let warm_account = cold_account.with_warm();
510
511 assert!(!warm_account.status.contains(AccountStatus::Cold));
513 }
514
515 #[test]
516 fn test_account_builder_chaining() {
517 let info = AccountInfo {
518 nonce: 5,
519 ..AccountInfo::default()
520 };
521
522 let slot_key = StorageKey::from(42);
523 let slot_value = EvmStorageSlot::new(StorageValue::from(123), 0);
524 let mut storage = HashMap::new();
525 storage.insert(slot_key, slot_value.clone());
526
527 let account = Account::default()
529 .with_info(info.clone())
530 .with_storage(storage.into_iter())
531 .with_created_mark()
532 .with_touched_mark()
533 .with_cold_mark()
534 .with_warm();
535
536 assert_eq!(account.info, info);
538 assert_eq!(account.storage.get(&slot_key), Some(&slot_value));
539 assert!(account.is_created());
540 assert!(account.is_touched());
541 assert!(!account.status.contains(AccountStatus::Cold));
542 }
543}