revm_state/
account_info.rs1use bytecode::Bytecode;
2use core::{
3 cmp::Ordering,
4 hash::{Hash, Hasher},
5};
6use primitives::{B256, KECCAK_EMPTY, U256};
7
8use nonmax::NonMaxU32;
9
10#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13pub struct AccountId(NonMaxU32);
14
15impl AccountId {
16 #[inline]
20 pub fn new(id: usize) -> Option<Self> {
21 let id = u32::try_from(id).ok()?;
22 NonMaxU32::new(id).map(Self)
23 }
24
25 #[inline]
27 pub const fn get(self) -> usize {
28 self.0.get() as usize
29 }
30}
31
32#[derive(Clone, Debug, Eq)]
36#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
37pub struct AccountInfo {
38 pub balance: U256,
40 pub nonce: u64,
42 pub code_hash: B256,
44 #[cfg_attr(feature = "serde", serde(skip))]
49 pub account_id: Option<AccountId>,
50 pub code: Option<Bytecode>,
57}
58
59impl Default for AccountInfo {
60 #[inline]
61 fn default() -> Self {
62 Self {
63 balance: U256::ZERO,
64 code_hash: KECCAK_EMPTY,
65 account_id: None,
66 nonce: 0,
67 code: Some(Bytecode::default()),
68 }
69 }
70}
71
72impl PartialEq for AccountInfo {
73 #[inline]
74 fn eq(&self, other: &Self) -> bool {
75 self.balance == other.balance
76 && self.nonce == other.nonce
77 && self.code_hash == other.code_hash
78 }
79}
80
81impl Hash for AccountInfo {
82 #[inline]
83 fn hash<H: Hasher>(&self, state: &mut H) {
84 self.balance.hash(state);
85 self.nonce.hash(state);
86 self.code_hash.hash(state);
87 }
88}
89
90impl PartialOrd for AccountInfo {
91 #[inline]
92 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
93 Some(self.cmp(other))
94 }
95}
96
97impl Ord for AccountInfo {
98 #[inline]
99 fn cmp(&self, other: &Self) -> Ordering {
100 self.balance
101 .cmp(&other.balance)
102 .then_with(|| self.nonce.cmp(&other.nonce))
103 .then_with(|| self.code_hash.cmp(&other.code_hash))
104 }
105}
106
107impl AccountInfo {
108 #[inline]
110 pub const fn new(balance: U256, nonce: u64, code_hash: B256, code: Bytecode) -> Self {
111 Self {
112 balance,
113 nonce,
114 code: Some(code),
115 code_hash,
116 account_id: None,
117 }
118 }
119
120 #[inline]
126 pub fn with_code(self, code: Bytecode) -> Self {
127 Self {
128 code_hash: code.hash_slow(),
129 code: Some(code),
130 ..self
131 }
132 }
133
134 #[inline]
141 pub fn with_code_hash(self, code_hash: B256) -> Self {
142 Self {
143 code_hash,
144 code: None,
145 ..self
146 }
147 }
148
149 #[inline]
156 pub fn with_code_and_hash(self, code: Bytecode, code_hash: B256) -> Self {
157 debug_assert_eq!(code.hash_slow(), code_hash);
158 Self {
159 code_hash,
160 code: Some(code),
161 ..self
162 }
163 }
164
165 #[inline]
167 pub const fn with_balance(mut self, balance: U256) -> Self {
168 self.balance = balance;
169 self
170 }
171
172 #[inline]
174 pub const fn with_nonce(mut self, nonce: u64) -> Self {
175 self.nonce = nonce;
176 self
177 }
178
179 #[inline]
181 pub const fn set_balance(&mut self, balance: U256) -> &mut Self {
182 self.balance = balance;
183 self
184 }
185
186 #[inline]
188 pub const fn set_nonce(&mut self, nonce: u64) -> &mut Self {
189 self.nonce = nonce;
190 self
191 }
192
193 #[inline]
200 pub fn set_code_hash(&mut self, code_hash: B256) -> &mut Self {
201 self.code = None;
202 self.code_hash = code_hash;
203 self
204 }
205
206 #[inline]
212 pub fn set_code(&mut self, code: Bytecode) -> &mut Self {
213 self.code_hash = code.hash_slow();
214 self.code = Some(code);
215 self
216 }
217 pub fn set_code_and_hash(&mut self, code: Bytecode, code_hash: B256) {
223 self.code_hash = code_hash;
224 self.code = Some(code);
225 }
226 #[inline]
238 pub const fn copy_without_code(&self) -> Self {
239 Self {
240 balance: self.balance,
241 nonce: self.nonce,
242 code_hash: self.code_hash,
243 account_id: self.account_id,
244 code: None,
245 }
246 }
247
248 #[inline]
261 pub fn without_code(mut self) -> Self {
262 self.take_bytecode();
263 self
264 }
265
266 #[inline]
273 pub fn is_empty(&self) -> bool {
274 let code_empty = self.is_empty_code_hash() || self.code_hash.is_zero();
275 code_empty && self.balance.is_zero() && self.nonce == 0
276 }
277
278 #[inline]
280 pub(crate) fn is_default(&self) -> bool {
281 self.is_empty() && self.code.as_ref().is_some_and(Bytecode::is_default)
282 }
283
284 #[inline]
286 pub fn exists(&self) -> bool {
287 !self.is_empty()
288 }
289
290 #[inline]
292 pub fn has_no_code_and_nonce(&self) -> bool {
293 self.is_empty_code_hash() && self.nonce == 0
294 }
295
296 #[inline]
300 pub const fn code_hash(&self) -> B256 {
301 self.code_hash
302 }
303
304 #[inline]
306 pub fn is_empty_code_hash(&self) -> bool {
307 self.code_hash == KECCAK_EMPTY
308 }
309
310 #[inline]
314 pub const fn take_bytecode(&mut self) -> Option<Bytecode> {
315 self.code.take()
316 }
317
318 #[inline]
321 pub fn from_balance(balance: U256) -> Self {
322 AccountInfo {
323 balance,
324 ..Default::default()
325 }
326 }
327
328 #[inline]
331 pub fn from_bytecode(bytecode: Bytecode) -> Self {
332 let hash = bytecode.hash_slow();
333
334 AccountInfo {
335 balance: U256::ZERO,
336 nonce: 1,
337 code: Some(bytecode),
338 code_hash: hash,
339 account_id: None,
340 }
341 }
342}
343
344#[cfg(test)]
345mod tests {
346 use super::*;
347 use std::collections::BTreeSet;
348
349 #[test]
350 fn test_account_info_trait_consistency() {
351 let bytecode = Bytecode::default();
352 let account1 = AccountInfo {
353 code: Some(bytecode),
354 ..AccountInfo::default()
355 };
356
357 let account2 = AccountInfo::default();
358
359 assert_eq!(account1, account2, "Accounts should be equal ignoring code");
360
361 assert_eq!(
362 account1.cmp(&account2),
363 Ordering::Equal,
364 "Ordering should be equal after ignoring code in Ord"
365 );
366
367 #[expect(clippy::mutable_key_type)] let mut set = BTreeSet::new();
369 assert!(set.insert(account1.clone()), "Inserted account1");
370 assert!(
371 !set.insert(account2.clone()),
372 "account2 not inserted (treated as duplicate)"
373 );
374
375 assert_eq!(set.len(), 1, "Set should have only one unique account");
376 assert!(set.contains(&account1), "Set contains account1");
377 assert!(
378 set.contains(&account2),
379 "Set contains account2 (since equal)"
380 );
381
382 let mut accounts = [account2, account1];
383 accounts.sort();
384 assert_eq!(accounts[0], accounts[1], "Sorted vec treats them as equal");
385 }
386
387 #[test]
388 fn is_default() {
389 assert!(AccountInfo::default().is_default())
390 }
391
392 #[test]
393 #[cfg(feature = "serde")]
394 fn is_default_after_serde() {
395 let info = AccountInfo::default();
396 let json = serde_json::to_string(&info).unwrap();
397 let deser: AccountInfo = serde_json::from_str(&json).unwrap();
398 assert!(deser.is_default());
399 }
400}