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, U256};
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 storage: EvmStorage,
27 pub status: AccountStatus,
29}
30
31impl Account {
32 pub fn new_not_existing() -> Self {
34 Self {
35 info: AccountInfo::default(),
36 storage: HashMap::default(),
37 status: AccountStatus::LoadedAsNotExisting,
38 }
39 }
40
41 #[inline]
43 pub fn state_clear_aware_is_empty(&self, spec: SpecId) -> bool {
44 if SpecId::is_enabled_in(spec, SpecId::SPURIOUS_DRAGON) {
45 self.is_empty()
46 } else {
47 let loaded_not_existing = self.is_loaded_as_not_existing();
48 let is_not_touched = !self.is_touched();
49 loaded_not_existing && is_not_touched
50 }
51 }
52
53 pub fn mark_selfdestruct(&mut self) {
55 self.status |= AccountStatus::SelfDestructed;
56 }
57
58 pub fn unmark_selfdestruct(&mut self) {
60 self.status -= AccountStatus::SelfDestructed;
61 }
62
63 pub fn is_selfdestructed(&self) -> bool {
65 self.status.contains(AccountStatus::SelfDestructed)
66 }
67
68 pub fn mark_touch(&mut self) {
70 self.status |= AccountStatus::Touched;
71 }
72
73 pub fn unmark_touch(&mut self) {
75 self.status -= AccountStatus::Touched;
76 }
77
78 pub fn is_touched(&self) -> bool {
80 self.status.contains(AccountStatus::Touched)
81 }
82
83 pub fn mark_created(&mut self) {
85 self.status |= AccountStatus::Created;
86 }
87
88 pub fn unmark_created(&mut self) {
90 self.status -= AccountStatus::Created;
91 }
92
93 pub fn mark_cold(&mut self) {
95 self.status |= AccountStatus::Cold;
96 }
97
98 pub fn mark_warm(&mut self) -> bool {
100 if self.status.contains(AccountStatus::Cold) {
101 self.status -= AccountStatus::Cold;
102 true
103 } else {
104 false
105 }
106 }
107
108 pub fn is_loaded_as_not_existing(&self) -> bool {
113 self.status.contains(AccountStatus::LoadedAsNotExisting)
114 }
115
116 pub fn is_created(&self) -> bool {
118 self.status.contains(AccountStatus::Created)
119 }
120
121 pub fn is_empty(&self) -> bool {
123 self.info.is_empty()
124 }
125
126 pub fn changed_storage_slots(&self) -> impl Iterator<Item = (&U256, &EvmStorageSlot)> {
130 self.storage.iter().filter(|(_, slot)| slot.is_changed())
131 }
132
133 pub fn with_info(mut self, info: AccountInfo) -> Self {
135 self.info = info;
136 self
137 }
138
139 pub fn with_storage<I>(mut self, storage_iter: I) -> Self
141 where
142 I: Iterator<Item = (U256, EvmStorageSlot)>,
143 {
144 for (key, slot) in storage_iter {
145 self.storage.insert(key, slot);
146 }
147 self
148 }
149
150 pub fn with_selfdestruct_mark(mut self) -> Self {
152 self.mark_selfdestruct();
153 self
154 }
155
156 pub fn with_touched_mark(mut self) -> Self {
158 self.mark_touch();
159 self
160 }
161
162 pub fn with_created_mark(mut self) -> Self {
164 self.mark_created();
165 self
166 }
167
168 pub fn with_cold_mark(mut self) -> Self {
170 self.mark_cold();
171 self
172 }
173
174 pub fn with_warm_mark(mut self) -> (Self, bool) {
177 let was_cold = self.mark_warm();
178 (self, was_cold)
179 }
180
181 pub fn with_warm(mut self) -> Self {
183 self.mark_warm();
184 self
185 }
186}
187
188impl From<AccountInfo> for Account {
189 fn from(info: AccountInfo) -> Self {
190 Self {
191 info,
192 storage: HashMap::default(),
193 status: AccountStatus::Loaded,
194 }
195 }
196}
197
198bitflags! {
200 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
202 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
203 #[cfg_attr(feature = "serde", serde(transparent))]
204 pub struct AccountStatus: u8 {
205 const Loaded = 0b00000000;
208 const Created = 0b00000001;
211 const SelfDestructed = 0b00000010;
213 const Touched = 0b00000100;
215 const LoadedAsNotExisting = 0b0001000;
218 const Cold = 0b0010000;
220 }
221}
222
223impl Default for AccountStatus {
224 fn default() -> Self {
225 Self::Loaded
226 }
227}
228
229#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
231#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
232pub struct EvmStorageSlot {
233 pub original_value: U256,
235 pub present_value: U256,
237 pub is_cold: bool,
239}
240
241impl EvmStorageSlot {
242 pub fn new(original: U256) -> Self {
244 Self {
245 original_value: original,
246 present_value: original,
247 is_cold: false,
248 }
249 }
250
251 pub fn new_changed(original_value: U256, present_value: U256) -> Self {
253 Self {
254 original_value,
255 present_value,
256 is_cold: false,
257 }
258 }
259 pub fn is_changed(&self) -> bool {
261 self.original_value != self.present_value
262 }
263
264 pub fn original_value(&self) -> U256 {
266 self.original_value
267 }
268
269 pub fn present_value(&self) -> U256 {
271 self.present_value
272 }
273
274 pub fn mark_cold(&mut self) {
276 self.is_cold = true;
277 }
278
279 pub fn mark_warm(&mut self) -> bool {
281 core::mem::replace(&mut self.is_cold, false)
282 }
283}
284
285#[cfg(test)]
286mod tests {
287 use super::*;
288 use crate::EvmStorageSlot;
289 use primitives::KECCAK_EMPTY;
290
291 #[test]
292 fn account_is_empty_balance() {
293 let mut account = Account::default();
294 assert!(account.is_empty());
295
296 account.info.balance = U256::from(1);
297 assert!(!account.is_empty());
298
299 account.info.balance = U256::ZERO;
300 assert!(account.is_empty());
301 }
302
303 #[test]
304 fn account_is_empty_nonce() {
305 let mut account = Account::default();
306 assert!(account.is_empty());
307
308 account.info.nonce = 1;
309 assert!(!account.is_empty());
310
311 account.info.nonce = 0;
312 assert!(account.is_empty());
313 }
314
315 #[test]
316 fn account_is_empty_code_hash() {
317 let mut account = Account::default();
318 assert!(account.is_empty());
319
320 account.info.code_hash = [1; 32].into();
321 assert!(!account.is_empty());
322
323 account.info.code_hash = [0; 32].into();
324 assert!(account.is_empty());
325
326 account.info.code_hash = KECCAK_EMPTY;
327 assert!(account.is_empty());
328 }
329
330 #[test]
331 fn account_state() {
332 let mut account = Account::default();
333
334 assert!(!account.is_touched());
335 assert!(!account.is_selfdestructed());
336
337 account.mark_touch();
338 assert!(account.is_touched());
339 assert!(!account.is_selfdestructed());
340
341 account.mark_selfdestruct();
342 assert!(account.is_touched());
343 assert!(account.is_selfdestructed());
344
345 account.unmark_selfdestruct();
346 assert!(account.is_touched());
347 assert!(!account.is_selfdestructed());
348 }
349
350 #[test]
351 fn account_is_cold() {
352 let mut account = Account::default();
353
354 assert!(!account.status.contains(crate::AccountStatus::Cold));
356
357 assert!(!account.mark_warm());
359
360 account.mark_cold();
362
363 assert!(account.status.contains(crate::AccountStatus::Cold));
365
366 assert!(account.mark_warm());
368 }
369
370 #[test]
371 fn test_account_with_info() {
372 let info = AccountInfo::default();
373 let account = Account::default().with_info(info.clone());
374
375 assert_eq!(account.info, info);
376 assert_eq!(account.storage, HashMap::default());
377 assert_eq!(account.status, AccountStatus::Loaded);
378 }
379
380 #[test]
381 fn test_account_with_storage() {
382 let mut storage = HashMap::new();
383 let key1 = U256::from(1);
384 let key2 = U256::from(2);
385 let slot1 = EvmStorageSlot::new(U256::from(10));
386 let slot2 = EvmStorageSlot::new(U256::from(20));
387
388 storage.insert(key1, slot1.clone());
389 storage.insert(key2, slot2.clone());
390
391 let account = Account::default().with_storage(storage.clone().into_iter());
392
393 assert_eq!(account.storage.len(), 2);
394 assert_eq!(account.storage.get(&key1), Some(&slot1));
395 assert_eq!(account.storage.get(&key2), Some(&slot2));
396 }
397
398 #[test]
399 fn test_account_with_selfdestruct_mark() {
400 let account = Account::default().with_selfdestruct_mark();
401
402 assert!(account.is_selfdestructed());
403 assert!(!account.is_touched());
404 assert!(!account.is_created());
405 }
406
407 #[test]
408 fn test_account_with_touched_mark() {
409 let account = Account::default().with_touched_mark();
410
411 assert!(!account.is_selfdestructed());
412 assert!(account.is_touched());
413 assert!(!account.is_created());
414 }
415
416 #[test]
417 fn test_account_with_created_mark() {
418 let account = Account::default().with_created_mark();
419
420 assert!(!account.is_selfdestructed());
421 assert!(!account.is_touched());
422 assert!(account.is_created());
423 }
424
425 #[test]
426 fn test_account_with_cold_mark() {
427 let account = Account::default().with_cold_mark();
428
429 assert!(account.status.contains(AccountStatus::Cold));
430 }
431
432 #[test]
433 fn test_account_with_warm_mark() {
434 let cold_account = Account::default().with_cold_mark();
436 assert!(cold_account.status.contains(AccountStatus::Cold));
437
438 let (warm_account, was_cold) = cold_account.with_warm_mark();
440
441 assert!(!warm_account.status.contains(AccountStatus::Cold));
443 assert!(was_cold);
444
445 let (still_warm_account, was_cold) = warm_account.with_warm_mark();
447 assert!(!still_warm_account.status.contains(AccountStatus::Cold));
448 assert!(!was_cold);
449 }
450
451 #[test]
452 fn test_account_with_warm() {
453 let cold_account = Account::default().with_cold_mark();
455 assert!(cold_account.status.contains(AccountStatus::Cold));
456
457 let warm_account = cold_account.with_warm();
459
460 assert!(!warm_account.status.contains(AccountStatus::Cold));
462 }
463
464 #[test]
465 fn test_account_builder_chaining() {
466 let info = AccountInfo {
467 nonce: 5,
468 ..AccountInfo::default()
469 };
470
471 let slot_key = U256::from(42);
472 let slot_value = EvmStorageSlot::new(U256::from(123));
473 let mut storage = HashMap::new();
474 storage.insert(slot_key, slot_value.clone());
475
476 let account = Account::default()
478 .with_info(info.clone())
479 .with_storage(storage.into_iter())
480 .with_created_mark()
481 .with_touched_mark()
482 .with_cold_mark()
483 .with_warm();
484
485 assert_eq!(account.info, info);
487 assert_eq!(account.storage.get(&slot_key), Some(&slot_value));
488 assert!(account.is_created());
489 assert!(account.is_touched());
490 assert!(!account.status.contains(AccountStatus::Cold));
491 }
492}