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