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, FilterBlockOption, FilterSet, 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, is_rpc_method_not_found};
39use foundry_evm::{
40 backend::{AccountFetchPolicy, BlockchainDb, account_fetch_policy_for_source},
41 fork::{cache_bal, validate_bal},
42 hardfork::FoundryHardfork,
43};
44use foundry_evm_networks::{NetworkConfigs, NetworkVariant};
45use foundry_primitives::FoundryTxReceipt;
46use parking_lot::{
47 RawRwLock, RwLock,
48 lock_api::{RwLockReadGuard, RwLockWriteGuard},
49};
50use revm::{context_interface::block::BlobExcessGasAndPrice, primitives::hardfork::SpecId};
51use std::{sync::Arc, time::Duration};
52use tokio::sync::RwLock as AsyncRwLock;
53
54#[derive(Clone, Copy, Debug, PartialEq, Eq)]
55pub(crate) struct ForkEndpointIdentity {
56 pub(crate) execution_chain_id: u64,
57 pub(crate) source_chain_id: u64,
58 pub(crate) network: Option<NetworkVariant>,
59 pub(crate) network_profile: Option<NetworkConfigs>,
60 pub(crate) hardfork: Option<FoundryHardfork>,
61 pub(crate) instance_id: Option<B256>,
62 pub(crate) source_fork_block_number: Option<u64>,
63 pub(crate) source_fork_block_hash: Option<B256>,
64}
65
66impl ForkEndpointIdentity {
67 pub(crate) const fn is_authoritative(self) -> bool {
69 self.hardfork.is_some()
70 }
71
72 pub(crate) fn context_eq(self, other: Self) -> bool {
74 self.execution_chain_id == other.execution_chain_id
75 && self.source_chain_id == other.source_chain_id
76 && self.network == other.network
77 && self.network_profile == other.network_profile
78 && self.hardfork == other.hardfork
79 && self.source_fork_block_number == other.source_fork_block_number
80 && self.source_fork_block_hash == other.source_fork_block_hash
81 }
82}
83
84pub(crate) fn ensure_fork_network_supported(chain_id: u64) -> Result<(), BlockchainError> {
88 if matches!(NamedChain::try_from(chain_id), Ok(NamedChain::ZkSync | NamedChain::ZkSyncTestnet))
89 {
90 return Err(BlockchainError::UnsupportedForkNetwork {
91 chain_id,
92 reason: "Anvil's EVM backend cannot execute native EraVM bytecode; use `anvil-zksync` for zkSync Era forks",
93 });
94 }
95 Ok(())
96}
97
98#[derive(Clone, Debug)]
103pub struct ClientFork<N: Network = AnyNetwork> {
104 pub storage: Arc<RwLock<ForkedStorage<N>>>,
106 pub config: Arc<RwLock<ClientForkConfig<N>>>,
110 pub database: Arc<AsyncRwLock<Box<dyn Db>>>,
112}
113
114impl<N: Network> ClientFork<N> {
115 pub fn new(config: ClientForkConfig<N>, database: Arc<AsyncRwLock<Box<dyn Db>>>) -> Self {
117 Self { storage: Default::default(), config: Arc::new(RwLock::new(config)), database }
118 }
119
120 pub fn clear_cached_storage(&self) {
122 self.storage.write().clear()
123 }
124
125 pub fn predates_fork(&self, block: u64) -> bool {
127 block < self.block_number()
128 }
129
130 pub fn predates_fork_inclusive(&self, block: u64) -> bool {
132 block <= self.block_number()
133 }
134
135 pub fn timestamp(&self) -> u64 {
136 self.config.read().timestamp
137 }
138
139 pub fn block_number(&self) -> u64 {
140 self.config.read().block_number
141 }
142
143 pub fn evm_block_number(&self, rpc_number: u64) -> U256 {
147 let config = self.config.read();
148 U256::from(rpc_number)
149 .saturating_add(U256::from(config.evm_block_number))
150 .saturating_sub(U256::from(config.block_number))
151 }
152
153 pub fn rpc_block_number(&self, evm_number: U256) -> u64 {
155 let config = self.config.read();
156 evm_number
157 .saturating_add(U256::from(config.block_number))
158 .saturating_sub(U256::from(config.evm_block_number))
159 .saturating_to()
160 }
161
162 pub fn transaction_hash(&self) -> Option<B256> {
164 self.config.read().transaction_hash
165 }
166
167 pub fn total_difficulty(&self) -> U256 {
168 self.config.read().total_difficulty
169 }
170
171 pub fn base_fee(&self) -> Option<u128> {
172 self.config.read().base_fee
173 }
174
175 pub fn block_hash(&self) -> B256 {
176 self.config.read().block_hash
177 }
178
179 pub fn eth_rpc_url(&self) -> Option<String> {
180 self.config.read().eth_rpc_url().map(|s| s.to_string())
181 }
182
183 pub fn chain_id(&self) -> u64 {
184 self.config.read().chain_id
185 }
186
187 pub fn requires_account_info(&self) -> bool {
189 let config = self.config.read();
190 account_fetch_policy_for_source(
191 config.chain_id,
192 config.endpoint_identity.network_profile.unwrap_or_default(),
193 ) == AccountFetchPolicy::RequireAccountInfo
194 }
195
196 pub fn execution_chain_id(&self) -> u64 {
198 self.config.read().execution_chain_id
199 }
200
201 fn provider(&self) -> Arc<RetryProvider<N>> {
202 self.config.read().provider.clone()
203 }
204
205 fn storage_read(&self) -> RwLockReadGuard<'_, RawRwLock, ForkedStorage<N>> {
206 self.storage.read()
207 }
208
209 fn storage_write(&self) -> RwLockWriteGuard<'_, RawRwLock, ForkedStorage<N>> {
210 self.storage.write()
211 }
212
213 pub async fn fee_history(
215 &self,
216 block_count: u64,
217 newest_block: BlockNumber,
218 reward_percentiles: &[f64],
219 ) -> Result<FeeHistory, TransportError> {
220 self.provider().get_fee_history(block_count, newest_block, reward_percentiles).await
221 }
222
223 pub async fn get_proof(
225 &self,
226 address: Address,
227 keys: Vec<B256>,
228 block_number: Option<BlockId>,
229 ) -> Result<EIP1186AccountProofResponse, TransportError> {
230 self.provider().get_proof(address, keys).block_id(block_number.unwrap_or_default()).await
231 }
232
233 pub async fn block_access_list(
235 &self,
236 block_id: BlockId,
237 ) -> Result<Option<serde_json::Value>, TransportError> {
238 self.provider().raw_request("eth_getBlockAccessList".into(), (block_id,)).await
239 }
240
241 pub async fn block_access_list_by_hash(
243 &self,
244 block_hash: B256,
245 ) -> Result<Option<serde_json::Value>, TransportError> {
246 self.provider().raw_request("eth_getBlockAccessListByBlockHash".into(), (block_hash,)).await
247 }
248
249 pub async fn block_access_list_by_number(
251 &self,
252 block_number: BlockNumber,
253 ) -> Result<Option<serde_json::Value>, TransportError> {
254 self.provider()
255 .raw_request("eth_getBlockAccessListByBlockNumber".into(), (block_number,))
256 .await
257 }
258
259 pub async fn block_access_list_raw(
261 &self,
262 block_id: BlockId,
263 ) -> Result<Option<Bytes>, TransportError> {
264 self.provider().raw_request("eth_getBlockAccessListRaw".into(), (block_id,)).await
265 }
266
267 pub async fn storage_at(
268 &self,
269 address: Address,
270 index: U256,
271 number: Option<BlockNumber>,
272 ) -> Result<StorageValue, TransportError> {
273 self.provider()
274 .get_storage_at(address, index)
275 .block_id(number.unwrap_or_default().into())
276 .await
277 }
278
279 pub async fn logs(&self, filter: &Filter) -> Result<Vec<Log>, TransportError> {
280 let key = LogsCacheKey::from(filter);
281 if let Some(logs) = self.storage_read().logs.get(&key).cloned() {
282 return Ok(logs);
283 }
284
285 let logs = self.provider().get_logs(filter).await?;
286
287 let mut storage = self.storage_write();
288 storage.logs.insert(key, logs.clone());
289 Ok(logs)
290 }
291
292 pub async fn get_code(
293 &self,
294 address: Address,
295 blocknumber: u64,
296 ) -> Result<Bytes, TransportError> {
297 trace!(target: "backend::fork", "get_code={:?}", address);
298 if let Some(code) = self.storage_read().code_at.get(&(address, blocknumber)).cloned() {
299 return Ok(code);
300 }
301
302 let block_id = BlockId::number(blocknumber);
303
304 let code = self.provider().get_code_at(address).block_id(block_id).await?;
305
306 let mut storage = self.storage_write();
307 storage.code_at.insert((address, blocknumber), code.clone());
308
309 Ok(code)
310 }
311
312 pub async fn get_balance(
313 &self,
314 address: Address,
315 blocknumber: u64,
316 ) -> Result<U256, TransportError> {
317 trace!(target: "backend::fork", "get_balance={:?}", address);
318 self.provider().get_balance(address).block_id(blocknumber.into()).await
319 }
320
321 pub async fn get_account_info(
322 &self,
323 address: Address,
324 blocknumber: u64,
325 ) -> Result<AccountInfo, TransportError> {
326 trace!(target: "backend::fork", "get_account_info={:?}", address);
327 self.provider().get_account_info(address).block_id(blocknumber.into()).await
328 }
329
330 pub async fn get_nonce(&self, address: Address, block: u64) -> Result<u64, TransportError> {
331 trace!(target: "backend::fork", "get_nonce={:?}", address);
332 self.provider().get_transaction_count(address).block_id(block.into()).await
333 }
334
335 pub async fn get_account(
336 &self,
337 address: Address,
338 blocknumber: u64,
339 ) -> Result<TrieAccount, TransportError> {
340 trace!(target: "backend::fork", "get_account={:?}", address);
341 self.provider().get_account(address).block_id(blocknumber.into()).await
342 }
343
344 pub async fn trace_transaction(
345 &self,
346 hash: B256,
347 ) -> Result<Option<Vec<Trace>>, TransportError> {
348 if let Some(traces) = self.storage_read().transaction_traces.get(&hash).cloned() {
349 return Ok(Some(traces));
350 }
351
352 let traces = self
353 .provider()
354 .raw_request::<_, Option<Vec<Trace>>>("trace_transaction".into(), (hash,))
355 .await?;
356
357 if let Some(traces) = &traces {
358 self.storage_write().transaction_traces.insert(hash, traces.clone());
359 }
360
361 Ok(traces)
362 }
363
364 pub async fn trace_transaction_opcode_gas(
365 &self,
366 hash: B256,
367 ) -> Result<Option<TransactionOpcodeGas>, TransportError> {
368 self.provider().raw_request("trace_transactionOpcodeGas".into(), (hash,)).await
369 }
370
371 pub async fn trace_call(
373 &self,
374 request: WithOtherFields<TransactionRequest>,
375 trace_types: HashSet<TraceType>,
376 block: BlockId,
377 ) -> Result<TraceResults, TransportError> {
378 self.provider().raw_request("trace_call".into(), (request, trace_types, block)).await
379 }
380
381 pub async fn trace_get(
383 &self,
384 hash: B256,
385 indices: Vec<Index>,
386 ) -> Result<Option<Trace>, TransportError> {
387 self.provider().raw_request("trace_get".into(), (hash, indices)).await
388 }
389
390 pub async fn debug_trace_transaction(
391 &self,
392 hash: B256,
393 opts: GethDebugTracingOptions,
394 ) -> Result<GethTrace, TransportError> {
395 if let Some(trace) = self
396 .storage_read()
397 .geth_transaction_traces
398 .get(&hash)
399 .and_then(|traces| traces.iter().find(|(cached_opts, _)| cached_opts == &opts))
400 .map(|(_, trace)| trace.clone())
401 {
402 return Ok(trace);
403 }
404
405 let trace = self.provider().debug_trace_transaction(hash, opts.clone()).await?;
406
407 let mut storage = self.storage_write();
408 let traces = storage.geth_transaction_traces.entry(hash).or_default();
409 if !traces.iter().any(|(cached_opts, _)| cached_opts == &opts) {
410 traces.push((opts, trace.clone()));
411 }
412
413 Ok(trace)
414 }
415
416 pub async fn debug_trace_call(
417 &self,
418 request: WithOtherFields<TransactionRequest>,
419 block_id: BlockId,
420 opts: GethDebugTracingCallOptions,
421 ) -> Result<GethTrace, TransportError> {
422 self.provider().raw_request("debug_traceCall".into(), (request, block_id, opts)).await
423 }
424
425 pub async fn debug_code_by_hash(
426 &self,
427 code_hash: B256,
428 block_id: Option<BlockId>,
429 ) -> Result<Option<Bytes>, TransportError> {
430 self.provider().debug_code_by_hash(code_hash, block_id).await
431 }
432
433 pub async fn debug_account_info_at(
434 &self,
435 block_id: BlockId,
436 tx_index: Index,
437 address: Address,
438 ) -> Result<Option<AccountInfo>, TransportError> {
439 self.provider()
440 .raw_request("debug_accountInfoAt".into(), (block_id, tx_index, address))
441 .await
442 }
443
444 pub async fn debug_trace_block_by_hash(
445 &self,
446 block_hash: B256,
447 opts: GethDebugTracingOptions,
448 ) -> Result<Vec<TraceResult>, TransportError> {
449 if let Some(traces) = self
450 .storage_read()
451 .geth_block_traces
452 .get(&block_hash)
453 .and_then(|traces| traces.iter().find(|(cached_opts, _)| cached_opts == &opts))
454 .map(|(_, traces)| traces.clone())
455 {
456 return Ok(traces);
457 }
458
459 let trace_results =
460 self.provider().debug_trace_block_by_hash(block_hash, opts.clone()).await?;
461
462 let mut storage = self.storage_write();
463 let traces = storage.geth_block_traces.entry(block_hash).or_default();
464 if !traces.iter().any(|(cached_opts, _)| cached_opts == &opts) {
465 traces.push((opts, trace_results.clone()));
466 }
467
468 Ok(trace_results)
469 }
470
471 pub async fn debug_trace_block_by_number(
472 &self,
473 number: u64,
474 opts: GethDebugTracingOptions,
475 ) -> Result<Vec<TraceResult>, TransportError> {
476 if let Ok(Some(block)) = self.provider().get_block_by_number(number.into()).await {
477 let block_hash = block.header().hash();
478 return self.debug_trace_block_by_hash(block_hash, opts).await;
479 }
480
481 self.provider().debug_trace_block_by_number(number.into(), opts).await
482 }
483
484 pub async fn trace_block(&self, number: u64) -> Result<Vec<Trace>, TransportError> {
485 if let Some(traces) = self.storage_read().block_traces.get(&number).cloned() {
486 return Ok(traces);
487 }
488
489 let traces =
490 self.provider().trace_block(number.into()).await?.into_iter().collect::<Vec<_>>();
491
492 let mut storage = self.storage_write();
493 storage.block_traces.insert(number, traces.clone());
494
495 Ok(traces)
496 }
497
498 pub async fn trace_replay_block_transactions(
499 &self,
500 number: u64,
501 trace_types: HashSet<TraceType>,
502 ) -> Result<Vec<TraceResultsWithTransactionHash>, TransportError> {
503 self.provider()
506 .trace_replay_block_transactions(BlockId::number(number))
507 .trace_types(trace_types)
508 .await
509 }
510
511 pub async fn trace_replay_transaction(
512 &self,
513 hash: B256,
514 trace_types: HashSet<TraceType>,
515 ) -> Result<Option<TraceResults>, TransportError> {
516 self.provider().raw_request("trace_replayTransaction".into(), (hash, trace_types)).await
517 }
518
519 pub async fn trace_block_opcode_gas(
520 &self,
521 block_id: BlockId,
522 ) -> Result<Option<BlockOpcodeGas>, TransportError> {
523 self.provider().raw_request("trace_blockOpcodeGas".into(), (block_id,)).await
524 }
525
526 pub async fn call(
528 &self,
529 request: &N::TransactionRequest,
530 block: Option<BlockNumber>,
531 ) -> Result<Bytes, TransportError> {
532 let block = block.unwrap_or(BlockNumber::Latest);
533 let res = self.provider().call(request.clone()).block(block.into()).await?;
534
535 Ok(res)
536 }
537
538 pub async fn call_raw(
540 &self,
541 request: &WithOtherFields<TransactionRequest>,
542 block: Option<BlockNumber>,
543 ) -> Result<Bytes, TransportError> {
544 self.provider()
545 .raw_request("eth_call".into(), (request, block.unwrap_or(BlockNumber::Latest)))
546 .await
547 }
548
549 pub async fn call_many(
551 &self,
552 bundles: Vec<Bundle<WithOtherFields<TransactionRequest>>>,
553 state_context: Option<StateContext>,
554 state_override: Option<StateOverride>,
555 ) -> Result<Vec<Vec<EthCallResponse>>, TransportError> {
556 self.provider()
557 .raw_request("eth_callMany".into(), (bundles, state_context, state_override))
558 .await
559 }
560
561 pub async fn call_bundle(
563 &self,
564 bundle: EthCallBundle,
565 ) -> Result<EthCallBundleResponse, TransportError> {
566 self.provider().raw_request("eth_callBundle".into(), (bundle,)).await
567 }
568
569 pub async fn simulate_v1(
571 &self,
572 request: &SimulatePayload<WithOtherFields<TransactionRequest>>,
573 block: Option<BlockId>,
574 ) -> Result<Vec<SimulatedBlock<N::BlockResponse>>, TransportError> {
575 self.provider().raw_request("eth_simulateV1".into(), (request, block)).await
576 }
577
578 pub async fn estimate_gas(
580 &self,
581 request: &N::TransactionRequest,
582 block: Option<BlockNumber>,
583 ) -> Result<u128, TransportError> {
584 let block = block.unwrap_or_default();
585 let res = self.provider().estimate_gas(request.clone()).block(block.into()).await?;
586
587 Ok(res as u128)
588 }
589
590 pub async fn estimate_gas_raw(
592 &self,
593 request: &WithOtherFields<TransactionRequest>,
594 block: Option<BlockNumber>,
595 ) -> Result<u128, TransportError> {
596 let gas: U256 = self
597 .provider()
598 .raw_request("eth_estimateGas".into(), (request, block.unwrap_or_default()))
599 .await?;
600 Ok(gas.saturating_to())
601 }
602
603 pub async fn create_access_list(
605 &self,
606 request: &N::TransactionRequest,
607 block: Option<BlockNumber>,
608 ) -> Result<AccessListResult, TransportError> {
609 self.provider().create_access_list(request).block_id(block.unwrap_or_default().into()).await
610 }
611
612 pub async fn create_access_list_raw(
614 &self,
615 request: &WithOtherFields<TransactionRequest>,
616 block: Option<BlockNumber>,
617 ) -> Result<AccessListResult, TransportError> {
618 self.provider()
619 .raw_request("eth_createAccessList".into(), (request, block.unwrap_or_default()))
620 .await
621 }
622
623 pub async fn transaction_by_block_number_and_index(
624 &self,
625 number: u64,
626 index: usize,
627 ) -> Result<Option<N::TransactionResponse>, TransportError> {
628 let block = self.block_by_number(number).await?;
629 self.transaction_at_block_index(block, index).await
630 }
631
632 pub async fn transaction_by_block_hash_and_index(
633 &self,
634 hash: B256,
635 index: usize,
636 ) -> Result<Option<N::TransactionResponse>, TransportError> {
637 let block = self.block_by_hash(hash).await?;
638 self.transaction_at_block_index(block, index).await
639 }
640
641 async fn transaction_at_block_index(
642 &self,
643 block: Option<N::BlockResponse>,
644 index: usize,
645 ) -> Result<Option<N::TransactionResponse>, TransportError> {
646 if let Some(block) = block {
647 match block.transactions() {
648 BlockTransactions::Full(txs) => {
649 if let Some(tx) = txs.get(index) {
650 return Ok(Some(tx.clone()));
651 }
652 }
653 BlockTransactions::Hashes(hashes) => {
654 if let Some(tx_hash) = hashes.get(index) {
655 return self.transaction_by_hash(*tx_hash).await;
656 }
657 }
658 BlockTransactions::Uncle => {}
659 }
660 }
661 Ok(None)
662 }
663
664 pub async fn transaction_by_hash(
665 &self,
666 hash: B256,
667 ) -> Result<Option<N::TransactionResponse>, TransportError> {
668 trace!(target: "backend::fork", "transaction_by_hash={:?}", hash);
669 if let tx @ Some(_) = self.storage_read().transactions.get(&hash).cloned() {
670 return Ok(tx);
671 }
672
673 let tx = self.provider().get_transaction_by_hash(hash).await?;
674 if let Some(tx) = tx.clone() {
675 let mut storage = self.storage_write();
676 storage.transactions.insert(hash, tx);
677 }
678 Ok(tx)
679 }
680
681 pub async fn block_by_hash(
682 &self,
683 hash: B256,
684 ) -> Result<Option<N::BlockResponse>, TransportError> {
685 if let Some(mut block) = self.storage_read().blocks.get(&hash).cloned() {
686 block.transactions_mut().convert_to_hashes();
687 return Ok(Some(block));
688 }
689
690 Ok(self.fetch_full_block(hash).await?.map(|mut b| {
691 b.transactions_mut().convert_to_hashes();
692 b
693 }))
694 }
695
696 pub async fn block_by_hash_full(
697 &self,
698 hash: B256,
699 ) -> Result<Option<N::BlockResponse>, TransportError> {
700 if let Some(block) = self.storage_read().blocks.get(&hash).cloned()
701 && let Some(block) = self.convert_to_full_block(block)
702 {
703 return Ok(Some(block));
704 }
705 self.fetch_full_block(hash).await
706 }
707
708 pub async fn block_by_number(
709 &self,
710 block_number: u64,
711 ) -> Result<Option<N::BlockResponse>, TransportError> {
712 if let Some(mut block) = self
713 .storage_read()
714 .hashes
715 .get(&block_number)
716 .and_then(|hash| self.storage_read().blocks.get(hash).cloned())
717 {
718 block.transactions_mut().convert_to_hashes();
719 return Ok(Some(block));
720 }
721
722 let mut block = self.fetch_full_block(block_number).await?;
723 if let Some(block) = &mut block {
724 block.transactions_mut().convert_to_hashes();
725 }
726 Ok(block)
727 }
728
729 pub async fn block_by_number_full(
730 &self,
731 block_number: u64,
732 ) -> Result<Option<N::BlockResponse>, TransportError> {
733 if let Some(block) = self
734 .storage_read()
735 .hashes
736 .get(&block_number)
737 .copied()
738 .and_then(|hash| self.storage_read().blocks.get(&hash).cloned())
739 && let Some(block) = self.convert_to_full_block(block)
740 {
741 return Ok(Some(block));
742 }
743
744 self.fetch_full_block(block_number).await
745 }
746
747 pub async fn fetch_block(
749 &self,
750 block_id: BlockId,
751 ) -> Result<Option<N::BlockResponse>, TransportError> {
752 self.fetch_full_block(block_id).await
753 }
754
755 async fn fetch_full_block(
756 &self,
757 block_id: impl Into<BlockId>,
758 ) -> Result<Option<N::BlockResponse>, TransportError> {
759 if let Some(block) = self.provider().get_block(block_id.into()).full().await? {
760 let hash = block.header().hash();
761 let block_number = block.header().number();
762 let mut storage = self.storage_write();
763 let block_txs = match block.transactions() {
765 BlockTransactions::Full(txs) => txs.to_owned(),
766 _ => vec![],
767 };
768 storage.transactions.extend(block_txs.iter().map(|tx| (tx.tx_hash(), tx.clone())));
769 storage.hashes.insert(block_number, hash);
770 storage.blocks.insert(hash, block.clone());
771 return Ok(Some(block));
772 }
773
774 Ok(None)
775 }
776
777 fn convert_to_full_block(&self, mut block: N::BlockResponse) -> Option<N::BlockResponse> {
779 let storage = self.storage.read();
780 let transactions = block
781 .transactions()
782 .hashes()
783 .map(|hash| storage.transactions.get(&hash).cloned())
784 .collect::<Option<Vec<_>>>()?;
785 *block.transactions_mut() = BlockTransactions::Full(transactions);
786 Some(block)
787 }
788}
789
790impl ClientFork {
791 pub async fn transaction_receipt(
792 &self,
793 hash: B256,
794 ) -> Result<Option<FoundryTxReceipt>, BlockchainError> {
795 if let Some(receipt) = self.storage_read().transaction_receipts.get(&hash).cloned() {
796 return Ok(Some(receipt));
797 }
798
799 if let Some(receipt) = self.provider().get_transaction_receipt(hash).await? {
800 let receipt = FoundryTxReceipt::try_from(receipt)
801 .map_err(|_| BlockchainError::FailedToDecodeReceipt)?;
802 let mut storage = self.storage_write();
803 storage.transaction_receipts.insert(hash, receipt.clone());
804 return Ok(Some(receipt));
805 }
806
807 Ok(None)
808 }
809
810 pub async fn block_receipts(
811 &self,
812 number: u64,
813 ) -> Result<Option<Vec<FoundryTxReceipt>>, BlockchainError> {
814 if let receipts @ Some(_) = self.storage_read().block_receipts.get(&number).cloned() {
815 return Ok(receipts);
816 }
817
818 if self.predates_fork_inclusive(number) {
822 let receipts = self.provider().get_block_receipts(BlockId::from(number)).await?;
823 let receipts = receipts
824 .map(|r| {
825 r.into_iter()
826 .map(|r| {
827 FoundryTxReceipt::try_from(r)
828 .map_err(|_| BlockchainError::FailedToDecodeReceipt)
829 })
830 .collect::<Result<Vec<_>, _>>()
831 })
832 .transpose()?;
833
834 if let Some(receipts) = receipts.clone() {
835 let mut storage = self.storage_write();
836 storage.block_receipts.insert(number, receipts);
837 }
838
839 return Ok(receipts);
840 }
841
842 Ok(None)
843 }
844
845 pub async fn uncle_by_block_hash_and_index(
846 &self,
847 hash: B256,
848 index: usize,
849 ) -> Result<Option<AnyRpcBlock>, TransportError> {
850 if let Some(block) = self.block_by_hash(hash).await? {
851 return self.uncles_by_block_and_index(block, index).await;
852 }
853 Ok(None)
854 }
855
856 pub async fn uncle_by_block_number_and_index(
857 &self,
858 number: u64,
859 index: usize,
860 ) -> Result<Option<AnyRpcBlock>, TransportError> {
861 if let Some(block) = self.block_by_number(number).await? {
862 return self.uncles_by_block_and_index(block, index).await;
863 }
864 Ok(None)
865 }
866
867 async fn uncles_by_block_and_index(
868 &self,
869 block: AnyRpcBlock,
870 index: usize,
871 ) -> Result<Option<AnyRpcBlock>, TransportError> {
872 let block_hash = block.header().hash();
873 let block_number = block.header().number();
874 if let Some(uncles) = self.storage_read().uncles.get(&block_hash) {
875 return Ok(uncles.get(index).cloned());
876 }
877
878 let mut uncles = Vec::with_capacity(block.uncles.len());
879 for (uncle_idx, _) in block.uncles.iter().enumerate() {
880 let uncle =
881 match self.provider().get_uncle(block_number.into(), uncle_idx as u64).await? {
882 Some(u) => u,
883 None => return Ok(None),
884 };
885 uncles.push(uncle);
886 }
887 self.storage_write().uncles.insert(block_hash, uncles.clone());
888 Ok(uncles.get(index).cloned())
889 }
890}
891
892#[derive(Clone, Debug)]
894pub struct ClientForkConfig<N: Network = AnyNetwork> {
895 pub fork_urls: Vec<String>,
899 pub block_number: u64,
901 pub evm_block_number: u64,
903 pub block_hash: B256,
905 pub transaction_hash: Option<B256>,
907 pub provider: Arc<RetryProvider<N>>,
908 pub chain_id: u64,
910 pub execution_chain_id: u64,
912 pub override_chain_id: Option<u64>,
914 pub fork_chain_id: Option<u64>,
916 pub hardfork: Option<FoundryHardfork>,
918 pub(crate) endpoint_identity: ForkEndpointIdentity,
920 pub(crate) state_is_mutable: bool,
922 pub timestamp: u64,
924 pub base_fee: Option<u128>,
926 pub blob_gas_used: Option<u128>,
928 pub blob_excess_gas_and_price: Option<BlobExcessGasAndPrice>,
930 pub timeout: Duration,
932 pub retries: u32,
934 pub backoff: Duration,
936 pub compute_units_per_second: u64,
938 pub headers: Vec<String>,
940 pub total_difficulty: U256,
942}
943
944impl<N: Network> ClientForkConfig<N> {
945 pub fn eth_rpc_url(&self) -> Option<&str> {
947 self.fork_urls.first().map(|s| s.as_str())
948 }
949
950 pub fn update_block(
952 &mut self,
953 block_number: u64,
954 evm_block_number: u64,
955 block_hash: B256,
956 timestamp: u64,
957 base_fee: Option<u128>,
958 total_difficulty: U256,
959 ) {
960 self.block_number = block_number;
961 self.evm_block_number = evm_block_number;
962 self.block_hash = block_hash;
963 self.timestamp = timestamp;
964 self.base_fee = base_fee;
965 self.total_difficulty = total_difficulty;
966 trace!(target: "fork", "Updated block number={} hash={:?}", block_number, block_hash);
967 }
968}
969
970impl ClientForkConfig {
971 fn bal_eligible(&self) -> bool {
973 let identity = self.endpoint_identity;
974 !self.state_is_mutable
975 && self.fork_urls.len() == 1
976 && !identity.is_authoritative()
977 && identity.network.is_none_or(|network| network.is_ethereum())
978 && matches!(
979 NamedChain::try_from(identity.source_chain_id),
980 Ok(NamedChain::Mainnet
981 | NamedChain::Sepolia
982 | NamedChain::Holesky
983 | NamedChain::Hoodi)
984 )
985 && matches!(
986 FoundryHardfork::from_chain_and_timestamp(identity.source_chain_id, self.timestamp),
987 Some(hardfork @ FoundryHardfork::Ethereum(_)) if SpecId::from(hardfork) >= SpecId::CANCUN
988 )
989 }
990
991 pub(crate) async fn prefill_cache(&self, db: &BlockchainDb) {
993 if !self.bal_eligible() || db.meta().read().fork_hash != Some(self.block_hash) {
994 return;
995 }
996
997 let prefill = async {
998 let Some(bal) =
999 self.provider.get_block_access_list(BlockId::hash(self.block_hash)).await?
1000 else {
1001 return Ok(());
1002 };
1003 let Some(block) = self.provider.get_block(BlockId::hash(self.block_hash)).await? else {
1004 return Ok(());
1005 };
1006 eyre::ensure!(block.header.hash == self.block_hash, "fork block hash mismatch");
1007 validate_bal(&bal, block.transactions.len(), block.header.block_access_list_hash())?;
1008
1009 match self
1012 .provider
1013 .raw_request::<_, serde_json::Value>("anvil_nodeInfo".into(), ())
1014 .await
1015 {
1016 Err(error) if is_rpc_method_not_found(&error) => {}
1017 _ => return Ok(()),
1018 }
1019 cache_bal(db.db(), bal);
1020 Ok::<_, eyre::Report>(())
1021 };
1022 match tokio::time::timeout(Duration::from_millis(500), prefill).await {
1024 Ok(Ok(())) => {}
1025 Ok(Err(_)) => debug!(target: "node", "fork BAL prefill unavailable"),
1026 Err(_) => debug!(target: "node", "fork BAL prefill timed out"),
1027 }
1028 }
1029}
1030
1031#[cfg(test)]
1032mod bal_tests;
1033
1034#[derive(Clone, Debug)]
1038pub struct ForkedStorage<N: Network = AnyNetwork> {
1039 pub uncles: FbHashMap<32, Vec<N::BlockResponse>>,
1040 pub blocks: FbHashMap<32, N::BlockResponse>,
1041 pub hashes: HashMap<u64, B256>,
1042 pub transactions: FbHashMap<32, N::TransactionResponse>,
1043 pub transaction_receipts: FbHashMap<32, FoundryTxReceipt>,
1044 pub transaction_traces: FbHashMap<32, Vec<Trace>>,
1045 pub logs: HashMap<LogsCacheKey, Vec<Log>>,
1046 pub geth_transaction_traces: FbHashMap<32, Vec<(GethDebugTracingOptions, GethTrace)>>,
1047 pub geth_block_traces: FbHashMap<32, Vec<(GethDebugTracingOptions, Vec<TraceResult>)>>,
1048 pub block_traces: HashMap<u64, Vec<Trace>>,
1049 pub block_receipts: HashMap<u64, Vec<FoundryTxReceipt>>,
1050 pub code_at: HashMap<(Address, u64), Bytes>,
1051}
1052
1053impl<N: Network> Default for ForkedStorage<N> {
1054 fn default() -> Self {
1055 Self {
1056 uncles: Default::default(),
1057 blocks: Default::default(),
1058 hashes: Default::default(),
1059 transactions: Default::default(),
1060 transaction_receipts: Default::default(),
1061 transaction_traces: Default::default(),
1062 logs: Default::default(),
1063 geth_transaction_traces: Default::default(),
1064 geth_block_traces: Default::default(),
1065 block_traces: Default::default(),
1066 block_receipts: Default::default(),
1067 code_at: Default::default(),
1068 }
1069 }
1070}
1071
1072impl<N: Network> ForkedStorage<N> {
1073 pub fn clear(&mut self) {
1075 *self = Self::default()
1077 }
1078}
1079
1080#[derive(Clone, Debug, PartialEq, Eq, Hash)]
1085pub struct LogsCacheKey {
1086 block_option: FilterBlockOption,
1087 address: Vec<Address>,
1088 topics: [Vec<B256>; 4],
1089}
1090
1091impl From<&Filter> for LogsCacheKey {
1092 fn from(filter: &Filter) -> Self {
1093 Self {
1094 block_option: filter.block_option,
1095 address: sorted_filter_set(&filter.address),
1096 topics: filter.topics.each_ref().map(sorted_filter_set),
1097 }
1098 }
1099}
1100
1101fn sorted_filter_set<T: Copy + Ord + std::hash::Hash>(set: &FilterSet<T>) -> Vec<T> {
1102 let mut values = set.iter().copied().collect::<Vec<_>>();
1103 values.sort_unstable();
1104 values
1105}