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::{HashMap, U256};
17use specification::hardfork::SpecId;
18
19#[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 storage: EvmStorage,
26 pub status: AccountStatus,
28}
29
30impl Account {
31 pub fn new_not_existing() -> Self {
33 Self {
34 info: AccountInfo::default(),
35 storage: HashMap::default(),
36 status: AccountStatus::LoadedAsNotExisting,
37 }
38 }
39
40 #[inline]
42 pub fn state_clear_aware_is_empty(&self, spec: SpecId) -> bool {
43 if SpecId::is_enabled_in(spec, SpecId::SPURIOUS_DRAGON) {
44 self.is_empty()
45 } else {
46 let loaded_not_existing = self.is_loaded_as_not_existing();
47 let is_not_touched = !self.is_touched();
48 loaded_not_existing && is_not_touched
49 }
50 }
51
52 pub fn mark_selfdestruct(&mut self) {
54 self.status |= AccountStatus::SelfDestructed;
55 }
56
57 pub fn unmark_selfdestruct(&mut self) {
59 self.status -= AccountStatus::SelfDestructed;
60 }
61
62 pub fn is_selfdestructed(&self) -> bool {
64 self.status.contains(AccountStatus::SelfDestructed)
65 }
66
67 pub fn mark_touch(&mut self) {
69 self.status |= AccountStatus::Touched;
70 }
71
72 pub fn unmark_touch(&mut self) {
74 self.status -= AccountStatus::Touched;
75 }
76
77 pub fn is_touched(&self) -> bool {
79 self.status.contains(AccountStatus::Touched)
80 }
81
82 pub fn mark_created(&mut self) {
84 self.status |= AccountStatus::Created;
85 }
86
87 pub fn unmark_created(&mut self) {
89 self.status -= AccountStatus::Created;
90 }
91
92 pub fn mark_cold(&mut self) {
94 self.status |= AccountStatus::Cold;
95 }
96
97 pub fn mark_warm(&mut self) -> bool {
99 if self.status.contains(AccountStatus::Cold) {
100 self.status -= AccountStatus::Cold;
101 true
102 } else {
103 false
104 }
105 }
106
107 pub fn is_loaded_as_not_existing(&self) -> bool {
112 self.status.contains(AccountStatus::LoadedAsNotExisting)
113 }
114
115 pub fn is_created(&self) -> bool {
117 self.status.contains(AccountStatus::Created)
118 }
119
120 pub fn is_empty(&self) -> bool {
122 self.info.is_empty()
123 }
124
125 pub fn changed_storage_slots(&self) -> impl Iterator<Item = (&U256, &EvmStorageSlot)> {
129 self.storage.iter().filter(|(_, slot)| slot.is_changed())
130 }
131}
132
133impl From<AccountInfo> for Account {
134 fn from(info: AccountInfo) -> Self {
135 Self {
136 info,
137 storage: HashMap::default(),
138 status: AccountStatus::Loaded,
139 }
140 }
141}
142
143bitflags! {
145 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
146 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
147 #[cfg_attr(feature = "serde", serde(transparent))]
148 pub struct AccountStatus: u8 {
149 const Loaded = 0b00000000;
152 const Created = 0b00000001;
155 const SelfDestructed = 0b00000010;
157 const Touched = 0b00000100;
159 const LoadedAsNotExisting = 0b0001000;
162 const Cold = 0b0010000;
164 }
165}
166
167impl Default for AccountStatus {
168 fn default() -> Self {
169 Self::Loaded
170 }
171}
172
173#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
175#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
176pub struct EvmStorageSlot {
177 pub original_value: U256,
179 pub present_value: U256,
181 pub is_cold: bool,
183}
184
185impl EvmStorageSlot {
186 pub fn new(original: U256) -> Self {
188 Self {
189 original_value: original,
190 present_value: original,
191 is_cold: false,
192 }
193 }
194
195 pub fn new_changed(original_value: U256, present_value: U256) -> Self {
197 Self {
198 original_value,
199 present_value,
200 is_cold: false,
201 }
202 }
203 pub fn is_changed(&self) -> bool {
205 self.original_value != self.present_value
206 }
207
208 pub fn original_value(&self) -> U256 {
210 self.original_value
211 }
212
213 pub fn present_value(&self) -> U256 {
215 self.present_value
216 }
217
218 pub fn mark_cold(&mut self) {
220 self.is_cold = true;
221 }
222
223 pub fn mark_warm(&mut self) -> bool {
225 core::mem::replace(&mut self.is_cold, false)
226 }
227}
228
229#[cfg(test)]
230mod tests {
231 use crate::Account;
232 use primitives::{KECCAK_EMPTY, U256};
233
234 #[test]
235 fn account_is_empty_balance() {
236 let mut account = Account::default();
237 assert!(account.is_empty());
238
239 account.info.balance = U256::from(1);
240 assert!(!account.is_empty());
241
242 account.info.balance = U256::ZERO;
243 assert!(account.is_empty());
244 }
245
246 #[test]
247 fn account_is_empty_nonce() {
248 let mut account = Account::default();
249 assert!(account.is_empty());
250
251 account.info.nonce = 1;
252 assert!(!account.is_empty());
253
254 account.info.nonce = 0;
255 assert!(account.is_empty());
256 }
257
258 #[test]
259 fn account_is_empty_code_hash() {
260 let mut account = Account::default();
261 assert!(account.is_empty());
262
263 account.info.code_hash = [1; 32].into();
264 assert!(!account.is_empty());
265
266 account.info.code_hash = [0; 32].into();
267 assert!(account.is_empty());
268
269 account.info.code_hash = KECCAK_EMPTY;
270 assert!(account.is_empty());
271 }
272
273 #[test]
274 fn account_state() {
275 let mut account = Account::default();
276
277 assert!(!account.is_touched());
278 assert!(!account.is_selfdestructed());
279
280 account.mark_touch();
281 assert!(account.is_touched());
282 assert!(!account.is_selfdestructed());
283
284 account.mark_selfdestruct();
285 assert!(account.is_touched());
286 assert!(account.is_selfdestructed());
287
288 account.unmark_selfdestruct();
289 assert!(account.is_touched());
290 assert!(!account.is_selfdestructed());
291 }
292
293 #[test]
294 fn account_is_cold() {
295 let mut account = Account::default();
296
297 assert!(!account.status.contains(crate::AccountStatus::Cold));
299
300 assert!(!account.mark_warm());
302
303 account.mark_cold();
305
306 assert!(account.status.contains(crate::AccountStatus::Cold));
308
309 assert!(account.mark_warm());
311 }
312}