1use crate::{Address, Bytecode, HashMap, SpecId, B256, KECCAK_EMPTY, U256};
2use bitflags::bitflags;
3use core::hash::{Hash, Hasher};
4
5pub type EvmState = HashMap<Address, Account>;
7
8pub type TransientStorage = HashMap<(Address, U256), U256>;
10
11pub type EvmStorage = HashMap<U256, EvmStorageSlot>;
13
14#[derive(Debug, Clone, PartialEq, Eq, Default)]
15#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
16pub struct Account {
17 pub info: AccountInfo,
19 pub storage: EvmStorage,
21 pub status: AccountStatus,
23}
24
25bitflags! {
27 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
28 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
29 #[cfg_attr(feature = "serde", serde(transparent))]
30 pub struct AccountStatus: u8 {
31 const Loaded = 0b00000000;
34 const Created = 0b00000001;
37 const SelfDestructed = 0b00000010;
39 const Touched = 0b00000100;
41 const LoadedAsNotExisting = 0b0001000;
44 const Cold = 0b0010000;
46 }
47}
48
49impl Default for AccountStatus {
50 fn default() -> Self {
51 Self::Loaded
52 }
53}
54
55impl Account {
56 pub fn new_not_existing() -> Self {
58 Self {
59 info: AccountInfo::default(),
60 storage: HashMap::default(),
61 status: AccountStatus::LoadedAsNotExisting,
62 }
63 }
64
65 #[inline]
67 pub fn state_clear_aware_is_empty(&self, spec: SpecId) -> bool {
68 if SpecId::enabled(spec, SpecId::SPURIOUS_DRAGON) {
69 self.is_empty()
70 } else {
71 let loaded_not_existing = self.is_loaded_as_not_existing();
72 let is_not_touched = !self.is_touched();
73 loaded_not_existing && is_not_touched
74 }
75 }
76
77 pub fn mark_selfdestruct(&mut self) {
79 self.status |= AccountStatus::SelfDestructed;
80 }
81
82 pub fn unmark_selfdestruct(&mut self) {
84 self.status -= AccountStatus::SelfDestructed;
85 }
86
87 pub fn is_selfdestructed(&self) -> bool {
89 self.status.contains(AccountStatus::SelfDestructed)
90 }
91
92 pub fn mark_touch(&mut self) {
94 self.status |= AccountStatus::Touched;
95 }
96
97 pub fn unmark_touch(&mut self) {
99 self.status -= AccountStatus::Touched;
100 }
101
102 pub fn is_touched(&self) -> bool {
104 self.status.contains(AccountStatus::Touched)
105 }
106
107 pub fn mark_created(&mut self) {
109 self.status |= AccountStatus::Created;
110 }
111
112 pub fn unmark_created(&mut self) {
114 self.status -= AccountStatus::Created;
115 }
116
117 pub fn mark_cold(&mut self) {
119 self.status |= AccountStatus::Cold;
120 }
121
122 pub fn mark_warm(&mut self) -> bool {
124 if self.status.contains(AccountStatus::Cold) {
125 self.status -= AccountStatus::Cold;
126 true
127 } else {
128 false
129 }
130 }
131
132 pub fn is_loaded_as_not_existing(&self) -> bool {
136 self.status.contains(AccountStatus::LoadedAsNotExisting)
137 }
138
139 pub fn is_created(&self) -> bool {
141 self.status.contains(AccountStatus::Created)
142 }
143
144 pub fn is_empty(&self) -> bool {
146 self.info.is_empty()
147 }
148
149 pub fn changed_storage_slots(&self) -> impl Iterator<Item = (&U256, &EvmStorageSlot)> {
153 self.storage.iter().filter(|(_, slot)| slot.is_changed())
154 }
155}
156
157impl From<AccountInfo> for Account {
158 fn from(info: AccountInfo) -> Self {
159 Self {
160 info,
161 storage: HashMap::default(),
162 status: AccountStatus::Loaded,
163 }
164 }
165}
166
167#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
169#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
170pub struct EvmStorageSlot {
171 pub original_value: U256,
173 pub present_value: U256,
175 pub is_cold: bool,
177}
178
179impl EvmStorageSlot {
180 pub fn new(original: U256) -> Self {
182 Self {
183 original_value: original,
184 present_value: original,
185 is_cold: false,
186 }
187 }
188
189 pub fn new_changed(original_value: U256, present_value: U256) -> Self {
191 Self {
192 original_value,
193 present_value,
194 is_cold: false,
195 }
196 }
197 pub fn is_changed(&self) -> bool {
199 self.original_value != self.present_value
200 }
201
202 pub fn original_value(&self) -> U256 {
204 self.original_value
205 }
206
207 pub fn present_value(&self) -> U256 {
209 self.present_value
210 }
211
212 pub fn mark_cold(&mut self) {
214 self.is_cold = true;
215 }
216
217 pub fn mark_warm(&mut self) -> bool {
219 core::mem::replace(&mut self.is_cold, false)
220 }
221}
222
223#[derive(Clone, Debug, Eq)]
225#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
226pub struct AccountInfo {
227 pub balance: U256,
229 pub nonce: u64,
231 pub code_hash: B256,
233 pub code: Option<Bytecode>,
236}
237
238impl Default for AccountInfo {
239 fn default() -> Self {
240 Self {
241 balance: U256::ZERO,
242 code_hash: KECCAK_EMPTY,
243 code: Some(Bytecode::default()),
244 nonce: 0,
245 }
246 }
247}
248
249impl PartialEq for AccountInfo {
250 fn eq(&self, other: &Self) -> bool {
251 self.balance == other.balance
252 && self.nonce == other.nonce
253 && self.code_hash == other.code_hash
254 }
255}
256
257impl Hash for AccountInfo {
258 fn hash<H: Hasher>(&self, state: &mut H) {
259 self.balance.hash(state);
260 self.nonce.hash(state);
261 self.code_hash.hash(state);
262 }
263}
264
265impl AccountInfo {
266 pub fn new(balance: U256, nonce: u64, code_hash: B256, code: Bytecode) -> Self {
267 Self {
268 balance,
269 nonce,
270 code: Some(code),
271 code_hash,
272 }
273 }
274
275 pub fn copy_without_code(&self) -> Self {
285 Self {
286 balance: self.balance,
287 nonce: self.nonce,
288 code_hash: self.code_hash,
289 code: None,
290 }
291 }
292
293 pub fn without_code(mut self) -> Self {
303 self.take_bytecode();
304 self
305 }
306
307 pub fn is_empty(&self) -> bool {
314 let code_empty = self.is_empty_code_hash() || self.code_hash.is_zero();
315 code_empty && self.balance.is_zero() && self.nonce == 0
316 }
317
318 pub fn exists(&self) -> bool {
320 !self.is_empty()
321 }
322
323 pub fn has_no_code_and_nonce(&self) -> bool {
325 self.is_empty_code_hash() && self.nonce == 0
326 }
327
328 pub fn code_hash(&self) -> B256 {
331 self.code_hash
332 }
333
334 #[inline]
336 pub fn is_empty_code_hash(&self) -> bool {
337 self.code_hash == KECCAK_EMPTY
338 }
339
340 pub fn take_bytecode(&mut self) -> Option<Bytecode> {
342 self.code.take()
343 }
344
345 pub fn from_balance(balance: U256) -> Self {
346 AccountInfo {
347 balance,
348 ..Default::default()
349 }
350 }
351
352 pub fn from_bytecode(bytecode: Bytecode) -> Self {
353 let hash = bytecode.hash_slow();
354
355 AccountInfo {
356 balance: U256::ZERO,
357 nonce: 1,
358 code: Some(bytecode),
359 code_hash: hash,
360 }
361 }
362}
363
364#[cfg(test)]
365mod tests {
366 use crate::{Account, KECCAK_EMPTY, U256};
367
368 #[test]
369 fn account_is_empty_balance() {
370 let mut account = Account::default();
371 assert!(account.is_empty());
372
373 account.info.balance = U256::from(1);
374 assert!(!account.is_empty());
375
376 account.info.balance = U256::ZERO;
377 assert!(account.is_empty());
378 }
379
380 #[test]
381 fn account_is_empty_nonce() {
382 let mut account = Account::default();
383 assert!(account.is_empty());
384
385 account.info.nonce = 1;
386 assert!(!account.is_empty());
387
388 account.info.nonce = 0;
389 assert!(account.is_empty());
390 }
391
392 #[test]
393 fn account_is_empty_code_hash() {
394 let mut account = Account::default();
395 assert!(account.is_empty());
396
397 account.info.code_hash = [1; 32].into();
398 assert!(!account.is_empty());
399
400 account.info.code_hash = [0; 32].into();
401 assert!(account.is_empty());
402
403 account.info.code_hash = KECCAK_EMPTY;
404 assert!(account.is_empty());
405 }
406
407 #[test]
408 fn account_state() {
409 let mut account = Account::default();
410
411 assert!(!account.is_touched());
412 assert!(!account.is_selfdestructed());
413
414 account.mark_touch();
415 assert!(account.is_touched());
416 assert!(!account.is_selfdestructed());
417
418 account.mark_selfdestruct();
419 assert!(account.is_touched());
420 assert!(account.is_selfdestructed());
421
422 account.unmark_selfdestruct();
423 assert!(account.is_touched());
424 assert!(!account.is_selfdestructed());
425 }
426
427 #[test]
428 fn account_is_cold() {
429 let mut account = Account::default();
430
431 assert!(!account.status.contains(crate::AccountStatus::Cold));
433
434 assert!(!account.mark_warm());
436
437 account.mark_cold();
439
440 assert!(account.status.contains(crate::AccountStatus::Cold));
442
443 assert!(account.mark_warm());
445 }
446}