1use super::error::DatabaseError;
2use super::traits::DB;
3use revm::db::in_memory_db::DbAccount;
4use revm::db::{AccountState, DatabaseCommit};
5use revm::primitives::{
6 hash_map::Entry, Account, AccountInfo, Address, Bytecode, HashMap, Log, B256, KECCAK_EMPTY,
7 U256,
8};
9use revm::Database;
10
11#[derive(Debug, Clone)]
13pub struct LocalDB {
14 pub accounts: HashMap<Address, DbAccount>,
15 pub contracts: HashMap<B256, Bytecode>,
16 pub logs: Vec<Log>,
17 pub block_hashes: HashMap<U256, B256>,
18}
19
20impl Default for LocalDB {
21 fn default() -> Self {
22 Self::new()
23 }
24}
25
26impl LocalDB {
27 pub fn new() -> Self {
28 let mut contracts = HashMap::new();
29 contracts.insert(KECCAK_EMPTY, Bytecode::new());
30 contracts.insert(B256::ZERO, Bytecode::new());
31 Self {
32 accounts: HashMap::new(),
33 contracts,
34 logs: Vec::default(),
35 block_hashes: HashMap::new(),
36 }
37 }
38
39 pub fn insert_contract(&mut self, account: &mut AccountInfo) {
40 if let Some(code) = &account.code {
41 if !code.is_empty() {
42 if account.code_hash == KECCAK_EMPTY {
43 account.code_hash = code.hash_slow();
44 }
45 self.contracts
46 .entry(account.code_hash)
47 .or_insert_with(|| code.clone());
48 }
49 }
50 if account.code_hash == B256::ZERO {
51 account.code_hash = KECCAK_EMPTY;
52 }
53 }
54
55 pub fn insert_account_info(&mut self, address: Address, mut info: AccountInfo) {
56 self.insert_contract(&mut info);
57 self.accounts.entry(address).or_default().info = info;
58 }
59
60 pub fn load_account(&mut self, address: Address) -> Result<&mut DbAccount, DatabaseError> {
61 match self.accounts.entry(address) {
62 Entry::Occupied(entry) => Ok(entry.into_mut()),
63 Entry::Vacant(_) => Err(DatabaseError::GetAccount(address)),
64 }
65 }
66
67 pub fn insert_account_storage(
68 &mut self,
69 address: Address,
70 slot: U256,
71 value: U256,
72 ) -> Result<(), DatabaseError> {
73 let account = self.load_account(address)?;
74 account.storage.insert(slot, value);
75 Ok(())
76 }
77
78 pub fn replace_account_storage(
79 &mut self,
80 address: Address,
81 storage: HashMap<U256, U256>,
82 ) -> Result<(), DatabaseError> {
83 let account = self.load_account(address)?;
84 account.account_state = AccountState::StorageCleared;
85 account.storage = storage.into_iter().collect();
86 Ok(())
87 }
88}
89
90impl DB for LocalDB {
91 fn insert_account_info(&mut self, address: Address, account_info: AccountInfo) {
92 self.insert_account_info(address, account_info)
93 }
94
95 fn accounts(&self) -> &HashMap<Address, DbAccount> {
96 &self.accounts
97 }
98
99 fn contracts(&self) -> &HashMap<B256, Bytecode> {
100 &self.contracts
101 }
102
103 fn logs(&self) -> &Vec<Log> {
104 &self.logs
105 }
106
107 fn block_hashes(&self) -> &HashMap<U256, B256> {
108 &self.block_hashes
109 }
110}
111
112impl DatabaseCommit for LocalDB {
113 fn commit(&mut self, changes: HashMap<Address, Account>) {
114 for (address, mut account) in changes {
115 if !account.is_touched() {
116 continue;
117 }
118 if account.is_selfdestructed() {
119 let db_account = self.accounts.entry(address).or_default();
120 db_account.storage.clear();
121 db_account.account_state = AccountState::NotExisting;
122 db_account.info = AccountInfo::default();
123 continue;
124 }
125 let is_newly_created = account.is_created();
126 self.insert_contract(&mut account.info);
127
128 let db_account = self.accounts.entry(address).or_default();
129 db_account.info = account.info;
130
131 db_account.account_state = if is_newly_created {
132 db_account.storage.clear();
133 AccountState::StorageCleared
134 } else if db_account.account_state.is_storage_cleared() {
135 AccountState::StorageCleared
137 } else {
138 AccountState::Touched
139 };
140 db_account.storage.extend(
141 account
142 .storage
143 .into_iter()
144 .map(|(key, value)| (key, value.present_value())),
145 );
146 }
147 }
148}
149
150impl Database for LocalDB {
151 type Error = DatabaseError;
152
153 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
154 let basic = match self.accounts.entry(address) {
155 Entry::Occupied(entry) => entry.into_mut(),
156 Entry::Vacant(entry) => entry.insert(DbAccount::new_not_existing()),
157 };
158 Ok(basic.info())
159 }
160
161 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
162 match self.contracts.entry(code_hash) {
163 Entry::Occupied(entry) => Ok(entry.get().clone()),
164 Entry::Vacant(_) => Err(DatabaseError::MissingCode(code_hash)),
165 }
166 }
167
168 fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
172 match self.accounts.entry(address) {
173 Entry::Occupied(mut acc_entry) => {
174 let acc_entry = acc_entry.get_mut();
175 match acc_entry.storage.entry(index) {
176 Entry::Occupied(entry) => Ok(*entry.get()),
177 Entry::Vacant(_) => {
178 if matches!(
179 acc_entry.account_state,
180 AccountState::StorageCleared | AccountState::NotExisting
181 ) {
182 Ok(U256::ZERO)
183 } else {
184 Err(DatabaseError::GetStorage(address, index))
185 }
186 }
187 }
188 }
189 Entry::Vacant(_) => Err(DatabaseError::GetStorage(address, index)),
190 }
191 }
192
193 fn block_hash(&mut self, number: U256) -> Result<B256, Self::Error> {
194 match self.block_hashes.entry(number) {
195 Entry::Occupied(entry) => Ok(*entry.get()),
196 Entry::Vacant(_) => Err(DatabaseError::GetBlockHash(number)),
197 }
198 }
199}