example_database_components/
lib.rs

1//! Database component example.
2#![cfg_attr(not(test), warn(unused_crate_dependencies))]
3
4//! Database that is split on State and BlockHash traits.
5pub mod block_hash;
6pub mod state;
7
8pub use block_hash::{BlockHash, BlockHashRef};
9pub use state::{State, StateRef};
10
11use revm::{
12    database_interface::{DBErrorMarker, Database, DatabaseCommit, DatabaseRef},
13    primitives::{Address, HashMap, StorageKey, StorageValue, B256},
14    state::{Account, AccountInfo, Bytecode},
15};
16
17/// A database implementation that separates state and block hash components.
18/// This allows for modular database design where state and block hash
19/// functionality can be implemented independently.
20#[derive(Debug)]
21pub struct DatabaseComponents<S, BH> {
22    /// State component for account and storage operations
23    pub state: S,
24    /// Block hash component for retrieving historical block hashes
25    pub block_hash: BH,
26}
27
28/// Error type for database component operations.
29/// Wraps errors from both state and block hash components.
30#[derive(Debug, thiserror::Error)]
31pub enum DatabaseComponentError<SE, BHE> {
32    /// Error from state component operations
33    #[error(transparent)]
34    State(SE),
35    /// Error from block hash component operations
36    #[error(transparent)]
37    BlockHash(BHE),
38}
39
40impl<SE, BHE> DBErrorMarker for DatabaseComponentError<SE, BHE> {}
41
42impl<S: State, BH: BlockHash> Database for DatabaseComponents<S, BH> {
43    type Error = DatabaseComponentError<S::Error, BH::Error>;
44
45    fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
46        self.state.basic(address).map_err(Self::Error::State)
47    }
48
49    fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
50        self.state
51            .code_by_hash(code_hash)
52            .map_err(Self::Error::State)
53    }
54
55    fn storage(
56        &mut self,
57        address: Address,
58        index: StorageKey,
59    ) -> Result<StorageValue, Self::Error> {
60        self.state
61            .storage(address, index)
62            .map_err(Self::Error::State)
63    }
64
65    fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
66        self.block_hash
67            .block_hash(number)
68            .map_err(Self::Error::BlockHash)
69    }
70}
71
72impl<S: StateRef, BH: BlockHashRef> DatabaseRef for DatabaseComponents<S, BH> {
73    type Error = DatabaseComponentError<S::Error, BH::Error>;
74
75    fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
76        self.state.basic(address).map_err(Self::Error::State)
77    }
78
79    fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
80        self.state
81            .code_by_hash(code_hash)
82            .map_err(Self::Error::State)
83    }
84
85    fn storage_ref(
86        &self,
87        address: Address,
88        index: StorageKey,
89    ) -> Result<StorageValue, Self::Error> {
90        self.state
91            .storage(address, index)
92            .map_err(Self::Error::State)
93    }
94
95    fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
96        self.block_hash
97            .block_hash(number)
98            .map_err(Self::Error::BlockHash)
99    }
100}
101
102impl<S: DatabaseCommit, BH: BlockHashRef> DatabaseCommit for DatabaseComponents<S, BH> {
103    fn commit(&mut self, changes: HashMap<Address, Account>) {
104        self.state.commit(changes);
105    }
106}