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};
13
14/// Address with all `0xff..ff` in it. Used for testing.
15pub const FFADDRESS: Address = address!("0xffffffffffffffffffffffffffffffffffffffff");
16/// BENCH_TARGET address
17pub const BENCH_TARGET: Address = FFADDRESS;
18/// Common test balance used for benchmark addresses
19pub const TEST_BALANCE: U256 = U256::from_limbs([10_000_000_000_000_000, 0, 0, 0]);
20/// BENCH_TARGET_BALANCE balance
21pub const BENCH_TARGET_BALANCE: U256 = TEST_BALANCE;
22/// Address with all `0xee..ee` in it. Used for testing.
23pub const EEADDRESS: Address = address!("0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee");
24/// BENCH_CALLER address
25pub const BENCH_CALLER: Address = EEADDRESS;
26/// BENCH_CALLER_BALANCE balance
27pub const BENCH_CALLER_BALANCE: U256 = TEST_BALANCE;
28
29#[cfg(feature = "asyncdb")]
30pub mod async_db;
31pub mod either;
32pub mod empty_db;
33pub mod erased_error;
34pub mod try_commit;
35
36#[cfg(feature = "asyncdb")]
37pub use async_db::{DatabaseAsync, WrapDatabaseAsync};
38pub use empty_db::{EmptyDB, EmptyDBTyped};
39pub use erased_error::ErasedError;
40pub use try_commit::{ArcUpgradeError, TryDatabaseCommit};
41
42/// Database error marker is needed to implement From conversion for Error type.
43pub trait DBErrorMarker: core::error::Error + Send + Sync + 'static {}
44
45/// Implement marker for `()`.
46impl DBErrorMarker for Infallible {}
47impl DBErrorMarker for ErasedError {}
48
49/// EVM database interface.
50#[auto_impl(&mut, Box)]
51pub trait Database {
52    /// The database error type.
53    type Error: DBErrorMarker;
54
55    /// Gets basic account information.
56    fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error>;
57
58    /// Gets account code by its hash.
59    fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error>;
60
61    /// Gets storage value of address at index.
62    fn storage(&mut self, address: Address, index: StorageKey)
63        -> Result<StorageValue, Self::Error>;
64
65    /// Gets block hash by block number.
66    fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error>;
67}
68
69/// EVM database commit interface.
70#[auto_impl(&mut, Box)]
71pub trait DatabaseCommit {
72    /// Commit changes to the database.
73    fn commit(&mut self, changes: HashMap<Address, Account>);
74
75    /// Commit changes to the database with an iterator.
76    ///
77    /// Implementors of [`DatabaseCommit`] should override this method when possible for efficiency.
78    ///
79    /// Callers should prefer using [`DatabaseCommit::commit`] when they already have a [`HashMap`].
80    fn commit_iter(&mut self, changes: impl IntoIterator<Item = (Address, Account)>) {
81        let changes: HashMap<Address, Account> = changes.into_iter().collect();
82        self.commit(changes);
83    }
84}
85
86/// EVM database interface.
87///
88/// Contains the same methods as [`Database`], but with `&self` receivers instead of `&mut self`.
89///
90/// Use [`WrapDatabaseRef`] to provide [`Database`] implementation for a type
91/// that only implements this trait.
92#[auto_impl(&, &mut, Box, Rc, Arc)]
93pub trait DatabaseRef {
94    /// The database error type.
95    type Error: DBErrorMarker;
96
97    /// Gets basic account information.
98    fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error>;
99
100    /// Gets account code by its hash.
101    fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error>;
102
103    /// Gets storage value of address at index.
104    fn storage_ref(&self, address: Address, index: StorageKey)
105        -> Result<StorageValue, Self::Error>;
106
107    /// Gets block hash by block number.
108    fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error>;
109}
110
111/// Wraps a [`DatabaseRef`] to provide a [`Database`] implementation.
112#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
113pub struct WrapDatabaseRef<T: DatabaseRef>(pub T);
114
115impl<F: DatabaseRef> From<F> for WrapDatabaseRef<F> {
116    #[inline]
117    fn from(f: F) -> Self {
118        WrapDatabaseRef(f)
119    }
120}
121
122impl<T: DatabaseRef> Database for WrapDatabaseRef<T> {
123    type Error = T::Error;
124
125    #[inline]
126    fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
127        self.0.basic_ref(address)
128    }
129
130    #[inline]
131    fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
132        self.0.code_by_hash_ref(code_hash)
133    }
134
135    #[inline]
136    fn storage(
137        &mut self,
138        address: Address,
139        index: StorageKey,
140    ) -> Result<StorageValue, Self::Error> {
141        self.0.storage_ref(address, index)
142    }
143
144    #[inline]
145    fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
146        self.0.block_hash_ref(number)
147    }
148}
149
150impl<T: DatabaseRef + DatabaseCommit> DatabaseCommit for WrapDatabaseRef<T> {
151    #[inline]
152    fn commit(&mut self, changes: HashMap<Address, Account>) {
153        self.0.commit(changes)
154    }
155}
156
157impl<T: DatabaseRef> DatabaseRef for WrapDatabaseRef<T> {
158    type Error = T::Error;
159
160    #[inline]
161    fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
162        self.0.basic_ref(address)
163    }
164
165    #[inline]
166    fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
167        self.0.code_by_hash_ref(code_hash)
168    }
169
170    #[inline]
171    fn storage_ref(
172        &self,
173        address: Address,
174        index: StorageKey,
175    ) -> Result<StorageValue, Self::Error> {
176        self.0.storage_ref(address, index)
177    }
178
179    #[inline]
180    fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
181        self.0.block_hash_ref(number)
182    }
183}
184
185impl<T: Database + DatabaseCommit> DatabaseCommitExt for T {
186    // default implementation
187}
188
189/// EVM database commit interface.
190pub trait DatabaseCommitExt: Database + DatabaseCommit {
191    /// Iterates over received balances and increment all account balances.
192    ///
193    /// Update will create transitions for all accounts that are updated.
194    fn increment_balances(
195        &mut self,
196        balances: impl IntoIterator<Item = (Address, u128)>,
197    ) -> Result<(), Self::Error> {
198        // Make transition and update cache state
199        let balances = balances.into_iter();
200        let mut transitions: HashMap<Address, Account> = HashMap::default();
201        transitions.reserve(balances.size_hint().0);
202        for (address, balance) in balances {
203            let mut original_account = match self.basic(address)? {
204                Some(acc_info) => Account::from(acc_info),
205                None => Account::new_not_existing(0),
206            };
207            original_account.info.balance = original_account
208                .info
209                .balance
210                .saturating_add(U256::from(balance));
211            original_account.mark_touch();
212            transitions.insert(address, original_account);
213        }
214        self.commit(transitions);
215        Ok(())
216    }
217}