1use crate::eth::{backend::db::Db, error::BlockchainError, pool::transactions::PoolTransaction};
4use alloy_consensus::TrieAccount;
5use alloy_eips::eip2930::AccessListResult;
6use alloy_network::{AnyRpcBlock, AnyRpcTransaction, BlockResponse, TransactionResponse};
7use alloy_primitives::{
8 Address, B256, Bytes, StorageValue, U256,
9 map::{FbHashMap, HashMap, HashSet},
10};
11use alloy_provider::{
12 Provider,
13 ext::{DebugApi, TraceApi},
14};
15use alloy_rpc_types::{
16 BlockId, BlockNumberOrTag as BlockNumber, BlockTransactions, EIP1186AccountProofResponse,
17 FeeHistory, Filter, Log,
18 request::TransactionRequest,
19 simulate::{SimulatePayload, SimulatedBlock},
20 trace::{
21 geth::{GethDebugTracingOptions, GethTrace},
22 parity::{LocalizedTransactionTrace as Trace, TraceResultsWithTransactionHash, TraceType},
23 },
24};
25use alloy_serde::WithOtherFields;
26use alloy_transport::TransportError;
27use foundry_common::provider::{ProviderBuilder, RetryProvider};
28use foundry_primitives::FoundryTxReceipt;
29use parking_lot::{
30 RawRwLock, RwLock,
31 lock_api::{RwLockReadGuard, RwLockWriteGuard},
32};
33use revm::context_interface::block::BlobExcessGasAndPrice;
34use std::{sync::Arc, time::Duration};
35use tokio::sync::RwLock as AsyncRwLock;
36
37#[derive(Clone, Debug)]
42pub struct ClientFork {
43 pub storage: Arc<RwLock<ForkedStorage>>,
45 pub config: Arc<RwLock<ClientForkConfig>>,
49 pub database: Arc<AsyncRwLock<Box<dyn Db>>>,
51}
52
53impl ClientFork {
54 pub fn new(config: ClientForkConfig, database: Arc<AsyncRwLock<Box<dyn Db>>>) -> Self {
56 Self { storage: Default::default(), config: Arc::new(RwLock::new(config)), database }
57 }
58
59 pub async fn reset(
61 &self,
62 url: Option<String>,
63 block_number: impl Into<BlockId>,
64 ) -> Result<(), BlockchainError> {
65 let block_number = block_number.into();
66 {
67 self.database
68 .write()
69 .await
70 .maybe_reset(url.clone(), block_number)
71 .map_err(BlockchainError::Internal)?;
72 }
73
74 if let Some(url) = url {
75 self.config.write().update_url(url)?;
76 let override_chain_id = self.config.read().override_chain_id;
77 let chain_id = if let Some(chain_id) = override_chain_id {
78 chain_id
79 } else {
80 self.provider().get_chain_id().await?
81 };
82 self.config.write().chain_id = chain_id;
83 }
84
85 let provider = self.provider();
86 let block =
87 provider.get_block(block_number).await?.ok_or(BlockchainError::BlockNotFound)?;
88 let block_hash = block.header.hash;
89 let timestamp = block.header.timestamp;
90 let base_fee = block.header.base_fee_per_gas;
91 let total_difficulty = block.header.total_difficulty.unwrap_or_default();
92
93 let number = block.header.number;
94 self.config.write().update_block(
95 number,
96 block_hash,
97 timestamp,
98 base_fee.map(|g| g as u128),
99 total_difficulty,
100 );
101
102 self.clear_cached_storage();
103
104 self.database.write().await.insert_block_hash(U256::from(number), block_hash);
105
106 Ok(())
107 }
108
109 pub fn clear_cached_storage(&self) {
111 self.storage.write().clear()
112 }
113
114 pub fn predates_fork(&self, block: u64) -> bool {
116 block < self.block_number()
117 }
118
119 pub fn predates_fork_inclusive(&self, block: u64) -> bool {
121 block <= self.block_number()
122 }
123
124 pub fn timestamp(&self) -> u64 {
125 self.config.read().timestamp
126 }
127
128 pub fn block_number(&self) -> u64 {
129 self.config.read().block_number
130 }
131
132 pub fn transaction_hash(&self) -> Option<B256> {
134 self.config.read().transaction_hash
135 }
136
137 pub fn total_difficulty(&self) -> U256 {
138 self.config.read().total_difficulty
139 }
140
141 pub fn base_fee(&self) -> Option<u128> {
142 self.config.read().base_fee
143 }
144
145 pub fn block_hash(&self) -> B256 {
146 self.config.read().block_hash
147 }
148
149 pub fn eth_rpc_url(&self) -> String {
150 self.config.read().eth_rpc_url.clone()
151 }
152
153 pub fn chain_id(&self) -> u64 {
154 self.config.read().chain_id
155 }
156
157 fn provider(&self) -> Arc<RetryProvider> {
158 self.config.read().provider.clone()
159 }
160
161 fn storage_read(&self) -> RwLockReadGuard<'_, RawRwLock, ForkedStorage> {
162 self.storage.read()
163 }
164
165 fn storage_write(&self) -> RwLockWriteGuard<'_, RawRwLock, ForkedStorage> {
166 self.storage.write()
167 }
168
169 pub async fn fee_history(
171 &self,
172 block_count: u64,
173 newest_block: BlockNumber,
174 reward_percentiles: &[f64],
175 ) -> Result<FeeHistory, TransportError> {
176 self.provider().get_fee_history(block_count, newest_block, reward_percentiles).await
177 }
178
179 pub async fn get_proof(
181 &self,
182 address: Address,
183 keys: Vec<B256>,
184 block_number: Option<BlockId>,
185 ) -> Result<EIP1186AccountProofResponse, TransportError> {
186 self.provider().get_proof(address, keys).block_id(block_number.unwrap_or_default()).await
187 }
188
189 pub async fn call(
191 &self,
192 request: &WithOtherFields<TransactionRequest>,
193 block: Option<BlockNumber>,
194 ) -> Result<Bytes, TransportError> {
195 let block = block.unwrap_or(BlockNumber::Latest);
196 let res = self.provider().call(request.clone()).block(block.into()).await?;
197
198 Ok(res)
199 }
200
201 pub async fn simulate_v1(
203 &self,
204 request: &SimulatePayload,
205 block: Option<BlockNumber>,
206 ) -> Result<Vec<SimulatedBlock<AnyRpcBlock>>, TransportError> {
207 let mut simulate_call = self.provider().simulate(request);
208 if let Some(n) = block {
209 simulate_call = simulate_call.number(n.as_number().unwrap());
210 }
211
212 let res = simulate_call.await?;
213
214 Ok(res)
215 }
216
217 pub async fn estimate_gas(
219 &self,
220 request: &WithOtherFields<TransactionRequest>,
221 block: Option<BlockNumber>,
222 ) -> Result<u128, TransportError> {
223 let block = block.unwrap_or_default();
224 let res = self.provider().estimate_gas(request.clone()).block(block.into()).await?;
225
226 Ok(res as u128)
227 }
228
229 pub async fn create_access_list(
231 &self,
232 request: &WithOtherFields<TransactionRequest>,
233 block: Option<BlockNumber>,
234 ) -> Result<AccessListResult, TransportError> {
235 self.provider().create_access_list(request).block_id(block.unwrap_or_default().into()).await
236 }
237
238 pub async fn storage_at(
239 &self,
240 address: Address,
241 index: U256,
242 number: Option<BlockNumber>,
243 ) -> Result<StorageValue, TransportError> {
244 self.provider()
245 .get_storage_at(address, index)
246 .block_id(number.unwrap_or_default().into())
247 .await
248 }
249
250 pub async fn logs(&self, filter: &Filter) -> Result<Vec<Log>, TransportError> {
251 if let Some(logs) = self.storage_read().logs.get(filter).cloned() {
252 return Ok(logs);
253 }
254
255 let logs = self.provider().get_logs(filter).await?;
256
257 let mut storage = self.storage_write();
258 storage.logs.insert(filter.clone(), logs.clone());
259 Ok(logs)
260 }
261
262 pub async fn get_code(
263 &self,
264 address: Address,
265 blocknumber: u64,
266 ) -> Result<Bytes, TransportError> {
267 trace!(target: "backend::fork", "get_code={:?}", address);
268 if let Some(code) = self.storage_read().code_at.get(&(address, blocknumber)).cloned() {
269 return Ok(code);
270 }
271
272 let block_id = BlockId::number(blocknumber);
273
274 let code = self.provider().get_code_at(address).block_id(block_id).await?;
275
276 let mut storage = self.storage_write();
277 storage.code_at.insert((address, blocknumber), code.clone());
278
279 Ok(code)
280 }
281
282 pub async fn get_balance(
283 &self,
284 address: Address,
285 blocknumber: u64,
286 ) -> Result<U256, TransportError> {
287 trace!(target: "backend::fork", "get_balance={:?}", address);
288 self.provider().get_balance(address).block_id(blocknumber.into()).await
289 }
290
291 pub async fn get_nonce(&self, address: Address, block: u64) -> Result<u64, TransportError> {
292 trace!(target: "backend::fork", "get_nonce={:?}", address);
293 self.provider().get_transaction_count(address).block_id(block.into()).await
294 }
295
296 pub async fn get_account(
297 &self,
298 address: Address,
299 blocknumber: u64,
300 ) -> Result<TrieAccount, TransportError> {
301 trace!(target: "backend::fork", "get_account={:?}", address);
302 self.provider().get_account(address).block_id(blocknumber.into()).await
303 }
304
305 pub async fn transaction_by_block_number_and_index(
306 &self,
307 number: u64,
308 index: usize,
309 ) -> Result<Option<AnyRpcTransaction>, TransportError> {
310 if let Some(block) = self.block_by_number(number).await? {
311 match block.transactions() {
312 BlockTransactions::Full(txs) => {
313 if let Some(tx) = txs.get(index) {
314 return Ok(Some(tx.clone()));
315 }
316 }
317 BlockTransactions::Hashes(hashes) => {
318 if let Some(tx_hash) = hashes.get(index) {
319 return self.transaction_by_hash(*tx_hash).await;
320 }
321 }
322 BlockTransactions::Uncle => panic!("Uncles not supported"),
324 }
325 }
326 Ok(None)
327 }
328
329 pub async fn transaction_by_block_hash_and_index(
330 &self,
331 hash: B256,
332 index: usize,
333 ) -> Result<Option<AnyRpcTransaction>, TransportError> {
334 if let Some(block) = self.block_by_hash(hash).await? {
335 match block.transactions() {
336 BlockTransactions::Full(txs) => {
337 if let Some(tx) = txs.get(index) {
338 return Ok(Some(tx.clone()));
339 }
340 }
341 BlockTransactions::Hashes(hashes) => {
342 if let Some(tx_hash) = hashes.get(index) {
343 return self.transaction_by_hash(*tx_hash).await;
344 }
345 }
346 BlockTransactions::Uncle => panic!("Uncles not supported"),
348 }
349 }
350 Ok(None)
351 }
352
353 pub async fn transaction_by_hash(
354 &self,
355 hash: B256,
356 ) -> Result<Option<AnyRpcTransaction>, TransportError> {
357 trace!(target: "backend::fork", "transaction_by_hash={:?}", hash);
358 if let tx @ Some(_) = self.storage_read().transactions.get(&hash).cloned() {
359 return Ok(tx);
360 }
361
362 let tx = self.provider().get_transaction_by_hash(hash).await?;
363 if let Some(tx) = tx.clone() {
364 let mut storage = self.storage_write();
365 storage.transactions.insert(hash, tx);
366 }
367 Ok(tx)
368 }
369
370 pub async fn trace_transaction(&self, hash: B256) -> Result<Vec<Trace>, TransportError> {
371 if let Some(traces) = self.storage_read().transaction_traces.get(&hash).cloned() {
372 return Ok(traces);
373 }
374
375 let traces = self.provider().trace_transaction(hash).await?.into_iter().collect::<Vec<_>>();
376
377 let mut storage = self.storage_write();
378 storage.transaction_traces.insert(hash, traces.clone());
379
380 Ok(traces)
381 }
382
383 pub async fn debug_trace_transaction(
384 &self,
385 hash: B256,
386 opts: GethDebugTracingOptions,
387 ) -> Result<GethTrace, TransportError> {
388 if let Some(traces) = self.storage_read().geth_transaction_traces.get(&hash).cloned() {
389 return Ok(traces);
390 }
391
392 let trace = self.provider().debug_trace_transaction(hash, opts).await?;
393
394 let mut storage = self.storage_write();
395 storage.geth_transaction_traces.insert(hash, trace.clone());
396
397 Ok(trace)
398 }
399
400 pub async fn debug_code_by_hash(
401 &self,
402 code_hash: B256,
403 block_id: Option<BlockId>,
404 ) -> Result<Option<Bytes>, TransportError> {
405 self.provider().debug_code_by_hash(code_hash, block_id).await
406 }
407
408 pub async fn trace_block(&self, number: u64) -> Result<Vec<Trace>, TransportError> {
409 if let Some(traces) = self.storage_read().block_traces.get(&number).cloned() {
410 return Ok(traces);
411 }
412
413 let traces =
414 self.provider().trace_block(number.into()).await?.into_iter().collect::<Vec<_>>();
415
416 let mut storage = self.storage_write();
417 storage.block_traces.insert(number, traces.clone());
418
419 Ok(traces)
420 }
421
422 pub async fn trace_replay_block_transactions(
423 &self,
424 number: u64,
425 trace_types: HashSet<TraceType>,
426 ) -> Result<Vec<TraceResultsWithTransactionHash>, TransportError> {
427 let params = (number, trace_types.iter().map(|t| format!("{t:?}")).collect::<Vec<_>>());
429 self.provider().raw_request("trace_replayBlockTransactions".into(), params).await
430 }
431
432 pub async fn transaction_receipt(
433 &self,
434 hash: B256,
435 ) -> Result<Option<FoundryTxReceipt>, BlockchainError> {
436 if let Some(receipt) = self.storage_read().transaction_receipts.get(&hash).cloned() {
437 return Ok(Some(receipt));
438 }
439
440 if let Some(receipt) = self.provider().get_transaction_receipt(hash).await? {
441 let receipt = FoundryTxReceipt::try_from(receipt)
442 .map_err(|_| BlockchainError::FailedToDecodeReceipt)?;
443 let mut storage = self.storage_write();
444 storage.transaction_receipts.insert(hash, receipt.clone());
445 return Ok(Some(receipt));
446 }
447
448 Ok(None)
449 }
450
451 pub async fn block_receipts(
452 &self,
453 number: u64,
454 ) -> Result<Option<Vec<FoundryTxReceipt>>, BlockchainError> {
455 if let receipts @ Some(_) = self.storage_read().block_receipts.get(&number).cloned() {
456 return Ok(receipts);
457 }
458
459 if self.predates_fork_inclusive(number) {
463 let receipts = self.provider().get_block_receipts(BlockId::from(number)).await?;
464 let receipts = receipts
465 .map(|r| {
466 r.into_iter()
467 .map(|r| {
468 FoundryTxReceipt::try_from(r)
469 .map_err(|_| BlockchainError::FailedToDecodeReceipt)
470 })
471 .collect::<Result<Vec<_>, _>>()
472 })
473 .transpose()?;
474
475 if let Some(receipts) = receipts.clone() {
476 let mut storage = self.storage_write();
477 storage.block_receipts.insert(number, receipts);
478 }
479
480 return Ok(receipts);
481 }
482
483 Ok(None)
484 }
485
486 pub async fn block_by_hash(&self, hash: B256) -> Result<Option<AnyRpcBlock>, TransportError> {
487 if let Some(mut block) = self.storage_read().blocks.get(&hash).cloned() {
488 block.transactions.convert_to_hashes();
489 return Ok(Some(block));
490 }
491
492 Ok(self.fetch_full_block(hash).await?.map(|mut b| {
493 b.transactions.convert_to_hashes();
494 b
495 }))
496 }
497
498 pub async fn block_by_hash_full(
499 &self,
500 hash: B256,
501 ) -> Result<Option<AnyRpcBlock>, TransportError> {
502 if let Some(block) = self.storage_read().blocks.get(&hash).cloned() {
503 return Ok(Some(self.convert_to_full_block(block)));
504 }
505 self.fetch_full_block(hash).await
506 }
507
508 pub async fn block_by_number(
509 &self,
510 block_number: u64,
511 ) -> Result<Option<AnyRpcBlock>, TransportError> {
512 if let Some(mut block) = self
513 .storage_read()
514 .hashes
515 .get(&block_number)
516 .and_then(|hash| self.storage_read().blocks.get(hash).cloned())
517 {
518 block.transactions.convert_to_hashes();
519 return Ok(Some(block));
520 }
521
522 let mut block = self.fetch_full_block(block_number).await?;
523 if let Some(block) = &mut block {
524 block.transactions.convert_to_hashes();
525 }
526 Ok(block)
527 }
528
529 pub async fn block_by_number_full(
530 &self,
531 block_number: u64,
532 ) -> Result<Option<AnyRpcBlock>, TransportError> {
533 if let Some(block) = self
534 .storage_read()
535 .hashes
536 .get(&block_number)
537 .copied()
538 .and_then(|hash| self.storage_read().blocks.get(&hash).cloned())
539 {
540 return Ok(Some(self.convert_to_full_block(block)));
541 }
542
543 self.fetch_full_block(block_number).await
544 }
545
546 async fn fetch_full_block(
547 &self,
548 block_id: impl Into<BlockId>,
549 ) -> Result<Option<AnyRpcBlock>, TransportError> {
550 if let Some(block) = self.provider().get_block(block_id.into()).full().await? {
551 let hash = block.header.hash;
552 let block_number = block.header.number;
553 let mut storage = self.storage_write();
554 let block_txs = match block.transactions() {
556 BlockTransactions::Full(txs) => txs.to_owned(),
557 _ => vec![],
558 };
559 storage.transactions.extend(block_txs.iter().map(|tx| (tx.tx_hash(), tx.clone())));
560 storage.hashes.insert(block_number, hash);
561 storage.blocks.insert(hash, block.clone());
562 return Ok(Some(block));
563 }
564
565 Ok(None)
566 }
567
568 pub async fn uncle_by_block_hash_and_index(
569 &self,
570 hash: B256,
571 index: usize,
572 ) -> Result<Option<AnyRpcBlock>, TransportError> {
573 if let Some(block) = self.block_by_hash(hash).await? {
574 return self.uncles_by_block_and_index(block, index).await;
575 }
576 Ok(None)
577 }
578
579 pub async fn uncle_by_block_number_and_index(
580 &self,
581 number: u64,
582 index: usize,
583 ) -> Result<Option<AnyRpcBlock>, TransportError> {
584 if let Some(block) = self.block_by_number(number).await? {
585 return self.uncles_by_block_and_index(block, index).await;
586 }
587 Ok(None)
588 }
589
590 async fn uncles_by_block_and_index(
591 &self,
592 block: AnyRpcBlock,
593 index: usize,
594 ) -> Result<Option<AnyRpcBlock>, TransportError> {
595 let block_hash = block.header.hash;
596 let block_number = block.header.number;
597 if let Some(uncles) = self.storage_read().uncles.get(&block_hash) {
598 return Ok(uncles.get(index).cloned());
599 }
600
601 let mut uncles = Vec::with_capacity(block.uncles.len());
602 for (uncle_idx, _) in block.uncles.iter().enumerate() {
603 let uncle =
604 match self.provider().get_uncle(block_number.into(), uncle_idx as u64).await? {
605 Some(u) => u,
606 None => return Ok(None),
607 };
608 uncles.push(uncle);
609 }
610 self.storage_write().uncles.insert(block_hash, uncles.clone());
611 Ok(uncles.get(index).cloned())
612 }
613
614 fn convert_to_full_block(&self, mut block: AnyRpcBlock) -> AnyRpcBlock {
616 let storage = self.storage.read();
617 let block_txs_len = match block.transactions {
618 BlockTransactions::Full(ref txs) => txs.len(),
619 BlockTransactions::Hashes(ref hashes) => hashes.len(),
620 BlockTransactions::Uncle => 0,
622 };
623 let mut transactions = Vec::with_capacity(block_txs_len);
624 for tx in block.transactions.hashes() {
625 if let Some(tx) = storage.transactions.get(&tx).cloned() {
626 transactions.push(tx);
627 }
628 }
629 block.inner.transactions = BlockTransactions::Full(transactions);
631
632 block
633 }
634}
635
636#[derive(Clone, Debug)]
638pub struct ClientForkConfig {
639 pub eth_rpc_url: String,
640 pub block_number: u64,
642 pub block_hash: B256,
644 pub transaction_hash: Option<B256>,
646 pub provider: Arc<RetryProvider>,
648 pub chain_id: u64,
649 pub override_chain_id: Option<u64>,
650 pub timestamp: u64,
652 pub base_fee: Option<u128>,
654 pub blob_gas_used: Option<u128>,
656 pub blob_excess_gas_and_price: Option<BlobExcessGasAndPrice>,
658 pub timeout: Duration,
660 pub retries: u32,
662 pub backoff: Duration,
664 pub compute_units_per_second: u64,
666 pub total_difficulty: U256,
668 pub force_transactions: Option<Vec<PoolTransaction>>,
670}
671
672impl ClientForkConfig {
673 fn update_url(&mut self, url: String) -> Result<(), BlockchainError> {
679 self.provider = Arc::new(
681 ProviderBuilder::new(url.as_str())
682 .timeout(self.timeout)
683 .max_retry(self.retries)
685 .initial_backoff(self.backoff.as_millis() as u64)
686 .compute_units_per_second(self.compute_units_per_second)
687 .build()
688 .map_err(|_| BlockchainError::InvalidUrl(url.clone()))?, );
690 trace!(target: "fork", "Updated rpc url {}", url);
691 self.eth_rpc_url = url;
692 Ok(())
693 }
694 pub fn update_block(
696 &mut self,
697 block_number: u64,
698 block_hash: B256,
699 timestamp: u64,
700 base_fee: Option<u128>,
701 total_difficulty: U256,
702 ) {
703 self.block_number = block_number;
704 self.block_hash = block_hash;
705 self.timestamp = timestamp;
706 self.base_fee = base_fee;
707 self.total_difficulty = total_difficulty;
708 trace!(target: "fork", "Updated block number={} hash={:?}", block_number, block_hash);
709 }
710}
711
712#[derive(Clone, Debug, Default)]
716pub struct ForkedStorage {
717 pub uncles: FbHashMap<32, Vec<AnyRpcBlock>>,
718 pub blocks: FbHashMap<32, AnyRpcBlock>,
719 pub hashes: HashMap<u64, B256>,
720 pub transactions: FbHashMap<32, AnyRpcTransaction>,
721 pub transaction_receipts: FbHashMap<32, FoundryTxReceipt>,
722 pub transaction_traces: FbHashMap<32, Vec<Trace>>,
723 pub logs: HashMap<Filter, Vec<Log>>,
724 pub geth_transaction_traces: FbHashMap<32, GethTrace>,
725 pub block_traces: HashMap<u64, Vec<Trace>>,
726 pub block_receipts: HashMap<u64, Vec<FoundryTxReceipt>>,
727 pub code_at: HashMap<(Address, u64), Bytes>,
728}
729
730impl ForkedStorage {
731 pub fn clear(&mut self) {
733 *self = Self::default()
735 }
736}