revm_state/
account_info.rs

1use bytecode::Bytecode;
2use core::{
3    cmp::Ordering,
4    hash::{Hash, Hasher},
5};
6use primitives::{B256, KECCAK_EMPTY, U256};
7
8/// Account information that contains balance, nonce, code hash and code
9///
10/// Code is set as optional.
11#[derive(Clone, Debug, Eq)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13pub struct AccountInfo {
14    /// Account balance.
15    pub balance: U256,
16    /// Account nonce.
17    pub nonce: u64,
18    /// Hash of the raw bytes in `code`, or [`KECCAK_EMPTY`].
19    pub code_hash: B256,
20    /// [`Bytecode`] data associated with this account.
21    ///
22    /// If [`None`], `code_hash` will be used to fetch it from the database, if code needs to be
23    /// loaded from inside `revm`.
24    ///
25    /// By default, this is `Some(Bytecode::default())`.
26    pub code: Option<Bytecode>,
27}
28
29impl Default for AccountInfo {
30    fn default() -> Self {
31        Self {
32            balance: U256::ZERO,
33            code_hash: KECCAK_EMPTY,
34            code: Some(Bytecode::default()),
35            nonce: 0,
36        }
37    }
38}
39
40impl PartialEq for AccountInfo {
41    fn eq(&self, other: &Self) -> bool {
42        self.balance == other.balance
43            && self.nonce == other.nonce
44            && self.code_hash == other.code_hash
45    }
46}
47
48impl Hash for AccountInfo {
49    fn hash<H: Hasher>(&self, state: &mut H) {
50        self.balance.hash(state);
51        self.nonce.hash(state);
52        self.code_hash.hash(state);
53    }
54}
55
56impl PartialOrd for AccountInfo {
57    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
58        Some(self.cmp(other))
59    }
60}
61
62impl Ord for AccountInfo {
63    fn cmp(&self, other: &Self) -> Ordering {
64        self.balance
65            .cmp(&other.balance)
66            .then_with(|| self.nonce.cmp(&other.nonce))
67            .then_with(|| self.code_hash.cmp(&other.code_hash))
68    }
69}
70
71impl AccountInfo {
72    /// Creates a new [`AccountInfo`] with the given fields.
73    #[inline]
74    pub fn new(balance: U256, nonce: u64, code_hash: B256, code: Bytecode) -> Self {
75        Self {
76            balance,
77            nonce,
78            code: Some(code),
79            code_hash,
80        }
81    }
82
83    /// Creates a new [`AccountInfo`] with the given code.
84    ///
85    /// # Note
86    ///
87    /// As code hash is calculated with [`Bytecode::hash_slow`] there will be performance penalty if used frequently.
88    pub fn with_code(self, code: Bytecode) -> Self {
89        Self {
90            balance: self.balance,
91            nonce: self.nonce,
92            code_hash: code.hash_slow(),
93            code: Some(code),
94        }
95    }
96
97    /// Creates a new [`AccountInfo`] with the given code hash.
98    ///
99    /// # Note
100    ///
101    /// Resets code to `None`. Not guaranteed to maintain invariant `code` and `code_hash`. See
102    /// also [Self::with_code_and_hash].
103    pub fn with_code_hash(self, code_hash: B256) -> Self {
104        Self {
105            balance: self.balance,
106            nonce: self.nonce,
107            code_hash,
108            code: None,
109        }
110    }
111
112    /// Creates a new [`AccountInfo`] with the given code and code hash.
113    ///
114    /// # Note
115    ///
116    /// In debug mode panics if [`Bytecode::hash_slow`] called on `code` is not equivalent to
117    /// `code_hash`. See also [`Self::with_code`].
118    pub fn with_code_and_hash(self, code: Bytecode, code_hash: B256) -> Self {
119        debug_assert_eq!(code.hash_slow(), code_hash);
120        Self {
121            balance: self.balance,
122            nonce: self.nonce,
123            code_hash,
124            code: Some(code),
125        }
126    }
127
128    /// Creates a new [`AccountInfo`] with the given balance.
129    pub fn with_balance(mut self, balance: U256) -> Self {
130        self.balance = balance;
131        self
132    }
133
134    /// Creates a new [`AccountInfo`] with the given nonce.
135    pub fn with_nonce(mut self, nonce: u64) -> Self {
136        self.nonce = nonce;
137        self
138    }
139
140    /// Sets the [`AccountInfo`] `balance`.
141    #[inline]
142    pub fn set_balance(&mut self, balance: U256) -> &mut Self {
143        self.balance = balance;
144        self
145    }
146
147    /// Sets the [`AccountInfo`] `nonce`.
148    #[inline]
149    pub fn set_nonce(&mut self, nonce: u64) -> &mut Self {
150        self.nonce = nonce;
151        self
152    }
153
154    /// Sets the [`AccountInfo`] `code_hash` and clears any cached bytecode.
155    ///
156    /// # Note
157    ///
158    /// Calling this after `set_code(...)` will remove the bytecode you just set.
159    /// If you intend to mutate the code, use only `set_code`.
160    #[inline]
161    pub fn set_code_hash(&mut self, code_hash: B256) -> &mut Self {
162        self.code = None;
163        self.code_hash = code_hash;
164        self
165    }
166
167    /// Replaces the [`AccountInfo`] bytecode and recalculates `code_hash`.
168    ///
169    /// # Note
170    ///
171    /// As code hash is calculated with [`Bytecode::hash_slow`] there will be performance penalty if used frequently.
172    #[inline]
173    pub fn set_code(&mut self, code: Bytecode) -> &mut Self {
174        self.code_hash = code.hash_slow();
175        self.code = Some(code);
176        self
177    }
178    /// Sets the bytecode and its hash.
179    ///
180    /// # Note
181    ///
182    /// It is on the caller's responsibility to ensure that the bytecode hash is correct.
183    pub fn set_code_and_hash(&mut self, code: Bytecode, code_hash: B256) {
184        self.code_hash = code_hash;
185        self.code = Some(code);
186    }
187    /// Returns a copy of this account with the [`Bytecode`] removed.
188    ///
189    /// This is useful when creating journals or snapshots of the state, where it is
190    /// desirable to store the code blobs elsewhere.
191    ///
192    /// ## Note
193    ///
194    /// This is distinct from [`without_code`][Self::without_code] in that it returns
195    /// a new [`AccountInfo`] instance with the code removed.
196    ///
197    /// [`without_code`][Self::without_code] will modify and return the same instance.
198    #[inline]
199    pub fn copy_without_code(&self) -> Self {
200        Self {
201            balance: self.balance,
202            nonce: self.nonce,
203            code_hash: self.code_hash,
204            code: None,
205        }
206    }
207
208    /// Strips the [`Bytecode`] from this account and drop it.
209    ///
210    /// This is useful when creating journals or snapshots of the state, where it is
211    /// desirable to store the code blobs elsewhere.
212    ///
213    /// ## Note
214    ///
215    /// This is distinct from [`copy_without_code`][Self::copy_without_code] in that it
216    /// modifies the account in place.
217    ///
218    /// [`copy_without_code`][Self::copy_without_code]
219    /// will copy the non-code fields and return a new [`AccountInfo`] instance.
220    pub fn without_code(mut self) -> Self {
221        self.take_bytecode();
222        self
223    }
224
225    /// Returns if an account is empty.
226    ///
227    /// An account is empty if the following conditions are met.
228    /// - code hash is zero or set to the Keccak256 hash of the empty string `""`
229    /// - balance is zero
230    /// - nonce is zero
231    #[inline]
232    pub fn is_empty(&self) -> bool {
233        let code_empty = self.is_empty_code_hash() || self.code_hash.is_zero();
234        code_empty && self.balance.is_zero() && self.nonce == 0
235    }
236
237    /// Returns `true` if the account is not empty.
238    #[inline]
239    pub fn exists(&self) -> bool {
240        !self.is_empty()
241    }
242
243    /// Returns `true` if account has no nonce and code.
244    #[inline]
245    pub fn has_no_code_and_nonce(&self) -> bool {
246        self.is_empty_code_hash() && self.nonce == 0
247    }
248
249    /// Returns bytecode hash associated with this account.
250    ///
251    /// If account does not have code, it returns `KECCAK_EMPTY` hash.
252    #[inline]
253    pub fn code_hash(&self) -> B256 {
254        self.code_hash
255    }
256
257    /// Returns true if the code hash is the Keccak256 hash of the empty string `""`.
258    #[inline]
259    pub fn is_empty_code_hash(&self) -> bool {
260        self.code_hash == KECCAK_EMPTY
261    }
262
263    /// Takes bytecode from account.
264    ///
265    /// Code will be set to [None].
266    #[inline]
267    pub fn take_bytecode(&mut self) -> Option<Bytecode> {
268        self.code.take()
269    }
270
271    /// Initializes an [`AccountInfo`] with the given balance, setting all other fields to their
272    /// default values.
273    #[inline]
274    pub fn from_balance(balance: U256) -> Self {
275        AccountInfo {
276            balance,
277            ..Default::default()
278        }
279    }
280
281    /// Initializes an [`AccountInfo`] with the given bytecode, setting its balance to zero, its
282    /// nonce to `1`, and calculating the code hash from the given bytecode.
283    #[inline]
284    pub fn from_bytecode(bytecode: Bytecode) -> Self {
285        let hash = bytecode.hash_slow();
286
287        AccountInfo {
288            balance: U256::ZERO,
289            nonce: 1,
290            code: Some(bytecode),
291            code_hash: hash,
292        }
293    }
294}
295
296#[cfg(test)]
297mod tests {
298    use crate::AccountInfo;
299    use bytecode::Bytecode;
300    use core::cmp::Ordering;
301    use primitives::{KECCAK_EMPTY, U256};
302    use std::collections::BTreeSet;
303
304    #[test]
305    fn test_account_info_trait_consistency() {
306        let bytecode = Bytecode::default();
307        let account1 = AccountInfo {
308            balance: U256::ZERO,
309            nonce: 0,
310            code_hash: KECCAK_EMPTY,
311            code: Some(bytecode.clone()),
312        };
313
314        let account2 = AccountInfo {
315            balance: U256::ZERO,
316            nonce: 0,
317            code_hash: KECCAK_EMPTY,
318            code: None,
319        };
320
321        assert_eq!(account1, account2, "Accounts should be equal ignoring code");
322
323        assert_eq!(
324            account1.cmp(&account2),
325            Ordering::Equal,
326            "Ordering should be equal after ignoring code in Ord"
327        );
328
329        let mut set = BTreeSet::new();
330        assert!(set.insert(account1.clone()), "Inserted account1");
331        assert!(
332            !set.insert(account2.clone()),
333            "account2 not inserted (treated as duplicate)"
334        );
335
336        assert_eq!(set.len(), 1, "Set should have only one unique account");
337        assert!(set.contains(&account1), "Set contains account1");
338        assert!(
339            set.contains(&account2),
340            "Set contains account2 (since equal)"
341        );
342
343        let mut accounts = vec![account2.clone(), account1.clone()];
344        accounts.sort();
345        assert_eq!(accounts[0], accounts[1], "Sorted vec treats them as equal");
346    }
347}