Skip to main content

revm_database_interface/
lib.rs

1//! Database interface.
2#![cfg_attr(not(test), warn(unused_crate_dependencies))]
3#![cfg_attr(not(feature = "std"), no_std)]
4
5#[cfg(not(feature = "std"))]
6extern crate alloc as std;
7
8use core::convert::Infallible;
9
10use auto_impl::auto_impl;
11use primitives::{address, Address, AddressMap, StorageKey, StorageValue, B256, U256};
12use state::{Account, AccountId, AccountInfo, Bytecode, TransactionId};
13use std::vec::Vec;
14
15/// Address with all `0xff..ff` in it. Used for testing.
16pub const FFADDRESS: Address = address!("0xffffffffffffffffffffffffffffffffffffffff");
17/// BENCH_TARGET address
18pub const BENCH_TARGET: Address = FFADDRESS;
19/// Common test balance used for benchmark addresses
20pub const TEST_BALANCE: U256 = U256::from_limbs([10_000_000_000_000_000, 0, 0, 0]);
21/// BENCH_TARGET_BALANCE balance
22pub const BENCH_TARGET_BALANCE: U256 = TEST_BALANCE;
23/// Address with all `0xee..ee` in it. Used for testing.
24pub const EEADDRESS: Address = address!("0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee");
25/// BENCH_CALLER address
26pub const BENCH_CALLER: Address = EEADDRESS;
27/// BENCH_CALLER_BALANCE balance
28pub const BENCH_CALLER_BALANCE: U256 = TEST_BALANCE;
29
30pub use primitives;
31pub use state;
32
33#[cfg(feature = "asyncdb")]
34pub mod async_db;
35pub mod bal;
36pub mod either;
37pub mod empty_db;
38pub mod erased_error;
39pub mod try_commit;
40
41#[cfg(feature = "asyncdb")]
42pub use async_db::{DatabaseAsync, WrapDatabaseAsync};
43pub use empty_db::{EmptyDB, EmptyDBTyped};
44pub use erased_error::ErasedError;
45pub use try_commit::{ArcUpgradeError, TryDatabaseCommit};
46
47/// Database error marker is needed to implement From conversion for Error type.
48pub trait DBErrorMarker: core::error::Error + Send + Sync + 'static {
49    /// Returns `true` if the error is fatal and execution cannot recover from it.
50    ///
51    /// Defaults to `true`. Implementors can override this to signal recoverable errors.
52    fn is_fatal(&self) -> bool {
53        true
54    }
55}
56
57/// Implement marker for `()`.
58impl DBErrorMarker for Infallible {}
59impl DBErrorMarker for ErasedError {}
60
61/// EVM database interface.
62#[auto_impl(&mut, Box)]
63pub trait Database {
64    /// The database error type.
65    type Error: DBErrorMarker;
66
67    /// Gets basic account information.
68    fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error>;
69
70    /// Gets account code by its hash.
71    fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error>;
72
73    /// Gets storage value of address at index.
74    fn storage(&mut self, address: Address, index: StorageKey)
75        -> Result<StorageValue, Self::Error>;
76
77    /// Gets storage value of account by its id. By default call [`Database::storage`] method.
78    ///
79    /// If basic account sets account_id inside [`AccountInfo::account_id`], evm will call this
80    /// function with that given account_id. This can be useful if IndexMap is used to get faster access to the account.
81    #[inline]
82    fn storage_by_account_id(
83        &mut self,
84        address: Address,
85        account_id: AccountId,
86        storage_key: StorageKey,
87    ) -> Result<StorageValue, Self::Error> {
88        let _ = account_id;
89        self.storage(address, storage_key)
90    }
91
92    /// Gets block hash by block number.
93    fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error>;
94}
95
96/// EVM database commit interface.
97///
98/// # Dyn Compatibility
99///
100/// This trait is dyn-compatible. The `commit_iter` method uses `&mut dyn Iterator`
101/// which allows it to be called on trait objects while remaining in the vtable.
102#[auto_impl(&mut, Box)]
103pub trait DatabaseCommit {
104    /// Commit changes to the database.
105    fn commit(&mut self, changes: AddressMap<Account>);
106
107    /// Commit changes to the database with an iterator.
108    ///
109    /// Implementors of [`DatabaseCommit`] should override this method when possible for efficiency.
110    ///
111    /// Callers should prefer using [`DatabaseCommit::commit`] when they already have a [`AddressMap`].
112    ///
113    /// # Dyn Compatibility
114    ///
115    /// This method uses `&mut dyn Iterator` to remain object-safe and callable on trait objects.
116    /// For ergonomic usage with `impl IntoIterator`, use the inherent method
117    /// `commit_from_iter` on `dyn DatabaseCommit`.
118    fn commit_iter(&mut self, changes: &mut dyn Iterator<Item = (Address, Account)>) {
119        let changes: AddressMap<Account> = changes.collect();
120        self.commit(changes);
121    }
122}
123
124/// Inherent implementation for `dyn DatabaseCommit` trait objects.
125///
126/// This provides `commit_from_iter` as an ergonomic wrapper around the trait's
127/// `commit_iter` method, accepting `impl IntoIterator` for convenience.
128impl dyn DatabaseCommit {
129    /// Commit changes to the database with an iterator.
130    ///
131    /// This is an ergonomic wrapper that accepts `impl IntoIterator` and delegates
132    /// to the trait's [`commit_iter`](DatabaseCommit::commit_iter) method.
133    #[inline]
134    pub fn commit_from_iter(&mut self, changes: impl IntoIterator<Item = (Address, Account)>) {
135        self.commit_iter(&mut changes.into_iter())
136    }
137}
138
139/// EVM database interface.
140///
141/// Contains the same methods as [`Database`], but with `&self` receivers instead of `&mut self`.
142///
143/// Use [`WrapDatabaseRef`] to provide [`Database`] implementation for a type
144/// that only implements this trait.
145#[auto_impl(&, &mut, Box, Rc, Arc)]
146pub trait DatabaseRef {
147    /// The database error type.
148    type Error: DBErrorMarker;
149
150    /// Gets basic account information.
151    fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error>;
152
153    /// Gets account code by its hash.
154    fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error>;
155
156    /// Gets storage value of address at index.
157    fn storage_ref(&self, address: Address, index: StorageKey)
158        -> Result<StorageValue, Self::Error>;
159
160    /// Gets storage value of account by its id.
161    ///
162    /// Default implementation is to call [`DatabaseRef::storage_ref`] method.
163    #[inline]
164    fn storage_by_account_id_ref(
165        &self,
166        address: Address,
167        account_id: AccountId,
168        storage_key: StorageKey,
169    ) -> Result<StorageValue, Self::Error> {
170        let _ = account_id;
171        self.storage_ref(address, storage_key)
172    }
173
174    /// Gets block hash by block number.
175    fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error>;
176}
177
178/// Wraps a [`DatabaseRef`] to provide a [`Database`] implementation.
179#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
180pub struct WrapDatabaseRef<T: DatabaseRef>(pub T);
181
182impl<F: DatabaseRef> From<F> for WrapDatabaseRef<F> {
183    #[inline]
184    fn from(f: F) -> Self {
185        WrapDatabaseRef(f)
186    }
187}
188
189impl<T: DatabaseRef> Database for WrapDatabaseRef<T> {
190    type Error = T::Error;
191
192    #[inline]
193    fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
194        self.0.basic_ref(address)
195    }
196
197    #[inline]
198    fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
199        self.0.code_by_hash_ref(code_hash)
200    }
201
202    #[inline]
203    fn storage(
204        &mut self,
205        address: Address,
206        index: StorageKey,
207    ) -> Result<StorageValue, Self::Error> {
208        self.0.storage_ref(address, index)
209    }
210
211    #[inline]
212    fn storage_by_account_id(
213        &mut self,
214        address: Address,
215        account_id: AccountId,
216        storage_key: StorageKey,
217    ) -> Result<StorageValue, Self::Error> {
218        self.0
219            .storage_by_account_id_ref(address, account_id, storage_key)
220    }
221
222    #[inline]
223    fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
224        self.0.block_hash_ref(number)
225    }
226}
227
228impl<T: DatabaseRef + DatabaseCommit> DatabaseCommit for WrapDatabaseRef<T> {
229    #[inline]
230    fn commit(&mut self, changes: AddressMap<Account>) {
231        self.0.commit(changes)
232    }
233
234    #[inline]
235    fn commit_iter(&mut self, changes: &mut dyn Iterator<Item = (Address, Account)>) {
236        self.0.commit_iter(changes)
237    }
238}
239
240impl<T: DatabaseRef> DatabaseRef for WrapDatabaseRef<T> {
241    type Error = T::Error;
242
243    #[inline]
244    fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
245        self.0.basic_ref(address)
246    }
247
248    #[inline]
249    fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
250        self.0.code_by_hash_ref(code_hash)
251    }
252
253    #[inline]
254    fn storage_ref(
255        &self,
256        address: Address,
257        index: StorageKey,
258    ) -> Result<StorageValue, Self::Error> {
259        self.0.storage_ref(address, index)
260    }
261
262    #[inline]
263    fn storage_by_account_id_ref(
264        &self,
265        address: Address,
266        account_id: AccountId,
267        storage_key: StorageKey,
268    ) -> Result<StorageValue, Self::Error> {
269        self.0
270            .storage_by_account_id_ref(address, account_id, storage_key)
271    }
272
273    #[inline]
274    fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
275        self.0.block_hash_ref(number)
276    }
277}
278
279impl<T: Database + DatabaseCommit> DatabaseCommitExt for T {
280    // default implementation
281}
282
283/// EVM database commit interface.
284pub trait DatabaseCommitExt: Database + DatabaseCommit {
285    /// Iterates over received balances and increment all account balances.
286    ///
287    /// Update will create transitions for all accounts that are updated.
288    fn increment_balances(
289        &mut self,
290        balances: impl IntoIterator<Item = (Address, u128)>,
291    ) -> Result<(), Self::Error> {
292        // Make transition and update cache state
293        let transitions = balances
294            .into_iter()
295            .map(|(address, balance)| {
296                let mut original_account = match self.basic(address)? {
297                    Some(acc_info) => Account::from(acc_info),
298                    None => Account::new_not_existing(TransactionId::ZERO),
299                };
300                original_account.info.balance = original_account
301                    .info
302                    .balance
303                    .saturating_add(U256::from(balance));
304                original_account.mark_touch();
305                Ok((address, original_account))
306            })
307            // Unfortunately must collect here to short circuit on error
308            .collect::<Result<Vec<_>, _>>()?;
309
310        self.commit_iter(&mut transitions.into_iter());
311        Ok(())
312    }
313
314    /// Drains balances from given account and return those values.
315    ///
316    /// It is used for DAO hardfork state change to move values from given accounts.
317    fn drain_balances(
318        &mut self,
319        addresses: impl IntoIterator<Item = Address>,
320    ) -> Result<Vec<u128>, Self::Error> {
321        // Make transition and update cache state
322        let addresses_iter = addresses.into_iter();
323        let (lower, _) = addresses_iter.size_hint();
324        let mut transitions = Vec::with_capacity(lower);
325        let balances = addresses_iter
326            .map(|address| {
327                let mut original_account = match self.basic(address)? {
328                    Some(acc_info) => Account::from(acc_info),
329                    None => Account::new_not_existing(TransactionId::ZERO),
330                };
331                let balance = core::mem::take(&mut original_account.info.balance);
332                original_account.mark_touch();
333                transitions.push((address, original_account));
334                Ok(balance.try_into().unwrap())
335            })
336            .collect::<Result<Vec<_>, _>>()?;
337
338        self.commit_iter(&mut transitions.into_iter());
339        Ok(balances)
340    }
341}
342
343#[cfg(test)]
344mod tests {
345    use super::*;
346
347    /// Compile-time test that DatabaseCommit is dyn-compatible.
348    /// This mirrors Foundry's approach: `struct _ObjectSafe(dyn DatabaseExt);`
349    struct _DatabaseCommitObjectSafe(dyn DatabaseCommit);
350
351    /// Test that dyn DatabaseCommit works correctly.
352    #[test]
353    fn test_dyn_database_commit() {
354        use std::collections::HashMap as StdHashMap;
355
356        struct MockDb {
357            commits: Vec<StdHashMap<Address, Account>>,
358        }
359
360        impl DatabaseCommit for MockDb {
361            fn commit(&mut self, changes: AddressMap<Account>) {
362                let std_map: StdHashMap<_, _> = changes.into_iter().collect();
363                self.commits.push(std_map);
364            }
365        }
366
367        let mut db = MockDb { commits: vec![] };
368
369        // Test commit_iter on concrete types
370        let items: Vec<(Address, Account)> = vec![];
371        db.commit_iter(&mut items.into_iter());
372        assert_eq!(db.commits.len(), 1);
373
374        // Test commit() on trait objects
375        {
376            let db_dyn: &mut dyn DatabaseCommit = &mut db;
377            db_dyn.commit(AddressMap::default());
378        }
379        assert_eq!(db.commits.len(), 2);
380
381        // Test commit_iter on trait objects (now works directly!)
382        {
383            let db_dyn: &mut dyn DatabaseCommit = &mut db;
384            let items: Vec<(Address, Account)> = vec![];
385            db_dyn.commit_iter(&mut items.into_iter());
386        }
387        assert_eq!(db.commits.len(), 3);
388
389        // Test ergonomic commit_from_iter on trait objects
390        {
391            let db_dyn: &mut dyn DatabaseCommit = &mut db;
392            db_dyn.commit_from_iter(vec![]);
393        }
394        assert_eq!(db.commits.len(), 4);
395    }
396
397    #[test]
398    fn wrappers_forward_commit_iter() {
399        #[derive(Default)]
400        struct MockDb {
401            commits: usize,
402            commit_iters: usize,
403            committed_accounts: usize,
404        }
405
406        impl DatabaseCommit for MockDb {
407            fn commit(&mut self, changes: AddressMap<Account>) {
408                self.commits += 1;
409                self.committed_accounts += changes.len();
410            }
411
412            fn commit_iter(&mut self, changes: &mut dyn Iterator<Item = (Address, Account)>) {
413                self.commit_iters += 1;
414                self.committed_accounts += changes.count();
415            }
416        }
417
418        impl DatabaseRef for MockDb {
419            type Error = Infallible;
420
421            fn basic_ref(&self, _address: Address) -> Result<Option<AccountInfo>, Self::Error> {
422                Ok(None)
423            }
424
425            fn code_by_hash_ref(&self, _code_hash: B256) -> Result<Bytecode, Self::Error> {
426                Ok(Bytecode::default())
427            }
428
429            fn storage_ref(
430                &self,
431                _address: Address,
432                _index: StorageKey,
433            ) -> Result<StorageValue, Self::Error> {
434                Ok(StorageValue::ZERO)
435            }
436
437            fn block_hash_ref(&self, _number: u64) -> Result<B256, Self::Error> {
438                Ok(B256::ZERO)
439            }
440        }
441
442        fn changes() -> Vec<(Address, Account)> {
443            vec![(Address::with_last_byte(1), Account::default())]
444        }
445
446        let mut db = WrapDatabaseRef(MockDb::default());
447        db.commit_iter(&mut changes().into_iter());
448        assert_eq!(db.0.commits, 0);
449        assert_eq!(db.0.commit_iters, 1);
450        assert_eq!(db.0.committed_accounts, 1);
451
452        let mut db: ::either::Either<MockDb, MockDb> = ::either::Either::Left(MockDb::default());
453        db.commit_iter(&mut changes().into_iter());
454        let ::either::Either::Left(db) = db else {
455            unreachable!()
456        };
457        assert_eq!(db.commits, 0);
458        assert_eq!(db.commit_iters, 1);
459        assert_eq!(db.committed_accounts, 1);
460
461        let address = Address::with_last_byte(2);
462        let mut account = Account::default();
463        account.mark_touch();
464
465        let mut db = bal::BalDatabase::new(MockDb::default()).with_bal_builder();
466        db.commit_iter(&mut [(address, account)].into_iter());
467        assert_eq!(db.db.commits, 0);
468        assert_eq!(db.db.commit_iters, 1);
469        assert_eq!(db.db.committed_accounts, 1);
470
471        let bal = db.bal_state.take_built_bal().expect("BAL should be built");
472        assert!(bal.accounts.get(&address).is_some());
473    }
474}