1#![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, AccountInfo, Bytecode};
13use std::vec::Vec;
14
15pub const FFADDRESS: Address = address!("0xffffffffffffffffffffffffffffffffffffffff");
17pub const BENCH_TARGET: Address = FFADDRESS;
19pub const TEST_BALANCE: U256 = U256::from_limbs([10_000_000_000_000_000, 0, 0, 0]);
21pub const BENCH_TARGET_BALANCE: U256 = TEST_BALANCE;
23pub const EEADDRESS: Address = address!("0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee");
25pub const BENCH_CALLER: Address = EEADDRESS;
27pub 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
44pub trait DBErrorMarker: core::error::Error + Send + Sync + 'static {}
46
47impl DBErrorMarker for Infallible {}
49impl DBErrorMarker for ErasedError {}
50
51#[auto_impl(&mut, Box)]
53pub trait Database {
54 type Error: DBErrorMarker;
56
57 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error>;
59
60 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error>;
62
63 fn storage(&mut self, address: Address, index: StorageKey)
65 -> Result<StorageValue, Self::Error>;
66
67 #[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 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error>;
84}
85
86#[auto_impl(&mut, Box)]
93pub trait DatabaseCommit {
94 fn commit(&mut self, changes: AddressMap<Account>);
96
97 fn commit_iter(&mut self, changes: &mut dyn Iterator<Item = (Address, Account)>) {
109 let changes: AddressMap<Account> = changes.collect();
110 self.commit(changes);
111 }
112}
113
114impl dyn DatabaseCommit {
119 #[inline]
124 pub fn commit_from_iter(&mut self, changes: impl IntoIterator<Item = (Address, Account)>) {
125 self.commit_iter(&mut changes.into_iter())
126 }
127}
128
129#[auto_impl(&, &mut, Box, Rc, Arc)]
136pub trait DatabaseRef {
137 type Error: DBErrorMarker;
139
140 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error>;
142
143 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error>;
145
146 fn storage_ref(&self, address: Address, index: StorageKey)
148 -> Result<StorageValue, Self::Error>;
149
150 #[inline]
154 fn storage_by_account_id_ref(
155 &self,
156 address: Address,
157 account_id: usize,
158 storage_key: StorageKey,
159 ) -> Result<StorageValue, Self::Error> {
160 let _ = account_id;
161 self.storage_ref(address, storage_key)
162 }
163
164 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error>;
166}
167
168#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
170pub struct WrapDatabaseRef<T: DatabaseRef>(pub T);
171
172impl<F: DatabaseRef> From<F> for WrapDatabaseRef<F> {
173 #[inline]
174 fn from(f: F) -> Self {
175 WrapDatabaseRef(f)
176 }
177}
178
179impl<T: DatabaseRef> Database for WrapDatabaseRef<T> {
180 type Error = T::Error;
181
182 #[inline]
183 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
184 self.0.basic_ref(address)
185 }
186
187 #[inline]
188 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
189 self.0.code_by_hash_ref(code_hash)
190 }
191
192 #[inline]
193 fn storage(
194 &mut self,
195 address: Address,
196 index: StorageKey,
197 ) -> Result<StorageValue, Self::Error> {
198 self.0.storage_ref(address, index)
199 }
200
201 #[inline]
202 fn storage_by_account_id(
203 &mut self,
204 address: Address,
205 account_id: usize,
206 storage_key: StorageKey,
207 ) -> Result<StorageValue, Self::Error> {
208 self.0
209 .storage_by_account_id_ref(address, account_id, storage_key)
210 }
211
212 #[inline]
213 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
214 self.0.block_hash_ref(number)
215 }
216}
217
218impl<T: DatabaseRef + DatabaseCommit> DatabaseCommit for WrapDatabaseRef<T> {
219 #[inline]
220 fn commit(&mut self, changes: AddressMap<Account>) {
221 self.0.commit(changes)
222 }
223}
224
225impl<T: DatabaseRef> DatabaseRef for WrapDatabaseRef<T> {
226 type Error = T::Error;
227
228 #[inline]
229 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
230 self.0.basic_ref(address)
231 }
232
233 #[inline]
234 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
235 self.0.code_by_hash_ref(code_hash)
236 }
237
238 #[inline]
239 fn storage_ref(
240 &self,
241 address: Address,
242 index: StorageKey,
243 ) -> Result<StorageValue, Self::Error> {
244 self.0.storage_ref(address, index)
245 }
246
247 #[inline]
248 fn storage_by_account_id_ref(
249 &self,
250 address: Address,
251 account_id: usize,
252 storage_key: StorageKey,
253 ) -> Result<StorageValue, Self::Error> {
254 self.0
255 .storage_by_account_id_ref(address, account_id, storage_key)
256 }
257
258 #[inline]
259 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
260 self.0.block_hash_ref(number)
261 }
262}
263
264impl<T: Database + DatabaseCommit> DatabaseCommitExt for T {
265 }
267
268pub trait DatabaseCommitExt: Database + DatabaseCommit {
270 fn increment_balances(
274 &mut self,
275 balances: impl IntoIterator<Item = (Address, u128)>,
276 ) -> Result<(), Self::Error> {
277 let transitions = balances
279 .into_iter()
280 .map(|(address, balance)| {
281 let mut original_account = match self.basic(address)? {
282 Some(acc_info) => Account::from(acc_info),
283 None => Account::new_not_existing(0),
284 };
285 original_account.info.balance = original_account
286 .info
287 .balance
288 .saturating_add(U256::from(balance));
289 original_account.mark_touch();
290 Ok((address, original_account))
291 })
292 .collect::<Result<Vec<_>, _>>()?;
294
295 self.commit_iter(&mut transitions.into_iter());
296 Ok(())
297 }
298
299 fn drain_balances(
303 &mut self,
304 addresses: impl IntoIterator<Item = Address>,
305 ) -> Result<Vec<u128>, Self::Error> {
306 let addresses_iter = addresses.into_iter();
308 let (lower, _) = addresses_iter.size_hint();
309 let mut transitions = Vec::with_capacity(lower);
310 let balances = addresses_iter
311 .map(|address| {
312 let mut original_account = match self.basic(address)? {
313 Some(acc_info) => Account::from(acc_info),
314 None => Account::new_not_existing(0),
315 };
316 let balance = core::mem::take(&mut original_account.info.balance);
317 original_account.mark_touch();
318 transitions.push((address, original_account));
319 Ok(balance.try_into().unwrap())
320 })
321 .collect::<Result<Vec<_>, _>>()?;
322
323 self.commit_iter(&mut transitions.into_iter());
324 Ok(balances)
325 }
326}
327
328#[cfg(test)]
329mod tests {
330 use super::*;
331
332 struct _DatabaseCommitObjectSafe(dyn DatabaseCommit);
335
336 #[test]
338 fn test_dyn_database_commit() {
339 use std::collections::HashMap as StdHashMap;
340
341 struct MockDb {
342 commits: Vec<StdHashMap<Address, Account>>,
343 }
344
345 impl DatabaseCommit for MockDb {
346 fn commit(&mut self, changes: AddressMap<Account>) {
347 let std_map: StdHashMap<_, _> = changes.into_iter().collect();
348 self.commits.push(std_map);
349 }
350 }
351
352 let mut db = MockDb { commits: vec![] };
353
354 let items: Vec<(Address, Account)> = vec![];
356 db.commit_iter(&mut items.into_iter());
357 assert_eq!(db.commits.len(), 1);
358
359 {
361 let db_dyn: &mut dyn DatabaseCommit = &mut db;
362 db_dyn.commit(AddressMap::default());
363 }
364 assert_eq!(db.commits.len(), 2);
365
366 {
368 let db_dyn: &mut dyn DatabaseCommit = &mut db;
369 let items: Vec<(Address, Account)> = vec![];
370 db_dyn.commit_iter(&mut items.into_iter());
371 }
372 assert_eq!(db.commits.len(), 3);
373
374 {
376 let db_dyn: &mut dyn DatabaseCommit = &mut db;
377 db_dyn.commit_from_iter(vec![]);
378 }
379 assert_eq!(db.commits.len(), 4);
380 }
381}