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, AccountId, AccountInfo, Bytecode, TransactionId};
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
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 state_hook;
40pub mod try_commit;
41
42#[cfg(feature = "asyncdb")]
43pub use async_db::{DatabaseAsync, WrapDatabaseAsync};
44pub use empty_db::{EmptyDB, EmptyDBTyped};
45pub use erased_error::ErasedError;
46pub use state_hook::{NoopHook, OnStateHook};
47pub use try_commit::{ArcUpgradeError, TryDatabaseCommit};
48
49pub trait DBErrorMarker: core::error::Error + Send + Sync + 'static {
51 fn is_fatal(&self) -> bool {
55 true
56 }
57}
58
59impl DBErrorMarker for Infallible {}
61impl DBErrorMarker for ErasedError {}
62
63#[auto_impl(&mut, Box)]
65pub trait Database {
66 type Error: DBErrorMarker;
68
69 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error>;
71
72 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error>;
74
75 fn storage(&mut self, address: Address, index: StorageKey)
77 -> Result<StorageValue, Self::Error>;
78
79 #[inline]
84 fn storage_by_account_id(
85 &mut self,
86 address: Address,
87 account_id: AccountId,
88 storage_key: StorageKey,
89 ) -> Result<StorageValue, Self::Error> {
90 let _ = account_id;
91 self.storage(address, storage_key)
92 }
93
94 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error>;
96}
97
98#[auto_impl(&mut, Box)]
105pub trait DatabaseCommit {
106 fn commit(&mut self, changes: AddressMap<Account>);
108
109 fn commit_iter(&mut self, changes: &mut dyn Iterator<Item = (Address, Account)>) {
121 let changes: AddressMap<Account> = changes.collect();
122 self.commit(changes);
123 }
124}
125
126impl dyn DatabaseCommit {
131 #[inline]
136 pub fn commit_from_iter(&mut self, changes: impl IntoIterator<Item = (Address, Account)>) {
137 self.commit_iter(&mut changes.into_iter())
138 }
139}
140
141#[auto_impl(&, &mut, Box, Rc, Arc)]
148pub trait DatabaseRef {
149 type Error: DBErrorMarker;
151
152 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error>;
154
155 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error>;
157
158 fn storage_ref(&self, address: Address, index: StorageKey)
160 -> Result<StorageValue, Self::Error>;
161
162 #[inline]
166 fn storage_by_account_id_ref(
167 &self,
168 address: Address,
169 account_id: AccountId,
170 storage_key: StorageKey,
171 ) -> Result<StorageValue, Self::Error> {
172 let _ = account_id;
173 self.storage_ref(address, storage_key)
174 }
175
176 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error>;
178}
179
180#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
182pub struct WrapDatabaseRef<T: DatabaseRef>(pub T);
183
184impl<F: DatabaseRef> From<F> for WrapDatabaseRef<F> {
185 #[inline]
186 fn from(f: F) -> Self {
187 WrapDatabaseRef(f)
188 }
189}
190
191impl<T: DatabaseRef> Database for WrapDatabaseRef<T> {
192 type Error = T::Error;
193
194 #[inline]
195 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
196 self.0.basic_ref(address)
197 }
198
199 #[inline]
200 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
201 self.0.code_by_hash_ref(code_hash)
202 }
203
204 #[inline]
205 fn storage(
206 &mut self,
207 address: Address,
208 index: StorageKey,
209 ) -> Result<StorageValue, Self::Error> {
210 self.0.storage_ref(address, index)
211 }
212
213 #[inline]
214 fn storage_by_account_id(
215 &mut self,
216 address: Address,
217 account_id: AccountId,
218 storage_key: StorageKey,
219 ) -> Result<StorageValue, Self::Error> {
220 self.0
221 .storage_by_account_id_ref(address, account_id, storage_key)
222 }
223
224 #[inline]
225 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
226 self.0.block_hash_ref(number)
227 }
228}
229
230impl<T: DatabaseRef + DatabaseCommit> DatabaseCommit for WrapDatabaseRef<T> {
231 #[inline]
232 fn commit(&mut self, changes: AddressMap<Account>) {
233 self.0.commit(changes)
234 }
235
236 #[inline]
237 fn commit_iter(&mut self, changes: &mut dyn Iterator<Item = (Address, Account)>) {
238 self.0.commit_iter(changes)
239 }
240}
241
242impl<T: DatabaseRef> DatabaseRef for WrapDatabaseRef<T> {
243 type Error = T::Error;
244
245 #[inline]
246 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
247 self.0.basic_ref(address)
248 }
249
250 #[inline]
251 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
252 self.0.code_by_hash_ref(code_hash)
253 }
254
255 #[inline]
256 fn storage_ref(
257 &self,
258 address: Address,
259 index: StorageKey,
260 ) -> Result<StorageValue, Self::Error> {
261 self.0.storage_ref(address, index)
262 }
263
264 #[inline]
265 fn storage_by_account_id_ref(
266 &self,
267 address: Address,
268 account_id: AccountId,
269 storage_key: StorageKey,
270 ) -> Result<StorageValue, Self::Error> {
271 self.0
272 .storage_by_account_id_ref(address, account_id, storage_key)
273 }
274
275 #[inline]
276 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
277 self.0.block_hash_ref(number)
278 }
279}
280
281impl<T: Database + DatabaseCommit> DatabaseCommitExt for T {
282 }
284
285pub trait DatabaseCommitExt: Database + DatabaseCommit {
287 fn increment_balances(
291 &mut self,
292 balances: impl IntoIterator<Item = (Address, u128)>,
293 ) -> Result<(), Self::Error> {
294 let transitions = balances
296 .into_iter()
297 .map(|(address, balance)| {
298 let mut original_account = match self.basic(address)? {
299 Some(acc_info) => Account::from(acc_info),
300 None => Account::new_not_existing(TransactionId::ZERO),
301 };
302 original_account.info.balance = original_account
303 .info
304 .balance
305 .saturating_add(U256::from(balance));
306 original_account.mark_touch();
307 Ok((address, original_account))
308 })
309 .collect::<Result<Vec<_>, _>>()?;
311
312 self.commit_iter(&mut transitions.into_iter());
313 Ok(())
314 }
315
316 fn drain_balances(
320 &mut self,
321 addresses: impl IntoIterator<Item = Address>,
322 ) -> Result<Vec<u128>, Self::Error> {
323 let addresses_iter = addresses.into_iter();
325 let (lower, _) = addresses_iter.size_hint();
326 let mut transitions = Vec::with_capacity(lower);
327 let balances = addresses_iter
328 .map(|address| {
329 let mut original_account = match self.basic(address)? {
330 Some(acc_info) => Account::from(acc_info),
331 None => Account::new_not_existing(TransactionId::ZERO),
332 };
333 let balance = core::mem::take(&mut original_account.info.balance);
334 original_account.mark_touch();
335 transitions.push((address, original_account));
336 Ok(balance.try_into().unwrap())
337 })
338 .collect::<Result<Vec<_>, _>>()?;
339
340 self.commit_iter(&mut transitions.into_iter());
341 Ok(balances)
342 }
343}
344
345#[cfg(test)]
346mod tests {
347 use super::*;
348
349 struct _DatabaseCommitObjectSafe(dyn DatabaseCommit);
352
353 #[test]
355 fn test_dyn_database_commit() {
356 use std::collections::HashMap as StdHashMap;
357
358 struct MockDb {
359 commits: Vec<StdHashMap<Address, Account>>,
360 }
361
362 impl DatabaseCommit for MockDb {
363 fn commit(&mut self, changes: AddressMap<Account>) {
364 let std_map: StdHashMap<_, _> = changes.into_iter().collect();
365 self.commits.push(std_map);
366 }
367 }
368
369 let mut db = MockDb { commits: vec![] };
370
371 let items: Vec<(Address, Account)> = vec![];
373 db.commit_iter(&mut items.into_iter());
374 assert_eq!(db.commits.len(), 1);
375
376 {
378 let db_dyn: &mut dyn DatabaseCommit = &mut db;
379 db_dyn.commit(AddressMap::default());
380 }
381 assert_eq!(db.commits.len(), 2);
382
383 {
385 let db_dyn: &mut dyn DatabaseCommit = &mut db;
386 let items: Vec<(Address, Account)> = vec![];
387 db_dyn.commit_iter(&mut items.into_iter());
388 }
389 assert_eq!(db.commits.len(), 3);
390
391 {
393 let db_dyn: &mut dyn DatabaseCommit = &mut db;
394 db_dyn.commit_from_iter(vec![]);
395 }
396 assert_eq!(db.commits.len(), 4);
397 }
398
399 #[test]
400 fn wrappers_forward_commit_iter() {
401 #[derive(Default)]
402 struct MockDb {
403 commits: usize,
404 commit_iters: usize,
405 committed_accounts: usize,
406 }
407
408 impl DatabaseCommit for MockDb {
409 fn commit(&mut self, changes: AddressMap<Account>) {
410 self.commits += 1;
411 self.committed_accounts += changes.len();
412 }
413
414 fn commit_iter(&mut self, changes: &mut dyn Iterator<Item = (Address, Account)>) {
415 self.commit_iters += 1;
416 self.committed_accounts += changes.count();
417 }
418 }
419
420 impl DatabaseRef for MockDb {
421 type Error = Infallible;
422
423 fn basic_ref(&self, _address: Address) -> Result<Option<AccountInfo>, Self::Error> {
424 Ok(None)
425 }
426
427 fn code_by_hash_ref(&self, _code_hash: B256) -> Result<Bytecode, Self::Error> {
428 Ok(Bytecode::default())
429 }
430
431 fn storage_ref(
432 &self,
433 _address: Address,
434 _index: StorageKey,
435 ) -> Result<StorageValue, Self::Error> {
436 Ok(StorageValue::ZERO)
437 }
438
439 fn block_hash_ref(&self, _number: u64) -> Result<B256, Self::Error> {
440 Ok(B256::ZERO)
441 }
442 }
443
444 fn changes() -> Vec<(Address, Account)> {
445 vec![(Address::with_last_byte(1), Account::default())]
446 }
447
448 let mut db = WrapDatabaseRef(MockDb::default());
449 db.commit_iter(&mut changes().into_iter());
450 assert_eq!(db.0.commits, 0);
451 assert_eq!(db.0.commit_iters, 1);
452 assert_eq!(db.0.committed_accounts, 1);
453
454 let mut db: ::either::Either<MockDb, MockDb> = ::either::Either::Left(MockDb::default());
455 db.commit_iter(&mut changes().into_iter());
456 let ::either::Either::Left(db) = db else {
457 unreachable!()
458 };
459 assert_eq!(db.commits, 0);
460 assert_eq!(db.commit_iters, 1);
461 assert_eq!(db.committed_accounts, 1);
462
463 let address = Address::with_last_byte(2);
464 let mut account = Account::default();
465 account.mark_touch();
466
467 let mut db = bal::BalDatabase::new(MockDb::default()).with_bal_builder();
468 db.commit_iter(&mut [(address, account)].into_iter());
469 assert_eq!(db.db.commits, 0);
470 assert_eq!(db.db.commit_iters, 1);
471 assert_eq!(db.db.committed_accounts, 1);
472
473 let bal = db.bal_state.take_built_bal().expect("BAL should be built");
474 assert!(bal.accounts.get(&address).is_some());
475 }
476}