revm_context_interface/journaled_state/
account.rs

1//! This module contains [`JournaledAccount`] struct a wrapper around account and journal entries that
2//! allow updates to the account and journal entries.
3//!
4//! Useful to encapsulate account and journal entries together. So when account gets changed, we can add a journal entry for it.
5
6use super::entry::JournalEntryTr;
7use core::ops::Deref;
8use primitives::{Address, B256, KECCAK_EMPTY, U256};
9use state::{Account, Bytecode};
10use std::vec::Vec;
11
12/// Journaled account contains both mutable account and journal entries.
13///
14/// Useful to encapsulate account and journal entries together. So when account gets changed, we can add a journal entry for it.
15#[derive(Debug, PartialEq, Eq)]
16pub struct JournaledAccount<'a, ENTRY: JournalEntryTr> {
17    /// Address of the account.
18    address: Address,
19    /// Mutable account.
20    account: &'a mut Account,
21    /// Journal entries.
22    journal_entries: &'a mut Vec<ENTRY>,
23}
24
25impl<'a, ENTRY: JournalEntryTr> JournaledAccount<'a, ENTRY> {
26    /// Consumes the journaled account and returns the mutable account.
27    #[inline]
28    pub fn into_account_ref(self) -> &'a Account {
29        self.account
30    }
31
32    /// Creates a new journaled account.
33    #[inline]
34    pub fn new(
35        address: Address,
36        account: &'a mut Account,
37        journal_entries: &'a mut Vec<ENTRY>,
38    ) -> Self {
39        Self {
40            address,
41            account,
42            journal_entries,
43        }
44    }
45
46    /// Returns the balance of the account.
47    #[inline]
48    pub fn balance(&self) -> &U256 {
49        &self.account.info.balance
50    }
51
52    /// Returns the nonce of the account.
53    #[inline]
54    pub fn nonce(&self) -> u64 {
55        self.account.info.nonce
56    }
57
58    /// Returns the code hash of the account.
59    #[inline]
60    pub fn code_hash(&self) -> &B256 {
61        &self.account.info.code_hash
62    }
63
64    /// Returns the code of the account.
65    #[inline]
66    pub fn code(&self) -> Option<&Bytecode> {
67        self.account.info.code.as_ref()
68    }
69
70    /// Touches the account.
71    #[inline]
72    pub fn touch(&mut self) {
73        if !self.account.status.is_touched() {
74            self.account.mark_touch();
75            self.journal_entries
76                .push(ENTRY::account_touched(self.address));
77        }
78    }
79
80    /// Sets the balance of the account.
81    ///
82    /// If balance is the same, we don't add a journal entry.
83    ///
84    /// Touches the account in all cases.
85    #[inline]
86    pub fn set_balance(&mut self, balance: U256) {
87        self.touch();
88        if self.account.info.balance != balance {
89            self.journal_entries.push(ENTRY::balance_changed(
90                self.address,
91                self.account.info.balance,
92            ));
93            self.account.info.set_balance(balance);
94        }
95    }
96
97    /// Increments the balance of the account.
98    ///
99    /// Touches the account in all cases.
100    #[inline]
101    pub fn incr_balance(&mut self, balance: U256) -> bool {
102        self.touch();
103        let Some(balance) = self.account.info.balance.checked_add(balance) else {
104            return false;
105        };
106        self.set_balance(balance);
107        true
108    }
109
110    /// Decrements the balance of the account.
111    ///
112    /// Touches the account in all cases.
113    #[inline]
114    pub fn decr_balance(&mut self, balance: U256) -> bool {
115        self.touch();
116        let Some(balance) = self.account.info.balance.checked_sub(balance) else {
117            return false;
118        };
119        self.set_balance(balance);
120        true
121    }
122
123    /// Bumps the nonce of the account.
124    ///
125    /// Touches the account in all cases.
126    ///
127    /// Returns true if nonce was bumped, false if nonce is at the max value.
128    #[inline]
129    pub fn bump_nonce(&mut self) -> bool {
130        self.touch();
131        let Some(nonce) = self.account.info.nonce.checked_add(1) else {
132            return false;
133        };
134        self.account.info.set_nonce(nonce);
135        self.journal_entries
136            .push(ENTRY::nonce_changed(self.address));
137        true
138    }
139
140    /// Sets the code of the account.
141    ///
142    /// Touches the account in all cases.
143    #[inline]
144    pub fn set_code(&mut self, code_hash: B256, code: Bytecode) {
145        self.touch();
146        self.account.info.set_code_hash(code_hash);
147        self.account.info.set_code(code);
148        self.journal_entries.push(ENTRY::code_changed(self.address));
149    }
150
151    /// Sets the code of the account. Calculates hash of the code.
152    ///
153    /// Touches the account in all cases.
154    #[inline]
155    pub fn set_code_and_hash_slow(&mut self, code: Bytecode) {
156        let code_hash = code.hash_slow();
157        self.set_code(code_hash, code);
158    }
159
160    /// Delegates the account to another address (EIP-7702).
161    ///
162    /// This touches the account, sets the code to the delegation designation,
163    /// and bumps the nonce.
164    #[inline]
165    pub fn delegate(&mut self, address: Address) {
166        let (bytecode, hash) = if address.is_zero() {
167            (Bytecode::default(), KECCAK_EMPTY)
168        } else {
169            let bytecode = Bytecode::new_eip7702(address);
170            let hash = bytecode.hash_slow();
171            (bytecode, hash)
172        };
173        self.touch();
174        self.set_code(hash, bytecode);
175        self.bump_nonce();
176    }
177}
178
179impl<'a, ENTRY: JournalEntryTr> Deref for JournaledAccount<'a, ENTRY> {
180    type Target = Account;
181
182    fn deref(&self) -> &Self::Target {
183        self.account
184    }
185}