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, 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/// Represents a fork of a remote client
49///
50/// This type contains a subset of the [`EthApi`](crate::eth::EthApi) functions but will exclusively
51/// fetch the requested data from the remote client, if it wasn't already fetched.
52#[derive(Clone, Debug)]
53pub struct ClientFork<N: Network = AnyNetwork> {
54    /// Contains the cached data
55    pub storage: Arc<RwLock<ForkedStorage<N>>>,
56    /// contains the info how the fork is configured
57    // Wrapping this in a lock, ensures we can update this on the fly via additional custom RPC
58    // endpoints
59    pub config: Arc<RwLock<ClientForkConfig<N>>>,
60    /// This also holds a handle to the underlying database
61    pub database: Arc<AsyncRwLock<Box<dyn Db>>>,
62    /// The RPC URL associated with the state in the underlying database.
63    database_rpc_url: Arc<RwLock<Option<String>>>,
64}
65
66impl<N: Network> ClientFork<N> {
67    /// Creates a new instance of the fork
68    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    /// Removes all data cached from previous responses
79    pub fn clear_cached_storage(&self) {
80        self.storage.write().clear()
81    }
82
83    /// Returns true whether the block predates the fork
84    pub fn predates_fork(&self, block: u64) -> bool {
85        block < self.block_number()
86    }
87
88    /// Returns true whether the block predates the fork _or_ is the same block as the fork
89    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    /// Returns the transaction hash we forked off of, if any.
102    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    /// Returns the fee history  `eth_feeHistory`
147    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    /// Sends `eth_getProof`
157    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    /// Sends `eth_getBlockAccessList`
167    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    /// Sends `eth_getBlockAccessListByBlockHash`
175    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    /// Sends `eth_getBlockAccessListByBlockNumber`
183    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    /// Sends `eth_getBlockAccessListRaw`.
193    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    /// Sends `trace_call`.
288    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    /// Sends `trace_get`.
298    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        // Forward to upstream provider for historical blocks. Use the typed trace API so the block
401        // and trace types are serialized in the format upstream providers expect.
402        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    /// Reset the fork to a fresh forked state, and optionally update the fork config
424    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    /// Updates the fork configuration for a reset without modifying the current database.
448    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    /// Sends `eth_call`
487    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    /// Sends `eth_callMany`
499    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    /// Sends `eth_callBundle`.
511    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    /// Sends `eth_simulateV1`
519    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    /// Sends `eth_estimateGas`
535    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    /// Sends `eth_createAccessList`
547    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            // also insert all transactions
688            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    /// Converts a block of hashes into a full block
702    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        // TODO Needs to be removed.
743        // Since alloy doesn't indicate in the result whether the block exists,
744        // this is being temporarily implemented in anvil.
745        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/// Contains all fork metadata
817#[derive(Clone, Debug)]
818pub struct ClientForkConfig<N: Network = AnyNetwork> {
819    /// All fork URLs. The first entry is the primary endpoint.
820    /// When multiple URLs are present, requests are distributed using
821    /// round-robin load balancing with retry-based failover.
822    pub fork_urls: Vec<String>,
823    /// The block number of the forked block
824    pub block_number: u64,
825    /// The hash of the forked block
826    pub block_hash: B256,
827    /// The transaction hash we forked off of, if any.
828    pub transaction_hash: Option<B256>,
829    pub provider: Arc<RetryProvider<N>>,
830    pub chain_id: u64,
831    pub override_chain_id: Option<u64>,
832    /// The hardfork resolved for the forked block, if known.
833    pub hardfork: Option<FoundryHardfork>,
834    /// The timestamp for the forked block
835    pub timestamp: u64,
836    /// The basefee of the forked block
837    pub base_fee: Option<u128>,
838    /// Blob gas used of the forked block
839    pub blob_gas_used: Option<u128>,
840    /// Blob excess gas and price of the forked block
841    pub blob_excess_gas_and_price: Option<BlobExcessGasAndPrice>,
842    /// request timeout
843    pub timeout: Duration,
844    /// request retries for spurious networks
845    pub retries: u32,
846    /// request retries for spurious networks
847    pub backoff: Duration,
848    /// available CUPS
849    pub compute_units_per_second: u64,
850    /// Headers to include with RPC requests
851    pub headers: Vec<String>,
852    /// total difficulty of the chain until this block
853    pub total_difficulty: U256,
854    /// Transactions to force include in the forked chain
855    pub force_transactions: Option<Vec<PoolTransaction<FoundryTxEnvelope>>>,
856}
857
858impl<N: Network> ClientForkConfig<N> {
859    /// Returns the primary RPC URL (first entry in `fork_urls`).
860    pub fn eth_rpc_url(&self) -> Option<&str> {
861        self.fork_urls.first().map(|s| s.as_str())
862    }
863
864    /// Updates the provider URLs
865    ///
866    /// # Errors
867    ///
868    /// This will fail if no new provider could be established (erroneous URL)
869    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    /// Updates the block forked off `(block number, block hash, timestamp)`
894    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/// Contains cached state fetched to serve EthApi requests
912///
913/// This is used as a cache so repeated requests to the same data are not sent to the remote client
914#[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    /// Clears all data
951    pub fn clear(&mut self) {
952        // simply replace with a completely new, empty instance
953        *self = Self::default()
954    }
955}