alloy_evm/
traits.rs

1//! EVM traits.
2
3use crate::Database;
4use alloc::boxed::Box;
5use alloy_primitives::{Address, Log, B256, U256};
6use core::{error::Error, fmt, fmt::Debug};
7use revm::{
8    context::{journaled_state::TransferError, Block, DBErrorMarker, JournalTr},
9    interpreter::{SStoreResult, StateLoad},
10    primitives::{StorageKey, StorageValue},
11    state::{Account, AccountInfo, Bytecode},
12};
13
14/// Erased error type.
15#[derive(thiserror::Error, Debug)]
16#[error(transparent)]
17pub struct ErasedError(Box<dyn Error + Send + Sync + 'static>);
18
19impl ErasedError {
20    /// Creates a new [`ErasedError`].
21    pub fn new(error: impl Error + Send + Sync + 'static) -> Self {
22        Self(Box::new(error))
23    }
24}
25
26impl DBErrorMarker for ErasedError {}
27
28/// Errors returned by [`EvmInternals`].
29#[derive(Debug, thiserror::Error)]
30pub enum EvmInternalsError {
31    /// Database error.
32    #[error(transparent)]
33    Database(ErasedError),
34}
35
36impl EvmInternalsError {
37    /// Creates a new [`EvmInternalsError::Database`]
38    pub fn database(err: impl Error + Send + Sync + 'static) -> Self {
39        Self::Database(ErasedError::new(err))
40    }
41}
42
43/// dyn-compatible trait for accessing and modifying EVM internals, particularly the journal.
44///
45/// This trait provides an abstraction over journal operations without exposing
46/// associated types, making it object-safe and suitable for dynamic dispatch.
47trait EvmInternalsTr: Database<Error = ErasedError> + Debug {
48    fn load_account(&mut self, address: Address) -> Result<StateLoad<&Account>, EvmInternalsError>;
49
50    fn load_account_code(
51        &mut self,
52        address: Address,
53    ) -> Result<StateLoad<&Account>, EvmInternalsError>;
54
55    /// Increments the balance of the account.
56    fn balance_incr(&mut self, address: Address, balance: U256) -> Result<(), EvmInternalsError>;
57
58    /// Sets the balance of the the account
59    ///
60    /// Touches the account in all cases.
61    ///
62    /// If the given `balance` is the same as the account's, no journal entry is created.
63    fn set_balance(&mut self, address: Address, balance: U256) -> Result<(), EvmInternalsError>;
64
65    /// Transfers the balance from one account to another.
66    ///
67    /// This will load both accounts
68    fn transfer(
69        &mut self,
70        from: Address,
71        to: Address,
72        balance: U256,
73    ) -> Result<Option<TransferError>, EvmInternalsError>;
74
75    /// Increments the nonce of the account.
76    ///
77    /// This creates a new journal entry with this change.
78    fn bump_nonce(&mut self, address: Address) -> Result<(), EvmInternalsError>;
79
80    fn sload(
81        &mut self,
82        address: Address,
83        key: StorageKey,
84    ) -> Result<StateLoad<StorageValue>, EvmInternalsError>;
85
86    fn touch_account(&mut self, address: Address);
87
88    fn set_code(&mut self, address: Address, code: Bytecode);
89
90    /// Sets bytecode with hash. Assume that account is warm.
91    fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256);
92
93    fn sstore(
94        &mut self,
95        address: Address,
96        key: StorageKey,
97        value: StorageValue,
98    ) -> Result<StateLoad<SStoreResult>, EvmInternalsError>;
99
100    fn log(&mut self, log: Log);
101
102    fn tload(&mut self, address: Address, key: StorageKey) -> StorageValue;
103
104    fn tstore(&mut self, address: Address, key: StorageKey, value: StorageValue);
105}
106
107/// Helper internal struct for implementing [`EvmInternals`].
108#[derive(Debug)]
109struct EvmInternalsImpl<'a, T>(&'a mut T);
110
111impl<T> revm::Database for EvmInternalsImpl<'_, T>
112where
113    T: JournalTr<Database: Database>,
114{
115    type Error = ErasedError;
116
117    fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
118        self.0.db_mut().basic(address).map_err(ErasedError::new)
119    }
120
121    fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
122        self.0.db_mut().code_by_hash(code_hash).map_err(ErasedError::new)
123    }
124
125    fn storage(
126        &mut self,
127        address: Address,
128        index: StorageKey,
129    ) -> Result<StorageValue, Self::Error> {
130        self.0.db_mut().storage(address, index).map_err(ErasedError::new)
131    }
132
133    fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
134        self.0.db_mut().block_hash(number).map_err(ErasedError::new)
135    }
136}
137
138impl<T> EvmInternalsTr for EvmInternalsImpl<'_, T>
139where
140    T: JournalTr<Database: Database> + Debug,
141{
142    fn load_account(&mut self, address: Address) -> Result<StateLoad<&Account>, EvmInternalsError> {
143        self.0.load_account(address).map_err(EvmInternalsError::database)
144    }
145
146    fn load_account_code(
147        &mut self,
148        address: Address,
149    ) -> Result<StateLoad<&Account>, EvmInternalsError> {
150        self.0.load_account_with_code(address).map_err(EvmInternalsError::database)
151    }
152
153    fn balance_incr(&mut self, address: Address, balance: U256) -> Result<(), EvmInternalsError> {
154        self.0.balance_incr(address, balance).map_err(EvmInternalsError::database)
155    }
156
157    fn set_balance(&mut self, address: Address, balance: U256) -> Result<(), EvmInternalsError> {
158        let mut account = self.0.load_account_mut(address).map_err(EvmInternalsError::database)?;
159        account.set_balance(balance);
160        Ok(())
161    }
162
163    fn transfer(
164        &mut self,
165        from: Address,
166        to: Address,
167        balance: U256,
168    ) -> Result<Option<TransferError>, EvmInternalsError> {
169        self.0.transfer(from, to, balance).map_err(EvmInternalsError::database)
170    }
171
172    fn bump_nonce(&mut self, address: Address) -> Result<(), EvmInternalsError> {
173        self.0.load_account_mut(address).map_err(EvmInternalsError::database)?.bump_nonce();
174        Ok(())
175    }
176
177    fn sload(
178        &mut self,
179        address: Address,
180        key: StorageKey,
181    ) -> Result<StateLoad<StorageValue>, EvmInternalsError> {
182        self.0.sload(address, key).map_err(EvmInternalsError::database)
183    }
184
185    fn touch_account(&mut self, address: Address) {
186        self.0.touch_account(address);
187    }
188
189    fn set_code(&mut self, address: Address, code: Bytecode) {
190        self.0.set_code(address, code);
191    }
192
193    fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256) {
194        self.0.set_code_with_hash(address, code, hash);
195    }
196
197    fn sstore(
198        &mut self,
199        address: Address,
200        key: StorageKey,
201        value: StorageValue,
202    ) -> Result<StateLoad<SStoreResult>, EvmInternalsError> {
203        self.0.sstore(address, key, value).map_err(EvmInternalsError::database)
204    }
205
206    fn log(&mut self, log: Log) {
207        self.0.log(log);
208    }
209
210    fn tload(&mut self, address: Address, key: StorageKey) -> StorageValue {
211        self.0.tload(address, key)
212    }
213
214    fn tstore(&mut self, address: Address, key: StorageKey, value: StorageValue) {
215        self.0.tstore(address, key, value);
216    }
217}
218
219/// Helper type exposing hooks into EVM and access to evm internal settings.
220pub struct EvmInternals<'a> {
221    internals: Box<dyn EvmInternalsTr + 'a>,
222    block_env: &'a (dyn Block + 'a),
223}
224
225impl<'a> EvmInternals<'a> {
226    /// Creates a new [`EvmInternals`] instance.
227    pub fn new<T>(journal: &'a mut T, block_env: &'a dyn Block) -> Self
228    where
229        T: JournalTr<Database: Database> + Debug,
230    {
231        Self { internals: Box::new(EvmInternalsImpl(journal)), block_env }
232    }
233
234    /// Returns the  evm's block information.
235    pub const fn block_env(&self) -> impl Block + 'a {
236        self.block_env
237    }
238
239    /// Returns the current block number.
240    pub fn block_number(&self) -> U256 {
241        self.block_env.number()
242    }
243
244    /// Returns the current block timestamp.
245    pub fn block_timestamp(&self) -> U256 {
246        self.block_env.timestamp()
247    }
248
249    /// Returns a mutable reference to [`Database`] implementation with erased error type.
250    ///
251    /// Users should prefer using other methods for accessing state that rely on cached state in the
252    /// journal instead.
253    pub fn db_mut(&mut self) -> impl Database<Error = ErasedError> + '_ {
254        &mut *self.internals
255    }
256
257    /// Loads an account.
258    pub fn load_account(
259        &mut self,
260        address: Address,
261    ) -> Result<StateLoad<&Account>, EvmInternalsError> {
262        self.internals.load_account(address)
263    }
264
265    /// Loads an account AND it's code.
266    pub fn load_account_code(
267        &mut self,
268        address: Address,
269    ) -> Result<StateLoad<&Account>, EvmInternalsError> {
270        self.internals.load_account_code(address)
271    }
272
273    /// Increments the balance of the account.
274    pub fn balance_incr(
275        &mut self,
276        address: Address,
277        balance: U256,
278    ) -> Result<(), EvmInternalsError> {
279        self.internals.balance_incr(address, balance)
280    }
281
282    /// Sets the balance of the the account
283    ///
284    /// Touches the account in all cases.
285    ///
286    /// If the given `balance` is the same as the account's, no journal entry is created.
287    pub fn set_balance(
288        &mut self,
289        address: Address,
290        balance: U256,
291    ) -> Result<(), EvmInternalsError> {
292        self.internals.set_balance(address, balance)
293    }
294
295    /// Transfers the balance from one account to another.
296    ///
297    /// This will load both accounts and return an error if the transfer fails.
298    pub fn transfer(
299        &mut self,
300        from: Address,
301        to: Address,
302        balance: U256,
303    ) -> Result<Option<TransferError>, EvmInternalsError> {
304        self.internals.transfer(from, to, balance)
305    }
306
307    /// Increments the nonce of the account.
308    ///
309    /// This creates a new journal entry with this change.
310    pub fn bump_nonce(&mut self, address: Address) -> Result<(), EvmInternalsError> {
311        self.internals.bump_nonce(address)
312    }
313
314    /// Loads a storage slot.
315    pub fn sload(
316        &mut self,
317        address: Address,
318        key: StorageKey,
319    ) -> Result<StateLoad<StorageValue>, EvmInternalsError> {
320        self.internals.sload(address, key)
321    }
322
323    /// Touches the account.
324    pub fn touch_account(&mut self, address: Address) {
325        self.internals.touch_account(address);
326    }
327
328    /// Sets bytecode to the account.
329    pub fn set_code(&mut self, address: Address, code: Bytecode) {
330        self.internals.set_code(address, code);
331    }
332
333    /// Sets bytecode with hash to the account.
334    ///
335    /// Assumes that the account is warm.
336    pub fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256) {
337        self.internals.set_code_with_hash(address, code, hash);
338    }
339
340    /// Stores the storage value in Journal state.
341    pub fn sstore(
342        &mut self,
343        address: Address,
344        key: StorageKey,
345        value: StorageValue,
346    ) -> Result<StateLoad<SStoreResult>, EvmInternalsError> {
347        self.internals.sstore(address, key, value)
348    }
349
350    /// Logs the log in Journal state.
351    pub fn log(&mut self, log: Log) {
352        self.internals.log(log);
353    }
354
355    /// Loads a transient storage value.
356    pub fn tload(&mut self, address: Address, key: StorageKey) -> StorageValue {
357        self.internals.tload(address, key)
358    }
359
360    /// Stores a transient storage value.
361    pub fn tstore(&mut self, address: Address, key: StorageKey, value: StorageValue) {
362        self.internals.tstore(address, key, value);
363    }
364}
365
366impl<'a> fmt::Debug for EvmInternals<'a> {
367    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
368        f.debug_struct("EvmInternals")
369            .field("internals", &self.internals)
370            .field("block_env", &"{{}}")
371            .finish_non_exhaustive()
372    }
373}