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, HashMap, StorageKey, StorageValue, B256, U256};
12use state::{Account, AccountInfo, Bytecode};
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
30#[cfg(feature = "asyncdb")]
31pub mod async_db;
32pub mod bal;
33pub mod either;
34pub mod empty_db;
35pub mod erased_error;
36pub mod try_commit;
37
38#[cfg(feature = "asyncdb")]
39pub use async_db::{DatabaseAsync, WrapDatabaseAsync};
40pub use empty_db::{EmptyDB, EmptyDBTyped};
41pub use erased_error::ErasedError;
42pub use try_commit::{ArcUpgradeError, TryDatabaseCommit};
43
44/// Database error marker is needed to implement From conversion for Error type.
45pub trait DBErrorMarker: core::error::Error + Send + Sync + 'static {}
46
47/// Implement marker for `()`.
48impl DBErrorMarker for Infallible {}
49impl DBErrorMarker for ErasedError {}
50
51/// EVM database interface.
52#[auto_impl(&mut, Box)]
53pub trait Database {
54    /// The database error type.
55    type Error: DBErrorMarker;
56
57    /// Gets basic account information.
58    fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error>;
59
60    /// Gets account code by its hash.
61    fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error>;
62
63    /// Gets storage value of address at index.
64    fn storage(&mut self, address: Address, index: StorageKey)
65        -> Result<StorageValue, Self::Error>;
66
67    /// Gets storage value of account by its id. By default call [`Database::storage`] method.
68    ///
69    /// If basic account sets account_id inside [`AccountInfo::account_id`], evm will call this
70    /// function with that given account_id. This can be useful if IndexMap is used to get faster access to the account.
71    #[inline]
72    fn storage_by_account_id(
73        &mut self,
74        address: Address,
75        account_id: usize,
76        storage_key: StorageKey,
77    ) -> Result<StorageValue, Self::Error> {
78        let _ = account_id;
79        self.storage(address, storage_key)
80    }
81
82    /// Gets block hash by block number.
83    fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error>;
84}
85
86/// EVM database commit interface.
87#[auto_impl(&mut, Box)]
88pub trait DatabaseCommit {
89    /// Commit changes to the database.
90    fn commit(&mut self, changes: HashMap<Address, Account>);
91
92    /// Commit changes to the database with an iterator.
93    ///
94    /// Implementors of [`DatabaseCommit`] should override this method when possible for efficiency.
95    ///
96    /// Callers should prefer using [`DatabaseCommit::commit`] when they already have a [`HashMap`].
97    fn commit_iter(&mut self, changes: impl IntoIterator<Item = (Address, Account)>) {
98        let changes: HashMap<Address, Account> = changes.into_iter().collect();
99        self.commit(changes);
100    }
101}
102
103/// EVM database interface.
104///
105/// Contains the same methods as [`Database`], but with `&self` receivers instead of `&mut self`.
106///
107/// Use [`WrapDatabaseRef`] to provide [`Database`] implementation for a type
108/// that only implements this trait.
109#[auto_impl(&, &mut, Box, Rc, Arc)]
110pub trait DatabaseRef {
111    /// The database error type.
112    type Error: DBErrorMarker;
113
114    /// Gets basic account information.
115    fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error>;
116
117    /// Gets account code by its hash.
118    fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error>;
119
120    /// Gets storage value of address at index.
121    fn storage_ref(&self, address: Address, index: StorageKey)
122        -> Result<StorageValue, Self::Error>;
123
124    /// Gets storage value of account by its id.
125    ///
126    /// Default implementation is to call [`DatabaseRef::storage_ref`] method.
127    #[inline]
128    fn storage_by_account_id_ref(
129        &self,
130        address: Address,
131        account_id: usize,
132        storage_key: StorageKey,
133    ) -> Result<StorageValue, Self::Error> {
134        let _ = account_id;
135        self.storage_ref(address, storage_key)
136    }
137
138    /// Gets block hash by block number.
139    fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error>;
140}
141
142/// Wraps a [`DatabaseRef`] to provide a [`Database`] implementation.
143#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
144pub struct WrapDatabaseRef<T: DatabaseRef>(pub T);
145
146impl<F: DatabaseRef> From<F> for WrapDatabaseRef<F> {
147    #[inline]
148    fn from(f: F) -> Self {
149        WrapDatabaseRef(f)
150    }
151}
152
153impl<T: DatabaseRef> Database for WrapDatabaseRef<T> {
154    type Error = T::Error;
155
156    #[inline]
157    fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
158        self.0.basic_ref(address)
159    }
160
161    #[inline]
162    fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
163        self.0.code_by_hash_ref(code_hash)
164    }
165
166    #[inline]
167    fn storage(
168        &mut self,
169        address: Address,
170        index: StorageKey,
171    ) -> Result<StorageValue, Self::Error> {
172        self.0.storage_ref(address, index)
173    }
174
175    #[inline]
176    fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
177        self.0.block_hash_ref(number)
178    }
179}
180
181impl<T: DatabaseRef + DatabaseCommit> DatabaseCommit for WrapDatabaseRef<T> {
182    #[inline]
183    fn commit(&mut self, changes: HashMap<Address, Account>) {
184        self.0.commit(changes)
185    }
186}
187
188impl<T: DatabaseRef> DatabaseRef for WrapDatabaseRef<T> {
189    type Error = T::Error;
190
191    #[inline]
192    fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
193        self.0.basic_ref(address)
194    }
195
196    #[inline]
197    fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
198        self.0.code_by_hash_ref(code_hash)
199    }
200
201    #[inline]
202    fn storage_ref(
203        &self,
204        address: Address,
205        index: StorageKey,
206    ) -> Result<StorageValue, Self::Error> {
207        self.0.storage_ref(address, index)
208    }
209
210    #[inline]
211    fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
212        self.0.block_hash_ref(number)
213    }
214}
215
216impl<T: Database + DatabaseCommit> DatabaseCommitExt for T {
217    // default implementation
218}
219
220/// EVM database commit interface.
221pub trait DatabaseCommitExt: Database + DatabaseCommit {
222    /// Iterates over received balances and increment all account balances.
223    ///
224    /// Update will create transitions for all accounts that are updated.
225    fn increment_balances(
226        &mut self,
227        balances: impl IntoIterator<Item = (Address, u128)>,
228    ) -> Result<(), Self::Error> {
229        // Make transition and update cache state
230        let transitions = balances
231            .into_iter()
232            .map(|(address, balance)| {
233                let mut original_account = match self.basic(address)? {
234                    Some(acc_info) => Account::from(acc_info),
235                    None => Account::new_not_existing(0),
236                };
237                original_account.info.balance = original_account
238                    .info
239                    .balance
240                    .saturating_add(U256::from(balance));
241                original_account.mark_touch();
242                Ok((address, original_account))
243            })
244            // Unfortunately must collect here to short circuit on error
245            .collect::<Result<Vec<_>, _>>()?;
246
247        self.commit_iter(transitions);
248        Ok(())
249    }
250
251    /// Drains balances from given account and return those values.
252    ///
253    /// It is used for DAO hardfork state change to move values from given accounts.
254    fn drain_balances(
255        &mut self,
256        addresses: impl IntoIterator<Item = Address>,
257    ) -> Result<Vec<u128>, Self::Error> {
258        // Make transition and update cache state
259        let addresses_iter = addresses.into_iter();
260        let (lower, _) = addresses_iter.size_hint();
261        let mut transitions = Vec::with_capacity(lower);
262        let balances = addresses_iter
263            .map(|address| {
264                let mut original_account = match self.basic(address)? {
265                    Some(acc_info) => Account::from(acc_info),
266                    None => Account::new_not_existing(0),
267                };
268                let balance = core::mem::take(&mut original_account.info.balance);
269                original_account.mark_touch();
270                transitions.push((address, original_account));
271                Ok(balance.try_into().unwrap())
272            })
273            .collect::<Result<Vec<_>, _>>()?;
274
275        self.commit_iter(transitions);
276        Ok(balances)
277    }
278}