1use crate::eth::{backend::db::Db, error::BlockchainError, pool::transactions::PoolTransaction};
4use alloy_consensus::{BlockHeader, TrieAccount};
5use alloy_eips::eip2930::AccessListResult;
6use alloy_network::{
7 AnyNetwork, AnyRpcBlock, BlockResponse, Network, TransactionResponse,
8 primitives::HeaderResponse,
9};
10use alloy_primitives::{
11 Address, B256, Bytes, StorageValue, U256,
12 map::{FbHashMap, HashMap, HashSet},
13};
14use alloy_provider::{
15 Provider,
16 ext::{DebugApi, TraceApi},
17};
18use alloy_rpc_types::{
19 BlockId, BlockNumberOrTag as BlockNumber, BlockTransactions, EIP1186AccountProofResponse,
20 FeeHistory, Filter, Index, Log,
21 request::TransactionRequest,
22 simulate::{SimulatePayload, SimulatedBlock},
23 state::StateOverride,
24 trace::{
25 geth::{GethDebugTracingCallOptions, GethDebugTracingOptions, GethTrace, TraceResult},
26 opcode::{BlockOpcodeGas, TransactionOpcodeGas},
27 parity::{
28 LocalizedTransactionTrace as Trace, TraceResults, TraceResultsWithTransactionHash,
29 TraceType,
30 },
31 },
32};
33use alloy_rpc_types_eth::{AccountInfo, Bundle, EthCallResponse, StateContext};
34use alloy_rpc_types_mev::{EthCallBundle, EthCallBundleResponse};
35use alloy_serde::WithOtherFields;
36use alloy_transport::TransportError;
37use foundry_common::provider::{ProviderBuilder, RetryProvider};
38use foundry_evm::hardfork::FoundryHardfork;
39use foundry_primitives::{FoundryTxEnvelope, FoundryTxReceipt};
40use parking_lot::{
41 RawRwLock, RwLock,
42 lock_api::{RwLockReadGuard, RwLockWriteGuard},
43};
44use revm::context_interface::block::BlobExcessGasAndPrice;
45use std::{sync::Arc, time::Duration};
46use tokio::sync::RwLock as AsyncRwLock;
47
48#[derive(Clone, Debug)]
53pub struct ClientFork<N: Network = AnyNetwork> {
54 pub storage: Arc<RwLock<ForkedStorage<N>>>,
56 pub config: Arc<RwLock<ClientForkConfig<N>>>,
60 pub database: Arc<AsyncRwLock<Box<dyn Db>>>,
62 database_rpc_url: Arc<RwLock<Option<String>>>,
64}
65
66impl<N: Network> ClientFork<N> {
67 pub fn new(config: ClientForkConfig<N>, database: Arc<AsyncRwLock<Box<dyn Db>>>) -> Self {
69 let database_rpc_url = config.eth_rpc_url().map(ToOwned::to_owned);
70 Self {
71 storage: Default::default(),
72 config: Arc::new(RwLock::new(config)),
73 database,
74 database_rpc_url: Arc::new(RwLock::new(database_rpc_url)),
75 }
76 }
77
78 pub fn clear_cached_storage(&self) {
80 self.storage.write().clear()
81 }
82
83 pub fn predates_fork(&self, block: u64) -> bool {
85 block < self.block_number()
86 }
87
88 pub fn predates_fork_inclusive(&self, block: u64) -> bool {
90 block <= self.block_number()
91 }
92
93 pub fn timestamp(&self) -> u64 {
94 self.config.read().timestamp
95 }
96
97 pub fn block_number(&self) -> u64 {
98 self.config.read().block_number
99 }
100
101 pub fn transaction_hash(&self) -> Option<B256> {
103 self.config.read().transaction_hash
104 }
105
106 pub fn total_difficulty(&self) -> U256 {
107 self.config.read().total_difficulty
108 }
109
110 pub fn base_fee(&self) -> Option<u128> {
111 self.config.read().base_fee
112 }
113
114 pub fn block_hash(&self) -> B256 {
115 self.config.read().block_hash
116 }
117
118 pub fn eth_rpc_url(&self) -> Option<String> {
119 self.config.read().eth_rpc_url().map(|s| s.to_string())
120 }
121
122 pub(crate) fn database_rpc_url(&self) -> Option<String> {
123 self.database_rpc_url.read().clone()
124 }
125
126 pub(crate) fn set_database_rpc_url(&self, url: Option<String>) {
127 *self.database_rpc_url.write() = url;
128 }
129
130 pub fn chain_id(&self) -> u64 {
131 self.config.read().chain_id
132 }
133
134 fn provider(&self) -> Arc<RetryProvider<N>> {
135 self.config.read().provider.clone()
136 }
137
138 fn storage_read(&self) -> RwLockReadGuard<'_, RawRwLock, ForkedStorage<N>> {
139 self.storage.read()
140 }
141
142 fn storage_write(&self) -> RwLockWriteGuard<'_, RawRwLock, ForkedStorage<N>> {
143 self.storage.write()
144 }
145
146 pub async fn fee_history(
148 &self,
149 block_count: u64,
150 newest_block: BlockNumber,
151 reward_percentiles: &[f64],
152 ) -> Result<FeeHistory, TransportError> {
153 self.provider().get_fee_history(block_count, newest_block, reward_percentiles).await
154 }
155
156 pub async fn get_proof(
158 &self,
159 address: Address,
160 keys: Vec<B256>,
161 block_number: Option<BlockId>,
162 ) -> Result<EIP1186AccountProofResponse, TransportError> {
163 self.provider().get_proof(address, keys).block_id(block_number.unwrap_or_default()).await
164 }
165
166 pub async fn block_access_list(
168 &self,
169 block_id: BlockId,
170 ) -> Result<Option<serde_json::Value>, TransportError> {
171 self.provider().raw_request("eth_getBlockAccessList".into(), (block_id,)).await
172 }
173
174 pub async fn block_access_list_by_hash(
176 &self,
177 block_hash: B256,
178 ) -> Result<Option<serde_json::Value>, TransportError> {
179 self.provider().raw_request("eth_getBlockAccessListByBlockHash".into(), (block_hash,)).await
180 }
181
182 pub async fn block_access_list_by_number(
184 &self,
185 block_number: BlockNumber,
186 ) -> Result<Option<serde_json::Value>, TransportError> {
187 self.provider()
188 .raw_request("eth_getBlockAccessListByBlockNumber".into(), (block_number,))
189 .await
190 }
191
192 pub async fn block_access_list_raw(
194 &self,
195 block_id: BlockId,
196 ) -> Result<Option<Bytes>, TransportError> {
197 self.provider().raw_request("eth_getBlockAccessListRaw".into(), (block_id,)).await
198 }
199
200 pub async fn storage_at(
201 &self,
202 address: Address,
203 index: U256,
204 number: Option<BlockNumber>,
205 ) -> Result<StorageValue, TransportError> {
206 self.provider()
207 .get_storage_at(address, index)
208 .block_id(number.unwrap_or_default().into())
209 .await
210 }
211
212 pub async fn logs(&self, filter: &Filter) -> Result<Vec<Log>, TransportError> {
213 if let Some(logs) = self.storage_read().logs.get(filter).cloned() {
214 return Ok(logs);
215 }
216
217 let logs = self.provider().get_logs(filter).await?;
218
219 let mut storage = self.storage_write();
220 storage.logs.insert(filter.clone(), logs.clone());
221 Ok(logs)
222 }
223
224 pub async fn get_code(
225 &self,
226 address: Address,
227 blocknumber: u64,
228 ) -> Result<Bytes, TransportError> {
229 trace!(target: "backend::fork", "get_code={:?}", address);
230 if let Some(code) = self.storage_read().code_at.get(&(address, blocknumber)).cloned() {
231 return Ok(code);
232 }
233
234 let block_id = BlockId::number(blocknumber);
235
236 let code = self.provider().get_code_at(address).block_id(block_id).await?;
237
238 let mut storage = self.storage_write();
239 storage.code_at.insert((address, blocknumber), code.clone());
240
241 Ok(code)
242 }
243
244 pub async fn get_balance(
245 &self,
246 address: Address,
247 blocknumber: u64,
248 ) -> Result<U256, TransportError> {
249 trace!(target: "backend::fork", "get_balance={:?}", address);
250 self.provider().get_balance(address).block_id(blocknumber.into()).await
251 }
252
253 pub async fn get_nonce(&self, address: Address, block: u64) -> Result<u64, TransportError> {
254 trace!(target: "backend::fork", "get_nonce={:?}", address);
255 self.provider().get_transaction_count(address).block_id(block.into()).await
256 }
257
258 pub async fn get_account(
259 &self,
260 address: Address,
261 blocknumber: u64,
262 ) -> Result<TrieAccount, TransportError> {
263 trace!(target: "backend::fork", "get_account={:?}", address);
264 self.provider().get_account(address).block_id(blocknumber.into()).await
265 }
266
267 pub async fn trace_transaction(&self, hash: B256) -> Result<Vec<Trace>, TransportError> {
268 if let Some(traces) = self.storage_read().transaction_traces.get(&hash).cloned() {
269 return Ok(traces);
270 }
271
272 let traces = self.provider().trace_transaction(hash).await?.into_iter().collect::<Vec<_>>();
273
274 let mut storage = self.storage_write();
275 storage.transaction_traces.insert(hash, traces.clone());
276
277 Ok(traces)
278 }
279
280 pub async fn trace_transaction_opcode_gas(
281 &self,
282 hash: B256,
283 ) -> Result<Option<TransactionOpcodeGas>, TransportError> {
284 self.provider().raw_request("trace_transactionOpcodeGas".into(), (hash,)).await
285 }
286
287 pub async fn trace_call(
289 &self,
290 request: WithOtherFields<TransactionRequest>,
291 trace_types: HashSet<TraceType>,
292 block: BlockId,
293 ) -> Result<TraceResults, TransportError> {
294 self.provider().raw_request("trace_call".into(), (request, trace_types, block)).await
295 }
296
297 pub async fn trace_get(
299 &self,
300 hash: B256,
301 indices: Vec<Index>,
302 ) -> Result<Option<Trace>, TransportError> {
303 self.provider().raw_request("trace_get".into(), (hash, indices)).await
304 }
305
306 pub async fn debug_trace_transaction(
307 &self,
308 hash: B256,
309 opts: GethDebugTracingOptions,
310 ) -> Result<GethTrace, TransportError> {
311 if let Some(traces) = self.storage_read().geth_transaction_traces.get(&hash).cloned() {
312 return Ok(traces);
313 }
314
315 let trace = self.provider().debug_trace_transaction(hash, opts).await?;
316
317 let mut storage = self.storage_write();
318 storage.geth_transaction_traces.insert(hash, trace.clone());
319
320 Ok(trace)
321 }
322
323 pub async fn debug_trace_call(
324 &self,
325 request: WithOtherFields<TransactionRequest>,
326 block_id: BlockId,
327 opts: GethDebugTracingCallOptions,
328 ) -> Result<GethTrace, TransportError> {
329 self.provider().raw_request("debug_traceCall".into(), (request, block_id, opts)).await
330 }
331
332 pub async fn debug_code_by_hash(
333 &self,
334 code_hash: B256,
335 block_id: Option<BlockId>,
336 ) -> Result<Option<Bytes>, TransportError> {
337 self.provider().debug_code_by_hash(code_hash, block_id).await
338 }
339
340 pub async fn debug_account_info_at(
341 &self,
342 block_id: BlockId,
343 tx_index: Index,
344 address: Address,
345 ) -> Result<Option<AccountInfo>, TransportError> {
346 self.provider()
347 .raw_request("debug_accountInfoAt".into(), (block_id, tx_index, address))
348 .await
349 }
350
351 pub async fn debug_trace_block_by_hash(
352 &self,
353 block_hash: B256,
354 opts: GethDebugTracingOptions,
355 ) -> Result<Vec<TraceResult>, TransportError> {
356 if let Some(traces) = self.storage_read().geth_block_traces.get(&block_hash).cloned() {
357 return Ok(traces);
358 }
359
360 let trace_results = self.provider().debug_trace_block_by_hash(block_hash, opts).await?;
361
362 let mut storage = self.storage_write();
363 storage.geth_block_traces.insert(block_hash, trace_results.clone());
364
365 Ok(trace_results)
366 }
367
368 pub async fn debug_trace_block_by_number(
369 &self,
370 number: u64,
371 opts: GethDebugTracingOptions,
372 ) -> Result<Vec<TraceResult>, TransportError> {
373 if let Ok(Some(block)) = self.provider().get_block_by_number(number.into()).await {
374 let block_hash = block.header().hash();
375 return self.debug_trace_block_by_hash(block_hash, opts).await;
376 }
377
378 self.provider().debug_trace_block_by_number(number.into(), opts).await
379 }
380
381 pub async fn trace_block(&self, number: u64) -> Result<Vec<Trace>, TransportError> {
382 if let Some(traces) = self.storage_read().block_traces.get(&number).cloned() {
383 return Ok(traces);
384 }
385
386 let traces =
387 self.provider().trace_block(number.into()).await?.into_iter().collect::<Vec<_>>();
388
389 let mut storage = self.storage_write();
390 storage.block_traces.insert(number, traces.clone());
391
392 Ok(traces)
393 }
394
395 pub async fn trace_replay_block_transactions(
396 &self,
397 number: u64,
398 trace_types: HashSet<TraceType>,
399 ) -> Result<Vec<TraceResultsWithTransactionHash>, TransportError> {
400 self.provider()
403 .trace_replay_block_transactions(BlockId::number(number))
404 .trace_types(trace_types)
405 .await
406 }
407
408 pub async fn trace_replay_transaction(
409 &self,
410 hash: B256,
411 trace_types: HashSet<TraceType>,
412 ) -> Result<TraceResults, TransportError> {
413 self.provider().raw_request("trace_replayTransaction".into(), (hash, trace_types)).await
414 }
415
416 pub async fn trace_block_opcode_gas(
417 &self,
418 block_id: BlockId,
419 ) -> Result<Option<BlockOpcodeGas>, TransportError> {
420 self.provider().raw_request("trace_blockOpcodeGas".into(), (block_id,)).await
421 }
422
423 pub async fn reset(
425 &self,
426 urls: Vec<String>,
427 block_number: impl Into<BlockId>,
428 ) -> Result<(), BlockchainError> {
429 let block_number = block_number.into();
430 {
431 self.database
432 .write()
433 .await
434 .maybe_reset(urls.clone(), block_number)
435 .map_err(BlockchainError::Internal)?;
436 }
437
438 self.prepare_reset(urls, block_number).await?;
439
440 let number = self.block_number();
441 let block_hash = self.block_hash();
442 self.database.write().await.insert_block_hash(U256::from(number), block_hash);
443
444 Ok(())
445 }
446
447 pub(crate) async fn prepare_reset(
449 &self,
450 urls: Vec<String>,
451 block_number: BlockId,
452 ) -> Result<(), BlockchainError> {
453 if !urls.is_empty() {
454 self.config.write().update_urls(urls)?;
455 let override_chain_id = self.config.read().override_chain_id;
456 let chain_id = if let Some(chain_id) = override_chain_id {
457 chain_id
458 } else {
459 self.provider().get_chain_id().await?
460 };
461 self.config.write().chain_id = chain_id;
462 }
463
464 let provider = self.provider();
465 let block =
466 provider.get_block(block_number).await?.ok_or(BlockchainError::BlockNotFound)?;
467 let block_hash = block.header().hash();
468 let timestamp = block.header().timestamp();
469 let base_fee = block.header().base_fee_per_gas();
470 let total_difficulty = block.header().difficulty();
471
472 let number = block.header().number();
473 self.config.write().update_block(
474 number,
475 block_hash,
476 timestamp,
477 base_fee.map(|g| g as u128),
478 total_difficulty,
479 );
480
481 self.clear_cached_storage();
482
483 Ok(())
484 }
485
486 pub async fn call(
488 &self,
489 request: &N::TransactionRequest,
490 block: Option<BlockNumber>,
491 ) -> Result<Bytes, TransportError> {
492 let block = block.unwrap_or(BlockNumber::Latest);
493 let res = self.provider().call(request.clone()).block(block.into()).await?;
494
495 Ok(res)
496 }
497
498 pub async fn call_many(
500 &self,
501 bundles: Vec<Bundle<WithOtherFields<TransactionRequest>>>,
502 state_context: Option<StateContext>,
503 state_override: Option<StateOverride>,
504 ) -> Result<Vec<Vec<EthCallResponse>>, TransportError> {
505 self.provider()
506 .raw_request("eth_callMany".into(), (bundles, state_context, state_override))
507 .await
508 }
509
510 pub async fn call_bundle(
512 &self,
513 bundle: EthCallBundle,
514 ) -> Result<EthCallBundleResponse, TransportError> {
515 self.provider().raw_request("eth_callBundle".into(), (bundle,)).await
516 }
517
518 pub async fn simulate_v1(
520 &self,
521 request: &SimulatePayload,
522 block: Option<BlockNumber>,
523 ) -> Result<Vec<SimulatedBlock<N::BlockResponse>>, TransportError> {
524 let mut simulate_call = self.provider().simulate(request);
525 if let Some(n) = block {
526 simulate_call = simulate_call.number(n.as_number().unwrap());
527 }
528
529 let res = simulate_call.await?;
530
531 Ok(res)
532 }
533
534 pub async fn estimate_gas(
536 &self,
537 request: &N::TransactionRequest,
538 block: Option<BlockNumber>,
539 ) -> Result<u128, TransportError> {
540 let block = block.unwrap_or_default();
541 let res = self.provider().estimate_gas(request.clone()).block(block.into()).await?;
542
543 Ok(res as u128)
544 }
545
546 pub async fn create_access_list(
548 &self,
549 request: &N::TransactionRequest,
550 block: Option<BlockNumber>,
551 ) -> Result<AccessListResult, TransportError> {
552 self.provider().create_access_list(request).block_id(block.unwrap_or_default().into()).await
553 }
554
555 pub async fn transaction_by_block_number_and_index(
556 &self,
557 number: u64,
558 index: usize,
559 ) -> Result<Option<N::TransactionResponse>, TransportError> {
560 let block = self.block_by_number(number).await?;
561 self.transaction_at_block_index(block, index).await
562 }
563
564 pub async fn transaction_by_block_hash_and_index(
565 &self,
566 hash: B256,
567 index: usize,
568 ) -> Result<Option<N::TransactionResponse>, TransportError> {
569 let block = self.block_by_hash(hash).await?;
570 self.transaction_at_block_index(block, index).await
571 }
572
573 async fn transaction_at_block_index(
574 &self,
575 block: Option<N::BlockResponse>,
576 index: usize,
577 ) -> Result<Option<N::TransactionResponse>, TransportError> {
578 if let Some(block) = block {
579 match block.transactions() {
580 BlockTransactions::Full(txs) => {
581 if let Some(tx) = txs.get(index) {
582 return Ok(Some(tx.clone()));
583 }
584 }
585 BlockTransactions::Hashes(hashes) => {
586 if let Some(tx_hash) = hashes.get(index) {
587 return self.transaction_by_hash(*tx_hash).await;
588 }
589 }
590 BlockTransactions::Uncle => {}
591 }
592 }
593 Ok(None)
594 }
595
596 pub async fn transaction_by_hash(
597 &self,
598 hash: B256,
599 ) -> Result<Option<N::TransactionResponse>, TransportError> {
600 trace!(target: "backend::fork", "transaction_by_hash={:?}", hash);
601 if let tx @ Some(_) = self.storage_read().transactions.get(&hash).cloned() {
602 return Ok(tx);
603 }
604
605 let tx = self.provider().get_transaction_by_hash(hash).await?;
606 if let Some(tx) = tx.clone() {
607 let mut storage = self.storage_write();
608 storage.transactions.insert(hash, tx);
609 }
610 Ok(tx)
611 }
612
613 pub async fn block_by_hash(
614 &self,
615 hash: B256,
616 ) -> Result<Option<N::BlockResponse>, TransportError> {
617 if let Some(mut block) = self.storage_read().blocks.get(&hash).cloned() {
618 block.transactions_mut().convert_to_hashes();
619 return Ok(Some(block));
620 }
621
622 Ok(self.fetch_full_block(hash).await?.map(|mut b| {
623 b.transactions_mut().convert_to_hashes();
624 b
625 }))
626 }
627
628 pub async fn block_by_hash_full(
629 &self,
630 hash: B256,
631 ) -> Result<Option<N::BlockResponse>, TransportError> {
632 if let Some(block) = self.storage_read().blocks.get(&hash).cloned()
633 && let Some(block) = self.convert_to_full_block(block)
634 {
635 return Ok(Some(block));
636 }
637 self.fetch_full_block(hash).await
638 }
639
640 pub async fn block_by_number(
641 &self,
642 block_number: u64,
643 ) -> Result<Option<N::BlockResponse>, TransportError> {
644 if let Some(mut block) = self
645 .storage_read()
646 .hashes
647 .get(&block_number)
648 .and_then(|hash| self.storage_read().blocks.get(hash).cloned())
649 {
650 block.transactions_mut().convert_to_hashes();
651 return Ok(Some(block));
652 }
653
654 let mut block = self.fetch_full_block(block_number).await?;
655 if let Some(block) = &mut block {
656 block.transactions_mut().convert_to_hashes();
657 }
658 Ok(block)
659 }
660
661 pub async fn block_by_number_full(
662 &self,
663 block_number: u64,
664 ) -> Result<Option<N::BlockResponse>, TransportError> {
665 if let Some(block) = self
666 .storage_read()
667 .hashes
668 .get(&block_number)
669 .copied()
670 .and_then(|hash| self.storage_read().blocks.get(&hash).cloned())
671 && let Some(block) = self.convert_to_full_block(block)
672 {
673 return Ok(Some(block));
674 }
675
676 self.fetch_full_block(block_number).await
677 }
678
679 async fn fetch_full_block(
680 &self,
681 block_id: impl Into<BlockId>,
682 ) -> Result<Option<N::BlockResponse>, TransportError> {
683 if let Some(block) = self.provider().get_block(block_id.into()).full().await? {
684 let hash = block.header().hash();
685 let block_number = block.header().number();
686 let mut storage = self.storage_write();
687 let block_txs = match block.transactions() {
689 BlockTransactions::Full(txs) => txs.to_owned(),
690 _ => vec![],
691 };
692 storage.transactions.extend(block_txs.iter().map(|tx| (tx.tx_hash(), tx.clone())));
693 storage.hashes.insert(block_number, hash);
694 storage.blocks.insert(hash, block.clone());
695 return Ok(Some(block));
696 }
697
698 Ok(None)
699 }
700
701 fn convert_to_full_block(&self, mut block: N::BlockResponse) -> Option<N::BlockResponse> {
703 let storage = self.storage.read();
704 let transactions = block
705 .transactions()
706 .hashes()
707 .map(|hash| storage.transactions.get(&hash).cloned())
708 .collect::<Option<Vec<_>>>()?;
709 *block.transactions_mut() = BlockTransactions::Full(transactions);
710 Some(block)
711 }
712}
713
714impl ClientFork {
715 pub async fn transaction_receipt(
716 &self,
717 hash: B256,
718 ) -> Result<Option<FoundryTxReceipt>, BlockchainError> {
719 if let Some(receipt) = self.storage_read().transaction_receipts.get(&hash).cloned() {
720 return Ok(Some(receipt));
721 }
722
723 if let Some(receipt) = self.provider().get_transaction_receipt(hash).await? {
724 let receipt = FoundryTxReceipt::try_from(receipt)
725 .map_err(|_| BlockchainError::FailedToDecodeReceipt)?;
726 let mut storage = self.storage_write();
727 storage.transaction_receipts.insert(hash, receipt.clone());
728 return Ok(Some(receipt));
729 }
730
731 Ok(None)
732 }
733
734 pub async fn block_receipts(
735 &self,
736 number: u64,
737 ) -> Result<Option<Vec<FoundryTxReceipt>>, BlockchainError> {
738 if let receipts @ Some(_) = self.storage_read().block_receipts.get(&number).cloned() {
739 return Ok(receipts);
740 }
741
742 if self.predates_fork_inclusive(number) {
746 let receipts = self.provider().get_block_receipts(BlockId::from(number)).await?;
747 let receipts = receipts
748 .map(|r| {
749 r.into_iter()
750 .map(|r| {
751 FoundryTxReceipt::try_from(r)
752 .map_err(|_| BlockchainError::FailedToDecodeReceipt)
753 })
754 .collect::<Result<Vec<_>, _>>()
755 })
756 .transpose()?;
757
758 if let Some(receipts) = receipts.clone() {
759 let mut storage = self.storage_write();
760 storage.block_receipts.insert(number, receipts);
761 }
762
763 return Ok(receipts);
764 }
765
766 Ok(None)
767 }
768
769 pub async fn uncle_by_block_hash_and_index(
770 &self,
771 hash: B256,
772 index: usize,
773 ) -> Result<Option<AnyRpcBlock>, TransportError> {
774 if let Some(block) = self.block_by_hash(hash).await? {
775 return self.uncles_by_block_and_index(block, index).await;
776 }
777 Ok(None)
778 }
779
780 pub async fn uncle_by_block_number_and_index(
781 &self,
782 number: u64,
783 index: usize,
784 ) -> Result<Option<AnyRpcBlock>, TransportError> {
785 if let Some(block) = self.block_by_number(number).await? {
786 return self.uncles_by_block_and_index(block, index).await;
787 }
788 Ok(None)
789 }
790
791 async fn uncles_by_block_and_index(
792 &self,
793 block: AnyRpcBlock,
794 index: usize,
795 ) -> Result<Option<AnyRpcBlock>, TransportError> {
796 let block_hash = block.header().hash();
797 let block_number = block.header().number();
798 if let Some(uncles) = self.storage_read().uncles.get(&block_hash) {
799 return Ok(uncles.get(index).cloned());
800 }
801
802 let mut uncles = Vec::with_capacity(block.uncles.len());
803 for (uncle_idx, _) in block.uncles.iter().enumerate() {
804 let uncle =
805 match self.provider().get_uncle(block_number.into(), uncle_idx as u64).await? {
806 Some(u) => u,
807 None => return Ok(None),
808 };
809 uncles.push(uncle);
810 }
811 self.storage_write().uncles.insert(block_hash, uncles.clone());
812 Ok(uncles.get(index).cloned())
813 }
814}
815
816#[derive(Clone, Debug)]
818pub struct ClientForkConfig<N: Network = AnyNetwork> {
819 pub fork_urls: Vec<String>,
823 pub block_number: u64,
825 pub block_hash: B256,
827 pub transaction_hash: Option<B256>,
829 pub provider: Arc<RetryProvider<N>>,
830 pub chain_id: u64,
831 pub override_chain_id: Option<u64>,
832 pub hardfork: Option<FoundryHardfork>,
834 pub timestamp: u64,
836 pub base_fee: Option<u128>,
838 pub blob_gas_used: Option<u128>,
840 pub blob_excess_gas_and_price: Option<BlobExcessGasAndPrice>,
842 pub timeout: Duration,
844 pub retries: u32,
846 pub backoff: Duration,
848 pub compute_units_per_second: u64,
850 pub headers: Vec<String>,
852 pub total_difficulty: U256,
854 pub force_transactions: Option<Vec<PoolTransaction<FoundryTxEnvelope>>>,
856}
857
858impl<N: Network> ClientForkConfig<N> {
859 pub fn eth_rpc_url(&self) -> Option<&str> {
861 self.fork_urls.first().map(|s| s.as_str())
862 }
863
864 fn update_urls(&mut self, urls: Vec<String>) -> Result<(), BlockchainError> {
870 let primary = urls.first().ok_or_else(|| {
871 BlockchainError::InvalidUrl("at least one fork URL required".to_string())
872 })?;
873
874 let builder = ProviderBuilder::<N>::new(primary.as_str())
875 .timeout(self.timeout)
876 .max_retry(self.retries)
877 .initial_backoff(self.backoff.as_millis() as u64)
878 .compute_units_per_second(self.compute_units_per_second)
879 .headers(self.headers.clone());
880
881 self.provider = Arc::new(if urls.len() > 1 {
882 builder
883 .build_fallback(urls.clone())
884 .map_err(|e| BlockchainError::InvalidUrl(format!("{primary}: {e}")))?
885 } else {
886 builder.build().map_err(|e| BlockchainError::InvalidUrl(format!("{primary}: {e}")))?
887 });
888 trace!(target: "fork", "Updated fork urls: {:?}", urls);
889 self.fork_urls = urls;
890 Ok(())
891 }
892
893 pub fn update_block(
895 &mut self,
896 block_number: u64,
897 block_hash: B256,
898 timestamp: u64,
899 base_fee: Option<u128>,
900 total_difficulty: U256,
901 ) {
902 self.block_number = block_number;
903 self.block_hash = block_hash;
904 self.timestamp = timestamp;
905 self.base_fee = base_fee;
906 self.total_difficulty = total_difficulty;
907 trace!(target: "fork", "Updated block number={} hash={:?}", block_number, block_hash);
908 }
909}
910
911#[derive(Clone, Debug)]
915pub struct ForkedStorage<N: Network = AnyNetwork> {
916 pub uncles: FbHashMap<32, Vec<N::BlockResponse>>,
917 pub blocks: FbHashMap<32, N::BlockResponse>,
918 pub hashes: HashMap<u64, B256>,
919 pub transactions: FbHashMap<32, N::TransactionResponse>,
920 pub transaction_receipts: FbHashMap<32, FoundryTxReceipt>,
921 pub transaction_traces: FbHashMap<32, Vec<Trace>>,
922 pub logs: HashMap<Filter, Vec<Log>>,
923 pub geth_transaction_traces: FbHashMap<32, GethTrace>,
924 pub geth_block_traces: FbHashMap<32, Vec<TraceResult>>,
925 pub block_traces: HashMap<u64, Vec<Trace>>,
926 pub block_receipts: HashMap<u64, Vec<FoundryTxReceipt>>,
927 pub code_at: HashMap<(Address, u64), Bytes>,
928}
929
930impl<N: Network> Default for ForkedStorage<N> {
931 fn default() -> Self {
932 Self {
933 uncles: Default::default(),
934 blocks: Default::default(),
935 hashes: Default::default(),
936 transactions: Default::default(),
937 transaction_receipts: Default::default(),
938 transaction_traces: Default::default(),
939 logs: Default::default(),
940 geth_transaction_traces: Default::default(),
941 geth_block_traces: Default::default(),
942 block_traces: Default::default(),
943 block_receipts: Default::default(),
944 code_at: Default::default(),
945 }
946 }
947}
948
949impl<N: Network> ForkedStorage<N> {
950 pub fn clear(&mut self) {
952 *self = Self::default()
954 }
955}