rtvm_primitives/
state.rs

1use crate::{Address, Bytecode, HashMap, B256, KECCAK_EMPTY, U256};
2use bitflags::bitflags;
3use core::hash::{Hash, Hasher};
4
5/// EVM State is a mapping from addresses to accounts.
6pub type State = HashMap<Address, Account>;
7
8/// Structure used for EIP-1153 transient storage.
9pub type TransientStorage = HashMap<(Address, U256), U256>;
10
11/// An account's Storage is a mapping from 256-bit integer keys to [StorageSlot]s.
12pub type Storage = HashMap<U256, StorageSlot>;
13
14#[derive(Debug, Clone, PartialEq, Eq, Default)]
15#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
16pub struct Account {
17    /// Balance, nonce, and code.
18    pub info: AccountInfo,
19    /// Storage cache
20    pub storage: Storage,
21    /// Account status flags.
22    pub status: AccountStatus,
23}
24
25// The `bitflags!` macro generates `struct`s that manage a set of flags.
26bitflags! {
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        /// When account is loaded but not touched or interacted with.
32        /// This is the default state.
33        const Loaded = 0b00000000;
34        /// When account is newly created we will not access database
35        /// to fetch storage values
36        const Created = 0b00000001;
37        /// If account is marked for self destruction.
38        const SelfDestructed = 0b00000010;
39        /// Only when account is marked as touched we will save it to database.
40        const Touched = 0b00000100;
41        /// used only for pre spurious dragon hardforks where existing and empty were two separate states.
42        /// it became same state after EIP-161: State trie clearing
43        const LoadedAsNotExisting = 0b0001000;
44    }
45}
46
47impl Default for AccountStatus {
48    fn default() -> Self {
49        Self::Loaded
50    }
51}
52
53impl Account {
54    /// Create new account and mark it as non existing.
55    pub fn new_not_existing() -> Self {
56        Self {
57            info: AccountInfo::default(),
58            storage: HashMap::new(),
59            status: AccountStatus::LoadedAsNotExisting,
60        }
61    }
62
63    /// Mark account as self destructed.
64    pub fn mark_selfdestruct(&mut self) {
65        self.status |= AccountStatus::SelfDestructed;
66    }
67
68    /// Unmark account as self destructed.
69    pub fn unmark_selfdestruct(&mut self) {
70        self.status -= AccountStatus::SelfDestructed;
71    }
72
73    /// Is account marked for self destruct.
74    pub fn is_selfdestructed(&self) -> bool {
75        self.status.contains(AccountStatus::SelfDestructed)
76    }
77
78    /// Mark account as touched
79    pub fn mark_touch(&mut self) {
80        self.status |= AccountStatus::Touched;
81    }
82
83    /// Unmark the touch flag.
84    pub fn unmark_touch(&mut self) {
85        self.status -= AccountStatus::Touched;
86    }
87
88    /// If account status is marked as touched.
89    pub fn is_touched(&self) -> bool {
90        self.status.contains(AccountStatus::Touched)
91    }
92
93    /// Mark account as newly created.
94    pub fn mark_created(&mut self) {
95        self.status |= AccountStatus::Created;
96    }
97
98    /// Unmark created flag.
99    pub fn unmark_created(&mut self) {
100        self.status -= AccountStatus::Created;
101    }
102
103    /// Is account loaded as not existing from database
104    /// This is needed for pre spurious dragon hardforks where
105    /// existing and empty were two separate states.
106    pub fn is_loaded_as_not_existing(&self) -> bool {
107        self.status.contains(AccountStatus::LoadedAsNotExisting)
108    }
109
110    /// Is account newly created in this transaction.
111    pub fn is_created(&self) -> bool {
112        self.status.contains(AccountStatus::Created)
113    }
114
115    /// Is account empty, check if nonce and balance are zero and code is empty.
116    pub fn is_empty(&self) -> bool {
117        self.info.is_empty()
118    }
119
120    /// Returns an iterator over the storage slots that have been changed.
121    ///
122    /// See also [StorageSlot::is_changed]
123    pub fn changed_storage_slots(&self) -> impl Iterator<Item = (&U256, &StorageSlot)> {
124        self.storage.iter().filter(|(_, slot)| slot.is_changed())
125    }
126}
127
128impl From<AccountInfo> for Account {
129    fn from(info: AccountInfo) -> Self {
130        Self {
131            info,
132            storage: HashMap::new(),
133            status: AccountStatus::Loaded,
134        }
135    }
136}
137
138/// This type keeps track of the current value of a storage slot.
139#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
140#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
141pub struct StorageSlot {
142    /// The value of the storage slot before it was changed.
143    ///
144    /// When the slot is first loaded, this is the original value.
145    ///
146    /// If the slot was not changed, this is equal to the present value.
147    pub previous_or_original_value: U256,
148    /// When loaded with sload present value is set to original value
149    pub present_value: U256,
150}
151
152impl StorageSlot {
153    /// Creates a new _unchanged_ `StorageSlot` for the given value.
154    pub fn new(original: U256) -> Self {
155        Self {
156            previous_or_original_value: original,
157            present_value: original,
158        }
159    }
160
161    /// Creates a new _changed_ `StorageSlot`.
162    pub fn new_changed(previous_or_original_value: U256, present_value: U256) -> Self {
163        Self {
164            previous_or_original_value,
165            present_value,
166        }
167    }
168
169    /// Returns true if the present value differs from the original value
170    pub fn is_changed(&self) -> bool {
171        self.previous_or_original_value != self.present_value
172    }
173
174    /// Returns the original value of the storage slot.
175    pub fn original_value(&self) -> U256 {
176        self.previous_or_original_value
177    }
178
179    /// Returns the current value of the storage slot.
180    pub fn present_value(&self) -> U256 {
181        self.present_value
182    }
183}
184
185/// AccountInfo account information.
186#[derive(Clone, Debug, Eq)]
187#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
188pub struct AccountInfo {
189    /// Account balance.
190    pub balance: U256,
191    /// Account nonce.
192    pub nonce: u64,
193    /// code hash,
194    pub code_hash: B256,
195    /// code: if None, `code_by_hash` will be used to fetch it if code needs to be loaded from
196    /// inside of `rtvm`.
197    pub code: Option<Bytecode>,
198}
199
200impl Default for AccountInfo {
201    fn default() -> Self {
202        Self {
203            balance: U256::ZERO,
204            code_hash: KECCAK_EMPTY,
205            code: Some(Bytecode::default()),
206            nonce: 0,
207        }
208    }
209}
210
211impl PartialEq for AccountInfo {
212    fn eq(&self, other: &Self) -> bool {
213        self.balance == other.balance
214            && self.nonce == other.nonce
215            && self.code_hash == other.code_hash
216    }
217}
218
219impl Hash for AccountInfo {
220    fn hash<H: Hasher>(&self, state: &mut H) {
221        self.balance.hash(state);
222        self.nonce.hash(state);
223        self.code_hash.hash(state);
224    }
225}
226
227impl AccountInfo {
228    pub fn new(balance: U256, nonce: u64, code_hash: B256, code: Bytecode) -> Self {
229        Self {
230            balance,
231            nonce,
232            code: Some(code),
233            code_hash,
234        }
235    }
236
237    /// Returns account info without the code.
238    pub fn without_code(mut self) -> Self {
239        self.take_bytecode();
240        self
241    }
242
243    /// Returns if an account is empty.
244    ///
245    /// An account is empty if the following conditions are met.
246    /// - code hash is zero or set to the Keccak256 hash of the empty string `""`
247    /// - balance is zero
248    /// - nonce is zero
249    pub fn is_empty(&self) -> bool {
250        let code_empty = self.is_empty_code_hash() || self.code_hash == B256::ZERO;
251        code_empty && self.balance == U256::ZERO && self.nonce == 0
252    }
253
254    /// Returns `true` if the account is not empty.
255    pub fn exists(&self) -> bool {
256        !self.is_empty()
257    }
258
259    /// Returns `true` if account has no nonce and code.
260    pub fn has_no_code_and_nonce(&self) -> bool {
261        self.is_empty_code_hash() && self.nonce == 0
262    }
263
264    /// Return bytecode hash associated with this account.
265    /// If account does not have code, it return's `KECCAK_EMPTY` hash.
266    pub fn code_hash(&self) -> B256 {
267        self.code_hash
268    }
269
270    /// Returns true if the code hash is the Keccak256 hash of the empty string `""`.
271    #[inline]
272    pub fn is_empty_code_hash(&self) -> bool {
273        self.code_hash == KECCAK_EMPTY
274    }
275
276    /// Take bytecode from account. Code will be set to None.
277    pub fn take_bytecode(&mut self) -> Option<Bytecode> {
278        self.code.take()
279    }
280
281    pub fn from_balance(balance: U256) -> Self {
282        AccountInfo {
283            balance,
284            ..Default::default()
285        }
286    }
287}
288
289#[cfg(test)]
290mod tests {
291    use crate::{Account, KECCAK_EMPTY, U256};
292
293    #[test]
294    fn account_is_empty_balance() {
295        let mut account = Account::default();
296        assert!(account.is_empty());
297
298        account.info.balance = U256::from(1);
299        assert!(!account.is_empty());
300
301        account.info.balance = U256::ZERO;
302        assert!(account.is_empty());
303    }
304
305    #[test]
306    fn account_is_empty_nonce() {
307        let mut account = Account::default();
308        assert!(account.is_empty());
309
310        account.info.nonce = 1;
311        assert!(!account.is_empty());
312
313        account.info.nonce = 0;
314        assert!(account.is_empty());
315    }
316
317    #[test]
318    fn account_is_empty_code_hash() {
319        let mut account = Account::default();
320        assert!(account.is_empty());
321
322        account.info.code_hash = [1; 32].into();
323        assert!(!account.is_empty());
324
325        account.info.code_hash = [0; 32].into();
326        assert!(account.is_empty());
327
328        account.info.code_hash = KECCAK_EMPTY;
329        assert!(account.is_empty());
330    }
331
332    #[test]
333    fn account_state() {
334        let mut account = Account::default();
335
336        assert!(!account.is_touched());
337        assert!(!account.is_selfdestructed());
338
339        account.mark_touch();
340        assert!(account.is_touched());
341        assert!(!account.is_selfdestructed());
342
343        account.mark_selfdestruct();
344        assert!(account.is_touched());
345        assert!(account.is_selfdestructed());
346
347        account.unmark_selfdestruct();
348        assert!(account.is_touched());
349        assert!(!account.is_selfdestructed());
350    }
351}