1use super::error::DatabaseError;
2use super::provider::ProviderBuilder;
3use super::runtime_client::RuntimeClient;
4use super::traits::DB;
5use super::types::RequestCache;
6use super::types::{ToAlloy, ToEthers};
7use alloy_primitives::{keccak256, Address, Bytes};
8pub use ethers_core::types::BlockNumber;
9use ethers_core::types::{BigEndianHash, Block, BlockId, NameOrAddress, H256};
10use ethers_providers::{Middleware, Provider, ProviderError};
11use revm::db::in_memory_db::DbAccount;
12use revm::db::{AccountState, DatabaseCommit};
13use revm::primitives::{
14 hash_map::Entry, Account, AccountInfo, Bytecode, HashMap, Log, B256, KECCAK_EMPTY, U256,
15};
16use revm::Database;
17
18#[derive(Debug, Clone)]
35pub struct ForkDb {
36 pub accounts: HashMap<Address, DbAccount>,
37 pub contracts: HashMap<B256, Bytecode>,
38 pub logs: Vec<Log>,
39 pub block_hashes: HashMap<U256, B256>,
40 provider: Provider<RuntimeClient>,
41 block_id: Option<BlockId>,
42 pub block: Block<H256>,
43 pub requests: RequestCache,
44}
45
46impl ForkDb {
47 pub fn new(node_url: &str, block_number: Option<u64>) -> Self {
48 let block_number = match block_number {
49 Some(n) => BlockNumber::Number(n.into()),
50 None => BlockNumber::Latest,
51 };
52
53 let provider = ProviderBuilder::new(node_url).build().unwrap();
54
55 let rt = tokio::runtime::Builder::new_current_thread()
56 .enable_all()
57 .build()
58 .unwrap();
59
60 let block = rt.block_on(provider.get_block(block_number)).unwrap();
61
62 let block = match block {
63 Some(b) => b,
64 None => panic!("Could not retrieve block"),
65 };
66
67 let mut contracts = HashMap::new();
68 contracts.insert(KECCAK_EMPTY, Bytecode::new());
69 contracts.insert(B256::ZERO, Bytecode::new());
70
71 let timestamp = U256::try_from(block.timestamp.as_u128()).unwrap();
74 let block_number = match block.number {
75 Some(n) => U256::try_from(n.as_u64()).unwrap(),
76 None => U256::ZERO,
77 };
78
79 Self {
80 accounts: HashMap::new(),
81 contracts,
82 logs: Vec::default(),
83 block_hashes: HashMap::new(),
84 provider,
85 block_id: Some(block.number.unwrap().into()),
86 block,
87 requests: RequestCache {
88 start_timestamp: timestamp,
89 start_block_number: block_number,
90 accounts: Vec::new(),
91 storage: Vec::new(),
92 },
93 }
94 }
95
96 pub fn insert_contract(&mut self, account: &mut AccountInfo) {
97 if let Some(code) = &account.code {
98 if !code.is_empty() {
99 if account.code_hash == KECCAK_EMPTY {
100 account.code_hash = code.hash_slow();
101 }
102 self.contracts
103 .entry(account.code_hash)
104 .or_insert_with(|| code.clone());
105 }
106 }
107 if account.code_hash == B256::ZERO {
108 account.code_hash = KECCAK_EMPTY;
109 }
110 }
111
112 pub fn insert_account_info(&mut self, address: Address, mut info: AccountInfo) {
113 self.insert_contract(&mut info);
114 self.accounts.entry(address).or_default().info = info;
115 }
116
117 pub fn load_account(&mut self, address: Address) -> Result<&mut DbAccount, DatabaseError> {
118 match self.accounts.entry(address) {
119 Entry::Occupied(entry) => Ok(entry.into_mut()),
120 Entry::Vacant(_) => Err(DatabaseError::GetAccount(address)),
121 }
122 }
123
124 pub fn insert_account_storage(
125 &mut self,
126 address: Address,
127 slot: U256,
128 value: U256,
129 ) -> Result<(), DatabaseError> {
130 let account = self.load_account(address)?;
131 account.storage.insert(slot, value);
132 Ok(())
133 }
134
135 pub fn replace_account_storage(
136 &mut self,
137 address: Address,
138 storage: HashMap<U256, U256>,
139 ) -> Result<(), DatabaseError> {
140 let account = self.load_account(address)?;
141 account.account_state = AccountState::StorageCleared;
142 account.storage = storage.into_iter().collect();
143 Ok(())
144 }
145}
146
147impl DB for ForkDb {
148 fn insert_account_info(&mut self, address: Address, account_info: AccountInfo) {
149 self.insert_account_info(address, account_info)
150 }
151
152 fn accounts(&self) -> &HashMap<Address, DbAccount> {
153 &self.accounts
154 }
155
156 fn contracts(&self) -> &HashMap<B256, Bytecode> {
157 &self.contracts
158 }
159
160 fn logs(&self) -> &Vec<Log> {
161 &self.logs
162 }
163
164 fn block_hashes(&self) -> &HashMap<U256, B256> {
165 &self.block_hashes
166 }
167}
168
169impl DatabaseCommit for ForkDb {
170 fn commit(&mut self, changes: HashMap<Address, Account>) {
171 for (address, mut account) in changes {
172 if !account.is_touched() {
173 continue;
174 }
175 if account.is_selfdestructed() {
176 let db_account = self.accounts.entry(address).or_default();
177 db_account.storage.clear();
178 db_account.account_state = AccountState::NotExisting;
179 db_account.info = AccountInfo::default();
180 continue;
181 }
182 let is_newly_created = account.is_created();
183 self.insert_contract(&mut account.info);
184
185 let db_account = self.accounts.entry(address).or_default();
186 db_account.info = account.info;
187
188 db_account.account_state = if is_newly_created {
189 db_account.storage.clear();
190 AccountState::StorageCleared
191 } else if db_account.account_state.is_storage_cleared() {
192 AccountState::StorageCleared
194 } else {
195 AccountState::Touched
196 };
197 db_account.storage.extend(
198 account
199 .storage
200 .into_iter()
201 .map(|(key, value)| (key, value.present_value())),
202 );
203 }
204 }
205}
206
207impl Database for ForkDb {
208 type Error = DatabaseError;
209
210 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
211 let basic = self.accounts.entry(address);
212 let basic = match basic {
213 Entry::Occupied(entry) => entry.into_mut(),
214 Entry::Vacant(entry) => {
215 let info = basic_from_fork(&self.provider, address, self.block_id);
216 let account = match info {
217 Ok(i) => {
218 self.requests.accounts.push((address, i.clone()));
219 DbAccount {
220 info: i,
221 ..Default::default()
222 }
223 }
224 Err(_) => DbAccount::new_not_existing(),
225 };
226 entry.insert(account)
227 }
228 };
229 Ok(basic.info())
230 }
231
232 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
233 match self.contracts.entry(code_hash) {
234 Entry::Occupied(entry) => Ok(entry.get().clone()),
235 Entry::Vacant(_) => Err(DatabaseError::MissingCode(code_hash)),
236 }
237 }
238
239 fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
240 match self.accounts.entry(address) {
241 Entry::Occupied(mut acc_entry) => {
242 let acc_entry = acc_entry.get_mut();
243 match acc_entry.storage.entry(index) {
244 Entry::Occupied(entry) => Ok(*entry.get()),
245 Entry::Vacant(entry) => {
246 if matches!(
247 acc_entry.account_state,
248 AccountState::StorageCleared | AccountState::NotExisting
249 ) {
250 Ok(U256::ZERO)
251 } else {
252 let slot =
253 storage_from_fork(&self.provider, address, index, self.block_id);
254 match slot {
255 Ok(s) => {
256 self.requests.storage.push((address, index, s));
257 entry.insert(s);
258 Ok(s)
259 }
260 Err(_) => Err(DatabaseError::GetStorage(address, index)),
261 }
262 }
263 }
264 }
265 }
266 Entry::Vacant(_) => Err(DatabaseError::GetAccount(address)),
267 }
268 }
269
270 fn block_hash(&mut self, number: U256) -> Result<B256, Self::Error> {
271 match self.block_hashes.entry(number) {
272 Entry::Occupied(entry) => Ok(*entry.get()),
273 Entry::Vacant(entry) => {
274 let hash = block_hash_from_fork(&self.provider, number);
275 match hash {
276 Ok(h) => {
277 entry.insert(h);
278 Ok(h)
279 }
280 Err(_) => Err(DatabaseError::GetBlockHash(number)),
281 }
282 }
283 }
284 }
285}
286
287fn basic_from_fork(
288 provider: &Provider<RuntimeClient>,
289 address: Address,
290 block_id: Option<BlockId>,
291) -> Result<AccountInfo, ProviderError> {
292 let add = NameOrAddress::Address(address.to_ethers());
293
294 let rt = tokio::runtime::Builder::new_current_thread()
295 .enable_all()
296 .build()
297 .unwrap();
298
299 let balance = rt.block_on(provider.get_balance(add.clone(), block_id))?;
300 let nonce = rt.block_on(provider.get_transaction_count(add.clone(), block_id))?;
301 let code = rt.block_on(provider.get_code(add, block_id))?;
302 let code = Bytes::from(code.0);
303
304 let (code, code_hash) = if !code.is_empty() {
305 (code.clone(), keccak256(&code))
306 } else {
307 (Bytes::default(), KECCAK_EMPTY)
308 };
309
310 Ok(AccountInfo {
311 balance: balance.to_alloy(),
312 nonce: nonce.as_u64(),
313 code_hash,
314 code: Some(Bytecode::new_raw(code).to_checked()),
315 })
316}
317
318fn storage_from_fork(
319 provider: &Provider<RuntimeClient>,
320 address: Address,
321 index: U256,
322 block_id: Option<BlockId>,
323) -> Result<U256, ProviderError> {
324 let idx_req = B256::from(index);
325
326 let rt = tokio::runtime::Builder::new_current_thread()
327 .enable_all()
328 .build()
329 .unwrap();
330 let storage = rt.block_on(provider.get_storage_at(
331 NameOrAddress::Address(address.to_ethers()),
332 idx_req.to_ethers(),
333 block_id,
334 ))?;
335 Ok(storage.into_uint().to_alloy())
336}
337
338fn block_hash_from_fork(
339 provider: &Provider<RuntimeClient>,
340 number: U256,
341) -> Result<B256, ProviderError> {
342 let n: u64 = number.try_into().unwrap();
343 let block_id = BlockId::from(n);
344
345 let rt = tokio::runtime::Builder::new_current_thread()
346 .enable_all()
347 .build()
348 .unwrap();
349
350 let block = rt.block_on(provider.get_block(block_id));
351
352 match block {
353 Ok(Some(block)) => Ok(block
354 .hash
355 .expect("empty block hash on mined block, this should never happen")
356 .to_alloy()),
357 Ok(None) => Ok(KECCAK_EMPTY),
358 Err(e) => Err(e),
359 }
360}