Skip to main content

anvil/eth/
api.rs

1use super::{
2    backend::mem::{
3        BlockRequest, DatabaseRef, GasEstimateCallOptions, MonadReplayContext, State,
4        sanitize_simulation_blocks,
5    },
6    preserve_simulation_request_fields,
7};
8use crate::{
9    ClientFork, LoggingManager, Miner, MiningMode, StorageInfo,
10    eth::{
11        backend::{
12            self, db::SerializableState, mem::MIN_TRANSACTION_GAS,
13            notifications::ChainNotifications, validate::TransactionValidator,
14        },
15        error::{
16            BlockchainError, FeeHistoryError, InvalidTransactionError, Result, ToRpcResponseResult,
17        },
18        fees::{
19            FeeDetails, FeeHistoryCache, FeeHistoryCacheItem, MIN_SUGGESTED_PRIORITY_FEE,
20            REWARD_PERCENTILE_RESOLUTION, create_fee_history_cache_item,
21        },
22        macros::node_info,
23        miner::FixedBlockTimeMiner,
24        pool::{
25            Pool, PoolSnapshot,
26            transactions::{
27                PoolTransaction, TransactionOrder, TransactionPriority, TxMarker, to_marker,
28            },
29        },
30        sign::Signer,
31    },
32    filter::{EthFilter, Filters, LogsFilter},
33    mem::transaction_build,
34};
35use alloy_consensus::{
36    Blob, BlockHeader, Transaction, TrieAccount, TxEip4844Variant, TxReceipt, Typed2718,
37    transaction::{Recovered, SignerRecoverable},
38};
39use alloy_dyn_abi::TypedData;
40use alloy_eips::{
41    eip2718::{EIP4844_TX_TYPE_ID, Encodable2718},
42    eip4844::DATA_GAS_PER_BLOB,
43    eip7910::{EthConfig, EthForkConfig},
44};
45use alloy_evm::overrides::{OverrideBlockHashes, apply_state_overrides};
46use alloy_network::{
47    AnyRpcBlock, AnyRpcHeader, AnyRpcTransaction, BlockResponse, Network,
48    NetworkTransactionBuilder, ReceiptResponse, TransactionBuilder, TransactionBuilder4844,
49    TransactionResponse, eip2718::Decodable2718,
50};
51use alloy_primitives::{
52    Address, B64, B256, Bytes, TxHash, TxKind, U64, U256,
53    map::{AddressSet, B256Set, HashMap, HashSet},
54};
55use alloy_rlp::{Encodable, Header, PayloadView};
56use alloy_rpc_types::{
57    AccessListResult, BlockId, BlockNumberOrTag as BlockNumber, BlockTransactions,
58    EIP1186AccountProofResponse, FeeHistory, Filter, FilteredParams, Index, Log, Work,
59    anvil::{
60        ForkedNetwork, Forking, Metadata, MineOptions, NodeEnvironment, NodeForkConfig, NodeInfo,
61    },
62    debug::ExecutionWitness,
63    erc4337::TransactionConditional,
64    pubsub::TransactionReceiptsParams,
65    request::TransactionRequest,
66    simulate::{MAX_SIMULATE_BLOCKS, SimulatePayload, SimulatedBlock},
67    state::{AccountOverride, EvmOverrides, StateOverride, StateOverridesBuilder},
68    trace::{
69        filter::TraceFilter,
70        geth::{GethDebugTracingCallOptions, GethDebugTracingOptions, GethTrace, TraceResult},
71        opcode::{BlockOpcodeGas, TransactionOpcodeGas},
72        parity::{
73            LocalizedTransactionTrace, TraceResults, TraceResultsWithTransactionHash, TraceType,
74        },
75    },
76    txpool::{TxpoolContent, TxpoolContentFrom, TxpoolInspect, TxpoolInspectSummary, TxpoolStatus},
77};
78use alloy_rpc_types_eth::{AccountInfo, Bundle, EthCallResponse, FillTransaction, StateContext};
79use alloy_rpc_types_mev::{EthCallBundle, EthCallBundleResponse};
80use alloy_serde::WithOtherFields;
81use alloy_sol_types::{SolCall, SolValue, sol};
82use anvil_core::{
83    eth::{
84        EthRequest,
85        block::{Block, BlockInfo, canonical_block},
86        transaction::{MaybeImpersonatedTransaction, PendingTransaction},
87    },
88    types::{ReorgOptions, TransactionData},
89};
90use anvil_rpc::{
91    error::{ErrorCode, RpcError},
92    response::ResponseResult,
93};
94use foundry_common::{
95    provider::redact_url,
96    tempo::{PaymentLaneClassification, PaymentLaneReason, classify_payment_lane},
97    version::{COMMIT_SHA, SEMVER_VERSION},
98};
99use foundry_evm::decode::RevertDecoder;
100use foundry_primitives::{
101    FoundryNetwork, FoundryReceiptEnvelope, FoundryTransactionRequest, FoundryTxEnvelope,
102    FoundryTxReceipt, FoundryTypedTx,
103};
104use futures::{
105    StreamExt, TryFutureExt,
106    channel::{mpsc::Receiver, oneshot},
107};
108use parking_lot::{Mutex, RwLock};
109use revm::{
110    context::BlockEnv,
111    context_interface::{
112        block::BlobExcessGasAndPrice,
113        result::{HaltReason, Output},
114    },
115    database::CacheDB,
116    interpreter::{InstructionResult, SuccessOrHalt, return_ok, return_revert},
117};
118use std::{sync::Arc, time::Duration};
119use tempo_hardfork::TempoHardfork;
120use tempo_primitives::{AASigned, TEMPO_TX_TYPE_ID, transaction::FEE_PAYER_SIGNATURE_MARKER};
121use tokio::{
122    sync::mpsc::{self, UnboundedReceiver, unbounded_channel},
123    try_join,
124};
125
126#[cfg(feature = "base")]
127use base_common_consensus::Eip8130Constants;
128#[cfg(feature = "base")]
129use base_common_evm::EIP8130_TRANSACTION_TYPE;
130#[cfg(feature = "base")]
131use base_common_precompiles::NonceManagerStorage;
132#[cfg(feature = "base")]
133use base_common_rpc_types::{BaseTransactionRequest, Eip8130Nonce};
134#[cfg(feature = "base")]
135use base_execution_eip8130::{FeeCheck, IntrinsicGas};
136
137/// The client version: `anvil/v{major}.{minor}.{patch}`
138pub const CLIENT_VERSION: &str = concat!("anvil/v", env!("CARGO_PKG_VERSION"));
139
140#[derive(Clone, Copy)]
141struct TransactionFeeDefaults {
142    gas_price: u128,
143    blob_gas_price: u128,
144}
145
146/// The entry point for executing eth api RPC call - The Eth RPC interface.
147///
148/// This type is cheap to clone and can be used concurrently
149pub struct EthApi<N: Network> {
150    /// The transaction pool
151    pool: Arc<Pool<N::TxEnvelope>>,
152    /// Transaction pool state captured by `evm_snapshot`.
153    pool_snapshots: Arc<Mutex<HashMap<U256, PoolSnapshot<N::TxEnvelope>>>>,
154    /// Holds all blockchain related data
155    /// In-Memory only for now
156    pub backend: Arc<backend::mem::Backend<N>>,
157    /// Whether this node is mining
158    is_mining: bool,
159    /// available signers
160    signers: Arc<Vec<Box<dyn Signer<N>>>>,
161    /// data required for `eth_feeHistory`
162    fee_history_cache: FeeHistoryCache,
163    /// max number of items kept in fee cache
164    fee_history_limit: u64,
165    /// access to the actual miner
166    ///
167    /// This access is required in order to adjust miner settings based on requests received from
168    /// custom RPC endpoints
169    miner: Miner<N::TxEnvelope>,
170    /// allows to enabled/disable logging
171    logger: LoggingManager,
172    /// Tracks all active filters
173    filters: Filters<N>,
174    /// How transactions are ordered in the pool
175    transaction_order: Arc<RwLock<TransactionOrder>>,
176    /// Whether we're listening for RPC calls
177    net_listening: bool,
178    /// The instance ID. Changes on every reset.
179    instance_id: Arc<RwLock<B256>>,
180    /// Serializes endpoint identity reads with reset transitions.
181    lifecycle_lock: Arc<tokio::sync::RwLock<()>>,
182    /// Serializes reset preparation without blocking identity RPCs made by the target endpoint.
183    reset_lock: Arc<tokio::sync::Mutex<()>>,
184    /// Serializes automatic nonce assignment through pool insertion for each sender.
185    nonce_locks: Arc<RwLock<HashMap<Address, Arc<tokio::sync::Mutex<()>>>>>,
186}
187
188impl<N: Network> Clone for EthApi<N> {
189    fn clone(&self) -> Self {
190        Self {
191            pool: self.pool.clone(),
192            pool_snapshots: self.pool_snapshots.clone(),
193            backend: self.backend.clone(),
194            is_mining: self.is_mining,
195            signers: self.signers.clone(),
196            fee_history_cache: self.fee_history_cache.clone(),
197            fee_history_limit: self.fee_history_limit,
198            miner: self.miner.clone(),
199            logger: self.logger.clone(),
200            filters: self.filters.clone(),
201            transaction_order: self.transaction_order.clone(),
202            net_listening: self.net_listening,
203            instance_id: self.instance_id.clone(),
204            lifecycle_lock: self.lifecycle_lock.clone(),
205            reset_lock: self.reset_lock.clone(),
206            nonce_locks: self.nonce_locks.clone(),
207        }
208    }
209}
210
211// == impl EthApi<N: Network> generic methods ==
212
213impl<N: Network> EthApi<N> {
214    /// Creates a new instance
215    #[expect(clippy::too_many_arguments)]
216    pub fn new(
217        pool: Arc<Pool<N::TxEnvelope>>,
218        backend: Arc<backend::mem::Backend<N>>,
219        signers: Arc<Vec<Box<dyn Signer<N>>>>,
220        fee_history_cache: FeeHistoryCache,
221        fee_history_limit: u64,
222        miner: Miner<N::TxEnvelope>,
223        logger: LoggingManager,
224        filters: Filters<N>,
225        transactions_order: TransactionOrder,
226    ) -> Self {
227        Self {
228            pool,
229            pool_snapshots: Arc::new(Mutex::new(HashMap::default())),
230            backend,
231            is_mining: true,
232            signers,
233            fee_history_cache,
234            fee_history_limit,
235            miner,
236            logger,
237            filters,
238            net_listening: true,
239            transaction_order: Arc::new(RwLock::new(transactions_order)),
240            instance_id: Arc::new(RwLock::new(B256::random())),
241            lifecycle_lock: Arc::new(tokio::sync::RwLock::new(())),
242            reset_lock: Arc::new(tokio::sync::Mutex::new(())),
243            nonce_locks: Default::default(),
244        }
245    }
246
247    /// Returns the current gas price
248    pub fn gas_price(&self) -> u128 {
249        if self.backend.is_eip1559() {
250            if self.backend.is_min_priority_fee_enforced() {
251                (self.backend.base_fee() as u128).saturating_add(self.lowest_suggestion_tip())
252            } else {
253                self.backend.base_fee() as u128
254            }
255        } else {
256            self.backend.fees().raw_gas_price()
257        }
258    }
259
260    /// Returns the suggested fee cap.
261    ///
262    /// Returns at least [MIN_SUGGESTED_PRIORITY_FEE]
263    fn lowest_suggestion_tip(&self) -> u128 {
264        let block_number = self.backend.best_number();
265        let cache = self.fee_history_cache.lock();
266        let latest_tip = self
267            .backend
268            .get_block_with_hash(block_number)
269            .and_then(|(_, hash)| cache.get(&block_number).filter(|item| item.block_hash == hash))
270            .and_then(|item| item.rewards.iter().copied().min());
271
272        latest_tip
273            .or_else(|| {
274                cache
275                    .iter()
276                    .filter(|(number, item)| {
277                        self.backend
278                            .get_block_with_hash(**number)
279                            .is_some_and(|(_, hash)| item.block_hash == hash)
280                    })
281                    .flat_map(|(_, item)| item.rewards.iter().copied())
282                    .min()
283            })
284            .map(|fee| fee.max(MIN_SUGGESTED_PRIORITY_FEE))
285            .unwrap_or(MIN_SUGGESTED_PRIORITY_FEE)
286    }
287
288    /// Returns true if auto mining is enabled, and false.
289    ///
290    /// Handler for ETH RPC call: `anvil_getAutomine`
291    pub fn anvil_get_auto_mine(&self) -> Result<bool> {
292        node_info!("anvil_getAutomine");
293        Ok(self.miner.is_auto_mine())
294    }
295
296    /// Returns the value of mining interval, if set.
297    ///
298    /// Handler for ETH RPC call: `anvil_getIntervalMining`.
299    pub fn anvil_get_interval_mining(&self) -> Result<Option<u64>> {
300        node_info!("anvil_getIntervalMining");
301        Ok(self.miner.get_interval())
302    }
303
304    /// Enables or disables, based on the single boolean argument, the automatic mining of new
305    /// blocks with each new transaction submitted to the network.
306    ///
307    /// Handler for ETH RPC call: `evm_setAutomine`
308    pub async fn anvil_set_auto_mine(&self, enable_automine: bool) -> Result<()> {
309        node_info!("evm_setAutomine");
310        if self.miner.is_auto_mine() {
311            if enable_automine {
312                return Ok(());
313            }
314            self.miner.set_mining_mode(MiningMode::None);
315        } else if enable_automine {
316            let listener = self.pool.add_ready_listener();
317            let window = self.backend.node_config.read().await.transaction_coalescing_window;
318            let mode = MiningMode::instant(1_000, listener).with_coalescing_window(window);
319            self.miner.set_mining_mode(mode);
320        }
321        Ok(())
322    }
323
324    /// Sets the mining behavior to interval with the given interval (seconds)
325    ///
326    /// Handler for ETH RPC call: `evm_setIntervalMining`
327    pub fn anvil_set_interval_mining(&self, secs: u64) -> Result<()> {
328        node_info!("evm_setIntervalMining");
329        let mining_mode = if secs == 0 {
330            MiningMode::None
331        } else {
332            let block_time = Duration::from_secs(secs);
333
334            // This ensures that memory limits are stricter in interval-mine mode
335            self.backend.update_interval_mine_block_time(block_time);
336
337            MiningMode::FixedBlockTime(FixedBlockTimeMiner::new(block_time))
338        };
339        self.miner.set_mining_mode(mining_mode);
340        Ok(())
341    }
342
343    /// Removes transactions from the pool
344    ///
345    /// Handler for RPC call: `anvil_dropTransaction`
346    pub async fn anvil_drop_transaction(&self, tx_hash: B256) -> Result<Option<B256>> {
347        node_info!("anvil_dropTransaction");
348        Ok(self.pool.drop_transaction(tx_hash).map(|tx| tx.hash()))
349    }
350
351    /// Removes all transactions from the pool
352    ///
353    /// Handler for RPC call: `anvil_dropAllTransactions`
354    pub async fn anvil_drop_all_transactions(&self) -> Result<()> {
355        node_info!("anvil_dropAllTransactions");
356        self.pool.clear();
357        Ok(())
358    }
359
360    /// Clears all transactions from the pool.
361    ///
362    /// Handler for RPC call: `debug_clearTxpool`
363    pub async fn debug_clear_txpool(&self) -> Result<()> {
364        node_info!("debug_clearTxpool");
365        self.pool.clear();
366        Ok(())
367    }
368
369    pub async fn anvil_set_chain_id(&self, chain_id: u64) -> Result<()> {
370        node_info!("anvil_setChainId");
371        self.backend.set_chain_id(chain_id);
372        #[cfg(feature = "base")]
373        self.invalidate_base_eip8130_pool();
374        Ok(())
375    }
376
377    /// Invalidates EIP-8130 admission state after out-of-band state mutation.
378    #[cfg(feature = "base")]
379    fn invalidate_base_eip8130_pool(&self) {
380        if self.backend.is_base() {
381            let _ = self.pool.clear_transaction_type(EIP8130_TRANSACTION_TYPE);
382        }
383    }
384
385    /// Modifies the balance of an account.
386    ///
387    /// Handler for RPC call: `anvil_setBalance`
388    pub async fn anvil_set_balance(&self, address: Address, balance: U256) -> Result<()> {
389        node_info!("anvil_setBalance");
390        self.backend.set_balance(address, balance).await?;
391        #[cfg(feature = "base")]
392        self.invalidate_base_eip8130_pool();
393        Ok(())
394    }
395
396    /// Sets the code of a contract.
397    ///
398    /// Handler for RPC call: `anvil_setCode`
399    pub async fn anvil_set_code(&self, address: Address, code: Bytes) -> Result<()> {
400        node_info!("anvil_setCode");
401        self.backend.set_code(address, code).await?;
402        #[cfg(feature = "base")]
403        self.invalidate_base_eip8130_pool();
404        Ok(())
405    }
406
407    /// Sets the nonce of an address.
408    ///
409    /// Handler for RPC call: `anvil_setNonce`
410    pub async fn anvil_set_nonce(&self, address: Address, nonce: U256) -> Result<()> {
411        node_info!("anvil_setNonce");
412        self.backend.set_nonce(address, nonce).await?;
413        #[cfg(feature = "base")]
414        self.invalidate_base_eip8130_pool();
415        Ok(())
416    }
417
418    /// Writes a single slot of the account's storage.
419    ///
420    /// Handler for RPC call: `anvil_setStorageAt`
421    pub async fn anvil_set_storage_at(
422        &self,
423        address: Address,
424        slot: U256,
425        val: B256,
426    ) -> Result<bool> {
427        node_info!("anvil_setStorageAt");
428        self.backend.set_storage_at(address, slot, val).await?;
429        #[cfg(feature = "base")]
430        self.invalidate_base_eip8130_pool();
431        Ok(true)
432    }
433
434    /// Enable or disable logging.
435    ///
436    /// Handler for RPC call: `anvil_setLoggingEnabled`
437    pub async fn anvil_set_logging(&self, enable: bool) -> Result<()> {
438        node_info!("anvil_setLoggingEnabled");
439        self.logger.set_enabled(enable);
440        Ok(())
441    }
442
443    /// Set the minimum gas price for the node.
444    ///
445    /// Handler for RPC call: `anvil_setMinGasPrice`
446    pub async fn anvil_set_min_gas_price(&self, gas: U256) -> Result<()> {
447        node_info!("anvil_setMinGasPrice");
448        if self.backend.is_eip1559() {
449            return Err(RpcError::invalid_params(
450                "anvil_setMinGasPrice is not supported when EIP-1559 is active",
451            )
452            .into());
453        }
454        self.backend.set_gas_price(gas.saturating_to());
455        Ok(())
456    }
457
458    /// Sets the base fee of the next block.
459    ///
460    /// Handler for RPC call: `anvil_setNextBlockBaseFeePerGas`
461    pub async fn anvil_set_next_block_base_fee_per_gas(&self, basefee: U256) -> Result<()> {
462        node_info!("anvil_setNextBlockBaseFeePerGas");
463        if !self.backend.is_eip1559() {
464            return Err(RpcError::invalid_params(
465                "anvil_setNextBlockBaseFeePerGas is only supported when EIP-1559 is active",
466            )
467            .into());
468        }
469        self.backend.set_base_fee(basefee.saturating_to());
470        Ok(())
471    }
472
473    /// Sets the coinbase address.
474    ///
475    /// Handler for RPC call: `anvil_setCoinbase`
476    pub async fn anvil_set_coinbase(&self, address: Address) -> Result<()> {
477        node_info!("anvil_setCoinbase");
478        self.backend.set_coinbase(address);
479        Ok(())
480    }
481
482    /// Sets the `prevrandao` value of the next block.
483    ///
484    /// This is a one-shot override: it applies to the next mined block only, after which anvil
485    /// resumes deriving `prevrandao` from the parent hash and block number.
486    ///
487    /// Handler for RPC call: `anvil_setNextBlockPrevRandao`
488    pub async fn anvil_set_next_block_prevrandao(&self, prevrandao: B256) -> Result<()> {
489        node_info!("anvil_setNextBlockPrevRandao");
490        self.backend.set_next_block_prevrandao(prevrandao);
491        Ok(())
492    }
493
494    /// Sets the parent beacon block root of the next block.
495    ///
496    /// This is a one-shot override: it applies to the next mined block only, after which anvil
497    /// resumes using the zero root. From Cancun the root is stored by the EIP-4788 beacon roots
498    /// contract when the block is mined.
499    ///
500    /// Handler for RPC call: `anvil_setNextBlockParentBeaconBlockRoot`
501    pub async fn anvil_set_next_block_parent_beacon_block_root(&self, root: B256) -> Result<()> {
502        node_info!("anvil_setNextBlockParentBeaconBlockRoot");
503        self.backend.set_next_block_parent_beacon_block_root(root);
504        Ok(())
505    }
506
507    /// Retrieves the Anvil node configuration params.
508    ///
509    /// Handler for RPC call: `anvil_nodeInfo`
510    pub async fn anvil_node_info(&self) -> Result<NodeInfo> {
511        node_info!("anvil_nodeInfo");
512        let _lifecycle = self.lifecycle_lock.read().await;
513
514        let evm_env = self.backend.evm_env().read().clone();
515        let fork_config = self.backend.get_fork();
516        let tx_order = self.transaction_order.read();
517        let hard_fork = self.backend.hardfork().name();
518
519        Ok(NodeInfo {
520            current_block_number: self.backend.best_number(),
521            current_block_timestamp: evm_env.block_env.timestamp.saturating_to(),
522            current_block_hash: self.backend.best_hash(),
523            hard_fork,
524            transaction_order: match *tx_order {
525                TransactionOrder::Fifo => "fifo".to_string(),
526                TransactionOrder::Fees => "fees".to_string(),
527            },
528            environment: NodeEnvironment {
529                base_fee: self.backend.base_fee() as u128,
530                chain_id: self.backend.chain_id().to::<u64>(),
531                gas_limit: self.backend.gas_limit(),
532                gas_price: self.gas_price(),
533            },
534            fork_config: fork_config
535                .map(|fork| {
536                    let config = fork.config.read();
537
538                    NodeForkConfig {
539                        fork_url: config.eth_rpc_url().map(redact_url),
540                        fork_block_number: Some(config.block_number),
541                        fork_retry_backoff: Some(config.backoff.as_millis()),
542                    }
543                })
544                .unwrap_or_default(),
545            // Always emit the execution profile. Older Anvil versions omitted plain Ethereum, so
546            // consumers must still treat `None` as legacy unspecified metadata.
547            network: Some(self.backend.execution_profile_name().to_string()),
548        })
549    }
550
551    /// Retrieves metadata about the Anvil instance.
552    ///
553    /// Handler for RPC call: `anvil_metadata`
554    pub async fn anvil_metadata(&self) -> Result<Metadata> {
555        node_info!("anvil_metadata");
556        let _lifecycle = self.lifecycle_lock.read().await;
557        let fork_config = self.backend.get_fork();
558
559        Ok(Metadata {
560            client_version: CLIENT_VERSION.to_string(),
561            client_semver: Some(SEMVER_VERSION.to_string()),
562            client_commit_sha: Some(COMMIT_SHA.to_string()),
563            chain_id: self.backend.chain_id().to::<u64>(),
564            latest_block_hash: self.backend.best_hash(),
565            latest_block_number: self.backend.best_number(),
566            instance_id: *self.instance_id.read(),
567            forked_network: fork_config.map(|cfg| ForkedNetwork {
568                chain_id: cfg.chain_id(),
569                fork_block_number: cfg.block_number(),
570                fork_block_hash: cfg.block_hash(),
571            }),
572            snapshots: self.backend.list_state_snapshots(),
573        })
574    }
575
576    pub async fn anvil_remove_pool_transactions(&self, address: Address) -> Result<()> {
577        node_info!("anvil_removePoolTransactions");
578        self.pool.remove_transactions_by_address(address);
579        Ok(())
580    }
581
582    /// Snapshot the state of the blockchain at the current block.
583    ///
584    /// Handler for RPC call: `evm_snapshot`
585    pub async fn evm_snapshot(&self) -> Result<U256> {
586        node_info!("evm_snapshot");
587        let _lifecycle = self.lifecycle_lock.read().await;
588        let _mining = self.backend.lock_mining().await;
589        let pool = self.pool.snapshot();
590        let id = self.backend.create_state_snapshot().await;
591        self.pool_snapshots.lock().insert(id, pool);
592        Ok(id)
593    }
594
595    /// Jump forward in time by the given amount of time, in seconds.
596    ///
597    /// Handler for RPC call: `evm_increaseTime`
598    pub async fn evm_increase_time(&self, seconds: U256) -> Result<i64> {
599        node_info!("evm_increaseTime");
600        Ok(self.backend.time().increase_time(seconds.try_into().unwrap_or(u64::MAX)) as i64)
601    }
602
603    /// Similar to `evm_increaseTime` but takes the exact timestamp that you want in the next block
604    ///
605    /// Handler for RPC call: `evm_setNextBlockTimestamp`
606    pub fn evm_set_next_block_timestamp(&self, seconds: u64) -> Result<()> {
607        node_info!("evm_setNextBlockTimestamp");
608        self.backend.time().set_next_block_timestamp(seconds)
609    }
610
611    /// Sets the specific timestamp and returns the number of seconds between the given timestamp
612    /// and the current time.
613    ///
614    /// The `timestamp` is in seconds. The `evm_setTime` JSON-RPC method accepts both seconds and
615    /// milliseconds (values above 1e12 are treated as milliseconds); the RPC handler normalises
616    /// the input to seconds before calling this function.
617    ///
618    /// Handler for RPC call: `evm_setTime`
619    pub fn evm_set_time(&self, timestamp: u64) -> Result<u64> {
620        node_info!("evm_setTime");
621        let now = self.backend.time().current_call_timestamp();
622        self.backend.time().set_time(timestamp);
623
624        // number of seconds between the given timestamp and the current time.
625        let offset = timestamp.saturating_sub(now);
626        Ok(offset)
627    }
628
629    /// Set the next block gas limit
630    ///
631    /// Handler for RPC call: `evm_setBlockGasLimit`
632    pub fn evm_set_block_gas_limit(&self, gas_limit: U256) -> Result<bool> {
633        node_info!("evm_setBlockGasLimit");
634        self.backend.set_gas_limit(gas_limit.saturating_to());
635        Ok(true)
636    }
637
638    /// Sets an interval for the block timestamp
639    ///
640    /// Handler for RPC call: `anvil_setBlockTimestampInterval`
641    pub fn evm_set_block_timestamp_interval(&self, seconds: u64) -> Result<()> {
642        node_info!("anvil_setBlockTimestampInterval");
643        self.backend.time().set_block_timestamp_interval(seconds);
644        Ok(())
645    }
646
647    /// Sets an interval for the block timestamp
648    ///
649    /// Handler for RPC call: `anvil_removeBlockTimestampInterval`
650    pub fn evm_remove_block_timestamp_interval(&self) -> Result<bool> {
651        node_info!("anvil_removeBlockTimestampInterval");
652        Ok(self.backend.time().remove_block_timestamp_interval())
653    }
654
655    /// Sets the backend rpc url
656    ///
657    /// Handler for ETH RPC call: `anvil_setRpcUrl`
658    pub async fn anvil_set_rpc_url(&self, url: String) -> Result<()> {
659        node_info!("anvil_setRpcUrl");
660        let _reset = self.reset_lock.lock().await;
661        let staged_fork = if let Some(fork) = self.backend.get_fork() {
662            let mut validation_config = self.backend.node_config.read().await.clone();
663            let (expected_identity, block_number, block_hash) = {
664                let config = fork.config.read();
665                (config.endpoint_identity, config.block_number, config.block_hash)
666            };
667            // A new URL replaces an offline discovery hint. Resolve the actual source identity so
668            // unsupported networks cannot be hidden behind the previous endpoint's hint.
669            validation_config.fork_chain_id = None;
670            let (provider, endpoint_identity) = validation_config
671                .replacement_fork_provider(
672                    &url,
673                    expected_identity,
674                    block_number,
675                    block_hash,
676                    self.instance_id(),
677                )
678                .await?;
679            Some((fork, provider, endpoint_identity))
680        } else {
681            None
682        };
683
684        let _lifecycle = self.lifecycle_lock.write().await;
685        let _mining = self.backend.lock_mining().await;
686        let mut node_config = self.backend.node_config.write().await;
687        if let Some((fork, provider, endpoint_identity)) = staged_fork {
688            let mut config = fork.config.write();
689            trace!(target: "backend", "Updated fork rpc from \"{}\" to \"{}\"", config.eth_rpc_url().map(redact_url).unwrap_or_else(|| "none".to_string()), redact_url(&url));
690            config.provider = provider;
691            config.fork_urls = vec![url.clone()];
692            config.fork_chain_id = None;
693            config.endpoint_identity = endpoint_identity;
694            node_config.fork_endpoint_is_anvil = endpoint_identity.is_authoritative();
695        }
696        // Keep node_config in sync so a subsequent URL-less fork reset uses the updated endpoint.
697        node_config.fork_urls = vec![url];
698        node_config.fork_chain_id = None;
699        Ok(())
700    }
701
702    /// Returns the number of transactions currently pending for inclusion in the next block(s), as
703    /// well as the ones that are being scheduled for future execution only.
704    /// Ref: [Here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_status)
705    ///
706    /// Handler for ETH RPC call: `txpool_status`
707    pub async fn txpool_status(&self) -> Result<TxpoolStatus> {
708        node_info!("txpool_status");
709        Ok(self.pool.txpool_status())
710    }
711
712    /// Executes the future on a new blocking task.
713    async fn on_blocking_task<C, F, R>(&self, c: C) -> Result<R>
714    where
715        C: FnOnce(Self) -> F,
716        F: Future<Output = Result<R>> + Send + 'static,
717        R: Send + 'static,
718    {
719        let (tx, rx) = oneshot::channel();
720        let this = self.clone();
721        let f = c(this);
722        tokio::task::spawn_blocking(move || {
723            tokio::runtime::Handle::current().block_on(async move {
724                let res = f.await;
725                let _ = tx.send(res);
726            })
727        });
728        rx.await.map_err(|_| BlockchainError::Internal("blocking task panicked".to_string()))?
729    }
730
731    /// Updates the `TransactionOrder`
732    pub fn set_transaction_order(&self, order: TransactionOrder) {
733        *self.transaction_order.write() = order;
734    }
735
736    /// Returns the chain ID used for transaction
737    pub fn chain_id(&self) -> u64 {
738        self.backend.chain_id().to::<u64>()
739    }
740
741    /// Returns the configured fork, if any.
742    pub fn get_fork(&self) -> Option<ClientFork> {
743        self.backend.get_fork()
744    }
745
746    /// Returns the current instance's ID.
747    pub fn instance_id(&self) -> B256 {
748        *self.instance_id.read()
749    }
750
751    /// Resets the instance ID.
752    pub fn reset_instance_id(&self) {
753        *self.instance_id.write() = B256::random();
754    }
755
756    /// Returns the first signer that can sign for the given address
757    #[expect(clippy::borrowed_box)]
758    pub fn get_signer(&self, address: Address) -> Option<&Box<dyn Signer<N>>> {
759        self.signers.iter().find(|signer| signer.is_signer_for(address))
760    }
761
762    /// Returns a new listeners for ready transactions
763    pub fn new_ready_transactions(&self) -> Receiver<TxHash> {
764        self.pool.add_ready_listener()
765    }
766
767    /// Returns true if forked
768    pub fn is_fork(&self) -> bool {
769        self.backend.is_fork()
770    }
771
772    /// Returns the current state root
773    pub async fn state_root(&self) -> Option<B256> {
774        self.backend.get_db().read().await.maybe_state_root()
775    }
776
777    /// Returns true if the `addr` is currently impersonated
778    pub fn is_impersonated(&self, addr: Address) -> bool {
779        self.backend.cheats().is_impersonated(addr)
780    }
781
782    /// Returns a new accessor for certain storage elements
783    pub fn storage_info(&self) -> StorageInfo<N> {
784        StorageInfo::new(Arc::clone(&self.backend))
785    }
786
787    /// Handler for RPC call: `anvil_getBlobByHash`
788    #[allow(clippy::large_stack_frames)]
789    pub fn anvil_get_blob_by_versioned_hash(
790        &self,
791        hash: B256,
792    ) -> Result<Option<alloy_consensus::Blob>> {
793        node_info!("anvil_getBlobByHash");
794        Ok(self.backend.get_blob_by_versioned_hash(hash)?)
795    }
796
797    /// Handler for RPC call: `anvil_getBlobsByBlockId`
798    pub fn anvil_get_blobs_by_block_id(
799        &self,
800        block_id: impl Into<BlockId>,
801        versioned_hashes: Vec<B256>,
802    ) -> Result<Option<Vec<Blob>>> {
803        node_info!("anvil_getBlobsByBlockId");
804        Ok(self.backend.get_blobs_by_block_id(block_id, versioned_hashes)?)
805    }
806
807    /// Returns the genesis time for the Beacon chain
808    ///
809    /// Handler for Beacon API call: `GET /eth/v1/beacon/genesis`
810    pub fn anvil_get_genesis_time(&self) -> Result<u64> {
811        node_info!("anvil_getGenesisTime");
812        Ok(self.backend.genesis_time())
813    }
814
815    /// Returns the UNIX wall time in milliseconds when the current head was installed.
816    ///
817    /// Handler for RPC call: `anvil_getLastBlockWallTime`
818    pub fn anvil_get_last_block_wall_time(&self) -> Result<u64> {
819        node_info!("anvil_getLastBlockWallTime");
820        Ok(self.backend.time().last_block_wall_time())
821    }
822
823    /// Reset the fork to a fresh forked state, and optionally update the fork config.
824    ///
825    /// If `forking` is `None` then this will disable forking entirely.
826    ///
827    /// Handler for RPC call: `anvil_reset`
828    pub async fn anvil_reset(&self, forking: Option<Forking>) -> Result<()> {
829        node_info!("anvil_reset");
830        let _reset = self.reset_lock.lock().await;
831        if let Some(forking) = forking {
832            let staged = self.backend.prepare_fork_reset(forking, self.instance_id()).await?;
833            let _lifecycle = self.lifecycle_lock.write().await;
834            // Stop an old-context block before publishing the replacement DB and environment.
835            let _mining = self.backend.lock_mining().await;
836            self.backend.commit_fork_reset(staged).await?;
837            self.reset_instance_id();
838            self.pool.clear();
839            self.pool_snapshots.lock().clear();
840            self.fee_history_cache.lock().clear();
841        } else {
842            let _lifecycle = self.lifecycle_lock.write().await;
843            // Unlike fork preparation, memory preparation snapshots live local fee state and does
844            // no remote I/O. Keep that snapshot and its publication in one lifecycle transition.
845            let _mining = self.backend.lock_mining().await;
846            let staged = self.backend.prepare_memory_reset().await?;
847            self.backend.commit_memory_reset(staged).await?;
848            self.reset_instance_id();
849            self.pool.clear();
850            self.pool_snapshots.lock().clear();
851            self.fee_history_cache.lock().clear();
852        }
853        Ok(())
854    }
855
856    /// Revert the state of the blockchain to a previous snapshot.
857    /// Takes a single parameter, which is the snapshot id to revert to.
858    ///
859    /// Handler for RPC call: `evm_revert`
860    pub async fn evm_revert(&self, id: U256) -> Result<bool>
861    where
862        N::ReceiptEnvelope: TxReceipt<Log = alloy_primitives::Log>,
863    {
864        node_info!("evm_revert");
865        let _lifecycle = self.lifecycle_lock.read().await;
866        let _mining = self.backend.lock_mining().await;
867        let reverted = self.backend.revert_state_snapshot(id).await?;
868        if reverted {
869            let pool = {
870                let mut snapshots = self.pool_snapshots.lock();
871                let pool = snapshots.remove(&id);
872                snapshots.retain(|snapshot_id, _| *snapshot_id < id);
873                pool
874            };
875            if let Some(pool) = pool {
876                self.pool.restore(pool);
877            }
878        }
879        Ok(reverted)
880    }
881
882    /// Send transactions impersonating specific account and contract addresses.
883    ///
884    /// Handler for ETH RPC call: `anvil_impersonateAccount`
885    pub async fn anvil_impersonate_account(&self, address: Address) -> Result<()> {
886        node_info!("anvil_impersonateAccount");
887        self.backend.impersonate(address);
888        Ok(())
889    }
890
891    /// Stops impersonating an account if previously set with `anvil_impersonateAccount`.
892    ///
893    /// Handler for ETH RPC call: `anvil_stopImpersonatingAccount`
894    pub async fn anvil_stop_impersonating_account(&self, address: Address) -> Result<()> {
895        node_info!("anvil_stopImpersonatingAccount");
896        self.backend.stop_impersonating(address);
897        Ok(())
898    }
899
900    /// If set to true will make every account impersonated
901    ///
902    /// Handler for ETH RPC call: `anvil_autoImpersonateAccount`
903    pub async fn anvil_auto_impersonate_account(&self, enabled: bool) -> Result<()> {
904        node_info!("anvil_autoImpersonateAccount");
905        self.backend.auto_impersonate_account(enabled);
906        Ok(())
907    }
908
909    /// Registers a new address and signature pair to impersonate.
910    pub async fn anvil_impersonate_signature(
911        &self,
912        signature: Bytes,
913        address: Address,
914    ) -> Result<()> {
915        node_info!("anvil_impersonateSignature");
916        self.backend.impersonate_signature(signature, address).await
917    }
918
919    /// Returns a new block event stream that yields Notifications when a new block was added or
920    /// when logs were removed from the canonical chain due to a reorg
921    pub fn new_block_notifications(&self) -> ChainNotifications {
922        self.backend.new_block_notifications()
923    }
924
925    /// Returns the current client version.
926    ///
927    /// Handler for ETH RPC call: `web3_clientVersion`
928    pub fn client_version(&self) -> Result<String> {
929        node_info!("web3_clientVersion");
930        Ok(CLIENT_VERSION.to_string())
931    }
932
933    /// Returns Keccak-256 (not the standardized SHA3-256) of the given data.
934    ///
935    /// Handler for ETH RPC call: `web3_sha3`
936    pub fn sha3(&self, bytes: Bytes) -> Result<String> {
937        node_info!("web3_sha3");
938        let hash = alloy_primitives::keccak256(bytes.as_ref());
939        Ok(alloy_primitives::hex::encode_prefixed(&hash[..]))
940    }
941
942    /// Returns protocol version encoded as a string (quotes are necessary).
943    ///
944    /// Handler for ETH RPC call: `eth_protocolVersion`
945    pub fn protocol_version(&self) -> Result<u64> {
946        node_info!("eth_protocolVersion");
947        Ok(1)
948    }
949
950    /// Returns the number of hashes per second that the node is mining with.
951    ///
952    /// Handler for ETH RPC call: `eth_hashrate`
953    pub fn hashrate(&self) -> Result<U256> {
954        node_info!("eth_hashrate");
955        Ok(U256::ZERO)
956    }
957
958    /// Returns the client coinbase address.
959    ///
960    /// Handler for ETH RPC call: `eth_coinbase`
961    pub fn author(&self) -> Result<Address> {
962        node_info!("eth_coinbase");
963        Ok(self.backend.coinbase())
964    }
965
966    /// Returns true if client is actively mining new blocks.
967    ///
968    /// Handler for ETH RPC call: `eth_mining`
969    pub fn is_mining(&self) -> Result<bool> {
970        node_info!("eth_mining");
971        Ok(self.is_mining)
972    }
973
974    /// Returns the chain ID used for transaction signing at the
975    /// current best block. None is returned if not
976    /// available.
977    ///
978    /// Handler for ETH RPC call: `eth_chainId`
979    pub fn eth_chain_id(&self) -> Result<Option<U64>> {
980        node_info!("eth_chainId");
981        Ok(Some(self.backend.chain_id().to::<U64>()))
982    }
983
984    /// Returns the same as `chain_id`
985    ///
986    /// Handler for ETH RPC call: `eth_networkId`
987    pub fn network_id(&self) -> Result<Option<String>> {
988        node_info!("eth_networkId");
989        let chain_id = self.backend.chain_id().to::<u64>();
990        Ok(Some(format!("{chain_id}")))
991    }
992
993    /// Returns true if client is actively listening for network connections.
994    ///
995    /// Handler for ETH RPC call: `net_listening`
996    pub fn net_listening(&self) -> Result<bool> {
997        node_info!("net_listening");
998        Ok(self.net_listening)
999    }
1000
1001    /// Returns the current gas price
1002    fn eth_gas_price(&self) -> Result<U256> {
1003        node_info!("eth_gasPrice");
1004        Ok(U256::from(self.gas_price()))
1005    }
1006
1007    /// Returns the base fee for the next block, or null before London.
1008    ///
1009    /// Handler for ETH RPC call: `eth_baseFee`
1010    pub fn base_fee(&self) -> Result<Option<U256>> {
1011        node_info!("eth_baseFee");
1012        Ok(self.backend.is_eip1559().then(|| U256::from(self.backend.base_fee())))
1013    }
1014
1015    /// Returns the excess blob gas and current blob gas price
1016    pub fn excess_blob_gas_and_price(&self) -> Result<Option<BlobExcessGasAndPrice>> {
1017        Ok(self.backend.excess_blob_gas_and_price())
1018    }
1019
1020    /// Returns a fee per gas that is an estimate of how much you can pay as a priority fee, or
1021    /// 'tip', to get a transaction included in the current block.
1022    ///
1023    /// Handler for ETH RPC call: `eth_maxPriorityFeePerGas`
1024    pub fn gas_max_priority_fee_per_gas(&self) -> Result<U256> {
1025        self.max_priority_fee_per_gas()
1026    }
1027
1028    /// Returns the base fee per blob required to send an EIP-4844 tx.
1029    ///
1030    /// Handler for ETH RPC call: `eth_blobBaseFee`
1031    pub fn blob_base_fee(&self) -> Result<U256> {
1032        Ok(U256::from(self.backend.fees().base_fee_per_blob_gas()))
1033    }
1034
1035    /// Returns the block gas limit
1036    pub fn gas_limit(&self) -> U256 {
1037        U256::from(self.backend.gas_limit())
1038    }
1039
1040    /// Returns the accounts list
1041    ///
1042    /// Handler for ETH RPC call: `eth_accounts`
1043    pub fn accounts(&self) -> Result<Vec<Address>> {
1044        node_info!("eth_accounts");
1045        let mut unique = AddressSet::default();
1046        let mut accounts: Vec<Address> = Vec::new();
1047        for signer in self.signers.iter() {
1048            accounts.extend(signer.accounts().into_iter().filter(|acc| unique.insert(*acc)));
1049        }
1050        accounts.extend(
1051            self.backend
1052                .cheats()
1053                .impersonated_accounts()
1054                .into_iter()
1055                .filter(|acc| unique.insert(*acc)),
1056        );
1057        Ok(accounts.into_iter().collect())
1058    }
1059
1060    /// Returns the number of most recent block.
1061    ///
1062    /// Handler for ETH RPC call: `eth_blockNumber`
1063    pub fn block_number(&self) -> Result<U256> {
1064        node_info!("eth_blockNumber");
1065        Ok(U256::from(self.backend.best_number()))
1066    }
1067
1068    /// Returns block with given hash.
1069    ///
1070    /// Handler for ETH RPC call: `eth_getBlockByHash`
1071    pub async fn block_by_hash(&self, hash: B256) -> Result<Option<AnyRpcBlock>> {
1072        node_info!("eth_getBlockByHash");
1073        self.backend.block_by_hash(hash).await
1074    }
1075
1076    /// Returns block header with given hash.
1077    ///
1078    /// Handler for ETH RPC call: `eth_getHeaderByHash`
1079    pub async fn header_by_hash(
1080        &self,
1081        hash: B256,
1082    ) -> Result<Option<WithOtherFields<AnyRpcHeader>>> {
1083        node_info!("eth_getHeaderByHash");
1084        Ok(self.backend.block_by_hash(hash).await?.map(|block| {
1085            let WithOtherFields { inner: block, other } = block.0;
1086            WithOtherFields { inner: block.header, other }
1087        }))
1088    }
1089
1090    /// Returns a _full_ block with given hash.
1091    ///
1092    /// Handler for ETH RPC call: `eth_getBlockByHash`
1093    pub async fn block_by_hash_full(&self, hash: B256) -> Result<Option<AnyRpcBlock>> {
1094        node_info!("eth_getBlockByHash");
1095        self.backend.block_by_hash_full(hash).await
1096    }
1097
1098    /// Returns the number of transactions in a block with given hash.
1099    ///
1100    /// Handler for ETH RPC call: `eth_getBlockTransactionCountByHash`
1101    pub async fn block_transaction_count_by_hash(&self, hash: B256) -> Result<Option<U256>> {
1102        node_info!("eth_getBlockTransactionCountByHash");
1103        let block = self.backend.block_by_hash(hash).await?;
1104        let txs = block.map(|b| match b.transactions() {
1105            BlockTransactions::Full(txs) => U256::from(txs.len()),
1106            BlockTransactions::Hashes(txs) => U256::from(txs.len()),
1107            BlockTransactions::Uncle => U256::ZERO,
1108        });
1109        Ok(txs)
1110    }
1111
1112    /// Returns the number of uncles in a block with given hash.
1113    ///
1114    /// Handler for ETH RPC call: `eth_getUncleCountByBlockHash`
1115    pub async fn block_uncles_count_by_hash(&self, hash: B256) -> Result<U256> {
1116        node_info!("eth_getUncleCountByBlockHash");
1117        let block =
1118            self.backend.block_by_hash(hash).await?.ok_or(BlockchainError::BlockNotFound)?;
1119        Ok(U256::from(block.uncles.len()))
1120    }
1121
1122    /// Returns the number of uncles in a block with given block number.
1123    ///
1124    /// Handler for ETH RPC call: `eth_getUncleCountByBlockNumber`
1125    pub async fn block_uncles_count_by_number(&self, block_number: BlockNumber) -> Result<U256> {
1126        node_info!("eth_getUncleCountByBlockNumber");
1127        let block = self
1128            .backend
1129            .block_by_number(block_number)
1130            .await?
1131            .ok_or(BlockchainError::BlockNotFound)?;
1132        Ok(U256::from(block.uncles.len()))
1133    }
1134
1135    /// Signs data via [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md).
1136    ///
1137    /// Handler for ETH RPC call: `eth_signTypedData`
1138    pub async fn sign_typed_data(
1139        &self,
1140        _address: Address,
1141        _data: serde_json::Value,
1142    ) -> Result<String> {
1143        node_info!("eth_signTypedData");
1144        Err(BlockchainError::RpcUnimplemented)
1145    }
1146
1147    /// Signs data via [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md).
1148    ///
1149    /// Handler for ETH RPC call: `eth_signTypedData_v3`
1150    pub async fn sign_typed_data_v3(
1151        &self,
1152        _address: Address,
1153        _data: serde_json::Value,
1154    ) -> Result<String> {
1155        node_info!("eth_signTypedData_v3");
1156        Err(BlockchainError::RpcUnimplemented)
1157    }
1158
1159    /// Signs data via [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md), and includes full support of arrays and recursive data structures.
1160    ///
1161    /// Handler for ETH RPC call: `eth_signTypedData_v4`
1162    pub async fn sign_typed_data_v4(&self, address: Address, data: &TypedData) -> Result<String> {
1163        node_info!("eth_signTypedData_v4");
1164        let signer = self.get_signer(address).ok_or(BlockchainError::NoSignerAvailable)?;
1165        let signature = signer.sign_typed_data(address, data).await?;
1166        let signature = alloy_primitives::hex::encode(signature.as_bytes());
1167        Ok(format!("0x{signature}"))
1168    }
1169
1170    /// The sign method calculates an Ethereum specific signature
1171    ///
1172    /// Handler for ETH RPC call: `eth_sign`
1173    pub async fn sign(&self, address: Address, content: impl AsRef<[u8]>) -> Result<String> {
1174        node_info!("eth_sign");
1175        let signer = self.get_signer(address).ok_or(BlockchainError::NoSignerAvailable)?;
1176        let signature =
1177            alloy_primitives::hex::encode(signer.sign(address, content.as_ref()).await?.as_bytes());
1178        Ok(format!("0x{signature}"))
1179    }
1180
1181    /// Returns transaction at given block hash and index.
1182    ///
1183    /// Handler for ETH RPC call: `eth_getTransactionByBlockHashAndIndex`
1184    pub async fn transaction_by_block_hash_and_index(
1185        &self,
1186        hash: B256,
1187        index: Index,
1188    ) -> Result<Option<AnyRpcTransaction>> {
1189        node_info!("eth_getTransactionByBlockHashAndIndex");
1190        self.backend.transaction_by_block_hash_and_index(hash, index).await
1191    }
1192
1193    /// Returns an uncles at given block and index.
1194    ///
1195    /// Handler for ETH RPC call: `eth_getUncleByBlockHashAndIndex`
1196    pub async fn uncle_by_block_hash_and_index(
1197        &self,
1198        block_hash: B256,
1199        idx: Index,
1200    ) -> Result<Option<AnyRpcBlock>> {
1201        node_info!("eth_getUncleByBlockHashAndIndex");
1202        let number = self.backend.ensure_block_number(Some(BlockId::hash(block_hash))).await?;
1203        if let Some(fork) = self.get_fork()
1204            && fork.predates_fork_inclusive(number)
1205        {
1206            return Ok(fork.uncle_by_block_hash_and_index(block_hash, idx.into()).await?);
1207        }
1208        // It's impossible to have uncles outside of fork mode
1209        Ok(None)
1210    }
1211
1212    /// Returns an uncles at given block and index.
1213    ///
1214    /// Handler for ETH RPC call: `eth_getUncleByBlockNumberAndIndex`
1215    pub async fn uncle_by_block_number_and_index(
1216        &self,
1217        block_number: BlockNumber,
1218        idx: Index,
1219    ) -> Result<Option<AnyRpcBlock>> {
1220        node_info!("eth_getUncleByBlockNumberAndIndex");
1221        let number = self.backend.ensure_block_number(Some(BlockId::Number(block_number))).await?;
1222        if let Some(fork) = self.get_fork()
1223            && fork.predates_fork_inclusive(number)
1224        {
1225            return Ok(fork.uncle_by_block_number_and_index(number, idx.into()).await?);
1226        }
1227        // It's impossible to have uncles outside of fork mode
1228        Ok(None)
1229    }
1230
1231    /// Returns the hash of the current block, the seedHash, and the boundary condition to be met.
1232    ///
1233    /// Handler for ETH RPC call: `eth_getWork`
1234    pub fn work(&self) -> Result<Work> {
1235        node_info!("eth_getWork");
1236        Err(BlockchainError::RpcUnimplemented)
1237    }
1238
1239    /// Returns the sync status, always be fails.
1240    ///
1241    /// Handler for ETH RPC call: `eth_syncing`
1242    pub fn syncing(&self) -> Result<bool> {
1243        node_info!("eth_syncing");
1244        Ok(false)
1245    }
1246
1247    /// Returns the current configuration of the chain.
1248    /// This is useful for finding out what precompiles and system contracts are available.
1249    ///
1250    /// Note: the activation timestamp is always 0 as the configuration is set at genesis.
1251    /// Note: the `fork_id` is always `0x00000000` as this node does not participate in any forking
1252    /// on the network.
1253    /// Note: the `next` and `last` fields are always `null` as this node does not participate in
1254    /// any forking on the network.
1255    ///
1256    /// Handler for ETH RPC call: `eth_config`
1257    pub fn config(&self) -> Result<EthConfig> {
1258        node_info!("eth_config");
1259        Ok(EthConfig {
1260            current: EthForkConfig {
1261                activation_time: 0,
1262                blob_schedule: self.backend.blob_params(),
1263                chain_id: self.backend.chain_id().to::<u64>(),
1264                fork_id: Bytes::from_static(&[0; 4]),
1265                precompiles: self.backend.precompiles(),
1266                system_contracts: self.backend.system_contracts(),
1267            },
1268            next: None,
1269            last: None,
1270        })
1271    }
1272
1273    /// Used for submitting a proof-of-work solution.
1274    ///
1275    /// Handler for ETH RPC call: `eth_submitWork`
1276    pub fn submit_work(&self, _: B64, _: B256, _: B256) -> Result<bool> {
1277        node_info!("eth_submitWork");
1278        Err(BlockchainError::RpcUnimplemented)
1279    }
1280
1281    /// Used for submitting mining hashrate.
1282    ///
1283    /// Handler for ETH RPC call: `eth_submitHashrate`
1284    pub fn submit_hashrate(&self, _: U256, _: B256) -> Result<bool> {
1285        node_info!("eth_submitHashrate");
1286        Err(BlockchainError::RpcUnimplemented)
1287    }
1288
1289    /// Introduced in EIP-1559 for getting information on the appropriate priority fee to use.
1290    ///
1291    /// Handler for ETH RPC call: `eth_feeHistory`
1292    pub async fn fee_history(
1293        &self,
1294        block_count: U256,
1295        newest_block: BlockNumber,
1296        reward_percentiles: Vec<f64>,
1297    ) -> Result<FeeHistory>
1298    where
1299        N::ReceiptEnvelope: TxReceipt<Log = alloy_primitives::Log>,
1300    {
1301        node_info!("eth_feeHistory");
1302
1303        if reward_percentiles.iter().any(|p| !(0.0..=100.0).contains(p))
1304            || reward_percentiles.windows(2).any(|pair| pair[0] >= pair[1])
1305        {
1306            return Err(FeeHistoryError::InvalidRewardPercentiles.into());
1307        }
1308        if block_count.is_zero() {
1309            return Ok(FeeHistory::default());
1310        }
1311
1312        // max number of blocks in the requested range
1313
1314        let number = self.backend.convert_block_number(Some(newest_block));
1315
1316        // Snapshot the fork block once so the early return here and the pre-fork split below agree
1317        // on the same value. Reading it a second time lets an `anvil_reset` move the fork between
1318        // the reads: the newest block could clear this early return, then the split treats the
1319        // whole range as pre-fork and tacks on a stray local next-block fee.
1320        let fork = self.get_fork();
1321        let fork_block = fork.as_ref().map(|fork| fork.block_number());
1322
1323        // check if the number predates the fork, if in fork mode
1324        if let (Some(fork), Some(fork_block)) = (fork.as_ref(), fork_block) {
1325            // if we're still at the forked block we don't have any history and can't compute it
1326            // efficiently, instead we fetch it from the fork
1327            if number <= fork_block {
1328                return fork
1329                    .fee_history(block_count.to(), BlockNumber::Number(number), &reward_percentiles)
1330                    .await
1331                    .map_err(BlockchainError::AlloyForkProvider);
1332            }
1333        }
1334
1335        const MAX_BLOCK_COUNT: u64 = 1024u64;
1336        let block_count = block_count.saturating_to::<u64>().min(MAX_BLOCK_COUNT);
1337
1338        // highest and lowest block num in the requested range
1339        let highest = number;
1340        let lowest = highest.saturating_sub(block_count.saturating_sub(1));
1341
1342        // only support ranges that are in cache range
1343        if lowest < self.backend.best_number().saturating_sub(self.fee_history_limit) {
1344            return Err(FeeHistoryError::InvalidBlockRange.into());
1345        }
1346
1347        let mut response = FeeHistory {
1348            oldest_block: lowest,
1349            base_fee_per_gas: Vec::new(),
1350            gas_used_ratio: Vec::new(),
1351            reward: Some(Default::default()),
1352            base_fee_per_blob_gas: Default::default(),
1353            blob_gas_used_ratio: Default::default(),
1354        };
1355        let mut rewards = Vec::new();
1356
1357        // The early return above only delegates when the *newest* block predates the fork, but a
1358        // range can dip below the fork block while its newest block is post-fork. Local storage
1359        // has no pre-fork blocks, so resolving them via `backend.get_block` below would fail.
1360        // Serve the pre-fork portion from the fork provider and compute only post-fork locally.
1361        // Reuse the `fork_block` snapshot from above so this split stays consistent with the early
1362        // return; we didn't return, so `fork_block < highest` and only a crossing range splits.
1363        let local_lowest = if let (Some(fork), Some(fork_block)) = (fork.as_ref(), fork_block) {
1364            if lowest <= fork_block {
1365                let count_pre = fork_block - lowest + 1;
1366                let pre = fork
1367                    .fee_history(count_pre, BlockNumber::Number(fork_block), &reward_percentiles)
1368                    .await
1369                    .map_err(BlockchainError::AlloyForkProvider)?;
1370                merge_pre_fork_fee_history(&mut response, &mut rewards, pre, fork_block);
1371                // Compute only post-fork blocks locally; the pre-fork portion is served above.
1372                fork_block + 1
1373            } else {
1374                lowest
1375            }
1376        } else {
1377            lowest
1378        };
1379
1380        {
1381            let storage_info = self.storage_info();
1382            let blob_params = self.backend.blob_params();
1383
1384            // Snapshot the cached entries for the whole range under a single lock. The
1385            // `FeeHistoryService` populates the cache asynchronously and can lag the chain head,
1386            // so some entries may still be missing here.
1387            let cached: Vec<Option<FeeHistoryCacheItem>> = {
1388                let cache = self.fee_history_cache.lock();
1389                (local_lowest..=highest).map(|n| cache.get(&n).cloned()).collect()
1390            };
1391
1392            // Resolve the whole range into concrete items. Cache entries include their block hash
1393            // so a reset or reorg that reuses a block number cannot return data from the old
1394            // canonical chain. Compute misses and stale entries on demand without holding the
1395            // lock. A block that can't be found is a hard error rather than a silently dropped
1396            // entry, so `items` always holds exactly one entry per requested block.
1397            let mut warmed: Vec<(u64, FeeHistoryCacheItem)> = Vec::new();
1398            let mut items: Vec<FeeHistoryCacheItem> = Vec::with_capacity(cached.len());
1399            for (cached_item, n) in cached.into_iter().zip(local_lowest..=highest) {
1400                let hash = self
1401                    .backend
1402                    .block_hash_by_number(n)
1403                    .ok_or(FeeHistoryError::BlockNotFound(BlockNumber::Number(n)))?;
1404                let item = match cached_item {
1405                    Some(item) if item.block_hash == hash => item,
1406                    _ => {
1407                        let block = self
1408                            .backend
1409                            .get_block_by_hash(hash)
1410                            .ok_or(FeeHistoryError::BlockNotFound(BlockNumber::Number(n)))?;
1411                        let header = block.header;
1412                        let (item, block_number) = create_fee_history_cache_item(
1413                            hash,
1414                            &header,
1415                            &storage_info,
1416                            blob_params,
1417                        );
1418                        // The block was found above, but missing stored block/receipts make the
1419                        // helper hand back a zero-filled item. Error out rather than serve
1420                        // synthetic data for a block we already confirmed exists.
1421                        let block_number = block_number
1422                            .ok_or(FeeHistoryError::BlockNotFound(BlockNumber::Number(n)))?;
1423                        warmed.push((block_number, item.clone()));
1424                        item
1425                    }
1426                };
1427                items.push(item);
1428            }
1429
1430            // Warm the cache with the on-demand entries under a single lock, then trim to the
1431            // limit by dropping the oldest blocks so the fallback can't grow the cache unbounded.
1432            if !warmed.is_empty() {
1433                let mut cache = self.fee_history_cache.lock();
1434                for (block_number, item) in warmed {
1435                    cache.insert(block_number, item);
1436                }
1437                while cache.len() as u64 > self.fee_history_limit {
1438                    cache.pop_first();
1439                }
1440            }
1441
1442            for item in items {
1443                response.base_fee_per_gas.push(item.base_fee);
1444                response.base_fee_per_blob_gas.push(item.base_fee_per_blob_gas.unwrap_or(0));
1445                response.blob_gas_used_ratio.push(item.blob_gas_used_ratio);
1446                response.gas_used_ratio.push(item.gas_used_ratio);
1447
1448                // requested percentiles
1449                if !reward_percentiles.is_empty() {
1450                    let mut block_rewards = Vec::new();
1451                    for p in &reward_percentiles {
1452                        block_rewards.push(reward_at_percentile(&item.rewards, *p));
1453                    }
1454                    rewards.push(block_rewards);
1455                }
1456            }
1457        }
1458
1459        response.reward = Some(rewards);
1460
1461        // Both base-fee arrays include the block after the returned range. For a historical
1462        // request, use that block's header; the fee manager tracks the block after the current
1463        // chain head and would therefore append an unrelated value. Prefer an existing child even
1464        // when `highest` was the head at the start of this request, since mining can advance it.
1465        let next_number = highest
1466            .checked_add(1)
1467            .ok_or(FeeHistoryError::BlockNotFound(BlockNumber::Number(highest)))?;
1468        let (next_base_fee, next_blob_base_fee) = self
1469            .backend
1470            .fee_history_next_fees(highest)
1471            .await
1472            .ok_or(FeeHistoryError::BlockNotFound(BlockNumber::Number(next_number)))?;
1473        response.base_fee_per_gas.push(next_base_fee);
1474        response.base_fee_per_blob_gas.push(next_blob_base_fee);
1475
1476        Ok(response)
1477    }
1478
1479    /// Introduced in EIP-1159, a Geth-specific and simplified priority fee oracle.
1480    /// Leverages the already existing fee history cache.
1481    ///
1482    /// Returns a suggestion for a gas tip cap for dynamic fee transactions.
1483    ///
1484    /// Handler for ETH RPC call: `eth_maxPriorityFeePerGas`
1485    pub fn max_priority_fee_per_gas(&self) -> Result<U256> {
1486        node_info!("eth_maxPriorityFeePerGas");
1487        Ok(U256::from(self.lowest_suggestion_tip()))
1488    }
1489
1490    /// Returns code by its hash
1491    ///
1492    /// Handler for RPC call: `debug_codeByHash`
1493    pub async fn debug_code_by_hash(
1494        &self,
1495        hash: B256,
1496        block_id: Option<BlockId>,
1497    ) -> Result<Option<Bytes>> {
1498        node_info!("debug_codeByHash");
1499        self.backend.debug_code_by_hash(hash, block_id).await
1500    }
1501
1502    /// Returns the value associated with a key from the database
1503    /// Only supports bytecode lookups.
1504    ///
1505    /// Handler for RPC call: `debug_dbGet`
1506    pub async fn debug_db_get(&self, key: String) -> Result<Option<Bytes>> {
1507        node_info!("debug_dbGet");
1508        self.backend.debug_db_get(key).await
1509    }
1510
1511    /// Handles reth's no-op `debug_getModifiedAccountsByNumber` endpoint.
1512    pub fn debug_get_modified_accounts_by_number(
1513        &self,
1514        _start_number: u64,
1515        _end_number: u64,
1516    ) -> Result<()> {
1517        node_info!("debug_getModifiedAccountsByNumber");
1518        Ok(())
1519    }
1520
1521    /// Handles reth's no-op `debug_freeOSMemory` endpoint.
1522    pub fn debug_free_os_memory(&self) -> Result<()> {
1523        node_info!("debug_freeOSMemory");
1524        Ok(())
1525    }
1526
1527    /// Executes a transaction and returns requested parity trace results.
1528    ///
1529    /// Handler for RPC call: `trace_call`
1530    pub async fn trace_call(
1531        &self,
1532        request: WithOtherFields<TransactionRequest>,
1533        trace_types: HashSet<TraceType>,
1534        block_id: Option<BlockId>,
1535    ) -> Result<TraceResults>
1536    where
1537        N: Network<TxEnvelope = FoundryTxEnvelope, ReceiptEnvelope = FoundryReceiptEnvelope>,
1538    {
1539        node_info!("trace_call");
1540        let block_id = block_id.unwrap_or_default();
1541        let block_request = match &block_id {
1542            BlockId::Number(BlockNumber::Pending) => {
1543                let pending_txs = self.pool.ready_transactions().collect();
1544                BlockRequest::Pending(pending_txs)
1545            }
1546            _ => {
1547                let number = self.backend.ensure_block_number(Some(block_id)).await?;
1548                BlockRequest::Number(number)
1549            }
1550        };
1551        let inner = request.as_ref();
1552        let fees = FeeDetails::new(
1553            inner.gas_price,
1554            inner.max_fee_per_gas,
1555            inner.max_priority_fee_per_gas,
1556            inner.max_fee_per_blob_gas,
1557        )?
1558        .or_zero_fees();
1559
1560        self.backend.trace_call(request, fees, trace_types, block_request, block_id).await
1561    }
1562
1563    /// Returns traces for the transaction hash via parity's tracing endpoint
1564    ///
1565    /// Handler for RPC call: `trace_transaction`
1566    pub async fn trace_transaction(
1567        &self,
1568        tx_hash: B256,
1569    ) -> Result<Option<Vec<LocalizedTransactionTrace>>> {
1570        node_info!("trace_transaction");
1571        self.backend.trace_transaction(tx_hash).await
1572    }
1573
1574    /// Returns traces for the transaction hash via parity's tracing endpoint
1575    ///
1576    /// Handler for RPC call: `trace_block`
1577    pub async fn trace_block(&self, block: BlockNumber) -> Result<Vec<LocalizedTransactionTrace>> {
1578        node_info!("trace_block");
1579        self.backend.trace_block(block).await
1580    }
1581
1582    /// Returns filtered traces over blocks
1583    ///
1584    /// Handler for RPC call: `trace_filter`
1585    pub async fn trace_filter(
1586        &self,
1587        filter: TraceFilter,
1588    ) -> Result<Vec<LocalizedTransactionTrace>> {
1589        node_info!("trace_filter");
1590        self.backend.trace_filter(filter).await
1591    }
1592
1593    /// Returns the transaction trace at the given trace address.
1594    ///
1595    /// Handler for RPC call: `trace_get`.
1596    pub async fn trace_get(
1597        &self,
1598        hash: B256,
1599        indices: Vec<Index>,
1600    ) -> Result<Option<LocalizedTransactionTrace>> {
1601        node_info!("trace_get");
1602        self.backend.trace_get(hash, indices).await
1603    }
1604
1605    /// Replays all transactions in a block returning the requested traces for each transaction
1606    ///
1607    /// Handler for RPC call: `trace_replayBlockTransactions`
1608    pub async fn trace_replay_block_transactions(
1609        &self,
1610        block: BlockNumber,
1611        trace_types: HashSet<TraceType>,
1612    ) -> Result<Option<Vec<TraceResultsWithTransactionHash>>> {
1613        node_info!("trace_replayBlockTransactions");
1614        self.backend.trace_replay_block_transactions(block, trace_types).await
1615    }
1616
1617    /// Replays a transaction returning the requested traces.
1618    ///
1619    /// Handler for RPC call: `trace_replayTransaction`.
1620    pub async fn trace_replay_transaction(
1621        &self,
1622        transaction: B256,
1623        trace_types: HashSet<TraceType>,
1624    ) -> Result<Option<TraceResultsWithTransactionHash>> {
1625        node_info!("trace_replayTransaction");
1626        self.backend.trace_replay_transaction(transaction, trace_types).await
1627    }
1628}
1629
1630impl<N: Network<ReceiptEnvelope = FoundryReceiptEnvelope>> EthApi<N> {
1631    /// Returns the current state
1632    pub async fn serialized_state(
1633        &self,
1634        preserve_historical_states: bool,
1635    ) -> Result<SerializableState> {
1636        self.backend.serialized_state(preserve_historical_states).await
1637    }
1638}
1639
1640// == impl EthApi anvil endpoints ==
1641
1642impl EthApi<FoundryNetwork> {
1643    /// Returns transaction by given block number and index.
1644    ///
1645    /// Handler for ETH RPC call: `eth_getTransactionByBlockNumberAndIndex`
1646    pub async fn transaction_by_block_number_and_index(
1647        &self,
1648        block: BlockNumber,
1649        idx: Index,
1650    ) -> Result<Option<AnyRpcTransaction>> {
1651        node_info!("eth_getTransactionByBlockNumberAndIndex");
1652        if block.is_pending() {
1653            return Ok(self.pending_block_full().await?.and_then(|block| {
1654                let WithOtherFields { inner: block, .. } = block.0;
1655                block.transactions.into_transactions().nth(idx.into())
1656            }));
1657        }
1658
1659        self.backend.transaction_by_block_number_and_index(block, idx).await
1660    }
1661
1662    /// Create a buffer that represents all state on the chain, which can be loaded to separate
1663    /// process by calling `anvil_loadState`
1664    ///
1665    /// Handler for RPC call: `anvil_dumpState`
1666    pub async fn anvil_dump_state(
1667        &self,
1668        preserve_historical_states: Option<bool>,
1669    ) -> Result<Bytes> {
1670        node_info!("anvil_dumpState");
1671        self.backend.dump_state(preserve_historical_states.unwrap_or(false)).await
1672    }
1673
1674    /// Append chain state buffer to current chain. Will overwrite any conflicting addresses or
1675    /// storage.
1676    ///
1677    /// Handler for RPC call: `anvil_loadState`
1678    pub async fn anvil_load_state(&self, buf: Bytes) -> Result<bool> {
1679        node_info!("anvil_loadState");
1680        let loaded = self.backend.load_state_bytes(buf).await?;
1681        #[cfg(feature = "base")]
1682        if loaded {
1683            self.invalidate_base_eip8130_pool();
1684        }
1685        Ok(loaded)
1686    }
1687
1688    async fn block_request(
1689        &self,
1690        block_number: Option<BlockId>,
1691    ) -> Result<BlockRequest<FoundryTxEnvelope>> {
1692        let block_request = match block_number {
1693            Some(BlockId::Number(BlockNumber::Pending)) => {
1694                let pending_txs = self.pool.ready_transactions().collect();
1695                BlockRequest::Pending(pending_txs)
1696            }
1697            _ => {
1698                let number = self.backend.ensure_block_number(block_number).await?;
1699                BlockRequest::Number(number)
1700            }
1701        };
1702        Ok(block_request)
1703    }
1704
1705    /// Returns account information after replaying a block through a transaction index.
1706    ///
1707    /// Handler for RPC call: `debug_accountInfoAt`.
1708    pub async fn debug_account_info_at(
1709        &self,
1710        block_id: BlockId,
1711        tx_index: Index,
1712        address: Address,
1713    ) -> Result<Option<AccountInfo>> {
1714        node_info!("debug_accountInfoAt");
1715        self.backend.debug_account_info_at(block_id, tx_index, address).await
1716    }
1717
1718    /// Returns a best-effort execution witness for the given block, built from the full parent
1719    /// state. See [`crate::eth::backend::mem::Backend::debug_execution_witness`] for the exact
1720    /// contents and limitations.
1721    ///
1722    /// Handler for RPC call: `debug_executionWitness`.
1723    pub async fn debug_execution_witness(&self, block: BlockNumber) -> Result<ExecutionWitness> {
1724        node_info!("debug_executionWitness");
1725        self.backend.debug_execution_witness(block).await
1726    }
1727
1728    /// Returns opcode gas usage for a transaction.
1729    ///
1730    /// Handler for RPC call: `trace_transactionOpcodeGas`.
1731    pub async fn trace_transaction_opcode_gas(
1732        &self,
1733        tx_hash: B256,
1734    ) -> Result<Option<TransactionOpcodeGas>> {
1735        node_info!("trace_transactionOpcodeGas");
1736        self.backend.trace_transaction_opcode_gas(tx_hash).await
1737    }
1738
1739    /// Returns opcode gas usage for all transactions in a block.
1740    ///
1741    /// Handler for RPC call: `trace_blockOpcodeGas`.
1742    pub async fn trace_block_opcode_gas(
1743        &self,
1744        block_id: BlockId,
1745    ) -> Result<Option<BlockOpcodeGas>> {
1746        node_info!("trace_blockOpcodeGas");
1747        self.backend.trace_block_opcode_gas(block_id).await
1748    }
1749
1750    /// Traces a raw signed transaction without importing it into the mempool.
1751    ///
1752    /// Handler for RPC call: `trace_rawTransaction`.
1753    pub async fn trace_raw_transaction(
1754        &self,
1755        tx: Bytes,
1756        trace_types: HashSet<TraceType>,
1757        block_number: Option<BlockId>,
1758    ) -> Result<TraceResults> {
1759        node_info!("trace_rawTransaction");
1760
1761        let mut data = tx.as_ref();
1762        if data.is_empty() {
1763            return Err(BlockchainError::EmptyRawTransactionData);
1764        }
1765
1766        let transaction = FoundryTxEnvelope::decode_2718(&mut data)
1767            .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
1768        self.ensure_typed_transaction_supported(&transaction)?;
1769
1770        #[cfg(feature = "base")]
1771        let is_eip8130 = transaction.is_eip8130();
1772        let pending_transaction = PendingTransaction::new(transaction).map_err(|error| {
1773            #[cfg(feature = "base")]
1774            if is_eip8130 {
1775                return BlockchainError::Eip8130TransactionRejected(error.to_string());
1776            }
1777            BlockchainError::RecoveryError(error)
1778        })?;
1779        let block_request = self.block_request(block_number).await?;
1780
1781        self.backend
1782            .trace_raw_transaction(pending_transaction, trace_types, Some(block_request))
1783            .await
1784    }
1785
1786    /// Increases the balance of an account.
1787    ///
1788    /// Handler for RPC call: `anvil_addBalance`
1789    pub async fn anvil_add_balance(&self, address: Address, balance: U256) -> Result<()> {
1790        node_info!("anvil_addBalance");
1791        self.backend.add_balance(address, balance).await?;
1792        Ok(())
1793    }
1794
1795    /// Returns a locally stored rollback ancestor, or the remote base of a Monad transaction-hash
1796    /// fork when that integration is enabled.
1797    async fn rollback_block(&self, number: u64) -> Result<Option<Block>> {
1798        if let Some(block) = self.backend.get_block(number) {
1799            return Ok(Some(block));
1800        }
1801        #[cfg(feature = "monad")]
1802        {
1803            if self.backend.is_monad() {
1804                self.backend.monad_rollback_block(number).await
1805            } else {
1806                Ok(None)
1807            }
1808        }
1809        #[cfg(not(feature = "monad"))]
1810        {
1811            Ok(None)
1812        }
1813    }
1814
1815    /// Rewinds through the selected execution family's recovery path.
1816    async fn rollback_backend(
1817        &self,
1818        common_block: Block,
1819        mining_guard: &tokio::sync::MutexGuard<'_, ()>,
1820    ) -> Result<()> {
1821        #[cfg(feature = "monad")]
1822        if self.backend.is_monad() {
1823            return self.backend.rollback_monad(common_block, mining_guard).await;
1824        }
1825        self.backend.rollback(common_block, mining_guard).await
1826    }
1827
1828    /// Rollback the chain to a specific depth.
1829    ///
1830    /// e.g depth = 3
1831    ///     A  -> B  -> C  -> D  -> E
1832    ///     A  -> B
1833    ///
1834    /// Depth specifies the height to rollback the chain back to. Depth must not exceed the current
1835    /// chain height, i.e. can't rollback past the genesis block.
1836    ///
1837    /// Handler for RPC call: `anvil_rollback`
1838    pub async fn anvil_rollback(&self, depth: Option<u64>) -> Result<()> {
1839        node_info!("anvil_rollback");
1840        let _lifecycle = self.lifecycle_lock.write().await;
1841        let mining_guard = self.backend.lock_mining().await;
1842        let depth = depth.unwrap_or(1);
1843
1844        // Check reorg depth doesn't exceed current chain height
1845        let current_height = self.backend.best_number();
1846        let common_height = current_height.checked_sub(depth).ok_or(BlockchainError::RpcError(
1847            RpcError::invalid_params(format!(
1848                "Rollback depth must not exceed current chain height: current height {current_height}, depth {depth}"
1849            )),
1850        ))?;
1851
1852        // Get the common ancestor block
1853        let common_block =
1854            self.rollback_block(common_height).await?.ok_or(BlockchainError::BlockNotFound)?;
1855
1856        self.rollback_backend(common_block, &mining_guard).await?;
1857        Ok(())
1858    }
1859
1860    /// Estimates the gas usage of the `request` with the state.
1861    ///
1862    /// This will execute the transaction request and find the best gas limit via binary search.
1863    fn do_estimate_gas_with_state(
1864        &self,
1865        mut request: FoundryTransactionRequest,
1866        state: &dyn DatabaseRef,
1867        block_env: BlockEnv,
1868        monad_context: Option<MonadReplayContext>,
1869    ) -> Result<u128> {
1870        // A blob request may carry only its sidecar. Take its versioned hashes first, so that the
1871        // funds check and every execution below price the blob fee.
1872        if request.as_ref().blob_versioned_hashes.is_none() {
1873            request.as_mut().populate_blob_hashes();
1874        }
1875        let inner = request.as_ref();
1876        let fees = FeeDetails::new(
1877            inner.gas_price,
1878            inner.max_fee_per_gas,
1879            inner.max_priority_fee_per_gas,
1880            inner.max_fee_per_blob_gas,
1881        )?
1882        .or_zero_fees();
1883
1884        #[cfg(feature = "base")]
1885        if self.backend.is_base() && request.is_base() {
1886            self.backend.ensure_base_eip8130_active_at(block_env.timestamp.saturating_to())?;
1887            let gas_limit = block_env.gas_limit;
1888            let result = self
1889                .backend
1890                .call_with_state_typed_gas_limit(
1891                    state,
1892                    request,
1893                    fees,
1894                    block_env,
1895                    GasEstimateCallOptions::new(gas_limit, false, monad_context),
1896                )
1897                .try_into()?;
1898            return match result {
1899                GasEstimationCallResult::Success(gas) => Ok(gas),
1900                GasEstimationCallResult::OutOfGas => {
1901                    Err(InvalidTransactionError::BasicOutOfGas(u128::from(gas_limit)).into())
1902                }
1903                GasEstimationCallResult::Revert(output) => {
1904                    Err(InvalidTransactionError::Revert(output).into())
1905                }
1906                GasEstimationCallResult::EvmError(error) => Err(BlockchainError::EvmError(error)),
1907            };
1908        }
1909
1910        // get the highest possible gas limit, either the request's set value or the currently
1911        // configured gas limit
1912        let mut highest_gas_limit = inner.gas.map_or(block_env.gas_limit.into(), |g| g as u128);
1913
1914        // Tempo AA transactions pay fees in ERC-20 tokens, not ETH. Only treat requests as
1915        // Tempo AA in Tempo mode, otherwise `feeToken` should not bypass ETH funds checks.
1916        let is_tempo_aa_tx = self.backend.is_tempo() && request.is_tempo();
1917        let is_tempo_keychain = matches!(
1918            &request,
1919            FoundryTransactionRequest::Tempo(request) if request.key_id.is_some()
1920        );
1921        let disable_fee_charge = is_tempo_keychain || inner.from.is_none();
1922
1923        // Requests without a sender historically estimate value transfers without requiring the
1924        // default caller to hold ETH. Fund only the simulation overlay so the execution probe
1925        // preserves that behavior, including transfers that need new-account state gas.
1926        let mut funded_state;
1927        let state = if !is_tempo_aa_tx
1928            && inner.from.is_none()
1929            && let Some(value) = inner.value
1930            && !value.is_zero()
1931        {
1932            funded_state = CacheDB::new(state);
1933            let mut caller = state.basic_ref(Address::ZERO)?.unwrap_or_default();
1934            caller.balance = caller.balance.max(value);
1935            funded_state.insert_account_info(Address::ZERO, caller);
1936            &funded_state as &dyn DatabaseRef
1937        } else {
1938            state
1939        };
1940
1941        let gas_price = fees.gas_price.unwrap_or_default();
1942        // Check transfer value before any fast path, and cap gas limit by sender balance when the
1943        // request has a non-zero gas price. Only enforce this for explicit senders: calls without
1944        // `from` historically estimate against the default caller and must not be capped by the
1945        // zero address balance.
1946        if !is_tempo_aa_tx && let Some(from) = inner.from {
1947            let mut available_funds = self.backend.get_balance_with_state(state, from)?;
1948            if let Some(value) = inner.value {
1949                if value > available_funds {
1950                    return Err(InvalidTransactionError::InsufficientFunds.into());
1951                }
1952                // safe: value <= available_funds
1953                available_funds -= value;
1954            }
1955            if gas_price > 0 {
1956                // Blob gas is paid on top of execution gas, so reserve its maximum cost first. Like
1957                // the call itself, pay no blob fee when no cap is given.
1958                if inner.minimal_tx_type().is_eip4844()
1959                    && let Some(hashes) = &inner.blob_versioned_hashes
1960                {
1961                    let max_fee_per_blob_gas = fees.max_fee_per_blob_gas.unwrap_or_default();
1962                    let blob_gas = U256::from(hashes.len() as u64 * DATA_GAS_PER_BLOB);
1963                    let blob_cost = blob_gas.saturating_mul(U256::from(max_fee_per_blob_gas));
1964                    if blob_cost >= available_funds {
1965                        return Err(InvalidTransactionError::InsufficientFunds.into());
1966                    }
1967                    available_funds -= blob_cost;
1968                }
1969                // amount of gas the sender can afford with the `gas_price`
1970                let allowance =
1971                    available_funds.checked_div(U256::from(gas_price)).unwrap_or_default();
1972                highest_gas_limit = std::cmp::min(highest_gas_limit, allowance.saturating_to());
1973            }
1974        }
1975
1976        // If the request is a simple native token transfer we can optimize
1977        // We assume it's a transfer if we have no input data.
1978        // Skip this optimization for Tempo mode since native ETH transfers are not allowed
1979        // and Tempo AA transactions have higher intrinsic gas costs (~46k).
1980        if !self.backend.is_tempo() {
1981            let to = inner.to.as_ref().and_then(TxKind::to);
1982
1983            // check certain fields to see if the request could be a simple transfer
1984            let maybe_transfer = (inner.input.input().is_none()
1985                || inner.input.input().is_some_and(|data| data.is_empty()))
1986                && inner.authorization_list.is_none()
1987                && inner.access_list.is_none()
1988                && inner.blob_versioned_hashes.is_none();
1989
1990            if maybe_transfer
1991                && let Some(to) = to
1992                && !self.backend.is_precompile(to, &block_env)
1993                && let Ok(target_code) = self.backend.get_code_with_state(&state, *to)
1994                && target_code.as_ref().is_empty()
1995            {
1996                // Execute the transfer to account for fork-dependent gas costs and validation.
1997                // With no bytecode or authorizations, a successful run receives no refunds and
1998                // its gas used is the exact gas required. A new-account state charge can make
1999                // this probe fail, in which case estimation continues below.
2000                let probe = self.backend.call_with_state_typed_gas_limit(
2001                    &state,
2002                    request.clone(),
2003                    fees.clone(),
2004                    block_env.clone(),
2005                    GasEstimateCallOptions::new(
2006                        highest_gas_limit.min(MIN_TRANSACTION_GAS) as u64,
2007                        disable_fee_charge,
2008                        monad_context.clone(),
2009                    ),
2010                );
2011                if let Ok(GasEstimationCallResult::Success(gas)) = probe.try_into() {
2012                    return Ok(gas);
2013                }
2014            }
2015        }
2016
2017        // execute the call without writing to db
2018        let ethres = self.backend.call_with_state_typed_gas_limit(
2019            &state,
2020            request.clone(),
2021            fees.clone(),
2022            block_env.clone(),
2023            GasEstimateCallOptions::new(
2024                highest_gas_limit as u64,
2025                disable_fee_charge,
2026                monad_context.clone(),
2027            ),
2028        );
2029
2030        let gas_used = match ethres.try_into()? {
2031            GasEstimationCallResult::Success(gas) => Ok(gas),
2032            GasEstimationCallResult::OutOfGas => {
2033                Err(InvalidTransactionError::BasicOutOfGas(highest_gas_limit).into())
2034            }
2035            GasEstimationCallResult::Revert(output) => {
2036                Err(InvalidTransactionError::Revert(output).into())
2037            }
2038            GasEstimationCallResult::EvmError(err) => {
2039                warn!(target: "node", "estimation failed due to {:?}", err);
2040                Err(BlockchainError::EvmError(err))
2041            }
2042        }?;
2043
2044        // at this point we know the call succeeded but want to find the _best_ (lowest) gas the
2045        // transaction succeeds with. we find this by doing a binary search over the
2046        // possible range NOTE: this is the gas the transaction used, which is less than the
2047        // transaction requires to succeed
2048
2049        // Gas used is a lower bound on the gas required. Keep it inside the search interval so
2050        // exact-cost transactions, including Amsterdam calls below 21,000 gas, are considered.
2051        let mut lowest_gas_limit = gas_used.saturating_sub(1);
2052
2053        // pick a point that's close to the estimated gas
2054        let mut mid_gas_limit =
2055            std::cmp::min(gas_used * 3, (highest_gas_limit + lowest_gas_limit) / 2);
2056
2057        // Binary search for the ideal gas limit
2058        while lowest_gas_limit + 1 < highest_gas_limit {
2059            let ethres = self.backend.call_with_state_typed_gas_limit(
2060                &state,
2061                request.clone(),
2062                fees.clone(),
2063                block_env.clone(),
2064                GasEstimateCallOptions::new(
2065                    mid_gas_limit as u64,
2066                    disable_fee_charge,
2067                    monad_context.clone(),
2068                ),
2069            );
2070
2071            match ethres.try_into()? {
2072                GasEstimationCallResult::Success(_) => {
2073                    // If the transaction succeeded, we can set a ceiling for the highest gas limit
2074                    // at the current midpoint, as spending any more gas would
2075                    // make no sense (as the TX would still succeed).
2076                    highest_gas_limit = mid_gas_limit;
2077                }
2078                GasEstimationCallResult::OutOfGas
2079                | GasEstimationCallResult::Revert(_)
2080                | GasEstimationCallResult::EvmError(_) => {
2081                    // If the transaction failed, we can set a floor for the lowest gas limit at the
2082                    // current midpoint, as spending any less gas would make no
2083                    // sense (as the TX would still revert due to lack of gas).
2084                    //
2085                    // We don't care about the reason here, as we known that transaction is correct
2086                    // as it succeeded earlier
2087                    lowest_gas_limit = mid_gas_limit;
2088                }
2089            };
2090            // new midpoint
2091            mid_gas_limit = (highest_gas_limit + lowest_gas_limit) / 2;
2092        }
2093
2094        trace!(target : "node", "Estimated Gas for call {:?}", highest_gas_limit);
2095
2096        Ok(highest_gas_limit)
2097    }
2098
2099    /// Executes the [EthRequest] and returns an RPC [ResponseResult].
2100    #[allow(clippy::large_stack_frames)]
2101    pub async fn execute(&self, request: EthRequest) -> ResponseResult {
2102        trace!(target: "rpc::api", "executing eth request");
2103        // Fork reset and RPC URL replacement take the write lock internally after their fallible
2104        // remote staging work. Memory reset takes it before staging because it snapshots live
2105        // state. Identity, snapshot, and chain-rewind methods also lock internally to keep direct
2106        // API callers safe without recursively acquiring this fair RwLock.
2107        let _lifecycle = if matches!(
2108            &request,
2109            EthRequest::Reset(_)
2110                | EthRequest::SetRpcUrl(_)
2111                | EthRequest::NodeInfo(_)
2112                | EthRequest::AnvilMetadata(_)
2113                | EthRequest::EvmSnapshot(_)
2114                | EthRequest::EvmRevert(_)
2115                | EthRequest::Reorg(_)
2116                | EthRequest::Rollback(_)
2117        ) {
2118            None
2119        } else {
2120            Some(self.lifecycle_lock.read().await)
2121        };
2122        let response = match request.clone() {
2123            EthRequest::EthProtocolVersion(()) => self.protocol_version().to_rpc_result(),
2124            EthRequest::Web3ClientVersion(()) => self.client_version().to_rpc_result(),
2125            EthRequest::Web3Sha3(content) => self.sha3(content).to_rpc_result(),
2126            EthRequest::EthGetAccount(addr, block) => {
2127                self.get_account(addr, block).await.to_rpc_result()
2128            }
2129            EthRequest::EthGetAccountInfo(addr, block) => {
2130                self.get_account_info(addr, block).await.to_rpc_result()
2131            }
2132            EthRequest::EthGetBalance(addr, block) => {
2133                self.balance(addr, block).await.to_rpc_result()
2134            }
2135            EthRequest::EthGetTransactionByHash(hash) => {
2136                self.transaction_by_hash(hash).await.to_rpc_result()
2137            }
2138            EthRequest::EthPendingTransactions(_) => {
2139                self.pending_transactions().await.to_rpc_result()
2140            }
2141            EthRequest::EthSendTransaction(request) => {
2142                self.send_transaction(*request).await.to_rpc_result()
2143            }
2144            EthRequest::EthResend(request, gas_price, gas_limit) => {
2145                self.resend_transaction(*request, gas_price, gas_limit).await.to_rpc_result()
2146            }
2147            EthRequest::EthSendTransactionSync(request) => {
2148                self.send_transaction_sync(*request).await.to_rpc_result()
2149            }
2150            EthRequest::EthChainId(_) => self.eth_chain_id().to_rpc_result(),
2151            EthRequest::EthNetworkId(_) => self.network_id().to_rpc_result(),
2152            EthRequest::NetListening(_) => self.net_listening().to_rpc_result(),
2153            EthRequest::EthHashrate(()) => self.hashrate().to_rpc_result(),
2154            EthRequest::EthGasPrice(_) => self.eth_gas_price().to_rpc_result(),
2155            EthRequest::EthBaseFee(_) => self.base_fee().to_rpc_result(),
2156            EthRequest::EthMaxPriorityFeePerGas(_) => {
2157                self.gas_max_priority_fee_per_gas().to_rpc_result()
2158            }
2159            EthRequest::EthBlobBaseFee(_) => self.blob_base_fee().to_rpc_result(),
2160            EthRequest::EthAccounts(_) => self.accounts().to_rpc_result(),
2161            EthRequest::EthBlockNumber(_) => self.block_number().to_rpc_result(),
2162            EthRequest::EthCoinbase(()) => self.author().to_rpc_result(),
2163            EthRequest::EthGetStorageAt(addr, slot, block) => {
2164                self.storage_at(addr, slot, block).await.to_rpc_result()
2165            }
2166            EthRequest::EthGetStorageValues(requests, block) => {
2167                self.storage_values(requests, block).await.to_rpc_result()
2168            }
2169            EthRequest::EthGetBlockByHash(hash, full) => {
2170                if full {
2171                    self.block_by_hash_full(hash).await.to_rpc_result()
2172                } else {
2173                    self.block_by_hash(hash).await.to_rpc_result()
2174                }
2175            }
2176            EthRequest::EthGetHeaderByHash(hash) => self.header_by_hash(hash).await.to_rpc_result(),
2177            EthRequest::EthGetBlockByNumber(num, full) => {
2178                if full {
2179                    self.block_by_number_full(num).await.to_rpc_result()
2180                } else {
2181                    self.block_by_number(num).await.to_rpc_result()
2182                }
2183            }
2184            EthRequest::EthGetHeaderByNumber(num) => {
2185                self.header_by_number(num).await.to_rpc_result()
2186            }
2187            EthRequest::EthGetBlockAccessList(block_id) => {
2188                self.block_access_list(block_id).await.to_rpc_result()
2189            }
2190            EthRequest::EthGetBlockAccessListByBlockHash(block_hash) => {
2191                self.block_access_list_by_hash(block_hash).await.to_rpc_result()
2192            }
2193            EthRequest::EthGetBlockAccessListByBlockNumber(block_number) => {
2194                self.block_access_list_by_number(block_number).await.to_rpc_result()
2195            }
2196            EthRequest::EthGetBlockAccessListRaw(block_id) => {
2197                self.block_access_list_raw(block_id).await.to_rpc_result()
2198            }
2199            EthRequest::EthGetTransactionCount(params) => {
2200                let (address, block, nonce_key) = params.into_parts();
2201                #[cfg(feature = "base")]
2202                {
2203                    self.transaction_count_with_key(address, block, nonce_key).await.to_rpc_result()
2204                }
2205                #[cfg(not(feature = "base"))]
2206                {
2207                    if nonce_key.is_some() {
2208                        return ResponseResult::Error(RpcError::invalid_params(
2209                            "nonce-key transaction counts require Base support",
2210                        ));
2211                    }
2212                    self.transaction_count(address, block).await.to_rpc_result()
2213                }
2214            }
2215            EthRequest::EthGetTransactionCountByHash(hash) => {
2216                self.block_transaction_count_by_hash(hash).await.to_rpc_result()
2217            }
2218            EthRequest::EthGetTransactionCountByNumber(num) => {
2219                self.block_transaction_count_by_number(num).await.to_rpc_result()
2220            }
2221            EthRequest::EthGetUnclesCountByHash(hash) => {
2222                self.block_uncles_count_by_hash(hash).await.to_rpc_result()
2223            }
2224            EthRequest::EthGetUnclesCountByNumber(num) => {
2225                self.block_uncles_count_by_number(num).await.to_rpc_result()
2226            }
2227            EthRequest::EthGetCodeAt(addr, block) => {
2228                self.get_code(addr, block).await.to_rpc_result()
2229            }
2230            EthRequest::EthGetProof(addr, keys, block) => {
2231                self.get_proof(addr, keys, block).await.to_rpc_result()
2232            }
2233            EthRequest::EthSign(addr, content) => self.sign(addr, content).await.to_rpc_result(),
2234            EthRequest::PersonalSign(content, addr) => {
2235                self.sign(addr, content).await.to_rpc_result()
2236            }
2237            EthRequest::EthSignTransaction(request) => {
2238                self.sign_transaction(*request).await.to_rpc_result()
2239            }
2240            EthRequest::EthSignTypedData(addr, data) => {
2241                self.sign_typed_data(addr, data).await.to_rpc_result()
2242            }
2243            EthRequest::EthSignTypedDataV3(addr, data) => {
2244                self.sign_typed_data_v3(addr, data).await.to_rpc_result()
2245            }
2246            EthRequest::EthSignTypedDataV4(addr, data) => {
2247                self.sign_typed_data_v4(addr, &data).await.to_rpc_result()
2248            }
2249            EthRequest::EthSendRawTransaction(tx) => {
2250                self.send_raw_transaction(tx).await.to_rpc_result()
2251            }
2252            EthRequest::EthSendRawTransactionSync(tx, timeout_ms) => {
2253                self.send_raw_transaction_sync(tx, timeout_ms).await.to_rpc_result()
2254            }
2255            EthRequest::EthSendRawTransactionConditional(tx, condition) => {
2256                self.send_raw_transaction_conditional(tx, condition).await.to_rpc_result()
2257            }
2258            EthRequest::EthSignRawTransaction(tx) => {
2259                self.sign_raw_transaction(tx).await.to_rpc_result()
2260            }
2261            EthRequest::AnvilClassifyTransaction(tx) => {
2262                self.anvil_classify_transaction(tx).to_rpc_result()
2263            }
2264            EthRequest::EthCall(call, block, state_override, block_overrides) => self
2265                .call(call, block, EvmOverrides::new(state_override, block_overrides))
2266                .await
2267                .to_rpc_result(),
2268            EthRequest::EthCallMany(bundles, state_context, state_override) => {
2269                self.call_many(bundles, state_context, state_override).await.to_rpc_result()
2270            }
2271            EthRequest::EthCallBundle(bundle) => self.call_bundle(bundle).await.to_rpc_result(),
2272            EthRequest::EthSimulateV1(simulation, block) => {
2273                self.simulate_v1_raw(simulation, block).await.to_rpc_result()
2274            }
2275            EthRequest::EthCreateAccessList(call, block, state_override) => {
2276                self.create_access_list(call, block, state_override).await.to_rpc_result()
2277            }
2278            EthRequest::EthEstimateGas(call, block, state_override, block_overrides) => self
2279                .estimate_gas(call, block, EvmOverrides::new(state_override, block_overrides))
2280                .await
2281                .to_rpc_result(),
2282            EthRequest::EthFillTransaction(request) => {
2283                self.fill_transaction(request).await.to_rpc_result()
2284            }
2285            EthRequest::EthGetRawTransactionByHash(hash) => {
2286                self.raw_transaction(hash).await.to_rpc_result()
2287            }
2288            EthRequest::GetBlobByHash(hash) => {
2289                self.anvil_get_blob_by_versioned_hash(hash).to_rpc_result()
2290            }
2291            EthRequest::GetBlobByTransactionHash(hash) => {
2292                self.anvil_get_blob_by_tx_hash(hash).to_rpc_result()
2293            }
2294            EthRequest::GetGenesisTime(()) => self.anvil_get_genesis_time().to_rpc_result(),
2295            EthRequest::GetLastBlockWallTime(()) => {
2296                self.anvil_get_last_block_wall_time().to_rpc_result()
2297            }
2298            EthRequest::EthGetRawTransactionByBlockHashAndIndex(hash, index) => {
2299                self.raw_transaction_by_block_hash_and_index(hash, index).await.to_rpc_result()
2300            }
2301            EthRequest::EthGetRawTransactionByBlockNumberAndIndex(num, index) => {
2302                self.raw_transaction_by_block_number_and_index(num, index).await.to_rpc_result()
2303            }
2304            EthRequest::EthGetTransactionByBlockHashAndIndex(hash, index) => {
2305                self.transaction_by_block_hash_and_index(hash, index).await.to_rpc_result()
2306            }
2307            EthRequest::EthGetTransactionByBlockNumberAndIndex(num, index) => {
2308                self.transaction_by_block_number_and_index(num, index).await.to_rpc_result()
2309            }
2310            EthRequest::EthGetTransactionReceipt(tx) => {
2311                self.transaction_receipt(tx).await.to_rpc_result()
2312            }
2313            EthRequest::EthGetBlockReceipts(number) => {
2314                self.block_receipts(number).await.to_rpc_result()
2315            }
2316            EthRequest::EthGetUncleByBlockHashAndIndex(hash, index) => {
2317                self.uncle_by_block_hash_and_index(hash, index).await.to_rpc_result()
2318            }
2319            EthRequest::EthGetUncleByBlockNumberAndIndex(num, index) => {
2320                self.uncle_by_block_number_and_index(num, index).await.to_rpc_result()
2321            }
2322            EthRequest::EthGetLogs(filter) => self.logs(filter).await.to_rpc_result(),
2323            EthRequest::EthGetWork(_) => self.work().to_rpc_result(),
2324            EthRequest::EthSyncing(_) => self.syncing().to_rpc_result(),
2325            EthRequest::EthConfig(_) => self.config().to_rpc_result(),
2326            EthRequest::EthSubmitWork(nonce, pow, digest) => {
2327                self.submit_work(nonce, pow, digest).to_rpc_result()
2328            }
2329            EthRequest::EthSubmitHashRate(rate, id) => {
2330                self.submit_hashrate(rate, id).to_rpc_result()
2331            }
2332            EthRequest::EthFeeHistory(count, newest, reward_percentiles) => {
2333                self.fee_history(count, newest, reward_percentiles).await.to_rpc_result()
2334            }
2335            // non eth-standard rpc calls
2336            EthRequest::DebugGetRawTransaction(hash) => {
2337                self.raw_transaction(hash).await.to_rpc_result()
2338            }
2339            EthRequest::DebugGetRawReceipts(block) => {
2340                self.raw_receipts(block).await.to_rpc_result()
2341            }
2342            EthRequest::DebugGetRawTransactions(block) => {
2343                self.raw_transactions(block).await.to_rpc_result()
2344            }
2345            EthRequest::DebugGetRawHeader(block) => self.raw_header(block).await.to_rpc_result(),
2346            EthRequest::DebugGetRawBlock(block) => self.raw_block(block).await.to_rpc_result(),
2347            // non eth-standard rpc calls
2348            EthRequest::DebugClearTxpool(_) => self.debug_clear_txpool().await.to_rpc_result(),
2349            // non eth-standard rpc calls
2350            EthRequest::DebugTraceTransaction(tx, opts) => {
2351                self.debug_trace_transaction(tx, opts).await.to_rpc_result()
2352            }
2353            // non eth-standard rpc calls
2354            EthRequest::DebugTraceCall(tx, block, opts) => {
2355                self.debug_trace_call(tx, block, opts).await.to_rpc_result()
2356            }
2357            EthRequest::DebugCodeByHash(hash, block) => {
2358                self.debug_code_by_hash(hash, block).await.to_rpc_result()
2359            }
2360            EthRequest::DebugDbGet(key) => self.debug_db_get(key).await.to_rpc_result(),
2361            EthRequest::DebugGetModifiedAccountsByNumber(start_number, end_number) => {
2362                self.debug_get_modified_accounts_by_number(start_number, end_number).to_rpc_result()
2363            }
2364            EthRequest::DebugFreeOsMemory(()) => self.debug_free_os_memory().to_rpc_result(),
2365            EthRequest::DebugAccountInfoAt(block_id, tx_index, address) => {
2366                self.debug_account_info_at(block_id, tx_index, address).await.to_rpc_result()
2367            }
2368            EthRequest::DebugExecutionWitness(block) => {
2369                self.debug_execution_witness(block).await.to_rpc_result()
2370            }
2371            EthRequest::DebugTraceBlock(rlp_block, opts) => {
2372                self.debug_trace_block(rlp_block, opts).await.to_rpc_result()
2373            }
2374            EthRequest::DebugTraceBlockByHash(block_hash, opts) => {
2375                self.debug_trace_block_by_hash(block_hash, opts).await.to_rpc_result()
2376            }
2377            EthRequest::DebugTraceBlockByNumber(block_number, opts) => {
2378                self.debug_trace_block_by_number(block_number, opts).await.to_rpc_result()
2379            }
2380            EthRequest::TraceCall(tx, trace_types, block) => {
2381                self.trace_call(tx, trace_types, block).await.to_rpc_result()
2382            }
2383            EthRequest::TraceTransaction(tx) => self.trace_transaction(tx).await.to_rpc_result(),
2384            EthRequest::TraceBlock(block) => self.trace_block(block).await.to_rpc_result(),
2385            EthRequest::TraceFilter(filter) => self.trace_filter(filter).await.to_rpc_result(),
2386            EthRequest::TraceGet(hash, indices) => {
2387                self.trace_get(hash, indices).await.to_rpc_result()
2388            }
2389            EthRequest::TraceReplayBlockTransactions(block, trace_types) => {
2390                self.trace_replay_block_transactions(block, trace_types).await.to_rpc_result()
2391            }
2392            EthRequest::TraceReplayTransaction(transaction, trace_types) => {
2393                self.trace_replay_transaction(transaction, trace_types).await.to_rpc_result()
2394            }
2395            EthRequest::TraceTransactionOpcodeGas(tx_hash) => {
2396                self.trace_transaction_opcode_gas(tx_hash).await.to_rpc_result()
2397            }
2398            EthRequest::TraceBlockOpcodeGas(block_id) => {
2399                self.trace_block_opcode_gas(block_id).await.to_rpc_result()
2400            }
2401            EthRequest::TraceRawTransaction(tx, trace_types, block_number) => {
2402                self.trace_raw_transaction(tx, trace_types, block_number).await.to_rpc_result()
2403            }
2404            EthRequest::TraceCallMany(calls, block_number) => {
2405                self.trace_call_many(calls, block_number).await.to_rpc_result()
2406            }
2407            EthRequest::ImpersonateAccount(addr) => {
2408                self.anvil_impersonate_account(addr).await.to_rpc_result()
2409            }
2410            EthRequest::StopImpersonatingAccount(addr) => {
2411                self.anvil_stop_impersonating_account(addr).await.to_rpc_result()
2412            }
2413            EthRequest::AutoImpersonateAccount(enable) => {
2414                self.anvil_auto_impersonate_account(enable).await.to_rpc_result()
2415            }
2416            EthRequest::ImpersonateSignature(signature, address) => {
2417                self.anvil_impersonate_signature(signature, address).await.to_rpc_result()
2418            }
2419            EthRequest::GetAutoMine(()) => self.anvil_get_auto_mine().to_rpc_result(),
2420            EthRequest::Mine(blocks, interval) => {
2421                self.anvil_mine(blocks, interval).await.to_rpc_result()
2422            }
2423            EthRequest::SetAutomine(enabled) => {
2424                self.anvil_set_auto_mine(enabled).await.to_rpc_result()
2425            }
2426            EthRequest::SetIntervalMining(interval) => {
2427                self.anvil_set_interval_mining(interval).to_rpc_result()
2428            }
2429            EthRequest::GetIntervalMining(()) => self.anvil_get_interval_mining().to_rpc_result(),
2430            EthRequest::DropTransaction(tx) => {
2431                self.anvil_drop_transaction(tx).await.to_rpc_result()
2432            }
2433            EthRequest::DropAllTransactions() => {
2434                self.anvil_drop_all_transactions().await.to_rpc_result()
2435            }
2436            EthRequest::Reset(fork) => {
2437                self.anvil_reset(fork.and_then(|p| p.params)).await.to_rpc_result()
2438            }
2439            EthRequest::SetBalance(addr, val) => {
2440                self.anvil_set_balance(addr, val).await.to_rpc_result()
2441            }
2442            EthRequest::AddBalance(addr, val) => {
2443                self.anvil_add_balance(addr, val).await.to_rpc_result()
2444            }
2445            EthRequest::DealERC20(addr, token_addr, val) => {
2446                self.anvil_deal_erc20(addr, token_addr, val).await.to_rpc_result()
2447            }
2448            EthRequest::DealTIP20(addr, token_addr, val) => {
2449                self.anvil_deal_tip20(addr, token_addr, val).await.to_rpc_result()
2450            }
2451            EthRequest::SetERC20Allowance(owner, spender, token_addr, val) => self
2452                .anvil_set_erc20_allowance(owner, spender, token_addr, val)
2453                .await
2454                .to_rpc_result(),
2455            EthRequest::SetCode(addr, code) => {
2456                self.anvil_set_code(addr, code).await.to_rpc_result()
2457            }
2458            EthRequest::SetNonce(addr, nonce) => {
2459                self.anvil_set_nonce(addr, nonce).await.to_rpc_result()
2460            }
2461            EthRequest::SetStorageAt(addr, slot, val) => {
2462                self.anvil_set_storage_at(addr, slot, val).await.to_rpc_result()
2463            }
2464            EthRequest::SetCoinbase(addr) => self.anvil_set_coinbase(addr).await.to_rpc_result(),
2465            EthRequest::SetNextBlockPrevRandao(prevrandao) => {
2466                self.anvil_set_next_block_prevrandao(prevrandao).await.to_rpc_result()
2467            }
2468            EthRequest::SetNextBlockParentBeaconBlockRoot(root) => {
2469                self.anvil_set_next_block_parent_beacon_block_root(root).await.to_rpc_result()
2470            }
2471            EthRequest::SetChainId(id) => self.anvil_set_chain_id(id).await.to_rpc_result(),
2472            EthRequest::SetLogging(log) => self.anvil_set_logging(log).await.to_rpc_result(),
2473            EthRequest::SetMinGasPrice(gas) => {
2474                self.anvil_set_min_gas_price(gas).await.to_rpc_result()
2475            }
2476            EthRequest::SetNextBlockBaseFeePerGas(gas) => {
2477                self.anvil_set_next_block_base_fee_per_gas(gas).await.to_rpc_result()
2478            }
2479            EthRequest::DumpState(preserve_historical_states) => self
2480                .anvil_dump_state(preserve_historical_states.and_then(|s| s.params))
2481                .await
2482                .to_rpc_result(),
2483            EthRequest::LoadState(buf) => self.anvil_load_state(buf).await.to_rpc_result(),
2484            EthRequest::NodeInfo(_) => self.anvil_node_info().await.to_rpc_result(),
2485            EthRequest::AnvilMetadata(_) => self.anvil_metadata().await.to_rpc_result(),
2486            EthRequest::EvmSnapshot(_) => self.evm_snapshot().await.to_rpc_result(),
2487            EthRequest::EvmRevert(id) => self.evm_revert(id).await.to_rpc_result(),
2488            EthRequest::EvmIncreaseTime(time) => self.evm_increase_time(time).await.to_rpc_result(),
2489            EthRequest::EvmSetNextBlockTimeStamp(time) => {
2490                if time >= U256::from(u64::MAX) {
2491                    return ResponseResult::Error(RpcError::invalid_params(
2492                        "The timestamp is too big",
2493                    ));
2494                }
2495                let time = time.to::<u64>();
2496                self.evm_set_next_block_timestamp(time).to_rpc_result()
2497            }
2498            EthRequest::EvmSetTime(timestamp) => {
2499                if timestamp >= U256::from(u64::MAX) {
2500                    return ResponseResult::Error(RpcError::invalid_params(
2501                        "The timestamp is too big",
2502                    ));
2503                }
2504                // evm_setTime accepts either seconds or milliseconds for Ganache compatibility.
2505                // Timestamps above 1e12 are interpreted as milliseconds and converted to
2506                // seconds; below that threshold they are treated as seconds directly.
2507                let raw = timestamp.to::<u64>();
2508                let time = if raw > 1_000_000_000_000 {
2509                    Duration::from_millis(raw).as_secs()
2510                } else {
2511                    raw
2512                };
2513                self.evm_set_time(time).to_rpc_result()
2514            }
2515            EthRequest::EvmSetBlockGasLimit(gas_limit) => {
2516                self.evm_set_block_gas_limit(gas_limit).to_rpc_result()
2517            }
2518            EthRequest::EvmSetBlockTimeStampInterval(time) => {
2519                self.evm_set_block_timestamp_interval(time).to_rpc_result()
2520            }
2521            EthRequest::EvmRemoveBlockTimeStampInterval(()) => {
2522                self.evm_remove_block_timestamp_interval().to_rpc_result()
2523            }
2524            EthRequest::EvmMine(mine) => {
2525                self.evm_mine(mine.and_then(|p| p.params)).await.to_rpc_result()
2526            }
2527            EthRequest::EvmMineDetailed(mine) => {
2528                self.evm_mine_detailed(mine.and_then(|p| p.params)).await.to_rpc_result()
2529            }
2530            EthRequest::SetRpcUrl(url) => self.anvil_set_rpc_url(url).await.to_rpc_result(),
2531            EthRequest::EthSendUnsignedTransaction(tx) => {
2532                self.eth_send_unsigned_transaction(*tx).await.to_rpc_result()
2533            }
2534            EthRequest::EthNewFilter(filter) => self.new_filter(filter).await.to_rpc_result(),
2535            EthRequest::EthGetFilterChanges(id) => self.get_filter_changes(&id).await,
2536            EthRequest::EthNewBlockFilter(_) => self.new_block_filter().await.to_rpc_result(),
2537            EthRequest::EthNewPendingTransactionFilter(full) => {
2538                self.new_pending_transaction_filter(full.unwrap_or(false)).await.to_rpc_result()
2539            }
2540            EthRequest::EthGetFilterLogs(id) => self.get_filter_logs(&id).await.to_rpc_result(),
2541            EthRequest::EthUninstallFilter(id) => self.uninstall_filter(&id).await.to_rpc_result(),
2542            EthRequest::TxPoolStatus(_) => self.txpool_status().await.to_rpc_result(),
2543            EthRequest::TxPoolInspect(_) => self.txpool_inspect().await.to_rpc_result(),
2544            EthRequest::TxPoolContent(_) => self.txpool_content().await.to_rpc_result(),
2545            EthRequest::TxPoolContentFrom(from) => {
2546                self.txpool_content_from(from).await.to_rpc_result()
2547            }
2548            EthRequest::ErigonGetHeaderByNumber(num) => {
2549                self.erigon_get_header_by_number(num).await.to_rpc_result()
2550            }
2551            EthRequest::OtsGetApiLevel(_) => self.ots_get_api_level().await.to_rpc_result(),
2552            EthRequest::OtsGetInternalOperations(hash) => {
2553                self.ots_get_internal_operations(hash).await.to_rpc_result()
2554            }
2555            EthRequest::OtsHasCode(addr, num) => self.ots_has_code(addr, num).await.to_rpc_result(),
2556            EthRequest::OtsTraceTransaction(hash) => {
2557                self.ots_trace_transaction(hash).await.to_rpc_result()
2558            }
2559            EthRequest::OtsGetTransactionError(hash) => {
2560                self.ots_get_transaction_error(hash).await.to_rpc_result()
2561            }
2562            EthRequest::OtsGetBlockDetails(num) => {
2563                self.ots_get_block_details(num).await.to_rpc_result()
2564            }
2565            EthRequest::OtsGetBlockDetailsByHash(hash) => {
2566                self.ots_get_block_details_by_hash(hash).await.to_rpc_result()
2567            }
2568            EthRequest::OtsGetBlockTransactions(num, page, page_size) => {
2569                self.ots_get_block_transactions(num, page, page_size).await.to_rpc_result()
2570            }
2571            EthRequest::OtsSearchTransactionsBefore(address, num, page_size) => {
2572                self.ots_search_transactions_before(address, num, page_size).await.to_rpc_result()
2573            }
2574            EthRequest::OtsSearchTransactionsAfter(address, num, page_size) => {
2575                self.ots_search_transactions_after(address, num, page_size).await.to_rpc_result()
2576            }
2577            EthRequest::OtsGetTransactionBySenderAndNonce(address, nonce) => {
2578                self.ots_get_transaction_by_sender_and_nonce(address, nonce).await.to_rpc_result()
2579            }
2580            EthRequest::EthGetTransactionBySenderAndNonce(sender, nonce) => {
2581                self.transaction_by_sender_and_nonce(sender, nonce).await.to_rpc_result()
2582            }
2583            EthRequest::OtsGetContractCreator(address) => {
2584                self.ots_get_contract_creator(address).await.to_rpc_result()
2585            }
2586            EthRequest::RemovePoolTransactions(address) => {
2587                self.anvil_remove_pool_transactions(address).await.to_rpc_result()
2588            }
2589            EthRequest::Reorg(reorg_options) => {
2590                self.anvil_reorg(reorg_options).await.to_rpc_result()
2591            }
2592            EthRequest::Rollback(depth) => self.anvil_rollback(depth).await.to_rpc_result(),
2593            EthRequest::SetFeeToken(user, token) => {
2594                self.anvil_set_fee_token(user, token).await.to_rpc_result()
2595            }
2596            EthRequest::SetValidatorFeeToken(validator, token) => {
2597                self.anvil_set_validator_fee_token(validator, token).await.to_rpc_result()
2598            }
2599            EthRequest::SetFeeAmmLiquidity(user_token, validator_token, amount) => self
2600                .anvil_set_fee_amm_liquidity(user_token, validator_token, amount)
2601                .await
2602                .to_rpc_result(),
2603        };
2604
2605        if let ResponseResult::Error(err) = &response {
2606            node_info!("\nRPC request failed:");
2607            node_info!("    Request: {:?}", request);
2608            node_info!("    Error: {}\n", err);
2609        }
2610
2611        response
2612    }
2613
2614    fn sign_request(&self, from: &Address, typed_tx: FoundryTypedTx) -> Result<FoundryTxEnvelope> {
2615        match typed_tx {
2616            #[cfg(feature = "optimism")]
2617            FoundryTypedTx::Deposit(_) => return Ok(typed_tx.into_impersonated()),
2618            _ => {
2619                for signer in self.signers.iter() {
2620                    if signer.accounts().contains(from) {
2621                        return signer.sign_transaction_from(from, typed_tx);
2622                    }
2623                }
2624            }
2625        }
2626        Err(BlockchainError::NoSignerAvailable)
2627    }
2628
2629    async fn inner_raw_transaction(&self, hash: B256) -> Result<Option<Bytes>> {
2630        match self.pool.get_transaction(hash) {
2631            Some(tx) => Ok(Some(tx.transaction.encoded_2718().into())),
2632            None => match self.backend.transaction_by_hash(hash).await? {
2633                Some(tx) => encode_rpc_transaction(&tx).map(Some),
2634                None => Ok(None),
2635            },
2636        }
2637    }
2638
2639    /// Returns balance of the given account.
2640    ///
2641    /// Handler for ETH RPC call: `eth_getBalance`
2642    pub async fn balance(&self, address: Address, block_number: Option<BlockId>) -> Result<U256> {
2643        node_info!("eth_getBalance");
2644        let block_request = self.block_request(block_number).await?;
2645
2646        // check if the number predates the fork, if in fork mode
2647        if let BlockRequest::Number(number) = block_request
2648            && let Some(fork) = self.get_fork()
2649            && fork.predates_fork(number)
2650        {
2651            return Ok(fork.get_balance(address, number).await?);
2652        }
2653
2654        self.backend.get_balance(address, Some(block_request)).await
2655    }
2656
2657    /// Returns the ethereum account.
2658    ///
2659    /// Handler for ETH RPC call: `eth_getAccount`
2660    pub async fn get_account(
2661        &self,
2662        address: Address,
2663        block_number: Option<BlockId>,
2664    ) -> Result<TrieAccount> {
2665        node_info!("eth_getAccount");
2666        let block_request = self.block_request(block_number).await?;
2667
2668        // check if the number predates the fork, if in fork mode
2669        if let BlockRequest::Number(number) = block_request
2670            && let Some(fork) = self.get_fork()
2671            && fork.predates_fork(number)
2672        {
2673            return Ok(fork.get_account(address, number).await?);
2674        }
2675
2676        self.backend.get_account_at_block(address, Some(block_request)).await
2677    }
2678
2679    /// Returns the account information including balance, nonce, code and storage
2680    ///
2681    /// Note: This isn't support by all providers
2682    pub async fn get_account_info(
2683        &self,
2684        address: Address,
2685        block_number: Option<BlockId>,
2686    ) -> Result<alloy_rpc_types::eth::AccountInfo> {
2687        node_info!("eth_getAccountInfo");
2688
2689        let block_request = self.block_request(block_number).await?;
2690        if let BlockRequest::Number(number) = block_request
2691            && let Some(fork) = self.get_fork()
2692        {
2693            trace!(target: "node", "get_account_info: fork block {}, requested block {number}", fork.block_number());
2694            if block_number.is_some_and(|block| !block.is_latest())
2695                && fork.predates_fork_inclusive(number)
2696            {
2697                if fork.requires_account_info() {
2698                    return Ok(fork.get_account_info(address, number).await?);
2699                }
2700                let balance = fork.get_balance(address, number).map_err(BlockchainError::from);
2701                let code = fork.get_code(address, number).map_err(BlockchainError::from);
2702                let nonce = fork.get_nonce(address, number).map_err(BlockchainError::from);
2703                let (balance, code, nonce) = try_join!(balance, code, nonce)?;
2704                return Ok(alloy_rpc_types::eth::AccountInfo { balance, nonce, code });
2705            }
2706        }
2707
2708        self.backend.get_account_info_at_block(address, Some(block_request)).await
2709    }
2710    /// Returns content of the storage at given address.
2711    ///
2712    /// Handler for ETH RPC call: `eth_getStorageAt`
2713    pub async fn storage_at(
2714        &self,
2715        address: Address,
2716        index: U256,
2717        block_number: Option<BlockId>,
2718    ) -> Result<B256> {
2719        node_info!("eth_getStorageAt");
2720        let block_request = self.block_request(block_number).await?;
2721
2722        // check if the number predates the fork, if in fork mode
2723        if let BlockRequest::Number(number) = block_request
2724            && let Some(fork) = self.get_fork()
2725            && fork.predates_fork(number)
2726        {
2727            return Ok(B256::from(
2728                fork.storage_at(address, index, Some(BlockNumber::Number(number))).await?,
2729            ));
2730        }
2731
2732        self.backend.storage_at(address, index, Some(block_request)).await
2733    }
2734
2735    /// Returns storage values for multiple accounts and slots in a single call.
2736    ///
2737    /// Handler for ETH RPC call: `eth_getStorageValues`
2738    pub async fn storage_values(
2739        &self,
2740        requests: HashMap<Address, Vec<B256>>,
2741        block_number: Option<BlockId>,
2742    ) -> Result<HashMap<Address, Vec<B256>>> {
2743        node_info!("eth_getStorageValues");
2744
2745        if requests.is_empty() {
2746            return Err(RpcError::invalid_params("empty request").into());
2747        }
2748
2749        let total_slots: usize = requests.values().map(|s| s.len()).sum();
2750        if total_slots > 1024 {
2751            return Err(BlockchainError::RpcError(RpcError::invalid_params(format!(
2752                "total slot count {total_slots} exceeds limit 1024"
2753            ))));
2754        }
2755
2756        let block_request = self.block_request(block_number).await?;
2757
2758        // check if the number predates the fork, if in fork mode
2759        if let BlockRequest::Number(number) = block_request
2760            && let Some(fork) = self.get_fork()
2761            && fork.predates_fork(number)
2762        {
2763            let mut result: HashMap<Address, Vec<B256>> = HashMap::default();
2764            for (address, slots) in requests {
2765                let mut values = Vec::with_capacity(slots.len());
2766                for slot in &slots {
2767                    let val = fork
2768                        .storage_at(address, (*slot).into(), Some(BlockNumber::Number(number)))
2769                        .await?;
2770                    values.push(B256::from(val));
2771                }
2772                result.insert(address, values);
2773            }
2774            return Ok(result);
2775        }
2776
2777        self.backend.storage_values(requests, Some(block_request)).await
2778    }
2779
2780    /// Returns block with given number.
2781    ///
2782    /// Handler for ETH RPC call: `eth_getBlockByNumber`
2783    pub async fn block_by_number(&self, number: BlockNumber) -> Result<Option<AnyRpcBlock>> {
2784        node_info!("eth_getBlockByNumber");
2785        if number.is_pending() {
2786            return Ok(Some(self.pending_block().await?));
2787        }
2788
2789        self.backend.block_by_number(number).await
2790    }
2791
2792    /// Returns block header with given number.
2793    ///
2794    /// Handler for ETH RPC call: `eth_getHeaderByNumber`
2795    pub async fn header_by_number(
2796        &self,
2797        number: BlockNumber,
2798    ) -> Result<Option<WithOtherFields<AnyRpcHeader>>> {
2799        node_info!("eth_getHeaderByNumber");
2800        if number.is_pending() {
2801            let WithOtherFields { inner: block, other } = self.pending_block().await?.0;
2802            return Ok(Some(WithOtherFields { inner: block.header, other }));
2803        }
2804
2805        Ok(self.backend.block_by_number(number).await?.map(|block| {
2806            let WithOtherFields { inner: block, other } = block.0;
2807            WithOtherFields { inner: block.header, other }
2808        }))
2809    }
2810
2811    /// Returns a _full_ block with given number
2812    ///
2813    /// Handler for ETH RPC call: `eth_getBlockByNumber`
2814    pub async fn block_by_number_full(&self, number: BlockNumber) -> Result<Option<AnyRpcBlock>> {
2815        node_info!("eth_getBlockByNumber");
2816        if number.is_pending() {
2817            return self.pending_block_full().await;
2818        }
2819        self.backend.block_by_number_full(number).await
2820    }
2821
2822    /// Returns the EIP-7928 block access list for a block.
2823    ///
2824    /// Handler for ETH RPC call: `eth_getBlockAccessList`
2825    pub async fn block_access_list(&self, block_id: BlockId) -> Result<Option<serde_json::Value>> {
2826        node_info!("eth_getBlockAccessList");
2827        let block_request = self.block_request(Some(block_id)).await?;
2828        let BlockRequest::Number(number) = block_request else { return Ok(None) };
2829
2830        if let Some(fork) = self.get_fork()
2831            && fork.predates_fork_inclusive(number)
2832        {
2833            return Ok(fork.block_access_list(block_id).await?);
2834        }
2835
2836        let block_access_list = match block_id {
2837            BlockId::Hash(hash) => self.backend.block_access_list_by_hash(hash.block_hash),
2838            BlockId::Number(_) => self.backend.block_access_list_by_number(number),
2839        };
2840        Ok(block_access_list
2841            .map(|bal| serde_json::to_value(bal).expect("BAL serialization is infallible")))
2842    }
2843
2844    /// Returns the EIP-7928 block access list for a block hash.
2845    ///
2846    /// Handler for ETH RPC call: `eth_getBlockAccessListByBlockHash`
2847    pub async fn block_access_list_by_hash(
2848        &self,
2849        block_hash: B256,
2850    ) -> Result<Option<serde_json::Value>> {
2851        node_info!("eth_getBlockAccessListByBlockHash");
2852        if let Some(block_access_list) = self.backend.block_access_list_by_hash(block_hash) {
2853            return Ok(Some(
2854                serde_json::to_value(block_access_list).expect("BAL serialization is infallible"),
2855            ));
2856        }
2857
2858        let Some(fork) = self.get_fork() else { return Ok(None) };
2859
2860        // Only blocks we know to be mined after the fork point are guaranteed to be unknown
2861        // upstream. Anything else, including hashes we cannot resolve locally, is left to the fork.
2862        if let Some(block) = self.backend.get_block_by_hash(block_hash)
2863            && !fork.predates_fork_inclusive(block.header.number)
2864        {
2865            return Ok(None);
2866        }
2867
2868        Ok(fork.block_access_list_by_hash(block_hash).await?)
2869    }
2870
2871    /// Returns the EIP-7928 block access list for a block number.
2872    ///
2873    /// Handler for ETH RPC call: `eth_getBlockAccessListByBlockNumber`
2874    pub async fn block_access_list_by_number(
2875        &self,
2876        block_number: BlockNumber,
2877    ) -> Result<Option<serde_json::Value>> {
2878        node_info!("eth_getBlockAccessListByBlockNumber");
2879        let block_request = self.block_request(Some(BlockId::Number(block_number))).await?;
2880        let BlockRequest::Number(number) = block_request else { return Ok(None) };
2881
2882        if let Some(fork) = self.get_fork()
2883            && fork.predates_fork_inclusive(number)
2884        {
2885            return Ok(fork.block_access_list_by_number(block_number).await?);
2886        }
2887
2888        Ok(self
2889            .backend
2890            .block_access_list_by_number(number)
2891            .map(|bal| serde_json::to_value(bal).expect("BAL serialization is infallible")))
2892    }
2893
2894    /// Returns the raw EIP-7928 block access list for a block.
2895    ///
2896    /// Handler for ETH RPC call: `eth_getBlockAccessListRaw`
2897    pub async fn block_access_list_raw(&self, block_id: BlockId) -> Result<Option<Bytes>> {
2898        node_info!("eth_getBlockAccessListRaw");
2899        let block_request = self.block_request(Some(block_id)).await?;
2900        let BlockRequest::Number(number) = block_request else { return Ok(None) };
2901
2902        if let Some(fork) = self.get_fork()
2903            && fork.predates_fork_inclusive(number)
2904        {
2905            return Ok(fork.block_access_list_raw(block_id).await?);
2906        }
2907
2908        let block_access_list = match block_id {
2909            BlockId::Hash(hash) => self.backend.block_access_list_by_hash(hash.block_hash),
2910            BlockId::Number(_) => self.backend.block_access_list_by_number(number),
2911        };
2912        Ok(block_access_list.map(|bal| {
2913            let mut encoded = Vec::new();
2914            alloy_rlp::encode_list(&bal, &mut encoded);
2915            encoded.into()
2916        }))
2917    }
2918
2919    /// Returns the number of transactions sent from given address at given time (block number).
2920    ///
2921    /// Also checks the pending transactions if `block_number` is
2922    /// `BlockId::Number(BlockNumber::Pending)`
2923    ///
2924    /// Handler for ETH RPC call: `eth_getTransactionCount`
2925    pub async fn transaction_count(
2926        &self,
2927        address: Address,
2928        block_number: Option<BlockId>,
2929    ) -> Result<U256> {
2930        node_info!("eth_getTransactionCount");
2931        self.get_transaction_count(address, block_number).await.map(U256::from)
2932    }
2933
2934    /// Returns a protocol or EIP-8130 channel nonce.
2935    #[cfg(feature = "base")]
2936    pub async fn transaction_count_with_key(
2937        &self,
2938        address: Address,
2939        block_number: Option<BlockId>,
2940        nonce_key: Option<U256>,
2941    ) -> Result<U256> {
2942        let Some(nonce_key) = nonce_key else {
2943            return self.transaction_count(address, block_number).await;
2944        };
2945        if nonce_key.is_zero() {
2946            return self.transaction_count(address, block_number).await;
2947        }
2948
2949        let block_request = self.block_request(block_number).await?;
2950        let timestamp = self.backend.block_request_timestamp(&block_request).await?;
2951        self.backend.ensure_base_eip8130_active_at(timestamp)?;
2952        if nonce_key == Eip8130Constants::NONCE_KEY_MAX {
2953            return Err(RpcError::invalid_params(
2954                "nonce_key NONCE_KEY_MAX selects the expiring-nonce channel which has no \
2955                 per-channel counter",
2956            )
2957            .into());
2958        }
2959        let slot = NonceManagerStorage::nonce_slot(address, nonce_key)
2960            .map_err(|error| RpcError::invalid_params(error.to_string()))?;
2961        let word = self
2962            .backend
2963            .storage_at(NonceManagerStorage::ADDRESS, slot, Some(block_request))
2964            .await?;
2965        Ok(Eip8130Nonce::decode_channel_nonce(word.into()))
2966    }
2967
2968    /// Returns the number of transactions in a block with given block number.
2969    ///
2970    /// Handler for ETH RPC call: `eth_getBlockTransactionCountByNumber`
2971    pub async fn block_transaction_count_by_number(
2972        &self,
2973        block_number: BlockNumber,
2974    ) -> Result<Option<U256>> {
2975        node_info!("eth_getBlockTransactionCountByNumber");
2976        if block_number.is_pending() {
2977            let txs = self.pool.ready_transactions().collect();
2978            let block = self.backend.pending_block(txs).await?;
2979            return Ok(Some(U256::from(block.block.body.transactions.len())));
2980        }
2981
2982        let block = self.backend.block_by_number(block_number).await?;
2983        let txs = block.map(|b| match b.transactions() {
2984            BlockTransactions::Full(txs) => U256::from(txs.len()),
2985            BlockTransactions::Hashes(txs) => U256::from(txs.len()),
2986            BlockTransactions::Uncle => U256::ZERO,
2987        });
2988        Ok(txs)
2989    }
2990
2991    /// Returns the code at given address at given time (block number).
2992    ///
2993    /// Handler for ETH RPC call: `eth_getCode`
2994    pub async fn get_code(&self, address: Address, block_number: Option<BlockId>) -> Result<Bytes> {
2995        node_info!("eth_getCode");
2996        let block_request = self.block_request(block_number).await?;
2997        // check if the number predates the fork, if in fork mode
2998        if let BlockRequest::Number(number) = block_request
2999            && let Some(fork) = self.get_fork()
3000            && fork.predates_fork(number)
3001        {
3002            return Ok(fork.get_code(address, number).await?);
3003        }
3004        self.backend.get_code(address, Some(block_request)).await
3005    }
3006
3007    /// Returns the account and storage values of the specified account including the Merkle-proof.
3008    /// This call can be used to verify that the data you are pulling from is not tampered with.
3009    ///
3010    /// Handler for ETH RPC call: `eth_getProof`
3011    pub async fn get_proof(
3012        &self,
3013        address: Address,
3014        keys: Vec<B256>,
3015        block_number: Option<BlockId>,
3016    ) -> Result<EIP1186AccountProofResponse> {
3017        node_info!("eth_getProof");
3018        let block_request = self.block_request(block_number).await?;
3019
3020        // If we're in forking mode, or still on the forked block (no blocks mined yet) then we can
3021        // delegate the call.
3022        if let BlockRequest::Number(number) = block_request
3023            && let Some(fork) = self.get_fork()
3024            && fork.predates_fork_inclusive(number)
3025        {
3026            return Ok(fork.get_proof(address, keys, Some(number.into())).await?);
3027        }
3028
3029        let proof = self.backend.prove_account_at(address, keys, Some(block_request)).await?;
3030        Ok(proof)
3031    }
3032
3033    /// Signs a transaction
3034    ///
3035    /// Handler for ETH RPC call: `eth_signTransaction`
3036    pub async fn sign_transaction(
3037        &self,
3038        request: WithOtherFields<TransactionRequest>,
3039    ) -> Result<String> {
3040        node_info!("eth_signTransaction");
3041        let request = self.parse_transaction_request(request)?;
3042
3043        let from = request.from().map(Ok).unwrap_or_else(|| {
3044            self.accounts()?.first().copied().ok_or(BlockchainError::NoSignerAvailable)
3045        })?;
3046
3047        let nonce = self.request_nonce_for_transaction(&request, from).await?;
3048
3049        let request = self.build_tx_request(request, nonce).await?;
3050
3051        let signed_transaction = self.sign_request(&from, request)?.encoded_2718();
3052        Ok(alloy_primitives::hex::encode_prefixed(signed_transaction))
3053    }
3054
3055    /// Sends a transaction
3056    ///
3057    /// Handler for ETH RPC call: `eth_sendTransaction`
3058    pub async fn send_transaction(
3059        &self,
3060        request: WithOtherFields<TransactionRequest>,
3061    ) -> Result<TxHash> {
3062        node_info!("eth_sendTransaction");
3063        let request = self.parse_transaction_request(request)?;
3064
3065        let from = request.from().map(Ok).unwrap_or_else(|| {
3066            self.accounts()?.first().copied().ok_or(BlockchainError::NoSignerAvailable)
3067        })?;
3068        // Keep nonce selection and pool insertion atomic with respect to other requests from
3069        // this sender. Explicit nonces retain the pool's normal replacement behavior.
3070        let _nonce_guard = if request.nonce().is_none() {
3071            let lock = self.nonce_locks.write().entry(from).or_default().clone();
3072            Some(lock.lock_owned().await)
3073        } else {
3074            None
3075        };
3076        let nonce = self.request_nonce_for_transaction(&request, from).await?;
3077
3078        let typed_tx = self.build_tx_request(request, nonce).await?;
3079
3080        // if the sender is currently impersonated we need to "bypass" signing
3081        let pending_transaction = if self.is_impersonated(from) {
3082            let transaction = typed_tx.into_impersonated();
3083            self.ensure_typed_transaction_supported(&transaction)?;
3084            trace!(target : "node", ?from, "eth_sendTransaction: impersonating");
3085            PendingTransaction::with_impersonated(transaction, from)
3086        } else {
3087            let transaction = self.sign_request(&from, typed_tx)?;
3088            self.ensure_typed_transaction_supported(&transaction)?;
3089            PendingTransaction::new(transaction)?
3090        };
3091        self.add_pending_transaction(pending_transaction).await
3092    }
3093
3094    /// Resends a pending transaction with an updated gas price or gas limit.
3095    ///
3096    /// Handler for ETH RPC call: `eth_resend`
3097    pub async fn resend_transaction(
3098        &self,
3099        request: WithOtherFields<TransactionRequest>,
3100        gas_price: Option<U256>,
3101        gas_limit: Option<U64>,
3102    ) -> Result<TxHash> {
3103        node_info!("eth_resend");
3104        let mut request = self.parse_transaction_request(request)?;
3105
3106        let from = request.from().map(Ok).unwrap_or_else(|| {
3107            self.accounts()?.first().copied().ok_or(BlockchainError::NoSignerAvailable)
3108        })?;
3109        let nonce = request.nonce().ok_or_else(|| {
3110            BlockchainError::InvalidTransactionRequest(
3111                "missing transaction nonce in transaction spec".to_string(),
3112            )
3113        })?;
3114
3115        if !self.pool.contains_sender_nonce(from, nonce) {
3116            return Err(BlockchainError::TransactionNotFound);
3117        }
3118
3119        if let Some(gas_price) = gas_price.filter(|gas_price| !gas_price.is_zero()) {
3120            request.set_gas_price(gas_price.saturating_to());
3121        }
3122
3123        if let Some(gas_limit) = gas_limit.filter(|gas_limit| *gas_limit != U64::ZERO) {
3124            request.set_gas_limit(gas_limit.to());
3125        }
3126
3127        let typed_tx = self.build_tx_request(request, nonce).await?;
3128
3129        let pending_transaction = if self.is_impersonated(from) {
3130            let transaction = typed_tx.into_impersonated();
3131            self.ensure_typed_transaction_supported(&transaction)?;
3132            trace!(target : "node", ?from, "eth_resend: impersonating");
3133            PendingTransaction::with_impersonated(transaction, from)
3134        } else {
3135            let transaction = self.sign_request(&from, typed_tx)?;
3136            self.ensure_typed_transaction_supported(&transaction)?;
3137            PendingTransaction::new(transaction)?
3138        };
3139
3140        self.add_pending_transaction(pending_transaction).await
3141    }
3142
3143    /// Waits for a transaction to be included in a block and returns its receipt (no timeout).
3144    async fn await_transaction_inclusion(&self, hash: TxHash) -> Result<FoundryTxReceipt> {
3145        let mut stream = self.new_block_notifications();
3146        // Check if the transaction is already included before listening for new blocks.
3147        if let Some(receipt) = self.backend.transaction_receipt(hash).await? {
3148            return Ok(receipt);
3149        }
3150        while let Some(notification) = stream.next().await {
3151            if let Some(new_block) = notification.as_new_block()
3152                && let Some(block) = self.backend.get_block_by_hash(new_block.hash)
3153                && block.body.transactions.iter().any(|tx| tx.hash() == hash)
3154                && let Some(receipt) = self.backend.transaction_receipt(hash).await?
3155            {
3156                return Ok(receipt);
3157            }
3158        }
3159
3160        Err(BlockchainError::Message("Failed to await transaction inclusion".to_string()))
3161    }
3162
3163    fn transaction_confirmation_timeout(timeout_ms: Option<u64>) -> Duration {
3164        const TIMEOUT_DURATION: Duration = Duration::from_secs(30);
3165        timeout_ms
3166            .filter(|timeout_ms| *timeout_ms > 0)
3167            .map(Duration::from_millis)
3168            .map(|timeout| timeout.min(TIMEOUT_DURATION))
3169            .unwrap_or(TIMEOUT_DURATION)
3170    }
3171
3172    /// Waits for a transaction to be included in a block and returns its receipt, with timeout.
3173    async fn check_transaction_inclusion(
3174        &self,
3175        hash: TxHash,
3176        timeout_ms: Option<u64>,
3177    ) -> Result<FoundryTxReceipt> {
3178        let timeout_duration = Self::transaction_confirmation_timeout(timeout_ms);
3179        tokio::time::timeout(timeout_duration, self.await_transaction_inclusion(hash))
3180            .await
3181            .unwrap_or_else(|_elapsed| {
3182                Err(BlockchainError::TransactionConfirmationTimeout {
3183                    hash,
3184                    duration: timeout_duration,
3185                })
3186            })
3187    }
3188
3189    /// Sends a transaction and waits for receipt
3190    ///
3191    /// Handler for ETH RPC call: `eth_sendTransactionSync`
3192    pub async fn send_transaction_sync(
3193        &self,
3194        request: WithOtherFields<TransactionRequest>,
3195    ) -> Result<FoundryTxReceipt> {
3196        node_info!("eth_sendTransactionSync");
3197        let hash = self.send_transaction(request).await?;
3198
3199        let receipt = self.check_transaction_inclusion(hash, None).await?;
3200
3201        Ok(receipt)
3202    }
3203
3204    /// Sends signed transaction, returning its hash.
3205    ///
3206    /// Handler for ETH RPC call: `eth_sendRawTransaction`
3207    pub async fn send_raw_transaction(&self, tx: Bytes) -> Result<TxHash> {
3208        node_info!("eth_sendRawTransaction");
3209        if tx.is_empty() {
3210            return Err(BlockchainError::EmptyRawTransactionData);
3211        }
3212
3213        // Built-in Tempo fee payer: raw transactions submitted in the fee payer service encoding
3214        // or carrying the sponsorship placeholder ask the node to sponsor them before submission
3215        // (the sign-and-relay mode of the fee payer service contract).
3216        let service_encoded = if self.backend.is_tempo() {
3217            normalize_fee_payer_service_encoding(tx.as_ref())
3218        } else {
3219            None
3220        };
3221        let raw = service_encoded.map(Bytes::from).unwrap_or(tx);
3222
3223        let transaction = if raw.first() == Some(&EIP4844_TX_TYPE_ID) {
3224            // Pooled EIP-4844 decoding uses large stack frames for inline blobs. Isolate it from
3225            // the already-large RPC dispatcher without increasing every worker's stack.
3226            let raw = raw.clone();
3227            tokio::task::spawn_blocking(move || FoundryTxEnvelope::decode_2718(&mut raw.as_ref()))
3228                .await
3229                .map_err(|_| {
3230                    BlockchainError::Internal("transaction decoding task panicked".into())
3231                })?
3232        } else {
3233            FoundryTxEnvelope::decode_2718(&mut raw.as_ref())
3234        }
3235        .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
3236
3237        self.ensure_typed_transaction_supported(&transaction)?;
3238
3239        let transaction = match transaction {
3240            FoundryTxEnvelope::Tempo(aa_tx)
3241                if self.backend.is_tempo()
3242                    && aa_tx.tx().fee_payer_signature == Some(FEE_PAYER_SIGNATURE_MARKER) =>
3243            {
3244                FoundryTxEnvelope::Tempo(self.sponsor_sign_tempo_transaction(aa_tx).await?)
3245            }
3246            transaction => transaction,
3247        };
3248
3249        if self.backend.is_tempo() && TempoHardfork::from(self.backend.hardfork()).is_t5() {
3250            let classification = classify_payment_lane(raw.as_ref());
3251            trace!(target: "node", tx = ?transaction.hash(), ?classification, "classified transaction lane");
3252        }
3253
3254        #[cfg(feature = "base")]
3255        let is_eip8130 = transaction.is_eip8130();
3256        let pending_transaction = PendingTransaction::new(transaction).map_err(|error| {
3257            #[cfg(feature = "base")]
3258            if is_eip8130 {
3259                return BlockchainError::Eip8130TransactionRejected(error.to_string());
3260            }
3261            BlockchainError::RecoveryError(error)
3262        })?;
3263
3264        self.add_pending_transaction(pending_transaction).await
3265    }
3266
3267    /// Sends a signed transaction with an ignored transaction condition.
3268    ///
3269    /// Handler for ETH RPC call: `eth_sendRawTransactionConditional`
3270    pub async fn send_raw_transaction_conditional(
3271        &self,
3272        tx: Bytes,
3273        _condition: TransactionConditional,
3274    ) -> Result<TxHash> {
3275        node_info!("eth_sendRawTransactionConditional");
3276        self.send_raw_transaction(tx).await
3277    }
3278
3279    /// Classifies a raw transaction with the active Anvil Tempo/T5 payment-lane classifier.
3280    pub fn anvil_classify_transaction(&self, tx: Bytes) -> Result<PaymentLaneClassification> {
3281        node_info!("anvil_classifyTransaction");
3282        let mut data = tx.as_ref();
3283        if data.is_empty() {
3284            return Err(BlockchainError::EmptyRawTransactionData);
3285        }
3286
3287        FoundryTxEnvelope::decode_2718(&mut data)
3288            .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
3289
3290        Ok(self.classify_transaction_lane(tx.as_ref()))
3291    }
3292
3293    fn classify_transaction_lane(&self, raw: &[u8]) -> PaymentLaneClassification {
3294        if !self.backend.is_tempo() {
3295            return PaymentLaneClassification::general(PaymentLaneReason::NotTempo);
3296        }
3297
3298        if !TempoHardfork::from(self.backend.hardfork()).is_t5() {
3299            return PaymentLaneClassification::general(PaymentLaneReason::T5NotActive);
3300        }
3301
3302        classify_payment_lane(raw)
3303    }
3304
3305    /// Sends signed transaction, returning its receipt.
3306    ///
3307    /// Handler for ETH RPC call: `eth_sendRawTransactionSync`
3308    pub async fn send_raw_transaction_sync(
3309        &self,
3310        tx: Bytes,
3311        timeout_ms: Option<u64>,
3312    ) -> Result<FoundryTxReceipt> {
3313        node_info!("eth_sendRawTransactionSync");
3314
3315        let hash = self.send_raw_transaction(tx).await?;
3316        let receipt = self.check_transaction_inclusion(hash, timeout_ms).await?;
3317
3318        Ok(receipt)
3319    }
3320
3321    /// Signs a raw Tempo transaction as the node's fee payer (sponsor) and returns the fully
3322    /// signed raw transaction without broadcasting it.
3323    ///
3324    /// This is the sign-only mode of the Tempo fee payer service contract, so
3325    /// `cast send --sponsor-url` and the tempo SDK relay transport can point directly at this
3326    /// node. Only available on Tempo networks.
3327    ///
3328    /// Handler for ETH RPC call: `eth_signRawTransaction`
3329    pub async fn sign_raw_transaction(&self, tx: Bytes) -> Result<Bytes> {
3330        node_info!("eth_signRawTransaction");
3331        if !self.backend.is_tempo() {
3332            return Err(BlockchainError::RpcUnimplemented);
3333        }
3334
3335        if tx.is_empty() {
3336            return Err(BlockchainError::EmptyRawTransactionData);
3337        }
3338
3339        // Fee payer service clients submit the request in the service encoding, which carries a
3340        // `0x00` placeholder in the fee payer signature field.
3341        let service_encoded = normalize_fee_payer_service_encoding(tx.as_ref());
3342        let mut data = service_encoded.as_deref().unwrap_or(tx.as_ref());
3343
3344        let transaction = FoundryTxEnvelope::decode_2718(&mut data)
3345            .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
3346
3347        let FoundryTxEnvelope::Tempo(aa_tx) = transaction else {
3348            return Err(RpcError::invalid_params(
3349                "only Tempo (0x76) transactions can be fee-payer signed",
3350            )
3351            .into());
3352        };
3353
3354        let signed = self.sponsor_sign_tempo_transaction(aa_tx).await?;
3355        Ok(FoundryTxEnvelope::Tempo(signed).encoded_2718().into())
3356    }
3357
3358    /// Fills the sponsor-owned fields of a sender-signed Tempo AA transaction.
3359    ///
3360    /// Mirrors the hosted Tempo fee payer service: the node's fee payer account selects the fee
3361    /// token when the sender left it open and signs the fee payer digest. Only the fee token and
3362    /// fee payer signature are touched, so the sender signature stays valid.
3363    async fn sponsor_sign_tempo_transaction(&self, tx: AASigned) -> Result<AASigned> {
3364        // The sender must have signed in the sponsored state (fee payer placeholder set): the
3365        // sender signature commits to whether a fee payer is present, so sponsoring a
3366        // transaction signed without the placeholder would invalidate it.
3367        match tx.tx().fee_payer_signature {
3368            Some(FEE_PAYER_SIGNATURE_MARKER) => {}
3369            Some(_) => {
3370                return Err(
3371                    RpcError::invalid_params("transaction is already fee-payer signed").into()
3372                );
3373            }
3374            None => {
3375                return Err(RpcError::invalid_params(
3376                    "transaction does not request sponsorship; sign it with the fee payer \
3377                     signature placeholder",
3378                )
3379                .into());
3380            }
3381        }
3382
3383        let sender = tx.recover_signer().map_err(|_| {
3384            BlockchainError::RpcError(RpcError::invalid_params(
3385                "transaction must be signed by the sender before fee-payer signing",
3386            ))
3387        })?;
3388
3389        let Some(sponsor) = self.backend.tempo_fee_payer().await else {
3390            return Err(RpcError::invalid_params("no Tempo fee payer account available").into());
3391        };
3392        if sponsor == sender {
3393            return Err(RpcError::invalid_params(format!(
3394                "Tempo fee payer {sponsor} must not equal the transaction sender"
3395            ))
3396            .into());
3397        }
3398        let signer = self.get_signer(sponsor).ok_or(BlockchainError::NoSignerAvailable)?;
3399
3400        let (mut tx, sender_signature, _) = tx.into_parts();
3401        // The fee payer digest commits to the fee token, so it must be resolved first. The
3402        // service encoding omits the sender's fee token preference, letting the sponsor pick the
3403        // token it pays with.
3404        if tx.fee_token.is_none() {
3405            tx.fee_token = Some(self.backend.tempo_user_fee_token(sponsor).await?);
3406        }
3407        let digest = tx.fee_payer_signature_hash(sender);
3408        tx.fee_payer_signature = Some(signer.sign_hash(sponsor, digest).await?);
3409
3410        Ok(tx.into_signed(sender_signature))
3411    }
3412
3413    /// Call contract, returning the output data.
3414    ///
3415    /// Handler for ETH RPC call: `eth_call`
3416    pub async fn call(
3417        &self,
3418        request: WithOtherFields<TransactionRequest>,
3419        block_number: Option<BlockId>,
3420        overrides: EvmOverrides,
3421    ) -> Result<Bytes> {
3422        node_info!("eth_call");
3423        let block_request = self.block_request(block_number).await?;
3424        // check if the number predates the fork, if in fork mode
3425        if let BlockRequest::Number(number) = block_request
3426            && let Some(fork) = self.get_fork()
3427            && fork.predates_fork(number)
3428        {
3429            if overrides.has_state() || overrides.has_block() {
3430                return Err(BlockchainError::EvmOverrideError(
3431                    "not available on past forked blocks".to_string(),
3432                ));
3433            }
3434            return Ok(fork.call_raw(&request, Some(number.into())).await?);
3435        }
3436
3437        #[cfg(feature = "base")]
3438        if self.backend.is_base()
3439            && serde_json::to_value(&request)
3440                .and_then(serde_json::from_value::<BaseTransactionRequest>)
3441                .is_ok_and(|request| request.as_eip8130().is_some())
3442        {
3443            let timestamp = self.backend.block_request_timestamp(&block_request).await?;
3444            self.backend.ensure_base_eip8130_active_at(timestamp)?;
3445        }
3446
3447        let fees = FeeDetails::new(
3448            request.gas_price,
3449            request.max_fee_per_gas,
3450            request.max_priority_fee_per_gas,
3451            request.max_fee_per_blob_gas,
3452        )?
3453        .or_zero_fees();
3454        // this can be blocking for a bit, especially in forking mode
3455        // <https://github.com/foundry-rs/foundry/issues/6036>
3456        self.on_blocking_task(|this| async move {
3457            let (exit, out, gas, _) =
3458                this.backend.call(request, fees, Some(block_request), overrides).await?;
3459            trace!(target : "node", "Call status {:?}, gas {}", exit, gas);
3460
3461            ensure_return_ok(exit, &out)
3462        })
3463        .await
3464    }
3465
3466    pub async fn call_many(
3467        &self,
3468        bundles: Vec<Bundle<WithOtherFields<TransactionRequest>>>,
3469        state_context: Option<StateContext>,
3470        state_override: Option<StateOverride>,
3471    ) -> Result<Vec<Vec<EthCallResponse>>> {
3472        node_info!("eth_callMany");
3473        let StateContext { transaction_index, block_number } = state_context.unwrap_or_default();
3474        if transaction_index.is_some_and(|index| index.index().is_some()) {
3475            return Err(BlockchainError::RpcError(RpcError::invalid_params(
3476                "transactionIndex is not supported for eth_callMany yet".to_string(),
3477            )));
3478        }
3479
3480        let block_request = self.block_request(block_number).await?;
3481        if let BlockRequest::Number(number) = block_request
3482            && let Some(fork) = self.get_fork()
3483            && fork.predates_fork(number)
3484        {
3485            return Ok(fork
3486                .call_many(
3487                    bundles,
3488                    Some(StateContext { transaction_index, block_number: Some(number.into()) }),
3489                    state_override,
3490                )
3491                .await?);
3492        }
3493
3494        self.on_blocking_task(|this| async move {
3495            this.backend.call_many(bundles, Some(block_request), state_override).await
3496        })
3497        .await
3498    }
3499
3500    /// Simulates a bundle of signed transactions against the requested state.
3501    ///
3502    /// Handler for ETH RPC call: `eth_callBundle`.
3503    pub async fn call_bundle(&self, bundle: EthCallBundle) -> Result<EthCallBundleResponse> {
3504        node_info!("eth_callBundle");
3505        if bundle.txs.is_empty() {
3506            return Err(BlockchainError::RpcError(RpcError::invalid_params(
3507                "bundle missing txs".to_string(),
3508            )));
3509        }
3510        if bundle.block_number == 0 {
3511            return Err(BlockchainError::RpcError(RpcError::invalid_params(
3512                "bundle missing blockNumber".to_string(),
3513            )));
3514        }
3515
3516        let block_request = self.block_request(Some(bundle.state_block_number.into())).await?;
3517        if let BlockRequest::Number(number) = block_request
3518            && let Some(fork) = self.get_fork()
3519            && fork.predates_fork(number)
3520        {
3521            return Ok(fork.call_bundle(bundle).await?);
3522        }
3523
3524        let transactions = bundle
3525            .txs
3526            .iter()
3527            .map(|raw| {
3528                let mut data = raw.as_ref();
3529                if data.is_empty() {
3530                    return Err(BlockchainError::EmptyRawTransactionData);
3531                }
3532                let transaction = FoundryTxEnvelope::decode_2718(&mut data)
3533                    .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
3534                self.ensure_typed_transaction_supported(&transaction)?;
3535                PendingTransaction::new(transaction).map_err(Into::into)
3536            })
3537            .collect::<Result<Vec<_>>>()?;
3538
3539        self.on_blocking_task(|this| async move {
3540            this.backend.call_bundle(bundle, transactions, Some(block_request)).await
3541        })
3542        .await
3543    }
3544
3545    pub async fn simulate_v1(
3546        &self,
3547        request: SimulatePayload,
3548        block_number: Option<BlockId>,
3549    ) -> Result<Vec<SimulatedBlock<AnyRpcBlock>>> {
3550        self.simulate_v1_raw(preserve_simulation_request_fields(request), block_number).await
3551    }
3552
3553    pub(crate) async fn simulate_v1_raw(
3554        &self,
3555        mut request: SimulatePayload<WithOtherFields<TransactionRequest>>,
3556        block_number: Option<BlockId>,
3557    ) -> Result<Vec<SimulatedBlock<AnyRpcBlock>>> {
3558        const DEFAULT_BLOCK_INTERVAL_SECS: u64 = 12;
3559
3560        node_info!("eth_simulateV1");
3561        if request.block_state_calls.is_empty() {
3562            return Err(BlockchainError::RpcError(RpcError::invalid_params("empty input")));
3563        }
3564        if request.block_state_calls.len() > MAX_SIMULATE_BLOCKS as usize {
3565            return Err(BlockchainError::RpcError(RpcError {
3566                code: ErrorCode::ServerError(-38026),
3567                message: "too many blocks".into(),
3568                data: None,
3569            }));
3570        }
3571        let block_id = block_number;
3572        let block_request =
3573            self.block_request(block_number).await.map_err(|error| match error {
3574                BlockchainError::BlockOutOfRange(_, _) | BlockchainError::BlockNotFound => {
3575                    BlockchainError::RpcError(RpcError {
3576                        code: ErrorCode::ServerError(-32000),
3577                        message: "header not found".into(),
3578                        data: None,
3579                    })
3580                }
3581                error => error,
3582            })?;
3583        let block_interval = self.backend.time().block_timestamp_interval().unwrap_or_else(|| {
3584            self.miner
3585                .block_interval()
3586                .map(|duration| {
3587                    duration
3588                        .as_secs()
3589                        .saturating_add(u64::from(duration.subsec_nanos() != 0))
3590                        .max(1)
3591                })
3592                .unwrap_or(DEFAULT_BLOCK_INTERVAL_SECS)
3593        });
3594
3595        // check if the number predates the fork, if in fork mode
3596        if let BlockRequest::Number(number) = block_request
3597            && let Some(fork) = self.get_fork()
3598            && fork.predates_fork(number)
3599        {
3600            let block_id = match block_id {
3601                Some(BlockId::Hash(hash)) => BlockId::Hash(hash),
3602                _ => number.into(),
3603            };
3604            let base_block = fork.fetch_block(block_id).await?.ok_or_else(|| {
3605                BlockchainError::RpcError(RpcError {
3606                    code: ErrorCode::ServerError(-32000),
3607                    message: "header not found".into(),
3608                    data: None,
3609                })
3610            })?;
3611            request.block_state_calls = sanitize_simulation_blocks(
3612                request.block_state_calls,
3613                base_block.header.number(),
3614                base_block.header.timestamp(),
3615                block_interval,
3616            )?;
3617            return Ok(fork.simulate_v1(&request, Some(base_block.header.hash.into())).await?);
3618        }
3619
3620        // this can be blocking for a bit, especially in forking mode
3621        // <https://github.com/foundry-rs/foundry/issues/6036>
3622        self.on_blocking_task(|this| async move {
3623            let simulated_blocks =
3624                this.backend.simulate_raw(request, Some(block_request), block_interval).await?;
3625            trace!(target : "node", "Simulate status {:?}", simulated_blocks);
3626
3627            Ok(simulated_blocks)
3628        })
3629        .await
3630    }
3631
3632    /// This method creates an EIP2930 type accessList based on a given Transaction. The accessList
3633    /// contains all storage slots and addresses read and written by the transaction, except for the
3634    /// sender account and the precompiles.
3635    ///
3636    /// It returns list of addresses and storage keys used by the transaction, plus the gas
3637    /// consumed when the access list is added. That is, it gives you the list of addresses and
3638    /// storage keys that will be used by that transaction, plus the gas consumed if the access
3639    /// list is included. Like eth_estimateGas, this is an estimation; the list could change
3640    /// when the transaction is actually mined. Adding an accessList to your transaction does
3641    /// not necessary result in lower gas usage compared to a transaction without an access
3642    /// list.
3643    ///
3644    /// Handler for ETH RPC call: `eth_createAccessList`
3645    pub async fn create_access_list(
3646        &self,
3647        request: WithOtherFields<TransactionRequest>,
3648        block_number: Option<BlockId>,
3649        state_override: Option<StateOverride>,
3650    ) -> Result<AccessListResult> {
3651        node_info!("eth_createAccessList");
3652        let block_request = self.block_request(block_number).await?;
3653        // check if the number predates the fork, if in fork mode
3654        if let BlockRequest::Number(number) = block_request
3655            && let Some(fork) = self.get_fork()
3656            && fork.predates_fork(number)
3657        {
3658            if state_override.is_some() {
3659                return Err(BlockchainError::EvmOverrideError(
3660                    "not available on past forked blocks".to_string(),
3661                ));
3662            }
3663            return Ok(fork.create_access_list_raw(&request, Some(number.into())).await?);
3664        }
3665        let typed_request = self.parse_transaction_request(request.clone())?;
3666
3667        #[cfg(feature = "base")]
3668        if self.backend.is_base()
3669            && serde_json::to_value(&request)
3670                .and_then(serde_json::from_value::<BaseTransactionRequest>)
3671                .is_ok_and(|request| request.as_eip8130().is_some())
3672        {
3673            let timestamp = self.backend.block_request_timestamp(&block_request).await?;
3674            self.backend.ensure_base_eip8130_active_at(timestamp)?;
3675            return Err(BlockchainError::InvalidTransactionRequest(
3676                "eth_createAccessList does not support EIP-8130 transaction requests".to_string(),
3677            ));
3678        }
3679
3680        self.backend
3681            .with_database_at_and_context(Some(block_request), |state, block_env, monad_context| {
3682                let mut cache_db = CacheDB::new(state);
3683                if let Some(state_override) = state_override {
3684                    apply_state_overrides(state_override.into_iter().collect(), &mut cache_db)?;
3685                }
3686
3687                let (_, _, _, access_list) =
3688                    self.backend.build_access_list_with_state_and_context(
3689                        &cache_db,
3690                        request.clone(),
3691                        FeeDetails::zero(),
3692                        block_env.clone(),
3693                        monad_context.clone(),
3694                    )?;
3695
3696                // Re-execute with the access list applied to get the post-AL gas usage.
3697                // EVM failures (including reverts) are surfaced in the result's `error`
3698                // field per the execution-apis `eth_createAccessList` spec, so callers
3699                // can still inspect the traced slots when execution fails.
3700                let (exit, _, gas_used, _) = self.backend.call_with_state_typed_access_list(
3701                    &cache_db,
3702                    typed_request,
3703                    FeeDetails::zero(),
3704                    block_env,
3705                    access_list.clone(),
3706                    monad_context,
3707                )?;
3708
3709                Ok(AccessListResult {
3710                    access_list,
3711                    gas_used: U256::from(gas_used),
3712                    error: execution_error(exit),
3713                })
3714            })
3715            .await
3716    }
3717
3718    /// Estimate gas needed for execution of given contract.
3719    /// If no block parameter is given, it will use the pending block by default
3720    ///
3721    /// Handler for ETH RPC call: `eth_estimateGas`
3722    pub async fn estimate_gas(
3723        &self,
3724        request: WithOtherFields<TransactionRequest>,
3725        block_number: Option<BlockId>,
3726        overrides: EvmOverrides,
3727    ) -> Result<U256> {
3728        node_info!("eth_estimateGas");
3729        self.do_estimate_gas(request, block_number.or_else(|| Some(BlockId::pending())), overrides)
3730            .await
3731            .map(U256::from)
3732    }
3733
3734    /// Fills a transaction request with default values for missing fields.
3735    ///
3736    /// This method populates missing transaction fields like nonce, gas limit,
3737    /// chain ID, and fee parameters with appropriate defaults.
3738    ///
3739    /// Handler for ETH RPC call: `eth_fillTransaction`
3740    pub async fn fill_transaction(
3741        &self,
3742        request: WithOtherFields<TransactionRequest>,
3743    ) -> Result<FillTransaction<AnyRpcTransaction>> {
3744        node_info!("eth_fillTransaction");
3745        let mut request = self.parse_transaction_request(request)?;
3746
3747        let from = match request.from() {
3748            Some(from) => from,
3749            None => self.accounts()?.first().copied().ok_or(BlockchainError::NoSignerAvailable)?,
3750        };
3751
3752        let nonce = self.request_nonce_for_transaction(&request, from).await?;
3753
3754        // Prefill gas limit with estimated gas and bubble up estimation errors directly.
3755        if request.gas_limit().is_none() {
3756            let estimated_gas =
3757                self.do_estimate_gas_typed(request.clone(), Some(BlockId::pending())).await?;
3758            request.set_gas_limit(estimated_gas as u64);
3759        }
3760
3761        let typed_tx = self.build_tx_request(request, nonce).await?;
3762        let tx = typed_tx.into_impersonated();
3763
3764        let raw = tx.encoded_2718().into();
3765
3766        let mut tx =
3767            transaction_build(None, MaybeImpersonatedTransaction::new(tx), None, None, None);
3768
3769        // Set the correct `from` address (overrides the recovered zero address from dummy
3770        // signature)
3771        tx.0.inner.inner = Recovered::new_unchecked(tx.0.inner.inner.into_inner(), from);
3772
3773        Ok(FillTransaction { raw, tx })
3774    }
3775
3776    /// Handler for RPC call: `anvil_getBlobsByTransactionHash`
3777    pub fn anvil_get_blob_by_tx_hash(&self, hash: B256) -> Result<Option<Vec<Blob>>> {
3778        node_info!("anvil_getBlobsByTransactionHash");
3779        Ok(self.backend.get_blob_by_tx_hash(hash)?)
3780    }
3781
3782    /// Get transaction by its hash.
3783    ///
3784    /// This will check the storage for a matching transaction, if no transaction exists in storage
3785    /// this will also scan the mempool for a matching pending transaction
3786    ///
3787    /// Handler for ETH RPC call: `eth_getTransactionByHash`
3788    pub async fn transaction_by_hash(&self, hash: B256) -> Result<Option<AnyRpcTransaction>> {
3789        node_info!("eth_getTransactionByHash");
3790        let mut tx =
3791            self.pool.get_transaction(hash).map(|pending| self.build_pool_transaction(pending));
3792        if tx.is_none() {
3793            tx = self.backend.transaction_by_hash(hash).await?
3794        }
3795
3796        Ok(tx)
3797    }
3798
3799    fn build_pool_transaction(
3800        &self,
3801        pending: PendingTransaction<FoundryTxEnvelope>,
3802    ) -> AnyRpcTransaction {
3803        let from = *pending.sender();
3804        let tx = transaction_build(
3805            Some(*pending.hash()),
3806            pending.transaction,
3807            None,
3808            None,
3809            Some(self.backend.base_fee()),
3810        );
3811
3812        let WithOtherFields { inner: mut tx, other } = tx.0;
3813        // we set the from field here explicitly to the set sender of the pending transaction,
3814        // in case the transaction is impersonated.
3815        tx.inner = Recovered::new_unchecked(tx.inner.into_inner(), from);
3816
3817        AnyRpcTransaction(WithOtherFields { inner: tx, other })
3818    }
3819
3820    /// Returns all ready transactions from the local pending pool.
3821    ///
3822    /// Handler for ETH RPC call: `eth_pendingTransactions`
3823    pub async fn pending_transactions(&self) -> Result<Vec<AnyRpcTransaction>> {
3824        node_info!("eth_pendingTransactions");
3825        Ok(self
3826            .pool
3827            .ready_transactions()
3828            .map(|pending| self.build_pool_transaction(pending.pending_transaction.clone()))
3829            .collect())
3830    }
3831
3832    /// Returns the transaction by sender and nonce.
3833    ///
3834    /// This will check the mempool for pending transactions first, then perform a binary search
3835    /// over mined blocks to find the transaction.
3836    ///
3837    /// Handler for ETH RPC call: `eth_getTransactionBySenderAndNonce`
3838    pub async fn transaction_by_sender_and_nonce(
3839        &self,
3840        sender: Address,
3841        nonce: U256,
3842    ) -> Result<Option<AnyRpcTransaction>> {
3843        node_info!("eth_getTransactionBySenderAndNonce");
3844
3845        // check pending txs first
3846        for pending_tx in self.pool.ready_transactions().chain(self.pool.pending_transactions()) {
3847            if U256::from(pending_tx.pending_transaction.nonce()) == nonce
3848                && *pending_tx.pending_transaction.sender() == sender
3849            {
3850                let tx = transaction_build(
3851                    Some(*pending_tx.pending_transaction.hash()),
3852                    pending_tx.pending_transaction.transaction.clone(),
3853                    None,
3854                    None,
3855                    Some(self.backend.base_fee()),
3856                );
3857
3858                let WithOtherFields { inner: mut tx, other } = tx.0;
3859                // we set the from field here explicitly to the set sender of the pending
3860                // transaction, in case the transaction is impersonated.
3861                let from = *pending_tx.pending_transaction.sender();
3862                tx.inner = Recovered::new_unchecked(tx.inner.into_inner(), from);
3863
3864                return Ok(Some(AnyRpcTransaction(WithOtherFields { inner: tx, other })));
3865            }
3866        }
3867
3868        let highest_nonce = self.transaction_count(sender, None).await?.saturating_to::<u64>();
3869        let target_nonce = nonce.saturating_to::<u64>();
3870
3871        // if the nonce is higher or equal to the highest nonce, the transaction doesn't exist
3872        if target_nonce >= highest_nonce {
3873            return Ok(None);
3874        }
3875
3876        // no mined blocks yet
3877        let latest_block = self.backend.best_number();
3878        if latest_block == 0 {
3879            return Ok(None);
3880        }
3881
3882        // binary search for the block containing the transaction
3883        let mut low = 1u64;
3884        let mut high = latest_block;
3885
3886        while low <= high {
3887            let mid = low + (high - low) / 2;
3888            let mid_nonce =
3889                self.transaction_count(sender, Some(mid.into())).await?.saturating_to::<u64>();
3890
3891            if mid_nonce > target_nonce {
3892                high = mid - 1;
3893            } else {
3894                low = mid + 1;
3895            }
3896        }
3897
3898        // search in the target block
3899        let target_block = low;
3900        if target_block <= latest_block
3901            && let Some(txs) =
3902                self.backend.mined_transactions_by_block_number(target_block.into()).await
3903        {
3904            for tx in txs {
3905                if tx.from() == sender && tx.nonce() == target_nonce {
3906                    return Ok(Some(tx));
3907                }
3908            }
3909        }
3910
3911        Ok(None)
3912    }
3913
3914    /// Returns transaction receipt by transaction hash.
3915    ///
3916    /// Handler for ETH RPC call: `eth_getTransactionReceipt`
3917    pub async fn transaction_receipt(&self, hash: B256) -> Result<Option<FoundryTxReceipt>> {
3918        node_info!("eth_getTransactionReceipt");
3919        self.backend.transaction_receipt(hash).await
3920    }
3921
3922    /// Returns block receipts by block number.
3923    ///
3924    /// Handler for ETH RPC call: `eth_getBlockReceipts`
3925    pub async fn block_receipts(&self, number: BlockId) -> Result<Option<Vec<FoundryTxReceipt>>> {
3926        node_info!("eth_getBlockReceipts");
3927        if number == BlockId::pending() {
3928            let transactions = self.pool.ready_transactions().collect::<Vec<_>>();
3929            return Ok(Some(self.backend.pending_block_receipts(transactions).await?));
3930        }
3931
3932        self.backend.block_receipts(number).await
3933    }
3934
3935    /// Returns logs matching given filter object.
3936    ///
3937    /// Handler for ETH RPC call: `eth_getLogs`
3938    pub async fn logs(&self, filter: Filter) -> Result<Vec<Log>> {
3939        node_info!("eth_getLogs");
3940        let best = self.backend.best_number();
3941        let to_block =
3942            self.backend.convert_block_number(filter.block_option.get_to_block().copied());
3943        if to_block > best {
3944            return Err(BlockchainError::BlockOutOfRange(best, to_block));
3945        }
3946        let from_block =
3947            self.backend.convert_block_number(filter.block_option.get_from_block().copied());
3948        if from_block > to_block {
3949            return Err(RpcError::invalid_params("invalid block range params").into());
3950        }
3951
3952        self.backend.logs(filter).await
3953    }
3954
3955    /// Creates a filter object, based on filter options, to notify when the state changes (logs).
3956    ///
3957    /// Handler for ETH RPC call: `eth_newFilter`
3958    pub async fn new_filter(&self, filter: Filter) -> Result<String> {
3959        node_info!("eth_newFilter");
3960        // Valid future ranges have no historic logs to seed yet.
3961        let historic = match filter.block_option.get_from_block() {
3962            Some(BlockNumber::Number(from))
3963                if *from > self.backend.best_number()
3964                    && filter.block_option.get_to_block().is_none_or(|to| {
3965                        to.is_latest() || to.as_number().is_some_and(|to| to >= *from)
3966                    }) =>
3967            {
3968                vec![]
3969            }
3970            Some(_) => self.backend.logs(filter.clone()).await?,
3971            None => vec![],
3972        };
3973        let filter = EthFilter::Logs(Box::new(LogsFilter {
3974            blocks: self.new_block_notifications(),
3975            storage: self.storage_info(),
3976            filter: FilteredParams::new(Some(filter)),
3977            historic: Some(historic),
3978        }));
3979        Ok(self.filters.add_filter(filter).await)
3980    }
3981
3982    /// Creates a filter in the node, to notify when a new block arrives.
3983    ///
3984    /// Handler for ETH RPC call: `eth_newBlockFilter`
3985    pub async fn new_block_filter(&self) -> Result<String> {
3986        node_info!("eth_newBlockFilter");
3987        let filter = EthFilter::Blocks(self.new_block_notifications());
3988        Ok(self.filters.add_filter(filter).await)
3989    }
3990
3991    /// Creates a filter in the node, to notify when new pending transactions arrive.
3992    ///
3993    /// Handler for ETH RPC call: `eth_newPendingTransactionFilter`
3994    pub async fn new_pending_transaction_filter(&self, full: bool) -> Result<String> {
3995        node_info!("eth_newPendingTransactionFilter");
3996        let filter = if full {
3997            EthFilter::FullPendingTransactions(self.full_pending_transactions_filter())
3998        } else {
3999            EthFilter::PendingTransactions(self.new_ready_transactions())
4000        };
4001        Ok(self.filters.add_filter(filter).await)
4002    }
4003
4004    /// Polling method for a filter, which returns an array of logs which occurred since last poll.
4005    ///
4006    /// Handler for ETH RPC call: `eth_getFilterChanges`
4007    pub async fn get_filter_changes(&self, id: &str) -> ResponseResult {
4008        node_info!("eth_getFilterChanges");
4009        self.filters.get_filter_changes(id).await
4010    }
4011
4012    /// Returns an array of all logs matching filter with given id.
4013    ///
4014    /// Handler for ETH RPC call: `eth_getFilterLogs`
4015    pub async fn get_filter_logs(&self, id: &str) -> Result<Vec<Log>> {
4016        node_info!("eth_getFilterLogs");
4017        if let Some(filter) = self.filters.get_log_filter(id).await {
4018            self.backend.logs(filter).await
4019        } else {
4020            Err(BlockchainError::FilterNotFound)
4021        }
4022    }
4023
4024    /// Handler for ETH RPC call: `eth_uninstallFilter`
4025    pub async fn uninstall_filter(&self, id: &str) -> Result<bool> {
4026        node_info!("eth_uninstallFilter");
4027        Ok(self.filters.uninstall_filter(id).await.is_some())
4028    }
4029
4030    /// Returns EIP-2718 encoded raw transaction
4031    ///
4032    /// Handler for RPC call: `debug_getRawTransaction`
4033    pub async fn raw_transaction(&self, hash: B256) -> Result<Option<Bytes>> {
4034        node_info!("debug_getRawTransaction");
4035        self.inner_raw_transaction(hash).await
4036    }
4037
4038    /// Returns EIP-2718 encoded raw receipts for the block.
4039    ///
4040    /// Handler for RPC call: `debug_getRawReceipts`.
4041    pub async fn raw_receipts(&self, block: BlockId) -> Result<Vec<Bytes>> {
4042        node_info!("debug_getRawReceipts");
4043
4044        // In fork mode, serve pre-fork blocks from the upstream provider.
4045        if let BlockRequest::Number(number) = self.block_request(Some(block)).await?
4046            && let Some(fork) = self.get_fork()
4047            && fork.predates_fork_inclusive(number)
4048        {
4049            let receipts = fork.block_receipts(number).await?.unwrap_or_default();
4050            return Ok(receipts
4051                .into_iter()
4052                .map(|receipt| {
4053                    receipt.0.inner.inner.map_logs(|log| log.inner).encoded_2718().into()
4054                })
4055                .collect());
4056        }
4057
4058        let block = self.backend.get_block(block).ok_or(BlockchainError::BlockNotFound)?;
4059        let receipts = self
4060            .backend
4061            .mined_receipts(block.header.hash_slow())
4062            .ok_or(BlockchainError::BlockNotFound)?;
4063        Ok(receipts.into_iter().map(|receipt| receipt.encoded_2718().into()).collect())
4064    }
4065
4066    /// Returns EIP-2718 encoded raw transactions for the block.
4067    ///
4068    /// Handler for RPC call: `debug_getRawTransactions`.
4069    pub async fn raw_transactions(&self, block: BlockId) -> Result<Vec<Bytes>> {
4070        node_info!("debug_getRawTransactions");
4071
4072        if let Some(block) = self.backend.get_block(block) {
4073            return Ok(block
4074                .body
4075                .transactions
4076                .into_iter()
4077                .map(|tx| tx.into_inner().into_canonical().encoded_2718().into())
4078                .collect());
4079        }
4080
4081        // In fork mode, serve pre-fork blocks from the upstream provider. Genuinely unknown or
4082        // out-of-range blocks yield an empty result, mirroring reth; transport errors propagate.
4083        let Some(fork) = self.get_fork() else {
4084            return Ok(Vec::new());
4085        };
4086        let block = match block {
4087            BlockId::Number(BlockNumber::Pending) => None,
4088            BlockId::Number(number) => {
4089                let number = self.backend.convert_block_number(Some(number));
4090                if !fork.predates_fork_inclusive(number) {
4091                    return Ok(Vec::new());
4092                }
4093                fork.block_by_number_full(number).await?
4094            }
4095            BlockId::Hash(hash) => fork
4096                .block_by_hash_full(hash.block_hash)
4097                .await?
4098                .filter(|block| fork.predates_fork_inclusive(block.header().number())),
4099        };
4100        let Some(block) = block else {
4101            return Ok(Vec::new());
4102        };
4103        let BlockTransactions::Full(txs) = block.transactions() else {
4104            return Err(BlockchainError::Internal(
4105                "fork provider returned a non-full block for a full block request".to_string(),
4106            ));
4107        };
4108        txs.iter().map(encode_rpc_transaction).collect()
4109    }
4110
4111    /// Returns RLP encoded raw block header.
4112    ///
4113    /// Handler for RPC call: `debug_getRawHeader`.
4114    pub async fn raw_header(&self, block: BlockId) -> Result<Bytes> {
4115        node_info!("debug_getRawHeader");
4116        let block = self.backend.get_block(block).ok_or(BlockchainError::BlockNotFound)?;
4117        Ok(alloy_rlp::encode(&block.header).into())
4118    }
4119
4120    /// Returns RLP encoded raw block.
4121    ///
4122    /// Handler for RPC call: `debug_getRawBlock`.
4123    pub async fn raw_block(&self, block: BlockId) -> Result<Bytes> {
4124        node_info!("debug_getRawBlock");
4125        let block = self.backend.get_block(block).ok_or(BlockchainError::BlockNotFound)?;
4126        Ok(alloy_rlp::encode(canonical_block(block)).into())
4127    }
4128
4129    /// Returns EIP-2718 encoded raw transaction by block hash and index
4130    ///
4131    /// Handler for RPC call: `eth_getRawTransactionByBlockHashAndIndex`
4132    pub async fn raw_transaction_by_block_hash_and_index(
4133        &self,
4134        block_hash: B256,
4135        index: Index,
4136    ) -> Result<Option<Bytes>> {
4137        node_info!("eth_getRawTransactionByBlockHashAndIndex");
4138        match self.backend.transaction_by_block_hash_and_index(block_hash, index).await? {
4139            Some(tx) => self.inner_raw_transaction(tx.tx_hash()).await,
4140            None => Ok(None),
4141        }
4142    }
4143
4144    /// Returns EIP-2718 encoded raw transaction by block number and index
4145    ///
4146    /// Handler for RPC call: `eth_getRawTransactionByBlockNumberAndIndex`
4147    pub async fn raw_transaction_by_block_number_and_index(
4148        &self,
4149        block_number: BlockNumber,
4150        index: Index,
4151    ) -> Result<Option<Bytes>> {
4152        node_info!("eth_getRawTransactionByBlockNumberAndIndex");
4153        match self.transaction_by_block_number_and_index(block_number, index).await? {
4154            Some(tx) => self.inner_raw_transaction(tx.tx_hash()).await,
4155            None => Ok(None),
4156        }
4157    }
4158
4159    /// Returns traces for the transaction hash for geth's tracing endpoint
4160    ///
4161    /// Handler for RPC call: `debug_traceTransaction`
4162    pub async fn debug_trace_transaction(
4163        &self,
4164        tx_hash: B256,
4165        opts: GethDebugTracingOptions,
4166    ) -> Result<GethTrace> {
4167        node_info!("debug_traceTransaction");
4168        self.backend.debug_trace_transaction(tx_hash, opts).await
4169    }
4170
4171    /// Returns traces for all transactions in an RLP-encoded block.
4172    ///
4173    /// Handler for RPC call: `debug_traceBlock`
4174    pub async fn debug_trace_block(
4175        &self,
4176        rlp_block: Bytes,
4177        opts: GethDebugTracingOptions,
4178    ) -> Result<Vec<TraceResult>> {
4179        node_info!("debug_traceBlock");
4180        self.backend.debug_trace_block(rlp_block, opts).await
4181    }
4182
4183    /// Returns traces for all transactions in a block by hash.
4184    ///
4185    /// Handler for RPC call: `debug_traceBlockByHash`
4186    pub async fn debug_trace_block_by_hash(
4187        &self,
4188        block_hash: B256,
4189        opts: GethDebugTracingOptions,
4190    ) -> Result<Vec<TraceResult>> {
4191        node_info!("debug_traceBlockByHash");
4192        self.backend.debug_trace_block_by_hash(block_hash, opts).await
4193    }
4194
4195    /// Returns traces for all transactions in a block by number.
4196    ///
4197    /// Handler for RPC call: `debug_traceBlockByNumber`
4198    pub async fn debug_trace_block_by_number(
4199        &self,
4200        block_number: BlockNumber,
4201        opts: GethDebugTracingOptions,
4202    ) -> Result<Vec<TraceResult>> {
4203        node_info!("debug_traceBlockByNumber");
4204        self.backend.debug_trace_block_by_number(block_number, opts).await
4205    }
4206
4207    /// Returns traces for the transaction for geth's tracing endpoint
4208    ///
4209    /// Handler for RPC call: `debug_traceCall`
4210    pub async fn debug_trace_call(
4211        &self,
4212        request: WithOtherFields<TransactionRequest>,
4213        block_number: Option<BlockId>,
4214        opts: GethDebugTracingCallOptions,
4215    ) -> Result<GethTrace> {
4216        node_info!("debug_traceCall");
4217        let block_request = self.block_request(block_number).await?;
4218        let fees = FeeDetails::new(
4219            request.gas_price,
4220            request.max_fee_per_gas,
4221            request.max_priority_fee_per_gas,
4222            request.max_fee_per_blob_gas,
4223        )?
4224        .or_zero_fees();
4225
4226        let result: std::result::Result<GethTrace, BlockchainError> =
4227            self.backend.call_with_tracing(request, fees, Some(block_request), opts).await;
4228        result
4229    }
4230
4231    /// Traces calls sequentially on top of the same block.
4232    ///
4233    /// Handler for RPC call: `trace_callMany`.
4234    pub async fn trace_call_many(
4235        &self,
4236        calls: Vec<(WithOtherFields<TransactionRequest>, HashSet<TraceType>)>,
4237        block_number: Option<BlockId>,
4238    ) -> Result<Vec<TraceResults>> {
4239        node_info!("trace_callMany");
4240        let block_request = self.block_request(block_number).await?;
4241
4242        self.backend.trace_call_many(calls, Some(block_request)).await
4243    }
4244}
4245
4246// == impl EthApi anvil endpoints ==
4247
4248impl EthApi<FoundryNetwork> {
4249    /// Mines a series of blocks.
4250    ///
4251    /// Handler for ETH RPC call: `anvil_mine`
4252    pub async fn anvil_mine(&self, num_blocks: Option<U256>, interval: Option<U256>) -> Result<()> {
4253        node_info!("anvil_mine");
4254        let interval = interval.map(|i| i.saturating_to::<u64>());
4255        let blocks = num_blocks.unwrap_or(U256::ONE);
4256        if blocks.is_zero() {
4257            return Ok(());
4258        }
4259
4260        self.on_blocking_task(|this| async move {
4261            // mine all the blocks
4262            for _ in 0..blocks.saturating_to::<u64>() {
4263                // If we have an interval, jump forwards in time to the "next" timestamp
4264                let pending_increase =
4265                    interval.map(|interval| this.backend.time().apply_time_increase(interval));
4266                if let Err(error) = this.mine_one().await {
4267                    if let Some(pending) = pending_increase {
4268                        this.backend.time().revert_time_increase(pending);
4269                    }
4270                    return Err(error);
4271                }
4272            }
4273            Ok(())
4274        })
4275        .await?;
4276
4277        Ok(())
4278    }
4279
4280    /// Helper function to find the storage slot for an ERC20 function call by testing slots
4281    /// from an access list until one produces the expected result.
4282    ///
4283    /// Rather than trying to reverse-engineer the storage layout, this function uses a
4284    /// "trial and error" approach: try overriding each slot that the function accesses,
4285    /// and see which one actually affects the function's return value.
4286    ///
4287    /// ## Parameters
4288    /// - `token_address`: The ERC20 token contract address
4289    /// - `calldata`: The encoded function call (e.g., `balanceOf(user)` or `allowance(owner,
4290    ///   spender)`)
4291    /// - `expected_value`: The value we want to set (balance or allowance amount)
4292    ///
4293    /// ## Returns
4294    /// The storage slot (B256) that contains the target ERC20 data, or an error if no slot is
4295    /// found.
4296    async fn find_erc20_storage_slot(
4297        &self,
4298        token_address: Address,
4299        calldata: Bytes,
4300        expected_value: U256,
4301    ) -> Result<B256> {
4302        let tx = TransactionRequest::default().with_to(token_address).with_input(calldata.clone());
4303
4304        // first collect all the slots that are used by the function call
4305        let access_list_result =
4306            self.create_access_list(WithOtherFields::new(tx.clone()), None, None).await?;
4307        let access_list = access_list_result.access_list;
4308
4309        // iterate over all the accessed slots and try to find the one that contains the
4310        // target value by overriding the slot and checking the function call result
4311        for item in access_list.0 {
4312            if item.address != token_address {
4313                continue;
4314            };
4315            for slot in &item.storage_keys {
4316                let account_override = AccountOverride::default()
4317                    .with_state_diff(std::iter::once((*slot, B256::from(expected_value))));
4318
4319                let state_override = StateOverridesBuilder::default()
4320                    .append(token_address, account_override)
4321                    .build();
4322
4323                let evm_override = EvmOverrides::state(Some(state_override));
4324
4325                let Ok(result) =
4326                    self.call(WithOtherFields::new(tx.clone()), None, evm_override).await
4327                else {
4328                    // overriding this slot failed
4329                    continue;
4330                };
4331
4332                let Ok(result_value) = U256::abi_decode(&result) else {
4333                    // response returned something other than a U256
4334                    continue;
4335                };
4336
4337                if result_value == expected_value {
4338                    return Ok(*slot);
4339                }
4340            }
4341        }
4342
4343        Err(BlockchainError::Message("Unable to find storage slot".to_string()))
4344    }
4345
4346    /// Deals ERC20 tokens to a address
4347    ///
4348    /// Handler for RPC call: `anvil_dealERC20`
4349    pub async fn anvil_deal_erc20(
4350        &self,
4351        address: Address,
4352        token_address: Address,
4353        balance: U256,
4354    ) -> Result<()> {
4355        node_info!("anvil_dealERC20");
4356
4357        if self.backend.is_tempo()
4358            && self.backend.try_set_tip20_balance(address, token_address, balance).await?
4359        {
4360            return Ok(());
4361        }
4362
4363        sol! {
4364            #[sol(rpc)]
4365            contract IERC20 {
4366                function balanceOf(address target) external view returns (uint256);
4367            }
4368        }
4369
4370        let calldata = IERC20::balanceOfCall { target: address }.abi_encode().into();
4371
4372        // Find the storage slot that contains the balance
4373        let slot =
4374            self.find_erc20_storage_slot(token_address, calldata, balance).await.map_err(|_| {
4375                BlockchainError::Message("Unable to set ERC20 balance, no slot found".to_string())
4376            })?;
4377
4378        // Set the storage slot to the desired balance
4379        self.anvil_set_storage_at(token_address, slot.into(), balance.into()).await?;
4380
4381        Ok(())
4382    }
4383
4384    /// Deals TIP-20 tokens to an address.
4385    ///
4386    /// Handler for RPC call: `anvil_dealTIP20`.
4387    pub async fn anvil_deal_tip20(
4388        &self,
4389        address: Address,
4390        token_address: Address,
4391        balance: U256,
4392    ) -> Result<()> {
4393        node_info!("anvil_dealTIP20");
4394        self.ensure_tempo_mode()?;
4395        self.backend.set_tip20_balance(address, token_address, balance).await?;
4396        Ok(())
4397    }
4398
4399    /// Sets the ERC20 allowance for a spender
4400    ///
4401    /// Handler for RPC call: `anvil_set_erc20_allowance`
4402    pub async fn anvil_set_erc20_allowance(
4403        &self,
4404        owner: Address,
4405        spender: Address,
4406        token_address: Address,
4407        amount: U256,
4408    ) -> Result<()> {
4409        node_info!("anvil_setERC20Allowance");
4410
4411        sol! {
4412            #[sol(rpc)]
4413            contract IERC20 {
4414                function allowance(address owner, address spender) external view returns (uint256);
4415            }
4416        }
4417
4418        let calldata = IERC20::allowanceCall { owner, spender }.abi_encode().into();
4419
4420        // Find the storage slot that contains the allowance
4421        let slot =
4422            self.find_erc20_storage_slot(token_address, calldata, amount).await.map_err(|_| {
4423                BlockchainError::Message("Unable to set ERC20 allowance, no slot found".to_string())
4424            })?;
4425
4426        // Set the storage slot to the desired allowance
4427        self.anvil_set_storage_at(token_address, slot.into(), amount.into()).await?;
4428
4429        Ok(())
4430    }
4431
4432    /// Recognizes a canonical Monad protocol envelope without requiring its reserved sender to be
4433    /// globally impersonated or recoverable from the envelope signature.
4434    #[cfg(feature = "monad")]
4435    fn monad_protocol_reorg_transaction(
4436        &self,
4437        transaction: FoundryTxEnvelope,
4438    ) -> Option<PendingTransaction<FoundryTxEnvelope>> {
4439        if !self.backend.is_monad() {
4440            return None;
4441        }
4442
4443        let pending = PendingTransaction::with_sender(
4444            MaybeImpersonatedTransaction::new(transaction),
4445            monad_revm::staking::constants::SYSTEM_ADDRESS,
4446        );
4447        let tx_env: revm::context::TxEnv = crate::eth::backend::executor::build_tx_env_for_pending(
4448            &pending,
4449            self.backend.cheats(),
4450        );
4451        foundry_evm::core::evm::protocol_system_call(&tx_env)
4452            .is_ok_and(|call| call.is_some())
4453            .then_some(pending)
4454    }
4455
4456    /// Reorg the chain to a specific depth and mine new blocks back to the canonical height.
4457    ///
4458    /// e.g depth = 3
4459    ///     A  -> B  -> C  -> D  -> E
4460    ///     A  -> B  -> C' -> D' -> E'
4461    ///
4462    /// Depth specifies the height to reorg the chain back to. Depth must not exceed the current
4463    /// chain height, i.e. can't reorg past the genesis block.
4464    ///
4465    /// Optionally supply a list of transaction and block pairs that will populate the reorged
4466    /// blocks. The maximum block number of the pairs must not exceed the specified depth.
4467    ///
4468    /// Handler for RPC call: `anvil_reorg`
4469    pub async fn anvil_reorg(&self, options: ReorgOptions) -> Result<()> {
4470        node_info!("anvil_reorg");
4471        let _lifecycle = self.lifecycle_lock.write().await;
4472        let mining_guard = self.backend.lock_mining().await;
4473        let depth = options.depth;
4474        let mut tx_block_pairs = options.tx_block_pairs;
4475
4476        if let Some((_, num)) = tx_block_pairs.iter().find(|(_, num)| *num >= depth) {
4477            // A reorg of depth 0 mines no blocks, so there is nowhere to place the transactions.
4478            let Some(last_block) = depth.checked_sub(1) else {
4479                return Err(BlockchainError::RpcError(RpcError::invalid_params(
4480                    "Reorg depth must be at least 1 to include transactions",
4481                )));
4482            };
4483            return Err(BlockchainError::RpcError(RpcError::invalid_params(format!(
4484                "Block number for reorg tx will exceed the reorged chain height. Block number {num} must not exceed (depth-1) {last_block}"
4485            ))));
4486        }
4487        tx_block_pairs.sort_by_key(|a| a.1);
4488
4489        // Check reorg depth doesn't exceed current chain height
4490        let current_height = self.backend.best_number();
4491        let common_height = current_height.checked_sub(depth).ok_or(BlockchainError::RpcError(
4492            RpcError::invalid_params(format!(
4493                "Reorg depth must not exceed current chain height: current height {current_height}, depth {depth}"
4494            )),
4495        ))?;
4496
4497        // Get the common ancestor block
4498        let common_block =
4499            self.rollback_block(common_height).await?.ok_or(BlockchainError::BlockNotFound)?;
4500
4501        #[cfg(feature = "monad")]
4502        let fee_defaults = if self.backend.is_monad() {
4503            self.backend
4504                .monad_rollback_fee_defaults(&common_block, self.lowest_suggestion_tip())
4505                .await
4506                .map(|(gas_price, blob_gas_price)| TransactionFeeDefaults {
4507                    gas_price,
4508                    blob_gas_price,
4509                })
4510        } else {
4511            None
4512        };
4513        #[cfg(not(feature = "monad"))]
4514        let fee_defaults = None;
4515
4516        // Convert the transaction requests to pool transactions if they exist, otherwise use empty
4517        // hashmap
4518        let block_pool_txs = if tx_block_pairs.is_empty() {
4519            HashMap::default()
4520        } else {
4521            // Manage nonces for each signer
4522            // address -> cumulative nonce
4523            let mut nonces: HashMap<Address, u64> = HashMap::default();
4524
4525            let mut txs: HashMap<u64, Vec<Arc<PoolTransaction<FoundryTxEnvelope>>>> =
4526                HashMap::default();
4527            for pair in tx_block_pairs {
4528                let (tx_data, block_index) = pair;
4529
4530                let pending = match tx_data {
4531                    TransactionData::Raw(bytes) => {
4532                        let mut data = bytes.as_ref();
4533                        let decoded = FoundryTxEnvelope::decode_2718(&mut data)
4534                            .map_err(|_| BlockchainError::FailedToDecodeSignedTransaction)?;
4535                        if matches!(&decoded, FoundryTxEnvelope::Celo(_)) {
4536                            self.ensure_typed_transaction_supported(&decoded)?;
4537                        }
4538                        let protocol_pending = {
4539                            #[cfg(feature = "monad")]
4540                            {
4541                                self.monad_protocol_reorg_transaction(decoded.clone())
4542                            }
4543                            #[cfg(not(feature = "monad"))]
4544                            {
4545                                None
4546                            }
4547                        };
4548                        if let Some(pending) = protocol_pending {
4549                            pending
4550                        } else {
4551                            PendingTransaction::new(decoded)?
4552                        }
4553                    }
4554
4555                    TransactionData::JSON(request) => {
4556                        let request = if request.transaction_type
4557                            == Some(foundry_primitives::CIP64_TX_TYPE)
4558                            || request
4559                                .other
4560                                .get("feeCurrency")
4561                                .is_some_and(|value| !value.is_null())
4562                        {
4563                            self.parse_transaction_request(request)?
4564                        } else {
4565                            request.inner.into()
4566                        };
4567                        let from = request.from().map(Ok).unwrap_or_else(|| {
4568                            self.accounts()?
4569                                .first()
4570                                .copied()
4571                                .ok_or(BlockchainError::NoSignerAvailable)
4572                        })?;
4573
4574                        // Get the nonce at the common block
4575                        let curr_nonce = nonces.entry(from).or_insert(
4576                            self.get_transaction_count(
4577                                from,
4578                                Some(common_block.header.number().into()),
4579                            )
4580                            .await?,
4581                        );
4582
4583                        // Build typed transaction request
4584                        let typed_tx = self
4585                            .build_tx_request_with_fee_defaults(request, *curr_nonce, fee_defaults)
4586                            .await?;
4587
4588                        // Increment nonce
4589                        *curr_nonce += 1;
4590
4591                        let protocol_pending = {
4592                            #[cfg(feature = "monad")]
4593                            {
4594                                if from == monad_revm::staking::constants::SYSTEM_ADDRESS {
4595                                    self.monad_protocol_reorg_transaction(
4596                                        typed_tx.clone().into_impersonated(),
4597                                    )
4598                                } else {
4599                                    None
4600                                }
4601                            }
4602                            #[cfg(not(feature = "monad"))]
4603                            {
4604                                None
4605                            }
4606                        };
4607                        if let Some(pending) = protocol_pending {
4608                            pending
4609                        } else if self.is_impersonated(from) {
4610                            let transaction = typed_tx.into_impersonated();
4611                            self.ensure_typed_transaction_supported(&transaction)?;
4612                            PendingTransaction::with_impersonated(transaction, from)
4613                        } else {
4614                            let transaction = self.sign_request(&from, typed_tx)?;
4615                            self.ensure_typed_transaction_supported(&transaction)?;
4616                            PendingTransaction::new(transaction)?
4617                        }
4618                    }
4619                };
4620
4621                let pooled = PoolTransaction::new(pending).with_replay();
4622                txs.entry(block_index).or_default().push(Arc::new(pooled));
4623            }
4624
4625            txs
4626        };
4627
4628        self.rollback_backend(common_block, &mining_guard).await?;
4629        self.backend.reorg(depth, block_pool_txs, &mining_guard).await?;
4630        Ok(())
4631    }
4632
4633    /// Mine blocks, instantly.
4634    ///
4635    /// Handler for RPC call: `evm_mine`
4636    ///
4637    /// This will mine the blocks regardless of the configured mining mode.
4638    /// **Note**: ganache returns `0x0` here as placeholder for additional meta-data in the future.
4639    pub async fn evm_mine(&self, opts: Option<MineOptions>) -> Result<String> {
4640        node_info!("evm_mine");
4641
4642        self.do_evm_mine(opts).await?;
4643
4644        Ok("0x0".to_string())
4645    }
4646
4647    /// Mine blocks, instantly and return the mined blocks.
4648    ///
4649    /// Handler for RPC call: `evm_mine_detailed`
4650    ///
4651    /// This will mine the blocks regardless of the configured mining mode.
4652    ///
4653    /// **Note**: This behaves exactly as [Self::evm_mine] but returns different output, for
4654    /// compatibility reasons, this is a separate call since `evm_mine` is not an anvil original.
4655    /// and `ganache` may change the `0x0` placeholder.
4656    pub async fn evm_mine_detailed(&self, opts: Option<MineOptions>) -> Result<Vec<AnyRpcBlock>> {
4657        node_info!("evm_mine_detailed");
4658
4659        let mined_blocks = self.do_evm_mine(opts).await?;
4660
4661        let mut blocks = Vec::with_capacity(mined_blocks as usize);
4662
4663        let latest = self.backend.best_number();
4664        for offset in (0..mined_blocks).rev() {
4665            let block_num = latest - offset;
4666            if let Some(mut block) =
4667                self.backend.block_by_number_full(BlockNumber::Number(block_num)).await?
4668            {
4669                let block_txs = match block.transactions_mut() {
4670                    BlockTransactions::Full(txs) => txs,
4671                    BlockTransactions::Hashes(_) | BlockTransactions::Uncle => unreachable!(),
4672                };
4673                for tx in block_txs.iter_mut() {
4674                    if let Some(receipt) = self.backend.mined_transaction_receipt(tx.tx_hash())
4675                        && let Some(output) = receipt.out
4676                    {
4677                        // insert revert reason if failure
4678                        if !receipt.inner.as_ref().status()
4679                            && let Some(reason) = RevertDecoder::new().maybe_decode(&output, None)
4680                        {
4681                            tx.other.insert(
4682                                "revertReason".to_string(),
4683                                serde_json::to_value(reason).expect("Infallible"),
4684                            );
4685                        }
4686                        tx.other.insert(
4687                            "output".to_string(),
4688                            serde_json::to_value(output).expect("Infallible"),
4689                        );
4690                    }
4691                }
4692                block.transactions = BlockTransactions::Full(block_txs.clone());
4693                blocks.push(block);
4694            }
4695        }
4696
4697        Ok(blocks)
4698    }
4699
4700    /// Execute a transaction regardless of signature status
4701    ///
4702    /// Handler for ETH RPC call: `eth_sendUnsignedTransaction`
4703    pub async fn eth_send_unsigned_transaction(
4704        &self,
4705        request: WithOtherFields<TransactionRequest>,
4706    ) -> Result<TxHash> {
4707        node_info!("eth_sendUnsignedTransaction");
4708        let request = self.parse_transaction_request(request)?;
4709        // either use the impersonated account of the request's `from` field
4710        let from = request.from().ok_or(BlockchainError::NoSignerAvailable)?;
4711
4712        let nonce = self.request_nonce_for_transaction(&request, from).await?;
4713
4714        let typed_tx = self.build_tx_request(request, nonce).await?;
4715
4716        let transaction = typed_tx.into_impersonated();
4717
4718        self.ensure_typed_transaction_supported(&transaction)?;
4719
4720        let pending_transaction = PendingTransaction::with_impersonated(transaction, from);
4721
4722        self.add_pending_transaction(pending_transaction).await
4723    }
4724
4725    /// Returns a summary of all the transactions currently pending for inclusion in the next
4726    /// block(s), as well as the ones that are being scheduled for future execution only.
4727    ///
4728    /// See [here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_inspect) for more details
4729    ///
4730    /// Handler for ETH RPC call: `txpool_inspect`
4731    pub async fn txpool_inspect(&self) -> Result<TxpoolInspect> {
4732        node_info!("txpool_inspect");
4733        let mut inspect = TxpoolInspect::default();
4734
4735        fn convert(tx: Arc<PoolTransaction<FoundryTxEnvelope>>) -> TxpoolInspectSummary {
4736            let tx = &tx.pending_transaction.transaction;
4737            let to = tx.to();
4738            let gas_price = tx.max_fee_per_gas();
4739            let value = tx.value();
4740            let gas = tx.gas_limit();
4741            TxpoolInspectSummary { to, value, gas, gas_price }
4742        }
4743
4744        // Note: naming differs geth vs anvil:
4745        //
4746        // _Pending transactions_ are transactions that are ready to be processed and included in
4747        // the block. _Queued transactions_ are transactions where the transaction nonce is
4748        // not in sequence. The transaction nonce is an incrementing number for each transaction
4749        // with the same From address.
4750        for pending in self.pool.ready_transactions() {
4751            let entry = inspect.pending.entry(*pending.pending_transaction.sender()).or_default();
4752            let key = txpool_transaction_key(&pending.pending_transaction);
4753            entry.insert(key, convert(pending));
4754        }
4755        for queued in self.pool.pending_transactions() {
4756            let entry = inspect.queued.entry(*queued.pending_transaction.sender()).or_default();
4757            let key = txpool_transaction_key(&queued.pending_transaction);
4758            entry.insert(key, convert(queued));
4759        }
4760        Ok(inspect)
4761    }
4762
4763    /// Returns the details of all transactions currently pending for inclusion in the next
4764    /// block(s), as well as the ones that are being scheduled for future execution only.
4765    ///
4766    /// See [here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_content) for more details
4767    ///
4768    /// Handler for ETH RPC call: `txpool_content`
4769    pub async fn txpool_content(&self) -> Result<TxpoolContent<AnyRpcTransaction>> {
4770        node_info!("txpool_content");
4771        self.build_txpool_content(None)
4772    }
4773
4774    /// Builds the txpool content, optionally filtered to a single sender.
4775    ///
4776    /// When `filter` is `Some`, only transactions from that sender are converted, avoiding the
4777    /// cost of building RPC transactions for unrelated senders.
4778    fn build_txpool_content(
4779        &self,
4780        filter: Option<Address>,
4781    ) -> Result<TxpoolContent<AnyRpcTransaction>> {
4782        let mut content = TxpoolContent::<AnyRpcTransaction>::default();
4783        fn convert(tx: Arc<PoolTransaction<FoundryTxEnvelope>>) -> Result<AnyRpcTransaction> {
4784            let from = *tx.pending_transaction.sender();
4785            let tx = transaction_build(
4786                Some(tx.hash()),
4787                tx.pending_transaction.transaction.clone(),
4788                None,
4789                None,
4790                None,
4791            );
4792
4793            let WithOtherFields { inner: mut tx, other } = tx.0;
4794
4795            // we set the from field here explicitly to the set sender of the pending transaction,
4796            // in case the transaction is impersonated.
4797            tx.inner = Recovered::new_unchecked(tx.inner.into_inner(), from);
4798
4799            let tx = AnyRpcTransaction(WithOtherFields { inner: tx, other });
4800
4801            Ok(tx)
4802        }
4803
4804        for pending in self.pool.ready_transactions() {
4805            let sender = *pending.pending_transaction.sender();
4806            if filter.is_some_and(|from| from != sender) {
4807                continue;
4808            }
4809            let entry = content.pending.entry(sender).or_default();
4810            let key = txpool_transaction_key(&pending.pending_transaction);
4811            entry.insert(key, convert(pending)?);
4812        }
4813        for queued in self.pool.pending_transactions() {
4814            let sender = *queued.pending_transaction.sender();
4815            if filter.is_some_and(|from| from != sender) {
4816                continue;
4817            }
4818            let entry = content.queued.entry(sender).or_default();
4819            let key = txpool_transaction_key(&queued.pending_transaction);
4820            entry.insert(key, convert(queued)?);
4821        }
4822
4823        Ok(content)
4824    }
4825
4826    /// Returns the details of all transactions currently pending for inclusion in the next
4827    /// block(s), as well as the ones that are being scheduled for future execution only, filtered
4828    /// by sender.
4829    ///
4830    /// See [here](https://geth.ethereum.org/docs/rpc/ns-txpool#txpool_contentFrom) for more details
4831    ///
4832    /// Handler for ETH RPC call: `txpool_contentFrom`
4833    pub async fn txpool_content_from(
4834        &self,
4835        from: Address,
4836    ) -> Result<TxpoolContentFrom<AnyRpcTransaction>> {
4837        node_info!("txpool_contentFrom");
4838        let mut content = self.build_txpool_content(Some(from))?;
4839        Ok(content.remove_from(&from))
4840    }
4841}
4842
4843impl EthApi<FoundryNetwork> {
4844    /// Executes the `evm_mine` and returns the number of blocks mined
4845    async fn do_evm_mine(&self, opts: Option<MineOptions>) -> Result<u64> {
4846        let mut blocks_to_mine = 1u64;
4847
4848        if let Some(opts) = opts {
4849            let timestamp = match opts {
4850                MineOptions::Timestamp(timestamp) => timestamp,
4851                MineOptions::Options { timestamp, blocks } => {
4852                    if let Some(blocks) = blocks {
4853                        blocks_to_mine = blocks;
4854                    }
4855                    timestamp
4856                }
4857            };
4858            if let Some(timestamp) = timestamp {
4859                // timestamp was explicitly provided to be the next timestamp
4860                self.evm_set_next_block_timestamp(timestamp)?;
4861            }
4862        }
4863
4864        // this can be blocking for a bit, especially in forking mode
4865        // <https://github.com/foundry-rs/foundry/issues/6036>
4866        self.on_blocking_task(|this| async move {
4867            // mine all the blocks
4868            for _ in 0..blocks_to_mine {
4869                this.mine_one().await?;
4870            }
4871            Ok(())
4872        })
4873        .await?;
4874
4875        Ok(blocks_to_mine)
4876    }
4877
4878    async fn do_estimate_gas(
4879        &self,
4880        request: WithOtherFields<TransactionRequest>,
4881        block_number: Option<BlockId>,
4882        overrides: EvmOverrides,
4883    ) -> Result<u128> {
4884        let block_request = self.block_request(block_number).await?;
4885        // check if the number predates the fork, if in fork mode
4886        if let BlockRequest::Number(number) = block_request
4887            && let Some(fork) = self.get_fork()
4888            && fork.predates_fork(number)
4889        {
4890            if overrides.has_state() || overrides.has_block() {
4891                return Err(BlockchainError::EvmOverrideError(
4892                    "not available on past forked blocks".to_string(),
4893                ));
4894            }
4895            return Ok(fork.estimate_gas_raw(&request, Some(number.into())).await?);
4896        }
4897
4898        // this can be blocking for a bit, especially in forking mode
4899        // <https://github.com/foundry-rs/foundry/issues/6036>
4900        self.on_blocking_task(|this| async move {
4901            let request = this.parse_transaction_request(request)?;
4902            this.backend
4903                .with_database_at_and_context(
4904                    Some(block_request),
4905                    |state, mut block, monad_context| {
4906                        let mut cache_db = CacheDB::new(state);
4907                        if let Some(state_overrides) = overrides.state {
4908                            apply_state_overrides(
4909                                state_overrides.into_iter().collect(),
4910                                &mut cache_db,
4911                            )?;
4912                        }
4913                        if let Some(block_overrides) = overrides.block {
4914                            cache_db.apply_block_overrides(*block_overrides, &mut block);
4915                        }
4916                        this.do_estimate_gas_with_state(request, &cache_db, block, monad_context)
4917                    },
4918                )
4919                .await
4920        })
4921        .await
4922    }
4923
4924    async fn do_estimate_gas_typed(
4925        &self,
4926        request: FoundryTransactionRequest,
4927        block_number: Option<BlockId>,
4928    ) -> Result<u128> {
4929        let block_request = self.block_request(block_number).await?;
4930        self.on_blocking_task(|this| async move {
4931            this.backend
4932                .with_database_at_and_context(Some(block_request), |state, block, monad_context| {
4933                    this.do_estimate_gas_with_state(request, &state, block, monad_context)
4934                })
4935                .await
4936        })
4937        .await
4938    }
4939
4940    /// Returns the priority of the transaction based on the current `TransactionOrder`
4941    fn transaction_priority(&self, tx: &FoundryTxEnvelope) -> TransactionPriority {
4942        self.transaction_order.read().priority(tx)
4943    }
4944
4945    /// Returns a listener for pending transactions, yielding full transactions
4946    pub fn full_pending_transactions(&self) -> UnboundedReceiver<AnyRpcTransaction> {
4947        let (tx, rx) = unbounded_channel();
4948        let mut hashes = self.new_ready_transactions();
4949
4950        let this = self.clone();
4951
4952        tokio::spawn(async move {
4953            while let Some(hash) = hashes.next().await {
4954                if let Ok(Some(txn)) = this.transaction_by_hash(hash).await
4955                    && tx.send(txn).is_err()
4956                {
4957                    break;
4958                }
4959            }
4960        });
4961
4962        rx
4963    }
4964
4965    /// Returns a bounded stream of full pending transactions for poll-based filters.
4966    ///
4967    /// Unlike [`Self::full_pending_transactions`], this applies backpressure via a bounded channel,
4968    /// so an unpolled filter cannot buffer transactions without bound.
4969    pub fn full_pending_transactions_filter(&self) -> mpsc::Receiver<AnyRpcTransaction> {
4970        // Mirror the pool's ready-listener buffer so a full filter is bounded like a hash filter.
4971        let (tx, rx) = mpsc::channel(2048);
4972        let mut hashes = self.new_ready_transactions();
4973        let this = self.clone();
4974
4975        tokio::spawn(async move {
4976            while let Some(hash) = hashes.next().await {
4977                if let Ok(Some(txn)) = this.transaction_by_hash(hash).await
4978                    && tx.send(txn).await.is_err()
4979                {
4980                    break;
4981                }
4982            }
4983        });
4984
4985        rx
4986    }
4987
4988    /// Returns a listener for new block receipts.
4989    pub fn transaction_receipts_subscription(
4990        &self,
4991        filter: TransactionReceiptsParams,
4992    ) -> UnboundedReceiver<Vec<FoundryTxReceipt>> {
4993        let (tx, rx) = unbounded_channel();
4994        let mut blocks = self.new_block_notifications();
4995        let this = self.clone();
4996
4997        tokio::spawn(async move {
4998            // Precompute the hash filter once.
4999            let hash_filter = filter
5000                .transaction_hashes
5001                .filter(|hashes| !hashes.is_empty())
5002                .map(|hashes| hashes.into_iter().collect::<B256Set>());
5003
5004            loop {
5005                let notification = tokio::select! {
5006                    biased;
5007                    // Exit when the subscriber unsubscribes, even while awaiting the next block.
5008                    _ = tx.closed() => break,
5009                    maybe_block = blocks.next() => match maybe_block {
5010                        Some(block) => block,
5011                        None => break,
5012                    },
5013                };
5014
5015                let Some(block) = notification.as_new_block() else {
5016                    continue;
5017                };
5018
5019                let receipts = match this.block_receipts(BlockId::hash(block.hash)).await {
5020                    Ok(Some(mut receipts)) => {
5021                        if let Some(hashes) = &hash_filter {
5022                            receipts.retain(|receipt| hashes.contains(&receipt.transaction_hash()));
5023                        }
5024                        receipts
5025                    }
5026                    Ok(None) => continue,
5027                    Err(err) => {
5028                        trace!(target: "node", %err, "failed to build block receipts for subscription");
5029                        continue;
5030                    }
5031                };
5032
5033                if receipts.is_empty() {
5034                    continue;
5035                }
5036
5037                if tx.send(receipts).is_err() {
5038                    break;
5039                }
5040            }
5041        });
5042
5043        rx
5044    }
5045
5046    /// Mines exactly one block
5047    pub async fn mine_one(&self) -> Result<()> {
5048        let _mining = self.backend.lock_mining().await;
5049        let transactions = self.pool.ready_transactions().collect::<Vec<_>>();
5050        let outcome = self.backend.mine_block_locked(transactions).await?;
5051
5052        trace!(target: "node", blocknumber = ?outcome.block_number, "mined block");
5053        if self.pool.on_mined_block(outcome) {
5054            self.miner.retry_ready_transactions();
5055        }
5056        Ok(())
5057    }
5058
5059    /// Returns the pending block with tx hashes
5060    async fn pending_block(&self) -> Result<AnyRpcBlock> {
5061        let transactions = self.pool.ready_transactions().collect::<Vec<_>>();
5062        let info = self.backend.pending_block(transactions).await?;
5063        Ok(self.backend.convert_block(info.block))
5064    }
5065
5066    /// Returns the full pending block with `Transaction` objects
5067    async fn pending_block_full(&self) -> Result<Option<AnyRpcBlock>> {
5068        let transactions = self.pool.ready_transactions().collect::<Vec<_>>();
5069        let BlockInfo { block, transactions, receipts: _ } =
5070            self.backend.pending_block(transactions).await?;
5071
5072        let mut partial_block = self.backend.convert_block(block.clone());
5073
5074        let mut block_transactions = Vec::with_capacity(block.body.transactions.len());
5075        let base_fee = self.backend.base_fee();
5076
5077        for info in transactions {
5078            let Some(tx) = block.body.transactions.get(info.transaction_index as usize).cloned()
5079            else {
5080                return Ok(None);
5081            };
5082
5083            let tx = transaction_build(
5084                Some(info.transaction_hash),
5085                tx,
5086                Some(&block),
5087                Some(info),
5088                Some(base_fee),
5089            );
5090            block_transactions.push(tx);
5091        }
5092
5093        partial_block.transactions = BlockTransactions::from(block_transactions);
5094
5095        Ok(Some(partial_block))
5096    }
5097
5098    /// Prepares transaction request by filling missing fields using Anvil's API, then attempts
5099    /// to build a [`FoundryTypedTx`].
5100    async fn build_tx_request(
5101        &self,
5102        request: FoundryTransactionRequest,
5103        nonce: u64,
5104    ) -> Result<FoundryTypedTx> {
5105        self.build_tx_request_with_fee_defaults(request, nonce, None).await
5106    }
5107
5108    async fn build_tx_request_with_fee_defaults(
5109        &self,
5110        mut request: FoundryTransactionRequest,
5111        nonce: u64,
5112        fee_defaults: Option<TransactionFeeDefaults>,
5113    ) -> Result<FoundryTypedTx> {
5114        let from = request.from().or(self.accounts()?.first().copied());
5115        if let Some(from) = from {
5116            request.set_from(from);
5117        }
5118
5119        // Fill common fields for all tx types
5120        request.chain_id().is_none().then(|| request.set_chain_id(self.chain_id()));
5121        request.nonce().is_none().then(|| request.set_nonce(nonce));
5122        let is_tempo_batch =
5123            matches!(&request, FoundryTransactionRequest::Tempo(tx) if !tx.calls.is_empty());
5124        if request.kind().is_none() && !is_tempo_batch {
5125            request.set_kind(TxKind::default());
5126        }
5127        if request.gas_limit().is_none() {
5128            let fallback_gas_limit = {
5129                let evm_env = self.backend.evm_env().read();
5130                self.backend.fallback_tx_gas_limit(&evm_env)
5131            };
5132            let estimated_gas = self
5133                .do_estimate_gas_typed(request.clone(), None)
5134                .await
5135                .map(|v| v as u64)
5136                .unwrap_or_else(|_| {
5137                    if is_simple_transfer_request(request.as_ref()) {
5138                        MIN_TRANSACTION_GAS as u64
5139                    } else {
5140                        fallback_gas_limit
5141                    }
5142                });
5143            request.set_gas_limit(estimated_gas);
5144        }
5145
5146        // Fill missing tx type specific fields
5147        if let Err((tx_type, _)) = request.missing_keys() {
5148            let gas_price = || fee_defaults.map_or_else(|| self.gas_price(), |fees| fees.gas_price);
5149            if tx_type.is_legacy() || tx_type.is_eip2930() {
5150                request.gas_price().is_none().then(|| request.set_gas_price(gas_price()));
5151            }
5152            if tx_type.is_eip2930() {
5153                request
5154                    .access_list()
5155                    .is_none()
5156                    .then(|| request.set_access_list(Default::default()));
5157            }
5158            if tx_type.is_eip1559()
5159                || tx_type.is_eip4844()
5160                || tx_type.is_eip7702()
5161                || tx_type.is_tempo()
5162                || tx_type.is_celo()
5163            {
5164                request
5165                    .max_fee_per_gas()
5166                    .is_none()
5167                    .then(|| request.set_max_fee_per_gas(gas_price()));
5168                request
5169                    .max_priority_fee_per_gas()
5170                    .is_none()
5171                    .then(|| request.set_max_priority_fee_per_gas(MIN_SUGGESTED_PRIORITY_FEE));
5172            }
5173            if tx_type.is_eip4844() {
5174                request.as_ref().max_fee_per_blob_gas().is_none().then(|| {
5175                    let blob_gas_price = fee_defaults.map_or_else(
5176                        || self.backend.fees().get_next_block_blob_base_fee_per_gas(),
5177                        |fees| fees.blob_gas_price,
5178                    );
5179                    request.as_mut().set_max_fee_per_blob_gas(blob_gas_price)
5180                });
5181            }
5182        }
5183
5184        match request
5185            .build_unsigned()
5186            .map_err(|e| BlockchainError::InvalidTransactionRequest(e.to_string()))?
5187        {
5188            FoundryTypedTx::Eip4844(TxEip4844Variant::TxEip4844(_))
5189                if !self.backend.skip_blob_validation(from) =>
5190            {
5191                // If blob validation is not skipped, reject TxEip4844 variant without sidecar.
5192                Err(BlockchainError::FailedToDecodeTransaction)
5193            }
5194            res => Ok(res),
5195        }
5196    }
5197
5198    /// Returns the nonce of the `address` depending on the `block_number`
5199    async fn get_transaction_count(
5200        &self,
5201        address: Address,
5202        block_number: Option<BlockId>,
5203    ) -> Result<u64> {
5204        let block_request = self.block_request(block_number).await?;
5205
5206        if let BlockRequest::Number(number) = block_request
5207            && let Some(fork) = self.get_fork()
5208            && fork.predates_fork(number)
5209        {
5210            return Ok(fork.get_nonce(address, number).await?);
5211        }
5212
5213        self.backend.get_nonce(address, block_request).await
5214    }
5215
5216    /// Returns the nonce for this request
5217    ///
5218    /// If the nonce field of the `request` is `None`, this accounts for pending transactions from
5219    /// the sender.
5220    async fn request_nonce(&self, request: &TransactionRequest, from: Address) -> Result<u64> {
5221        if let Some(nonce) = request.nonce {
5222            Ok(nonce)
5223        } else {
5224            self.get_transaction_count(from, Some(BlockId::pending())).await
5225        }
5226    }
5227
5228    /// Adds the given transaction to the pool
5229    async fn add_pending_transaction(
5230        &self,
5231        pending_transaction: PendingTransaction<FoundryTxEnvelope>,
5232    ) -> Result<TxHash> {
5233        let _mining = self.backend.lock_mining().await;
5234        self.backend.validate_pool_transaction(&pending_transaction).await?;
5235
5236        let from = *pending_transaction.sender();
5237        #[cfg(feature = "base")]
5238        let base_markers = self.eip8130_nonce_markers(&pending_transaction).await?;
5239        #[cfg(not(feature = "base"))]
5240        let base_markers = None;
5241
5242        let markers = if base_markers.is_some() {
5243            base_markers
5244        } else {
5245            self.tempo_nonce_markers(&pending_transaction).await?
5246        };
5247        let (requires, provides) = if let Some(markers) = markers {
5248            markers
5249        } else {
5250            let nonce = pending_transaction.transaction.nonce();
5251            let on_chain_nonce = self.backend.current_nonce(from).await?;
5252            (required_marker(nonce, on_chain_nonce, from), vec![to_marker(nonce, from)])
5253        };
5254
5255        debug_assert!(requires != provides);
5256        let priority = self.transaction_priority(&pending_transaction.transaction);
5257        let pool_transaction =
5258            PoolTransaction { requires, provides, pending_transaction, priority, is_replay: false };
5259        let tx = self.pool.add_transaction(pool_transaction)?;
5260        trace!(target: "node", "Added transaction: [{:?}] sender={:?}", tx.hash(), from);
5261        Ok(*tx.hash())
5262    }
5263
5264    /// Returns Tempo lane/replay markers when the transaction does not use the protocol nonce.
5265    async fn tempo_nonce_markers(
5266        &self,
5267        pending: &PendingTransaction<FoundryTxEnvelope>,
5268    ) -> Result<Option<(Vec<TxMarker>, Vec<TxMarker>)>> {
5269        let FoundryTxEnvelope::Tempo(signed) = pending.transaction.as_ref() else {
5270            return Ok(None);
5271        };
5272        let tx = signed.tx();
5273        if tx.nonce_key.is_zero() {
5274            return Ok(None);
5275        }
5276        if tx.nonce_key == U256::MAX {
5277            return Ok(Some((Vec::new(), vec![pending.hash().to_vec()])));
5278        }
5279
5280        let state_nonce = self.backend.tempo_nonce(*pending.sender(), tx.nonce_key, None).await?;
5281        if tx.nonce < state_nonce {
5282            return Err(InvalidTransactionError::NonceTooLow.into());
5283        }
5284
5285        let requires = if tx.nonce == state_nonce {
5286            Vec::new()
5287        } else {
5288            vec![tempo_nonce_marker(*pending.sender(), tx.nonce_key, tx.nonce - 1)]
5289        };
5290        let provides = vec![tempo_nonce_marker(*pending.sender(), tx.nonce_key, tx.nonce)];
5291        Ok(Some((requires, provides)))
5292    }
5293
5294    /// Returns Base EIP-8130 channel/replay markers when the transaction does not use the
5295    /// protocol nonce lane.
5296    #[cfg(feature = "base")]
5297    async fn eip8130_nonce_markers(
5298        &self,
5299        pending: &PendingTransaction<FoundryTxEnvelope>,
5300    ) -> Result<Option<(Vec<TxMarker>, Vec<TxMarker>)>> {
5301        if let FoundryTxEnvelope::Eip8130(signed) = pending.transaction.as_ref() {
5302            let tx = signed.tx();
5303            let now = self.backend.eip8130_pool_timestamp_ms();
5304            signed
5305                .validate_admission_static(self.backend.chain_id().to())
5306                .map_err(|error| BlockchainError::Eip8130TransactionRejected(error.to_string()))?;
5307            signed
5308                .validate_timestamp(now)
5309                .map_err(|error| BlockchainError::Eip8130TransactionRejected(error.to_string()))?;
5310            if tx.nonce_key.is_zero() {
5311                let state_nonce = self.backend.current_nonce(*pending.sender()).await?;
5312                if tx.nonce_sequence < state_nonce {
5313                    return Err(InvalidTransactionError::NonceTooLow.into());
5314                }
5315                let provides = vec![to_marker(tx.nonce_sequence, *pending.sender())];
5316                self.ensure_eip8130_replacement_price(pending, &provides)?;
5317                self.ensure_eip8130_payer_reservation(pending, &provides).await?;
5318                return Ok(None);
5319            }
5320            if tx.nonce_key == Eip8130Constants::NONCE_KEY_MAX {
5321                let replay_id = tx.replay_id(*pending.sender());
5322                let slot = NonceManagerStorage::expiring_nonce_seen_slot(replay_id);
5323                let word =
5324                    self.backend.storage_at(NonceManagerStorage::ADDRESS, slot, None).await?;
5325                let recorded_expiry = (Into::<U256>::into(word) & U256::from(u64::MAX)).to::<u64>();
5326                if recorded_expiry > now {
5327                    return Err(BlockchainError::Eip8130TransactionRejected(
5328                        "expiring nonce replay has already been recorded".to_string(),
5329                    ));
5330                }
5331                let provides = vec![eip8130_replay_marker(replay_id)];
5332                self.ensure_eip8130_replacement_price(pending, &provides)?;
5333                self.ensure_eip8130_payer_reservation(pending, &provides).await?;
5334                return Ok(Some((Vec::new(), provides)));
5335            }
5336
5337            let slot = NonceManagerStorage::nonce_slot(*pending.sender(), tx.nonce_key)
5338                .map_err(|error| BlockchainError::InvalidTransactionRequest(error.to_string()))?;
5339            let word = self.backend.storage_at(NonceManagerStorage::ADDRESS, slot, None).await?;
5340            let state_nonce = Eip8130Nonce::decode_channel_nonce(word.into()).to::<u64>();
5341            if tx.nonce_sequence < state_nonce {
5342                return Err(InvalidTransactionError::NonceTooLow.into());
5343            }
5344
5345            let requires = if tx.nonce_sequence == state_nonce {
5346                Vec::new()
5347            } else {
5348                vec![eip8130_channel_marker(*pending.sender(), tx.nonce_key, tx.nonce_sequence - 1)]
5349            };
5350            let provides =
5351                vec![eip8130_channel_marker(*pending.sender(), tx.nonce_key, tx.nonce_sequence)];
5352            self.ensure_eip8130_replacement_price(pending, &provides)?;
5353            self.ensure_eip8130_payer_reservation(pending, &provides).await?;
5354            return Ok(Some((requires, provides)));
5355        }
5356
5357        Ok(None)
5358    }
5359
5360    /// Enforces Base's default ten-percent EIP-8130 replacement price bump.
5361    #[cfg(feature = "base")]
5362    fn ensure_eip8130_replacement_price(
5363        &self,
5364        pending: &PendingTransaction<FoundryTxEnvelope>,
5365        provides: &[TxMarker],
5366    ) -> Result<()> {
5367        let Some(existing) = self.pool.transaction_with_markers(*pending.sender(), provides) else {
5368            return Ok(());
5369        };
5370        let FoundryTxEnvelope::Eip8130(incoming) = pending.transaction.as_ref() else {
5371            return Ok(());
5372        };
5373        let FoundryTxEnvelope::Eip8130(current) = existing.pending_transaction.transaction.as_ref()
5374        else {
5375            return Ok(());
5376        };
5377
5378        const PRICE_BUMP_PERCENT: u128 = 10;
5379        let bumped =
5380            |price: u128| price.saturating_mul(100 + PRICE_BUMP_PERCENT).saturating_add(99) / 100;
5381        if incoming.tx().max_fee_per_gas < bumped(current.tx().max_fee_per_gas)
5382            || incoming.tx().max_priority_fee_per_gas
5383                < bumped(current.tx().max_priority_fee_per_gas)
5384        {
5385            return Err(
5386                crate::eth::error::PoolError::ReplacementUnderpriced(*pending.hash()).into()
5387            );
5388        }
5389        Ok(())
5390    }
5391
5392    /// Reserves each payer's maximum EIP-8130 fee across pending transactions.
5393    #[cfg(feature = "base")]
5394    async fn ensure_eip8130_payer_reservation(
5395        &self,
5396        pending: &PendingTransaction<FoundryTxEnvelope>,
5397        replacing_markers: &[TxMarker],
5398    ) -> Result<()> {
5399        let FoundryTxEnvelope::Eip8130(incoming) = pending.transaction.as_ref() else {
5400            return Ok(());
5401        };
5402        let payer = incoming.tx().payer.unwrap_or(*pending.sender());
5403        let incoming_cost = FeeCheck::max_fee_charge(
5404            incoming.tx().gas_limit,
5405            IntrinsicGas::max_payer_auth_cost(incoming)
5406                .map_err(|error| BlockchainError::Eip8130TransactionRejected(error.to_string()))?,
5407            incoming.tx().max_fee_per_gas,
5408        );
5409        let mut reserved = U256::ZERO;
5410        for pooled in self.pool.all_transactions() {
5411            if pooled.provides == replacing_markers {
5412                continue;
5413            }
5414            let FoundryTxEnvelope::Eip8130(signed) =
5415                pooled.pending_transaction.transaction.as_ref()
5416            else {
5417                continue;
5418            };
5419            if signed.tx().payer.unwrap_or(*pooled.pending_transaction.sender()) != payer {
5420                continue;
5421            }
5422            let payer_auth = IntrinsicGas::max_payer_auth_cost(signed)
5423                .map_err(|error| BlockchainError::Eip8130TransactionRejected(error.to_string()))?;
5424            reserved = reserved.saturating_add(FeeCheck::max_fee_charge(
5425                signed.tx().gas_limit,
5426                payer_auth,
5427                signed.tx().max_fee_per_gas,
5428            ));
5429        }
5430        let balance = self.backend.get_account(payer).await?.balance;
5431        let required = reserved.saturating_add(incoming_cost);
5432        if balance < required {
5433            return Err(BlockchainError::Eip8130TransactionRejected(format!(
5434                "gas payer balance {balance} is below pending reservation {required}"
5435            )));
5436        }
5437        Ok(())
5438    }
5439
5440    /// additional validation against hardfork
5441    fn ensure_typed_transaction_supported(&self, tx: &FoundryTxEnvelope) -> Result<()> {
5442        match &tx {
5443            FoundryTxEnvelope::Eip2930(_) => self.backend.ensure_eip2930_active(),
5444            FoundryTxEnvelope::Eip1559(_) => self.backend.ensure_eip1559_active(),
5445            FoundryTxEnvelope::Eip4844(_) => self.backend.ensure_eip4844_active(),
5446            FoundryTxEnvelope::Eip7702(_) => self.backend.ensure_eip7702_active(),
5447            #[cfg(any(feature = "base", feature = "optimism"))]
5448            FoundryTxEnvelope::Deposit(_) => self.backend.ensure_deposits_active(),
5449            #[cfg(feature = "optimism")]
5450            FoundryTxEnvelope::PostExec(_) => Err(BlockchainError::InvalidTransactionRequest(
5451                "not implemented for post-exec tx".to_string(),
5452            )),
5453            #[cfg(feature = "base")]
5454            FoundryTxEnvelope::Eip8130(_) => self.backend.ensure_base_eip8130_submission_active(),
5455            FoundryTxEnvelope::Celo(_) => self.backend.ensure_cip64_active(),
5456            FoundryTxEnvelope::Legacy(_) => Ok(()),
5457            FoundryTxEnvelope::Tempo(_) => self.backend.ensure_tempo_active(),
5458        }
5459    }
5460
5461    /// Sets the fee token for a user address.
5462    ///
5463    /// Handler for RPC call: `anvil_setFeeToken`
5464    ///
5465    /// Only supported when running in Tempo mode (`--tempo`).
5466    pub async fn anvil_set_fee_token(&self, user: Address, token: Address) -> Result<()> {
5467        node_info!("anvil_setFeeToken");
5468        self.ensure_tempo_mode()?;
5469        self.backend.set_fee_token(user, token).await?;
5470        Ok(())
5471    }
5472
5473    /// Sets the fee token for a validator address.
5474    ///
5475    /// Handler for RPC call: `anvil_setValidatorFeeToken`
5476    ///
5477    /// Only supported when running in Tempo mode (`--tempo`).
5478    pub async fn anvil_set_validator_fee_token(
5479        &self,
5480        validator: Address,
5481        token: Address,
5482    ) -> Result<()> {
5483        node_info!("anvil_setValidatorFeeToken");
5484        self.ensure_tempo_mode()?;
5485        self.backend.set_validator_fee_token(validator, token).await?;
5486        Ok(())
5487    }
5488
5489    /// Mints FeeAMM liquidity for a token pair.
5490    ///
5491    /// Handler for RPC call: `anvil_setFeeAmmLiquidity`
5492    ///
5493    /// Only supported when running in Tempo mode (`--tempo`).
5494    pub async fn anvil_set_fee_amm_liquidity(
5495        &self,
5496        user_token: Address,
5497        validator_token: Address,
5498        amount: U256,
5499    ) -> Result<()> {
5500        node_info!("anvil_setFeeAmmLiquidity");
5501        self.ensure_tempo_mode()?;
5502        self.backend.set_fee_amm_liquidity(user_token, validator_token, amount).await?;
5503        Ok(())
5504    }
5505
5506    /// Ensures anvil runs in Tempo mode (`--tempo`), the RPC method is unavailable otherwise.
5507    fn ensure_tempo_mode(&self) -> Result<()> {
5508        if self.backend.is_tempo() { Ok(()) } else { Err(BlockchainError::RpcUnimplemented) }
5509    }
5510
5511    fn parse_transaction_request(
5512        &self,
5513        request: WithOtherFields<TransactionRequest>,
5514    ) -> Result<FoundryTransactionRequest> {
5515        self.backend.parse_transaction_request(request)
5516    }
5517
5518    async fn request_nonce_for_transaction(
5519        &self,
5520        request: &FoundryTransactionRequest,
5521        from: Address,
5522    ) -> Result<u64> {
5523        if let FoundryTransactionRequest::Tempo(request) = request
5524            && let Some(nonce_key) = request.nonce_key.filter(|key| !key.is_zero())
5525        {
5526            if let Some(nonce) = request.nonce() {
5527                return Ok(nonce);
5528            }
5529            let nonce = self.backend.tempo_nonce(from, nonce_key, None).await?;
5530            return Ok(nonce);
5531        }
5532        self.request_nonce(request.as_ref(), from).await
5533    }
5534}
5535
5536fn is_simple_transfer_request(request: &TransactionRequest) -> bool {
5537    request.to.as_ref().and_then(TxKind::to).is_some()
5538        && (request.input.input().is_none()
5539            || request.input.input().is_some_and(|data| data.is_empty()))
5540        && request.authorization_list.is_none()
5541        && request.access_list.is_none()
5542        && request.blob_versioned_hashes.is_none()
5543}
5544
5545fn required_marker(provided_nonce: u64, on_chain_nonce: u64, from: Address) -> Vec<TxMarker> {
5546    if provided_nonce == on_chain_nonce {
5547        return Vec::new();
5548    }
5549    let prev_nonce = provided_nonce.saturating_sub(1);
5550    if on_chain_nonce <= prev_nonce { vec![to_marker(prev_nonce, from)] } else { Vec::new() }
5551}
5552
5553fn tempo_nonce_marker(sender: Address, nonce_key: U256, nonce: u64) -> TxMarker {
5554    let mut marker = b"tempo-nonce".to_vec();
5555    marker.extend_from_slice(sender.as_slice());
5556    marker.extend_from_slice(&nonce_key.to_be_bytes::<32>());
5557    marker.extend_from_slice(&nonce.to_be_bytes());
5558    marker
5559}
5560
5561#[cfg(feature = "base")]
5562fn eip8130_channel_marker(sender: Address, nonce_key: U256, nonce_sequence: u64) -> TxMarker {
5563    let mut marker = b"base-eip8130-channel".to_vec();
5564    marker.extend_from_slice(sender.as_slice());
5565    marker.extend_from_slice(&nonce_key.to_be_bytes::<32>());
5566    marker.extend_from_slice(&nonce_sequence.to_be_bytes());
5567    marker
5568}
5569
5570#[cfg(feature = "base")]
5571fn eip8130_replay_marker(replay_id: B256) -> TxMarker {
5572    let mut marker = b"base-eip8130-replay".to_vec();
5573    marker.extend_from_slice(replay_id.as_slice());
5574    marker
5575}
5576
5577/// Rewrites the Tempo fee payer service encoding of a raw transaction into the standard envelope
5578/// encoding.
5579///
5580/// Fee payer service clients submit sponsorship requests with a `0x00` placeholder in the fee
5581/// payer signature field (and the fee token left empty for the sponsor to fill), which the
5582/// standard envelope decoder rejects. The placeholder is rewritten to the standard encoding of
5583/// [`FEE_PAYER_SIGNATURE_MARKER`], preserving the sponsored signing state the sender committed
5584/// to. Returns the normalized raw transaction when the input carries the placeholder and `None`
5585/// for any other encoding.
5586fn normalize_fee_payer_service_encoding(raw: &[u8]) -> Option<Vec<u8>> {
5587    let (tx_type, mut encoded_fields) = raw.split_first()?;
5588    if *tx_type != TEMPO_TX_TYPE_ID {
5589        return None;
5590    }
5591    let PayloadView::List(fields) = Header::decode_raw(&mut encoded_fields).ok()? else {
5592        return None;
5593    };
5594    if !encoded_fields.is_empty() {
5595        return None;
5596    }
5597    // The fee payer signature is the twelfth field of a Tempo AA transaction.
5598    if fields.get(11).is_none_or(|field| *field != [0x00]) {
5599        return None;
5600    }
5601
5602    // The standard encoding of the marker signature, mirroring the fee payer signature closure of
5603    // `TempoTransaction::rlp_encode_fields_default`.
5604    let marker = FEE_PAYER_SIGNATURE_MARKER;
5605    let mut marker_field = Vec::new();
5606    Header { list: true, payload_length: marker.rlp_rs_len() + marker.v().length() }
5607        .encode(&mut marker_field);
5608    marker.write_rlp_vrs(&mut marker_field, marker.v());
5609
5610    let mut payload = Vec::new();
5611    for (index, field) in fields.into_iter().enumerate() {
5612        if index == 11 {
5613            payload.extend_from_slice(&marker_field);
5614        } else {
5615            payload.extend_from_slice(field);
5616        }
5617    }
5618    let mut normalized = vec![TEMPO_TX_TYPE_ID];
5619    Header { list: true, payload_length: payload.len() }.encode(&mut normalized);
5620    normalized.extend_from_slice(&payload);
5621    Some(normalized)
5622}
5623
5624/// EIP-2718 encodes a transaction held in its JSON-RPC form, reporting the types anvil cannot
5625/// encode as [`BlockchainError::UnsupportedTransactionEncoding`].
5626fn encode_rpc_transaction(transaction: &AnyRpcTransaction) -> Result<Bytes> {
5627    FoundryTxEnvelope::encode_rpc_2718(transaction)
5628        .map_err(|_| BlockchainError::UnsupportedTransactionEncoding(transaction.ty()))
5629}
5630
5631fn txpool_transaction_key(pending_transaction: &PendingTransaction<FoundryTxEnvelope>) -> String {
5632    match pending_transaction.transaction.as_ref() {
5633        #[cfg(feature = "base")]
5634        FoundryTxEnvelope::Eip8130(signed) if !signed.tx().nonce_key.is_zero() => {
5635            if signed.tx().nonce_key == Eip8130Constants::NONCE_KEY_MAX {
5636                return signed.tx().replay_id(*pending_transaction.sender()).to_string();
5637            }
5638            format!("{}:{}", signed.tx().nonce_key, signed.tx().nonce_sequence)
5639        }
5640        FoundryTxEnvelope::Tempo(tx) if !tx.tx().nonce_key.is_zero() => {
5641            let tx = tx.tx();
5642            format!("{}:{}", tx.nonce_key, tx.nonce)
5643        }
5644        _ => pending_transaction.nonce().to_string(),
5645    }
5646}
5647
5648fn convert_transact_out(out: &Option<Output>) -> Bytes {
5649    out.as_ref().map(Output::data).cloned().unwrap_or_default()
5650}
5651
5652/// Returns an error if the `exit` code is _not_ ok
5653fn ensure_return_ok(exit: InstructionResult, out: &Option<Output>) -> Result<Bytes> {
5654    let out = convert_transact_out(out);
5655    match exit {
5656        return_ok!() => Ok(out),
5657        return_revert!() => Err(InvalidTransactionError::Revert(Some(out)).into()),
5658        reason => Err(BlockchainError::EvmError(reason)),
5659    }
5660}
5661
5662/// Maps an EVM exit code to the optional `error` string reported in
5663/// `eth_createAccessList` results.
5664fn execution_error(exit: InstructionResult) -> Option<String> {
5665    match SuccessOrHalt::<HaltReason>::from(exit) {
5666        SuccessOrHalt::Success(_) => None,
5667        SuccessOrHalt::Revert => Some("execution reverted".to_string()),
5668        SuccessOrHalt::Halt(reason) => Some(reason.to_string()),
5669        SuccessOrHalt::FatalExternalError => Some("fatal external error".to_string()),
5670        SuccessOrHalt::Internal(_) => Some("internal EVM error".to_string()),
5671    }
5672}
5673
5674/// Keeps result of a call to revm EVM used for gas estimation
5675enum GasEstimationCallResult {
5676    Success(u128),
5677    OutOfGas,
5678    Revert(Option<Bytes>),
5679    EvmError(InstructionResult),
5680}
5681
5682/// Converts the result of a call to revm EVM into a [`GasEstimationCallResult`].
5683///
5684/// Expected to stay up to date with: <https://github.com/bluealloy/revm/blob/main/crates/interpreter/src/instruction_result.rs>
5685impl TryFrom<Result<(InstructionResult, Option<Output>, u128, State)>> for GasEstimationCallResult {
5686    type Error = BlockchainError;
5687
5688    fn try_from(res: Result<(InstructionResult, Option<Output>, u128, State)>) -> Result<Self> {
5689        match res {
5690            // Exceptional case: init used too much gas, treated as out of gas error
5691            Err(BlockchainError::InvalidTransaction(InvalidTransactionError::GasTooHigh(_))) => {
5692                Ok(Self::OutOfGas)
5693            }
5694            // Tempo intrinsic gas errors come through as Message variants
5695            Err(BlockchainError::Message(ref msg))
5696                if msg.contains("insufficient gas for intrinsic cost") =>
5697            {
5698                Ok(Self::OutOfGas)
5699            }
5700            Err(err) => Err(err),
5701            Ok((exit, output, gas, _)) => match exit {
5702                return_ok!() => Ok(Self::Success(gas)),
5703
5704                // Revert opcodes:
5705                InstructionResult::Revert => {
5706                    Ok(Self::Revert(Some(output.map(|o| o.into_data()).unwrap_or_default())))
5707                }
5708                InstructionResult::CallTooDeep
5709                | InstructionResult::OutOfFunds
5710                | InstructionResult::CreateInitCodeStartingEF00
5711                | InstructionResult::InvalidEOFInitCode
5712                | InstructionResult::InvalidExtDelegateCallTarget => Ok(Self::EvmError(exit)),
5713
5714                // Out of gas errors:
5715                InstructionResult::OutOfGas
5716                | InstructionResult::MemoryOOG
5717                | InstructionResult::MemoryLimitOOG
5718                | InstructionResult::PrecompileOOG
5719                | InstructionResult::InvalidOperandOOG
5720                | InstructionResult::ReentrancySentryOOG => Ok(Self::OutOfGas),
5721
5722                // Other errors:
5723                InstructionResult::OpcodeNotFound
5724                | InstructionResult::CallNotAllowedInsideStatic
5725                | InstructionResult::StateChangeDuringStaticCall
5726                | InstructionResult::InvalidFEOpcode
5727                | InstructionResult::InvalidJump
5728                | InstructionResult::NotActivated
5729                | InstructionResult::StackUnderflow
5730                | InstructionResult::StackOverflow
5731                | InstructionResult::OutOfOffset
5732                | InstructionResult::CreateCollision
5733                | InstructionResult::OverflowPayment
5734                | InstructionResult::PrecompileError
5735                | InstructionResult::NonceOverflow
5736                | InstructionResult::CreateContractSizeLimit
5737                | InstructionResult::CreateContractStartingWithEF
5738                | InstructionResult::CreateInitCodeSizeLimit
5739                | InstructionResult::InvalidImmediateEncoding
5740                | InstructionResult::FatalExternalError => Ok(Self::EvmError(exit)),
5741            },
5742        }
5743    }
5744}
5745
5746/// Appends the upstream part of a fee-history range that crosses the fork boundary.
5747fn merge_pre_fork_fee_history(
5748    response: &mut FeeHistory,
5749    rewards: &mut Vec<Vec<u128>>,
5750    pre: FeeHistory,
5751    fork_block: u64,
5752) {
5753    // Upstream may return fewer blocks than requested when its available history starts later.
5754    response.oldest_block = pre.oldest_block;
5755    let count = fork_block.checked_sub(pre.oldest_block).map_or(0, |count| count.saturating_add(1))
5756        as usize;
5757
5758    // Base-fee arrays include a trailing next-block entry. The caller computes that block locally.
5759    response.base_fee_per_gas.extend(pre.base_fee_per_gas.into_iter().take(count));
5760    response.gas_used_ratio.extend(pre.gas_used_ratio.into_iter().take(count));
5761    if let Some(reward) = pre.reward {
5762        rewards.extend(reward.into_iter().take(count));
5763    }
5764
5765    // EIP-4844 fields may be omitted for pre-Cancun blocks. Pad to the actual returned count.
5766    response.base_fee_per_blob_gas.extend(pre.base_fee_per_blob_gas.into_iter().take(count));
5767    response.base_fee_per_blob_gas.resize(count, 0);
5768    response.blob_gas_used_ratio.extend(pre.blob_gas_used_ratio.into_iter().take(count));
5769    response.blob_gas_used_ratio.resize(count, 0.0);
5770}
5771
5772fn reward_at_percentile(rewards: &[u128], percentile: f64) -> u128 {
5773    let index = (percentile * REWARD_PERCENTILE_RESOLUTION).round() as usize;
5774    rewards.get(index).copied().unwrap_or_default()
5775}
5776
5777#[cfg(test)]
5778mod tests {
5779    use super::*;
5780    use crate::{NodeConfig, spawn};
5781
5782    #[cfg(feature = "base")]
5783    #[tokio::test(flavor = "multi_thread")]
5784    async fn base_requests_are_rejected_without_execution() {
5785        let (api, _handle) = spawn(NodeConfig::test()).await;
5786        for request in [serde_json::json!({ "type": "0x79" }), serde_json::json!({ "calls": [[]] })]
5787        {
5788            let request = serde_json::from_value(request).unwrap();
5789            assert!(matches!(
5790                api.parse_transaction_request(request),
5791                Err(BlockchainError::BaseTransactionUnsupported)
5792            ));
5793        }
5794    }
5795
5796    #[tokio::test(flavor = "multi_thread")]
5797    async fn set_rpc_url_installs_context_equivalent_identity_with_new_instance() {
5798        let genesis_timestamp = 1_700_000_000u64;
5799        let (_origin_api, origin_handle) =
5800            spawn(NodeConfig::test().with_genesis_timestamp(Some(genesis_timestamp))).await;
5801        let (api, _handle) =
5802            spawn(NodeConfig::test().with_eth_rpc_url(Some(origin_handle.http_endpoint()))).await;
5803        let (target_api, target_handle) =
5804            spawn(NodeConfig::test().with_genesis_timestamp(Some(genesis_timestamp))).await;
5805        let target_url = target_handle.http_endpoint();
5806        let fork = api.backend.get_fork().unwrap();
5807        let identity_before = fork.config.read().endpoint_identity;
5808
5809        api.anvil_set_rpc_url(target_url.clone()).await.unwrap();
5810
5811        let fork = api.backend.get_fork().unwrap();
5812        let config = fork.config.read();
5813        assert!(config.endpoint_identity.context_eq(identity_before));
5814        assert_ne!(config.endpoint_identity.instance_id, identity_before.instance_id);
5815        assert_eq!(config.endpoint_identity.instance_id, Some(target_api.instance_id()));
5816        assert_eq!(config.eth_rpc_url(), Some(target_url.as_str()));
5817    }
5818
5819    #[tokio::test(flavor = "multi_thread")]
5820    async fn memory_reset_stages_live_fees_after_active_mining() {
5821        let (api, _handle) = spawn(NodeConfig::test()).await;
5822        api.backend.set_base_fee(123);
5823
5824        // Model an in-flight miner that publishes its final fee update before completing. Reset
5825        // must wait to snapshot that state until mining finishes.
5826        let mining = api.backend.lock_mining().await;
5827        let reset_api = api.clone();
5828        let reset = tokio::spawn(async move { reset_api.anvil_reset(None).await });
5829
5830        tokio::time::timeout(Duration::from_secs(5), async {
5831            while api.lifecycle_lock.try_read().is_ok() {
5832                tokio::task::yield_now().await;
5833            }
5834        })
5835        .await
5836        .unwrap();
5837
5838        api.backend.set_base_fee(456);
5839        drop(mining);
5840        tokio::time::timeout(Duration::from_secs(5), reset).await.unwrap().unwrap().unwrap();
5841
5842        assert_eq!(api.backend.evm_env().read().block_env.basefee, 456);
5843        assert_eq!(api.base_fee().unwrap(), Some(U256::from(crate::eth::fees::INITIAL_BASE_FEE)));
5844    }
5845
5846    // Regression test for <https://github.com/foundry-rs/foundry/issues/13680>.
5847    #[tokio::test(flavor = "multi_thread")]
5848    async fn fee_history_is_complete_when_cache_entries_are_missing() {
5849        let (api, _handle) = spawn(NodeConfig::test()).await;
5850        let count = 10u64;
5851        api.anvil_mine(Some(U256::from(count)), None).await.unwrap();
5852
5853        // Wait until the asynchronous service has consumed all block notifications, then clear
5854        // its cache. With no notifications left to repopulate it, this deterministically exercises
5855        // the RPC handler's fallback for canonical blocks whose cache entries are absent.
5856        tokio::time::timeout(Duration::from_secs(5), async {
5857            loop {
5858                if (1..=count).all(|number| api.fee_history_cache.lock().contains_key(&number)) {
5859                    break;
5860                }
5861                tokio::task::yield_now().await;
5862            }
5863        })
5864        .await
5865        .unwrap();
5866        api.fee_history_cache.lock().clear();
5867
5868        let fee_history =
5869            api.fee_history(U256::from(count), BlockNumber::Latest, vec![50.0]).await.unwrap();
5870
5871        assert_eq!(fee_history.oldest_block, 1);
5872        assert_eq!(fee_history.gas_used_ratio.len(), count as usize);
5873        assert_eq!(fee_history.blob_gas_used_ratio.len(), count as usize);
5874        assert_eq!(fee_history.base_fee_per_gas.len(), count as usize + 1);
5875        assert_eq!(fee_history.base_fee_per_blob_gas.len(), count as usize + 1);
5876        let rewards = fee_history.reward.unwrap();
5877        assert_eq!(rewards.len(), count as usize);
5878        assert!(rewards.iter().all(|reward| reward.len() == 1));
5879    }
5880
5881    #[tokio::test(flavor = "multi_thread")]
5882    async fn fee_history_rejects_invalid_reward_percentiles() {
5883        let (api, _handle) = spawn(NodeConfig::test()).await;
5884
5885        for percentiles in [vec![-0.5], vec![100.5], vec![50.0, 25.0], vec![50.0, 50.0]] {
5886            let err =
5887                api.fee_history(U256::ONE, BlockNumber::Latest, percentiles).await.unwrap_err();
5888            assert!(matches!(
5889                err,
5890                BlockchainError::FeeHistory(FeeHistoryError::InvalidRewardPercentiles)
5891            ));
5892        }
5893
5894        for percentiles in [vec![], vec![0.0, 100.0]] {
5895            api.fee_history(U256::ONE, BlockNumber::Latest, percentiles).await.unwrap();
5896        }
5897    }
5898
5899    #[test]
5900    fn fractional_reward_percentiles_use_cache_resolution() {
5901        let rewards = (0..=200).collect::<Vec<_>>();
5902
5903        assert_eq!(reward_at_percentile(&rewards, 0.0), 0);
5904        assert_eq!(reward_at_percentile(&rewards, 0.5), 1);
5905        assert_eq!(reward_at_percentile(&rewards, 1.0), 2);
5906        assert_eq!(reward_at_percentile(&rewards, 100.0), 200);
5907    }
5908
5909    #[test]
5910    fn shortened_pre_fork_fee_history_uses_upstream_start() {
5911        let requested_lowest = 4;
5912        let fork_block = 10;
5913        let pre = FeeHistory {
5914            oldest_block: 5,
5915            base_fee_per_gas: vec![1; 7],
5916            gas_used_ratio: vec![0.0; 6],
5917            reward: Some(vec![vec![]; 6]),
5918            base_fee_per_blob_gas: vec![],
5919            blob_gas_used_ratio: vec![],
5920        };
5921
5922        let mut response = FeeHistory { oldest_block: requested_lowest, ..Default::default() };
5923        let mut rewards = Vec::new();
5924
5925        merge_pre_fork_fee_history(&mut response, &mut rewards, pre, fork_block);
5926
5927        assert_eq!(response.oldest_block, 5);
5928        assert_eq!(response.gas_used_ratio.len(), 6);
5929        assert_eq!(response.base_fee_per_gas.len(), 6);
5930        assert_eq!(response.blob_gas_used_ratio.len(), 6);
5931        assert_eq!(response.base_fee_per_blob_gas.len(), 6);
5932        assert_eq!(rewards.len(), 6);
5933    }
5934}