Skip to main content

anvil/eth/backend/
fork.rs

1//! Support for forking off another client
2
3use 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    /// Returns whether this identity was reported by an Anvil endpoint.
64    pub(crate) const fn is_authoritative(self) -> bool {
65        self.hardfork.is_some()
66    }
67
68    /// Returns whether two endpoints expose the same fork execution context.
69    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
80/// Ensures Anvil's EVM backend can execute the resolved upstream source chain.
81///
82/// Anvil's execution chain-ID override does not change the bytecode format in remote fork state.
83pub(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/// Represents a fork of a remote client
95///
96/// This type contains a subset of the [`EthApi`](crate::eth::EthApi) functions but will exclusively
97/// fetch the requested data from the remote client, if it wasn't already fetched.
98#[derive(Clone, Debug)]
99pub struct ClientFork<N: Network = AnyNetwork> {
100    /// Contains the cached data
101    pub storage: Arc<RwLock<ForkedStorage<N>>>,
102    /// contains the info how the fork is configured
103    // Wrapping this in a lock, ensures we can update this on the fly via additional custom RPC
104    // endpoints
105    pub config: Arc<RwLock<ClientForkConfig<N>>>,
106    /// This also holds a handle to the underlying database
107    pub database: Arc<AsyncRwLock<Box<dyn Db>>>,
108}
109
110impl<N: Network> ClientFork<N> {
111    /// Creates a new instance of the fork
112    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    /// Removes all data cached from previous responses
117    pub fn clear_cached_storage(&self) {
118        self.storage.write().clear()
119    }
120
121    /// Returns true whether the block predates the fork
122    pub fn predates_fork(&self, block: u64) -> bool {
123        block < self.block_number()
124    }
125
126    /// Returns true whether the block predates the fork _or_ is the same block as the fork
127    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    /// Returns the transaction hash we forked off of, if any.
140    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    /// Returns the execution chain ID exposed by the forked node.
165    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    /// Returns the fee history  `eth_feeHistory`
182    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    /// Sends `eth_getProof`
192    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    /// Sends `eth_getBlockAccessList`
202    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    /// Sends `eth_getBlockAccessListByBlockHash`
210    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    /// Sends `eth_getBlockAccessListByBlockNumber`
218    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    /// Sends `eth_getBlockAccessListRaw`.
228    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    /// Sends `trace_call`.
323    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    /// Sends `trace_get`.
333    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        // Forward to upstream provider for historical blocks. Use the typed trace API so the block
455        // and trace types are serialized in the format upstream providers expect.
456        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    /// Sends `eth_call`
478    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    /// Sends `eth_call` with a network-specific request.
490    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    /// Sends `eth_callMany`
501    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    /// Sends `eth_callBundle`.
513    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    /// Sends `eth_simulateV1`
521    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    /// Sends `eth_estimateGas`
530    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    /// Sends `eth_estimateGas` with a network-specific request.
542    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    /// Sends `eth_createAccessList`
555    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    /// Sends `eth_createAccessList` with a network-specific request.
564    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    /// Fetches a block selected by its original identifier directly from the fork provider.
699    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            // also insert all transactions
715            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    /// Converts a block of hashes into a full block
729    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        // TODO Needs to be removed.
770        // Since alloy doesn't indicate in the result whether the block exists,
771        // this is being temporarily implemented in anvil.
772        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/// Contains all fork metadata
844#[derive(Clone, Debug)]
845pub struct ClientForkConfig<N: Network = AnyNetwork> {
846    /// All fork URLs. The first entry is the primary endpoint.
847    /// When multiple URLs are present, requests are distributed using
848    /// round-robin load balancing with retry-based failover.
849    pub fork_urls: Vec<String>,
850    /// The block number of the forked block
851    pub block_number: u64,
852    /// The hash of the forked block
853    pub block_hash: B256,
854    /// The transaction hash we forked off of, if any.
855    pub transaction_hash: Option<B256>,
856    pub provider: Arc<RetryProvider<N>>,
857    /// Chain ID of the remote fork source.
858    pub chain_id: u64,
859    /// Chain ID exposed by the fork endpoint, including inherited execution overrides.
860    pub execution_chain_id: u64,
861    /// Explicit execution chain ID exposed by the local node.
862    pub override_chain_id: Option<u64>,
863    /// User-provided source chain ID that avoids remote discovery.
864    pub fork_chain_id: Option<u64>,
865    /// The effective hardfork used to execute the forked block.
866    pub hardfork: Option<FoundryHardfork>,
867    /// Stable endpoint identity captured with the fork block.
868    pub(crate) endpoint_identity: ForkEndpointIdentity,
869    /// The timestamp for the forked block
870    pub timestamp: u64,
871    /// The basefee of the forked block
872    pub base_fee: Option<u128>,
873    /// Blob gas used of the forked block
874    pub blob_gas_used: Option<u128>,
875    /// Blob excess gas and price of the forked block
876    pub blob_excess_gas_and_price: Option<BlobExcessGasAndPrice>,
877    /// request timeout
878    pub timeout: Duration,
879    /// request retries for spurious networks
880    pub retries: u32,
881    /// request retries for spurious networks
882    pub backoff: Duration,
883    /// available CUPS
884    pub compute_units_per_second: u64,
885    /// Headers to include with RPC requests
886    pub headers: Vec<String>,
887    /// total difficulty of the chain until this block
888    pub total_difficulty: U256,
889}
890
891impl<N: Network> ClientForkConfig<N> {
892    /// Returns the primary RPC URL (first entry in `fork_urls`).
893    pub fn eth_rpc_url(&self) -> Option<&str> {
894        self.fork_urls.first().map(|s| s.as_str())
895    }
896
897    /// Updates the block forked off `(block number, block hash, timestamp)`
898    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/// Contains cached state fetched to serve EthApi requests
916///
917/// This is used as a cache so repeated requests to the same data are not sent to the remote client
918#[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    /// Clears all data
955    pub fn clear(&mut self) {
956        // simply replace with a completely new, empty instance
957        *self = Self::default()
958    }
959}