Skip to main content

reth_rpc/eth/
core.rs

1//! Implementation of the [`jsonrpsee`] generated [`EthApiServer`](crate::EthApi) trait
2//! Handles RPC requests for the `eth_` namespace.
3
4use std::{sync::Arc, time::Duration};
5
6use crate::{eth::helpers::types::EthRpcConverter, EthApiBuilder};
7use alloy_consensus::BlockHeader;
8use alloy_eips::BlockNumberOrTag;
9use alloy_network::Ethereum;
10use alloy_primitives::{Bytes, U256};
11use alloy_rpc_client::RpcClient;
12use derive_more::Deref;
13use reth_chainspec::{ChainSpec, ChainSpecProvider};
14use reth_evm_ethereum::EthEvmConfig;
15use reth_network_api::noop::NoopNetwork;
16use reth_rpc_convert::{RpcConvert, RpcConverter};
17use reth_rpc_eth_api::{
18    helpers::{pending_block::PendingEnvBuilder, spec::SignersForRpc, SpawnBlocking},
19    node::{RpcNodeCoreAdapter, RpcNodeCoreExt},
20    EthApiTypes, RpcNodeCore,
21};
22use reth_rpc_eth_types::{
23    builder::config::PendingBlockKind, receipt::EthReceiptConverter, EthApiError, EthApiSettings,
24    EthStateCache, FeeHistoryCache, GasPriceOracle, PendingBlock,
25};
26use reth_storage_api::{noop::NoopProvider, BlockReaderIdExt, ProviderHeader};
27use reth_tasks::{
28    pool::{BlockingTaskGuard, BlockingTaskPool},
29    Runtime,
30};
31use reth_transaction_pool::{
32    blobstore::BlobSidecarConverter, noop::NoopTransactionPool, AddedTransactionOutcome,
33    BatchTxProcessor, BatchTxRequest, TransactionPool,
34};
35use tokio::sync::{broadcast, mpsc, Mutex, Semaphore};
36
37const DEFAULT_BROADCAST_CAPACITY: usize = 2000;
38
39/// `Eth` API implementation.
40///
41/// This type provides the functionality for handling `eth_` related requests.
42/// These are implemented two-fold: Core functionality is implemented as
43/// [`EthApiSpec`](reth_rpc_eth_api::helpers::EthApiSpec) trait. Additionally, the required server
44/// implementations (e.g. [`EthApiServer`](reth_rpc_eth_api::EthApiServer)) are implemented
45/// separately in submodules. The rpc handler implementation can then delegate to the main impls.
46/// This way [`EthApi`] is not limited to [`jsonrpsee`] and can be used standalone or in other
47/// network handlers (for example ipc).
48///
49/// ## Trait requirements
50///
51/// While this type requires various unrestricted generic components, trait bounds are enforced when
52/// additional traits are implemented for this type.
53#[derive(Deref)]
54pub struct EthApi<N: RpcNodeCore, Rpc: RpcConvert> {
55    /// All nested fields bundled together.
56    #[deref]
57    pub(super) inner: Arc<EthApiInner<N, Rpc>>,
58}
59
60impl<N, Rpc> Clone for EthApi<N, Rpc>
61where
62    N: RpcNodeCore,
63    Rpc: RpcConvert,
64{
65    fn clone(&self) -> Self {
66        Self { inner: self.inner.clone() }
67    }
68}
69
70impl
71    EthApi<
72        RpcNodeCoreAdapter<NoopProvider, NoopTransactionPool, NoopNetwork, EthEvmConfig>,
73        EthRpcConverter<ChainSpec>,
74    >
75{
76    /// Convenience fn to obtain a new [`EthApiBuilder`] instance with mandatory components.
77    ///
78    /// Creating an [`EthApi`] requires a few mandatory components:
79    ///  - provider: The type responsible for fetching requested data from disk.
80    ///  - transaction pool: To interact with the pool, submitting new transactions (e.g.
81    ///    `eth_sendRawTransactions`).
82    ///  - network: required to handle requests related to network state (e.g. `eth_syncing`).
83    ///  - evm config: Knows how create a new EVM instance to transact,estimate,call,trace.
84    ///
85    /// # Create an instance with noop ethereum implementations
86    ///
87    /// ```no_run
88    /// use alloy_network::Ethereum;
89    /// use reth_evm_ethereum::EthEvmConfig;
90    /// use reth_network_api::noop::NoopNetwork;
91    /// use reth_provider::noop::NoopProvider;
92    /// use reth_rpc::EthApi;
93    /// use reth_transaction_pool::noop::NoopTransactionPool;
94    /// let eth_api = EthApi::builder(
95    ///     NoopProvider::default(),
96    ///     NoopTransactionPool::default(),
97    ///     NoopNetwork::default(),
98    ///     EthEvmConfig::mainnet(),
99    /// )
100    /// .build();
101    /// ```
102    #[expect(clippy::type_complexity)]
103    pub fn builder<Provider, Pool, Network, EvmConfig, ChainSpec>(
104        provider: Provider,
105        pool: Pool,
106        network: Network,
107        evm_config: EvmConfig,
108    ) -> EthApiBuilder<
109        RpcNodeCoreAdapter<Provider, Pool, Network, EvmConfig>,
110        RpcConverter<Ethereum, EvmConfig, EthReceiptConverter<ChainSpec>>,
111    >
112    where
113        RpcNodeCoreAdapter<Provider, Pool, Network, EvmConfig>:
114            RpcNodeCore<Provider: ChainSpecProvider<ChainSpec = ChainSpec>, Evm = EvmConfig>,
115    {
116        EthApiBuilder::new(provider, pool, network, evm_config)
117    }
118}
119
120impl<N, Rpc> EthApiTypes for EthApi<N, Rpc>
121where
122    N: RpcNodeCore,
123    Rpc: RpcConvert<Error = EthApiError>,
124{
125    type Error = EthApiError;
126    type NetworkTypes = Rpc::Network;
127    type RpcConvert = Rpc;
128
129    fn eth_api_settings(&self) -> &EthApiSettings {
130        self.inner.eth_api_settings()
131    }
132
133    fn converter(&self) -> &Self::RpcConvert {
134        &self.converter
135    }
136}
137
138impl<N, Rpc> RpcNodeCore for EthApi<N, Rpc>
139where
140    N: RpcNodeCore,
141    Rpc: RpcConvert,
142{
143    type Primitives = N::Primitives;
144    type Provider = N::Provider;
145    type Pool = N::Pool;
146    type Evm = N::Evm;
147    type Network = N::Network;
148
149    fn pool(&self) -> &Self::Pool {
150        self.inner.pool()
151    }
152
153    fn evm_config(&self) -> &Self::Evm {
154        self.inner.evm_config()
155    }
156
157    fn network(&self) -> &Self::Network {
158        self.inner.network()
159    }
160
161    fn provider(&self) -> &Self::Provider {
162        self.inner.provider()
163    }
164}
165
166impl<N, Rpc> RpcNodeCoreExt for EthApi<N, Rpc>
167where
168    N: RpcNodeCore,
169    Rpc: RpcConvert,
170{
171    #[inline]
172    fn cache(&self) -> &EthStateCache<N::Primitives> {
173        self.inner.cache()
174    }
175}
176
177impl<N, Rpc> std::fmt::Debug for EthApi<N, Rpc>
178where
179    N: RpcNodeCore,
180    Rpc: RpcConvert,
181{
182    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
183        f.debug_struct("EthApi").finish_non_exhaustive()
184    }
185}
186
187impl<N, Rpc> SpawnBlocking for EthApi<N, Rpc>
188where
189    N: RpcNodeCore,
190    Rpc: RpcConvert<Error = EthApiError>,
191{
192    #[inline]
193    fn io_task_spawner(&self) -> &Runtime {
194        self.inner.task_spawner()
195    }
196
197    #[inline]
198    fn tracing_task_pool(&self) -> &BlockingTaskPool {
199        self.inner.blocking_task_pool()
200    }
201
202    #[inline]
203    fn tracing_task_guard(&self) -> &BlockingTaskGuard {
204        self.inner.blocking_task_guard()
205    }
206
207    #[inline]
208    fn blocking_io_task_guard(&self) -> &std::sync::Arc<tokio::sync::Semaphore> {
209        self.inner.blocking_io_request_semaphore()
210    }
211}
212
213/// Container type `EthApi`
214#[expect(missing_debug_implementations)]
215pub struct EthApiInner<N: RpcNodeCore, Rpc: RpcConvert> {
216    /// The components of the node.
217    components: N,
218    /// All configured Signers
219    signers: SignersForRpc<N::Provider, Rpc::Network>,
220    /// The async cache frontend for eth related data
221    eth_cache: EthStateCache<N::Primitives>,
222    /// The async gas oracle frontend for gas price suggestions
223    gas_oracle: GasPriceOracle<N::Provider>,
224    /// Settings shared by the `eth` RPC helpers.
225    settings: EthApiSettings,
226    /// The block number at which the node started
227    starting_block: U256,
228    /// The type that can spawn tasks which would otherwise block.
229    task_spawner: Runtime,
230    /// Cached pending block if any
231    pending_block: Mutex<Option<PendingBlock<N::Primitives>>>,
232    /// A pool dedicated to CPU heavy blocking tasks.
233    blocking_task_pool: BlockingTaskPool,
234    /// Cache for block fees history
235    fee_history_cache: FeeHistoryCache<ProviderHeader<N::Provider>>,
236
237    /// Guard for getproof calls
238    blocking_task_guard: BlockingTaskGuard,
239
240    /// Semaphore to limit concurrent blocking IO requests (`eth_call`, `eth_estimateGas`, etc.)
241    blocking_io_request_semaphore: Arc<Semaphore>,
242
243    /// Transaction broadcast channel
244    raw_tx_sender: broadcast::Sender<Bytes>,
245
246    /// Raw transaction forwarder
247    raw_tx_forwarder: Option<RpcClient>,
248
249    /// Converter for RPC types.
250    converter: Rpc,
251
252    /// Builder for pending block environment.
253    next_env_builder: Box<dyn PendingEnvBuilder<N::Evm>>,
254
255    /// Transaction batch sender for batching tx insertions
256    tx_batch_sender:
257        mpsc::UnboundedSender<BatchTxRequest<<N::Pool as TransactionPool>::Transaction>>,
258
259    /// Blob sidecar converter
260    blob_sidecar_converter: BlobSidecarConverter,
261}
262
263impl<N, Rpc> EthApiInner<N, Rpc>
264where
265    N: RpcNodeCore,
266    Rpc: RpcConvert,
267{
268    /// Creates a new, shareable instance using the default tokio task spawner.
269    #[expect(clippy::too_many_arguments)]
270    pub fn new(
271        components: N,
272        eth_cache: EthStateCache<N::Primitives>,
273        gas_oracle: GasPriceOracle<N::Provider>,
274        settings: EthApiSettings,
275        blocking_task_pool: BlockingTaskPool,
276        fee_history_cache: FeeHistoryCache<ProviderHeader<N::Provider>>,
277        task_spawner: Runtime,
278        converter: Rpc,
279        next_env: impl PendingEnvBuilder<N::Evm>,
280        raw_tx_forwarder: Option<RpcClient>,
281    ) -> Self {
282        let signers = parking_lot::RwLock::new(Default::default());
283        // get the block number of the latest block
284        let starting_block = U256::from(
285            components
286                .provider()
287                .header_by_number_or_tag(BlockNumberOrTag::Latest)
288                .ok()
289                .flatten()
290                .map(|header| header.number())
291                .unwrap_or_default(),
292        );
293
294        let (raw_tx_sender, _) = broadcast::channel(DEFAULT_BROADCAST_CAPACITY);
295
296        // Create tx pool insertion batcher
297        let (processor, tx_batch_sender) =
298            BatchTxProcessor::new(components.pool().clone(), settings.max_batch_size);
299        task_spawner.spawn_critical_task("tx-batcher", processor);
300
301        Self {
302            components,
303            signers,
304            eth_cache,
305            gas_oracle,
306            starting_block,
307            task_spawner,
308            pending_block: Default::default(),
309            blocking_task_pool,
310            fee_history_cache,
311            blocking_task_guard: BlockingTaskGuard::new(settings.proof_permits),
312            blocking_io_request_semaphore: Arc::new(Semaphore::new(
313                settings.max_blocking_io_requests,
314            )),
315            settings,
316            raw_tx_sender,
317            raw_tx_forwarder,
318            converter,
319            next_env_builder: Box::new(next_env),
320            tx_batch_sender,
321            blob_sidecar_converter: BlobSidecarConverter::new(),
322        }
323    }
324}
325
326impl<N, Rpc> EthApiInner<N, Rpc>
327where
328    N: RpcNodeCore,
329    Rpc: RpcConvert,
330{
331    /// Returns a handle to data on disk.
332    #[inline]
333    pub fn provider(&self) -> &N::Provider {
334        self.components.provider()
335    }
336
337    /// Returns a handle to the transaction response builder.
338    #[inline]
339    pub const fn converter(&self) -> &Rpc {
340        &self.converter
341    }
342
343    /// Returns a handle to data in memory.
344    #[inline]
345    pub const fn cache(&self) -> &EthStateCache<N::Primitives> {
346        &self.eth_cache
347    }
348
349    /// Returns a handle to the pending block.
350    #[inline]
351    pub const fn pending_block(&self) -> &Mutex<Option<PendingBlock<N::Primitives>>> {
352        &self.pending_block
353    }
354
355    /// Returns a type that knows how to build a [`reth_evm::ConfigureEvm::NextBlockEnvCtx`] for a
356    /// pending block.
357    #[inline]
358    pub const fn pending_env_builder(&self) -> &dyn PendingEnvBuilder<N::Evm> {
359        &*self.next_env_builder
360    }
361
362    /// Returns a handle to the task spawner.
363    #[inline]
364    pub const fn task_spawner(&self) -> &Runtime {
365        &self.task_spawner
366    }
367
368    /// Returns a handle to the blocking thread pool.
369    ///
370    /// This is intended for tasks that are CPU bound.
371    #[inline]
372    pub const fn blocking_task_pool(&self) -> &BlockingTaskPool {
373        &self.blocking_task_pool
374    }
375
376    /// Returns a handle to the EVM config.
377    #[inline]
378    pub fn evm_config(&self) -> &N::Evm {
379        self.components.evm_config()
380    }
381
382    /// Returns a handle to the transaction pool.
383    #[inline]
384    pub fn pool(&self) -> &N::Pool {
385        self.components.pool()
386    }
387
388    /// Returns the settings shared by the `eth` RPC helpers.
389    #[inline]
390    pub const fn eth_api_settings(&self) -> &EthApiSettings {
391        &self.settings
392    }
393
394    /// Returns the gas cap.
395    #[inline]
396    pub const fn gas_cap(&self) -> u64 {
397        self.settings.gas_cap
398    }
399
400    /// Returns the `max_simulate_blocks`.
401    #[inline]
402    pub const fn max_simulate_blocks(&self) -> u64 {
403        self.settings.max_simulate_blocks
404    }
405
406    /// Returns whether state roots are computed for `eth_simulateV1`.
407    #[inline]
408    pub const fn compute_state_root_for_eth_simulate(&self) -> bool {
409        self.settings.compute_state_root_for_eth_simulate
410    }
411
412    /// Returns a handle to the gas oracle.
413    #[inline]
414    pub const fn gas_oracle(&self) -> &GasPriceOracle<N::Provider> {
415        &self.gas_oracle
416    }
417
418    /// Returns a handle to the fee history cache.
419    #[inline]
420    pub const fn fee_history_cache(&self) -> &FeeHistoryCache<ProviderHeader<N::Provider>> {
421        &self.fee_history_cache
422    }
423
424    /// Returns a handle to the signers.
425    #[inline]
426    pub const fn signers(&self) -> &SignersForRpc<N::Provider, Rpc::Network> {
427        &self.signers
428    }
429
430    /// Returns the starting block.
431    #[inline]
432    pub const fn starting_block(&self) -> U256 {
433        self.starting_block
434    }
435
436    /// Returns the inner `Network`
437    #[inline]
438    pub fn network(&self) -> &N::Network {
439        self.components.network()
440    }
441
442    /// The maximum number of blocks into the past for generating state proofs.
443    #[inline]
444    pub const fn eth_proof_window(&self) -> u64 {
445        self.settings.eth_proof_window
446    }
447
448    /// Returns reference to [`BlockingTaskGuard`].
449    #[inline]
450    pub const fn blocking_task_guard(&self) -> &BlockingTaskGuard {
451        &self.blocking_task_guard
452    }
453
454    /// Returns [`broadcast::Receiver`] of new raw transactions
455    #[inline]
456    pub fn subscribe_to_raw_transactions(&self) -> broadcast::Receiver<Bytes> {
457        self.raw_tx_sender.subscribe()
458    }
459
460    /// Broadcasts raw transaction if there are active subscribers.
461    #[inline]
462    pub fn broadcast_raw_transaction(&self, raw_tx: Bytes) {
463        let _ = self.raw_tx_sender.send(raw_tx);
464    }
465
466    /// Returns the transaction batch sender
467    #[inline]
468    pub const fn tx_batch_sender(
469        &self,
470    ) -> &mpsc::UnboundedSender<BatchTxRequest<<N::Pool as TransactionPool>::Transaction>> {
471        &self.tx_batch_sender
472    }
473
474    /// Adds an _unvalidated_ transaction into the pool via the transaction batch sender.
475    #[inline]
476    pub async fn add_pool_transaction(
477        &self,
478        origin: reth_transaction_pool::TransactionOrigin,
479        transaction: <N::Pool as TransactionPool>::Transaction,
480    ) -> Result<AddedTransactionOutcome, EthApiError> {
481        let (response_tx, response_rx) = tokio::sync::oneshot::channel();
482        let request = reth_transaction_pool::BatchTxRequest::new(origin, transaction, response_tx);
483
484        self.tx_batch_sender()
485            .send(request)
486            .map_err(|_| reth_rpc_eth_types::EthApiError::BatchTxSendError)?;
487
488        Ok(response_rx.await??)
489    }
490
491    /// Returns the pending block kind
492    #[inline]
493    pub const fn pending_block_kind(&self) -> PendingBlockKind {
494        self.settings.pending_block_kind
495    }
496
497    /// Returns a handle to the raw transaction forwarder.
498    #[inline]
499    pub const fn raw_tx_forwarder(&self) -> Option<&RpcClient> {
500        self.raw_tx_forwarder.as_ref()
501    }
502
503    /// Returns the timeout duration for `send_raw_transaction_sync` RPC method.
504    #[inline]
505    pub const fn send_raw_transaction_sync_timeout(&self) -> Duration {
506        self.settings.send_raw_transaction_sync_timeout
507    }
508
509    /// Returns a handle to the blob sidecar converter.
510    #[inline]
511    pub const fn blob_sidecar_converter(&self) -> &BlobSidecarConverter {
512        &self.blob_sidecar_converter
513    }
514
515    /// Returns the EVM memory limit.
516    #[inline]
517    pub const fn evm_memory_limit(&self) -> u64 {
518        self.settings.evm_memory_limit
519    }
520
521    /// Returns a reference to the blocking IO request semaphore.
522    #[inline]
523    pub const fn blocking_io_request_semaphore(&self) -> &Arc<Semaphore> {
524        &self.blocking_io_request_semaphore
525    }
526
527    /// Returns whether to force upcasting EIP-4844 blob sidecars to EIP-7594 format.
528    #[inline]
529    pub const fn force_blob_sidecar_upcasting(&self) -> bool {
530        self.settings.force_blob_sidecar_upcasting
531    }
532}
533
534#[cfg(test)]
535mod tests {
536    use super::*;
537    use alloy_consensus::{Block, BlockBody, Header};
538    use alloy_eips::{
539        eip4844::DATA_GAS_PER_BLOB, eip7702::Authorization, BlockId, BlockNumberOrTag,
540    };
541    use alloy_genesis::{Genesis, GenesisAccount};
542    use alloy_network::TransactionBuilder;
543    use alloy_primitives::{Address, Bytes, Signature, B256, U256, U64};
544    use alloy_rpc_types::FeeHistory;
545    use alloy_rpc_types_eth::{
546        simulate::{SimBlock, SimulatePayload},
547        state::{AccountOverride, EvmOverrides, StateOverride},
548        BlockOverrides, Bundle, TransactionRequest,
549    };
550    use alloy_rpc_types_trace::{parity::TraceType, tracerequest::TraceCallRequest};
551    use evm2::{evm::CacheDB, AccountInfo};
552    use jsonrpsee_types::error::INVALID_PARAMS_CODE;
553    use rand::Rng;
554    use reth_chain_state::CanonStateSubscriptions;
555    use reth_chainspec::{ChainSpec, ChainSpecBuilder, ChainSpecProvider, EthChainSpec};
556    use reth_db_common::init::init_genesis;
557    use reth_ethereum_primitives::TransactionSigned;
558    use reth_evm::{ConfigureEvm, EvmEnvFor, TxEnvFor};
559    use reth_evm_ethereum::EthEvmConfig;
560    use reth_network_api::noop::NoopNetwork;
561    use reth_primitives_traits::{
562        crypto::secp256k1::sign_message, SealedHeader, SignerRecoverable,
563    };
564    use reth_provider::{
565        providers::BlockchainProvider,
566        test_utils::{
567            create_test_provider_factory_with_chain_spec, ExtendedAccount, MockEthProvider,
568            NoopProvider,
569        },
570        PruneCheckpointReader, StageCheckpointReader,
571    };
572    use reth_rpc_convert::{EthTxEnvError, TryIntoTxEnv};
573    use reth_rpc_eth_api::{
574        helpers::{Call, EthBlocks, EthCall, EthTransactions, LoadPendingBlock, SpawnBlocking},
575        node::RpcNodeCoreAdapter,
576        EthApiServer,
577    };
578    use reth_rpc_eth_types::{receipt::EthReceiptConverter, EthConfig, RpcInvalidTransactionError};
579    use reth_rpc_server_types::constants::DEFAULT_MAX_CALL_MANY_CALLS;
580    use reth_storage_api::{
581        BalProvider, BlockReaderIdExt, NodePrimitivesProvider, StateProviderFactory,
582    };
583    use reth_tasks::cancel::{is_cancelled, CancelOnDrop};
584    use reth_testing_utils::generators;
585    use reth_transaction_pool::test_utils::{testing_pool, MockTransaction, TestPool};
586    use std::time::{Duration, Instant};
587
588    type FakeEthApi<P = MockEthProvider> = EthApi<
589        RpcNodeCoreAdapter<P, TestPool, NoopNetwork, EthEvmConfig>,
590        EthRpcConverter<ChainSpec>,
591    >;
592
593    fn build_test_eth_api<
594        P: BlockReaderIdExt<
595                Block = reth_ethereum_primitives::Block,
596                Receipt = reth_ethereum_primitives::Receipt,
597                Header = alloy_consensus::Header,
598                Transaction = reth_ethereum_primitives::TransactionSigned,
599            > + ChainSpecProvider<ChainSpec = ChainSpec>
600            + StateProviderFactory<Primitives = reth_ethereum_primitives::EthPrimitives>
601            + NodePrimitivesProvider<Primitives = reth_ethereum_primitives::EthPrimitives>
602            + CanonStateSubscriptions<Primitives = reth_ethereum_primitives::EthPrimitives>
603            + StageCheckpointReader
604            + PruneCheckpointReader
605            + BalProvider
606            + Unpin
607            + Clone
608            + 'static,
609    >(
610        provider: P,
611    ) -> FakeEthApi<P> {
612        EthApiBuilder::new(
613            provider.clone(),
614            testing_pool(),
615            NoopNetwork::default(),
616            EthEvmConfig::new(provider.chain_spec()),
617        )
618        .build()
619    }
620
621    fn build_test_eth_api_with_gas_cap(provider: MockEthProvider, gas_cap: u64) -> FakeEthApi {
622        EthApiBuilder::new(
623            provider.clone(),
624            testing_pool(),
625            NoopNetwork::default(),
626            EthEvmConfig::new(provider.chain_spec()),
627        )
628        .gas_cap(gas_cap.into())
629        .build()
630    }
631
632    #[tokio::test(flavor = "multi_thread")]
633    async fn blocking_task_observes_dropped_request() {
634        let api = build_test_eth_api(MockEthProvider::default());
635        let (started_tx, started_rx) = tokio::sync::oneshot::channel();
636        let (cancelled_tx, cancelled_rx) = tokio::sync::oneshot::channel();
637
638        let request = api.spawn_blocking_io(move |_| {
639            let _ = started_tx.send(());
640            let deadline = Instant::now() + Duration::from_secs(5);
641            while !is_cancelled() && Instant::now() < deadline {
642                std::thread::sleep(Duration::from_millis(1));
643            }
644            let _ = cancelled_tx.send(is_cancelled());
645            Ok(())
646        });
647        // drop the request while its blocking task is running
648        tokio::select! {
649            _ = request => panic!("blocking task completed before the request was dropped"),
650            _ = started_rx => {}
651        }
652
653        assert!(cancelled_rx.await.unwrap());
654    }
655
656    #[tokio::test(flavor = "multi_thread")]
657    async fn pending_block_build_stops_when_cancelled() {
658        let provider = MockEthProvider::default();
659        let parent =
660            Header { gas_limit: 30_000_000, base_fee_per_gas: Some(1), ..Default::default() };
661        let parent_hash = B256::random();
662        provider.add_header(parent_hash, parent.clone());
663        let api = build_test_eth_api(provider);
664        api.pool().add_external_transaction(MockTransaction::eip1559()).await.unwrap();
665
666        // dropping the request's handle cancels the build running in its scope
667        let request = CancelOnDrop::default();
668        let scope = request.clone();
669        drop(request);
670
671        let parent = SealedHeader::new(parent, parent_hash);
672        let err = scope.scope(|| api.build_block(&parent)).unwrap_err();
673        assert!(matches!(err, EthApiError::InternalEthError));
674    }
675
676    #[tokio::test]
677    async fn test_transaction_by_sender_and_nonce_without_sender_transaction_returns_none() {
678        let provider = MockEthProvider::default();
679        let sender = Address::random();
680        provider.add_account(sender, ExtendedAccount::new(1, U256::ZERO));
681
682        let block_hash = B256::random();
683        provider.add_block(
684            block_hash,
685            Block {
686                header: Header { number: 1, ..Default::default() },
687                body: BlockBody::default(),
688            },
689        );
690
691        let api = build_test_eth_api(provider);
692        let transaction =
693            EthTransactions::get_transaction_by_sender_and_nonce(&api, sender, 0, false)
694                .await
695                .expect("existing block without a sender transaction should not be a header error");
696
697        assert!(transaction.is_none());
698    }
699
700    #[tokio::test]
701    async fn test_transaction_by_sender_and_nonce_missing_block_returns_error() {
702        use reth_rpc_eth_types::EthApiError;
703
704        let provider = MockEthProvider::default();
705        let sender = Address::random();
706        provider.add_account(sender, ExtendedAccount::new(1, U256::ZERO));
707        provider.add_header(B256::random(), Header { number: 1, ..Default::default() });
708
709        let api = build_test_eth_api(provider);
710        let error = EthTransactions::get_transaction_by_sender_and_nonce(&api, sender, 0, false)
711            .await
712            .unwrap_err();
713
714        assert!(matches!(error, EthApiError::HeaderNotFound(id) if id == 1.into()));
715    }
716
717    #[tokio::test]
718    async fn test_transaction_by_sender_and_nonce_returns_matching_transaction() {
719        let provider = MockEthProvider::default();
720        let tx = TransactionSigned::new_unhashed(
721            reth_ethereum_primitives::Transaction::Legacy(Default::default()),
722            Signature::test_signature(),
723        );
724        let sender = tx.recover_signer().unwrap();
725        provider.add_account(sender, ExtendedAccount::new(1, U256::ZERO));
726        let block = Block {
727            header: Header { number: 1, ..Default::default() },
728            body: BlockBody { transactions: vec![tx], ..Default::default() },
729        };
730        let block_hash = block.header.hash_slow();
731        provider.add_block(block_hash, block);
732
733        let api = build_test_eth_api(provider);
734        let transaction =
735            EthTransactions::get_transaction_by_sender_and_nonce(&api, sender, 0, false)
736                .await
737                .unwrap()
738                .expect("matching transaction should be returned");
739
740        assert_eq!(transaction.block_hash, Some(block_hash));
741        assert_eq!(transaction.block_number, Some(1));
742        assert_eq!(transaction.transaction_index, Some(0));
743        assert_eq!(transaction.inner.signer(), sender);
744    }
745
746    #[tokio::test]
747    async fn test_eth_api_settings() {
748        use reth_rpc_eth_api::{
749            helpers::{Call, EthState, EthTransactions, LoadPendingBlock},
750            EthApiTypes,
751        };
752        use reth_rpc_eth_types::{builder::config::PendingBlockKind, EthApiSettings};
753        use std::time::Duration;
754
755        fn settings(api: &impl EthApiTypes) -> &EthApiSettings {
756            api.eth_api_settings()
757        }
758
759        fn assert_settings(actual: &EthApiSettings, expected: &EthApiSettings) {
760            assert_eq!(actual.proof_permits, expected.proof_permits);
761            assert_eq!(actual.max_batch_size, expected.max_batch_size);
762            assert_eq!(actual.max_blocking_io_requests, expected.max_blocking_io_requests);
763            assert_eq!(actual.cache_computed_bals, expected.cache_computed_bals);
764            assert_eq!(actual.gas_cap, expected.gas_cap);
765            assert_eq!(actual.max_simulate_blocks, expected.max_simulate_blocks);
766            assert_eq!(
767                actual.compute_state_root_for_eth_simulate,
768                expected.compute_state_root_for_eth_simulate
769            );
770            assert_eq!(actual.eth_proof_window, expected.eth_proof_window);
771            assert_eq!(actual.pending_block_kind, expected.pending_block_kind);
772            assert_eq!(
773                actual.send_raw_transaction_sync_timeout,
774                expected.send_raw_transaction_sync_timeout
775            );
776            assert_eq!(actual.evm_memory_limit, expected.evm_memory_limit);
777            assert_eq!(actual.force_blob_sidecar_upcasting, expected.force_blob_sidecar_upcasting);
778            assert_eq!(
779                actual.sender_recovery_cache.is_some(),
780                expected.sender_recovery_cache.is_some()
781            );
782        }
783
784        let default_api = build_test_eth_api(MockEthProvider::default());
785        assert_settings(settings(&default_api), &EthApiSettings::default());
786
787        let expected = EthApiSettings {
788            sender_recovery_cache: Some(reth_evm::SenderRecoveryCache::new(16)),
789            proof_permits: 3,
790            max_batch_size: 5,
791            max_blocking_io_requests: 7,
792            cache_computed_bals: true,
793            gas_cap: 123_456,
794            max_simulate_blocks: 7,
795            compute_state_root_for_eth_simulate: true,
796            eth_proof_window: 42,
797            pending_block_kind: PendingBlockKind::Empty,
798            send_raw_transaction_sync_timeout: Duration::from_secs(9),
799            evm_memory_limit: 1 << 20,
800            force_blob_sidecar_upcasting: true,
801        };
802        let api = EthApiBuilder::new(
803            MockEthProvider::default(),
804            testing_pool(),
805            NoopNetwork::default(),
806            EthEvmConfig::mainnet(),
807        )
808        .eth_state_cache_config(reth_rpc_eth_types::EthStateCacheConfig {
809            cache_computed_bals: true,
810            ..Default::default()
811        })
812        .sender_recovery_cache(expected.sender_recovery_cache.clone())
813        .proof_permits(expected.proof_permits)
814        .max_batch_size(expected.max_batch_size)
815        .max_blocking_io_requests(expected.max_blocking_io_requests)
816        .gas_cap(expected.gas_cap.into())
817        .max_simulate_blocks(expected.max_simulate_blocks)
818        .compute_state_root_for_eth_simulate(expected.compute_state_root_for_eth_simulate)
819        .eth_proof_window(expected.eth_proof_window)
820        .pending_block_kind(expected.pending_block_kind)
821        .send_raw_transaction_sync_timeout(expected.send_raw_transaction_sync_timeout)
822        .evm_memory_limit(expected.evm_memory_limit)
823        .force_blob_sidecar_upcasting(expected.force_blob_sidecar_upcasting)
824        .build();
825
826        assert_settings(settings(&api), &expected);
827        assert_eq!(
828            api.inner.blocking_io_request_semaphore().available_permits(),
829            expected.max_blocking_io_requests
830        );
831        assert_eq!(Call::call_gas_limit(&api), expected.gas_cap);
832        assert_eq!(Call::max_simulate_blocks(&api), expected.max_simulate_blocks);
833        assert_eq!(
834            Call::compute_state_root_for_eth_simulate(&api),
835            expected.compute_state_root_for_eth_simulate
836        );
837        assert_eq!(Call::evm_memory_limit(&api), expected.evm_memory_limit);
838        assert_eq!(EthState::max_proof_window(&api), expected.eth_proof_window);
839        assert_eq!(LoadPendingBlock::pending_block_kind(&api), expected.pending_block_kind);
840        assert_eq!(
841            EthTransactions::send_raw_transaction_sync_timeout(&api),
842            expected.send_raw_transaction_sync_timeout
843        );
844        assert_eq!(api.inner.gas_cap(), expected.gas_cap);
845        assert_eq!(api.inner.max_simulate_blocks(), expected.max_simulate_blocks);
846        assert_eq!(
847            api.inner.compute_state_root_for_eth_simulate(),
848            expected.compute_state_root_for_eth_simulate
849        );
850        assert_eq!(api.inner.eth_proof_window(), expected.eth_proof_window);
851        assert_eq!(api.inner.pending_block_kind(), expected.pending_block_kind);
852        assert_eq!(
853            api.inner.send_raw_transaction_sync_timeout(),
854            expected.send_raw_transaction_sync_timeout
855        );
856        assert_eq!(api.inner.evm_memory_limit(), expected.evm_memory_limit);
857        assert_eq!(api.inner.force_blob_sidecar_upcasting(), expected.force_blob_sidecar_upcasting);
858        assert!(std::ptr::eq(settings(&api), settings(&api.clone())));
859    }
860
861    // Function to prepare the EthApi with mock data
862    fn prepare_eth_api(
863        newest_block: u64,
864        mut oldest_block: Option<B256>,
865        block_count: u64,
866        mock_provider: MockEthProvider,
867    ) -> (FakeEthApi, Vec<u128>, Vec<f64>) {
868        let mut rng = generators::rng();
869
870        // Build mock data
871        let mut gas_used_ratios = Vec::with_capacity(block_count as usize);
872        let mut base_fees_per_gas = Vec::with_capacity(block_count as usize);
873        let mut last_header = None;
874        let mut parent_hash = B256::default();
875
876        for i in (0..block_count).rev() {
877            let hash = rng.random();
878            // Note: Generates saner values to avoid invalid overflows later
879            let gas_limit = rng.random::<u32>() as u64;
880            let base_fee_per_gas: Option<u64> =
881                rng.random::<bool>().then(|| rng.random::<u32>() as u64);
882            let gas_used = rng.random::<u32>() as u64;
883
884            let header = Header {
885                number: newest_block - i,
886                gas_limit,
887                gas_used,
888                base_fee_per_gas,
889                parent_hash,
890                ..Default::default()
891            };
892            last_header = Some(header.clone());
893            parent_hash = hash;
894
895            const TOTAL_TRANSACTIONS: usize = 100;
896            let mut transactions = Vec::with_capacity(TOTAL_TRANSACTIONS);
897            for _ in 0..TOTAL_TRANSACTIONS {
898                let random_fee: u128 = rng.random();
899
900                if let Some(base_fee_per_gas) = header.base_fee_per_gas {
901                    let transaction = TransactionSigned::new_unhashed(
902                        reth_ethereum_primitives::Transaction::Eip1559(
903                            alloy_consensus::TxEip1559 {
904                                max_priority_fee_per_gas: random_fee,
905                                max_fee_per_gas: random_fee + base_fee_per_gas as u128,
906                                ..Default::default()
907                            },
908                        ),
909                        Signature::test_signature(),
910                    );
911
912                    transactions.push(transaction);
913                } else {
914                    let transaction = TransactionSigned::new_unhashed(
915                        reth_ethereum_primitives::Transaction::Legacy(Default::default()),
916                        Signature::test_signature(),
917                    );
918
919                    transactions.push(transaction);
920                }
921            }
922
923            mock_provider.add_block(
924                hash,
925                Block {
926                    header: header.clone(),
927                    body: BlockBody { transactions, ..Default::default() },
928                },
929            );
930            mock_provider.add_header(hash, header);
931
932            oldest_block.get_or_insert(hash);
933            gas_used_ratios.push(gas_used as f64 / gas_limit as f64);
934            base_fees_per_gas.push(base_fee_per_gas.map(|fee| fee as u128).unwrap_or_default());
935        }
936
937        // Add final base fee (for the next block outside of the request)
938        let last_header = last_header.unwrap();
939        let spec = mock_provider.chain_spec();
940        base_fees_per_gas.push(
941            spec.next_block_base_fee(&last_header, last_header.timestamp).unwrap_or_default()
942                as u128,
943        );
944
945        let eth_api = build_test_eth_api(mock_provider);
946
947        (eth_api, base_fees_per_gas, gas_used_ratios)
948    }
949
950    /// Invalid block range
951    #[tokio::test]
952    async fn test_fee_history_empty() {
953        let response = <EthApi<_, _> as EthApiServer<_, _, _, _, _, _>>::fee_history(
954            &build_test_eth_api(NoopProvider::default()),
955            U64::from(1),
956            BlockNumberOrTag::Latest,
957            None,
958        )
959        .await;
960        assert!(response.is_err());
961        let error_object = response.unwrap_err();
962        assert_eq!(error_object.code(), INVALID_PARAMS_CODE);
963    }
964
965    #[tokio::test]
966    /// Invalid block range (request is before genesis)
967    async fn test_fee_history_invalid_block_range_before_genesis() {
968        let block_count = 10;
969        let newest_block = 1337;
970        let oldest_block = None;
971
972        let (eth_api, _, _) =
973            prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default());
974
975        let response = <EthApi<_, _> as EthApiServer<_, _, _, _, _, _>>::fee_history(
976            &eth_api,
977            U64::from(newest_block + 1),
978            newest_block.into(),
979            Some(vec![10.0]),
980        )
981        .await;
982
983        assert!(response.is_err());
984        let error_object = response.unwrap_err();
985        assert_eq!(error_object.code(), INVALID_PARAMS_CODE);
986    }
987
988    #[tokio::test]
989    /// Invalid block range (request is in the future)
990    async fn test_fee_history_invalid_block_range_in_future() {
991        let block_count = 10;
992        let newest_block = 1337;
993        let oldest_block = None;
994
995        let (eth_api, _, _) =
996            prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default());
997
998        let response = <EthApi<_, _> as EthApiServer<_, _, _, _, _, _>>::fee_history(
999            &eth_api,
1000            U64::from(1),
1001            (newest_block + 1000).into(),
1002            Some(vec![10.0]),
1003        )
1004        .await;
1005
1006        assert!(response.is_err());
1007        let error_object = response.unwrap_err();
1008        assert_eq!(error_object.code(), INVALID_PARAMS_CODE);
1009    }
1010
1011    #[tokio::test]
1012    async fn test_call_many_maps_provider_block_lookup_error_with_eth_api_conversion() {
1013        let eth_api = build_test_eth_api(MockEthProvider::default());
1014        let bundles = vec![Bundle {
1015            transactions: vec![TransactionRequest::default()],
1016            block_override: None,
1017        }];
1018
1019        let response = <EthApi<_, _> as EthApiServer<_, _, _, _, _, _>>::call_many(
1020            &eth_api, bundles, None, None,
1021        )
1022        .await;
1023
1024        let err = response.expect_err("call_many should fail when latest block lookup errors");
1025        let message = err.message().to_ascii_lowercase();
1026        assert!(
1027            message.contains("block not found"),
1028            "best block lookup should map via EthApiError::from(ProviderError): {message}"
1029        );
1030        assert!(
1031            !message.contains("best block does not exist"),
1032            "provider implementation detail should not leak from converted error: {message}"
1033        );
1034    }
1035
1036    #[tokio::test]
1037    async fn test_call_many_keeps_header_not_found_when_block_hash_absent() {
1038        let eth_api = build_test_eth_api(NoopProvider::default());
1039        let bundles = vec![Bundle {
1040            transactions: vec![TransactionRequest::default()],
1041            block_override: None,
1042        }];
1043
1044        let response = <EthApi<_, _> as EthApiServer<_, _, _, _, _, _>>::call_many(
1045            &eth_api, bundles, None, None,
1046        )
1047        .await;
1048
1049        let err =
1050            response.expect_err("call_many should fail when latest block hash is unavailable");
1051        let message = err.message().to_ascii_lowercase();
1052        assert!(
1053            message.contains("block not found"),
1054            "missing block hash should still map to block-not-found: {message}"
1055        );
1056    }
1057
1058    #[tokio::test]
1059    async fn call_many_methods_limit_calls_and_share_gas_cap() {
1060        let provider = MockEthProvider::default();
1061        let header = Header { number: 1, gas_limit: 30_000_000, ..Default::default() };
1062        provider.add_block(header.hash_slow(), Block { header, body: BlockBody::default() });
1063        // Loops until it runs out of gas.
1064        let looping = Address::with_last_byte(0x43);
1065        provider.add_account(
1066            looping,
1067            ExtendedAccount::new(0, U256::ZERO).with_bytecode(alloy_primitives::bytes!("5b600056")),
1068        );
1069        // A transfer to an empty account uses 21_000 gas, so a third one only gets 8_000 and a
1070        // loop after one transfer runs out of the 29_000 left.
1071        let api = build_test_eth_api_with_gas_cap(provider, 50_000);
1072        let trace_api =
1073            crate::TraceApi::new(api.clone(), BlockingTaskGuard::new(1), EthConfig::default());
1074        let debug_api = crate::DebugApi::new(
1075            api.clone(),
1076            BlockingTaskGuard::new(1),
1077            &Runtime::test(),
1078            futures::stream::empty(),
1079        );
1080        let transfer = TransactionRequest::default().to(Address::with_last_byte(0x42));
1081        let transfers = |calls| vec![transfer.clone(); calls];
1082        let transfer_and_loop = vec![transfer.clone(), TransactionRequest::default().to(looping)];
1083        let bundles = |calls: Vec<TransactionRequest>| {
1084            vec![Bundle { transactions: calls, block_override: None }]
1085        };
1086        let trace_calls = |calls: Vec<TransactionRequest>| {
1087            calls
1088                .into_iter()
1089                .map(|call| (call, std::iter::once(TraceType::Trace).collect()))
1090                .collect::<Vec<_>>()
1091        };
1092
1093        assert_eq!(
1094            EthCall::call_many(&api, bundles(transfers(2)), None, None).await.unwrap()[0].len(),
1095            2
1096        );
1097        assert_eq!(
1098            trace_api.trace_call_many(trace_calls(transfers(2)), None).await.unwrap().len(),
1099            2
1100        );
1101        assert_eq!(
1102            debug_api.debug_trace_call_many(bundles(transfers(2)), None, None).await.unwrap()[0]
1103                .len(),
1104            2
1105        );
1106
1107        let gas_cap_err = "the request's calls exceed the RPC gas cap of 50000";
1108        for (calls, tx_index) in [(transfers(3), 2), (transfer_and_loop, 1)] {
1109            assert_eq!(
1110                EthCall::call_many(&api, bundles(calls.clone()), None, None)
1111                    .await
1112                    .unwrap_err()
1113                    .to_string(),
1114                format!("call_many error in bundle 0 and transaction {tx_index}: {gas_cap_err}")
1115            );
1116            assert_eq!(
1117                trace_api
1118                    .trace_call_many(trace_calls(calls.clone()), None)
1119                    .await
1120                    .unwrap_err()
1121                    .to_string(),
1122                gas_cap_err
1123            );
1124            assert_eq!(
1125                debug_api
1126                    .debug_trace_call_many(bundles(calls), None, None)
1127                    .await
1128                    .unwrap_err()
1129                    .to_string(),
1130                gas_cap_err
1131            );
1132        }
1133
1134        let too_many = transfers(DEFAULT_MAX_CALL_MANY_CALLS + 1);
1135        let limit_err = "call count 1025 exceeds limit 1024";
1136        assert_eq!(
1137            EthCall::call_many(&api, bundles(too_many.clone()), None, None)
1138                .await
1139                .unwrap_err()
1140                .to_string(),
1141            limit_err
1142        );
1143        assert_eq!(
1144            trace_api
1145                .trace_call_many(trace_calls(too_many.clone()), None)
1146                .await
1147                .unwrap_err()
1148                .to_string(),
1149            limit_err
1150        );
1151        assert_eq!(
1152            debug_api
1153                .debug_trace_call_many(bundles(too_many), None, None)
1154                .await
1155                .unwrap_err()
1156                .to_string(),
1157            limit_err
1158        );
1159    }
1160
1161    #[tokio::test]
1162    /// Requesting no block should result in a default response
1163    async fn test_fee_history_no_block_requested() {
1164        let block_count = 10;
1165        let newest_block = 1337;
1166        let oldest_block = None;
1167
1168        let (eth_api, _, _) =
1169            prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default());
1170
1171        let response = <EthApi<_, _> as EthApiServer<_, _, _, _, _, _>>::fee_history(
1172            &eth_api,
1173            U64::from(0),
1174            newest_block.into(),
1175            None,
1176        )
1177        .await
1178        .unwrap();
1179        assert_eq!(
1180            response,
1181            FeeHistory::default(),
1182            "none: requesting no block should yield a default response"
1183        );
1184    }
1185
1186    #[tokio::test]
1187    /// Requesting a single block should return 1 block (+ base fee for the next block over)
1188    async fn test_fee_history_single_block() {
1189        let block_count = 10;
1190        let newest_block = 1337;
1191        let oldest_block = None;
1192
1193        let (eth_api, base_fees_per_gas, gas_used_ratios) =
1194            prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default());
1195
1196        let fee_history =
1197            eth_api.fee_history(U64::from(1), newest_block.into(), None).await.unwrap();
1198        assert_eq!(
1199            fee_history.base_fee_per_gas,
1200            &base_fees_per_gas[base_fees_per_gas.len() - 2..],
1201            "one: base fee per gas is incorrect"
1202        );
1203        assert_eq!(
1204            fee_history.base_fee_per_gas.len(),
1205            2,
1206            "one: should return base fee of the next block as well"
1207        );
1208        assert_eq!(
1209            &fee_history.gas_used_ratio,
1210            &gas_used_ratios[gas_used_ratios.len() - 1..],
1211            "one: gas used ratio is incorrect"
1212        );
1213        assert_eq!(fee_history.oldest_block, newest_block, "one: oldest block is incorrect");
1214        assert!(
1215            fee_history.reward.is_none(),
1216            "one: no percentiles were requested, so there should be no rewards result"
1217        );
1218    }
1219
1220    /// Requesting all blocks should be ok
1221    #[tokio::test]
1222    async fn test_fee_history_all_blocks() {
1223        let block_count = 10;
1224        let newest_block = 1337;
1225        let oldest_block = None;
1226
1227        let (eth_api, base_fees_per_gas, gas_used_ratios) =
1228            prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default());
1229
1230        let fee_history =
1231            eth_api.fee_history(U64::from(block_count), newest_block.into(), None).await.unwrap();
1232
1233        assert_eq!(
1234            &fee_history.base_fee_per_gas, &base_fees_per_gas,
1235            "all: base fee per gas is incorrect"
1236        );
1237        assert_eq!(
1238            fee_history.base_fee_per_gas.len() as u64,
1239            block_count + 1,
1240            "all: should return base fee of the next block as well"
1241        );
1242        assert_eq!(
1243            &fee_history.gas_used_ratio, &gas_used_ratios,
1244            "all: gas used ratio is incorrect"
1245        );
1246        assert_eq!(
1247            fee_history.oldest_block,
1248            newest_block - block_count + 1,
1249            "all: oldest block is incorrect"
1250        );
1251        assert!(
1252            fee_history.reward.is_none(),
1253            "all: no percentiles were requested, so there should be no rewards result"
1254        );
1255    }
1256
1257    #[tokio::test]
1258    async fn call_allowance_respects_rpc_gas_cap() {
1259        use reth_tasks::pool::BlockingTaskGuard;
1260
1261        let sender = Address::repeat_byte(0x11);
1262        let contract = Address::repeat_byte(0xaa);
1263        // Return the initial execution gas and the caller's balance after the value transfer.
1264        let code = Bytes::from_static(&[
1265            0x5a, 0x60, 0x00, 0x52, 0x33, 0x31, 0x60, 0x20, 0x52, 0x60, 0x40, 0x60, 0x00, 0xf3,
1266        ]);
1267
1268        // RPC cap, supplied gas, price, balance after value, block limit, expected budget.
1269        for (gas_cap, gas, price, balance, block_limit, budget) in [
1270            (50_000, None, 1, 100_000, 100_000, 50_000),
1271            (50_000, None, 0, 100_000, 100_000, 50_000),
1272            (50_000, None, 1, 40_000, 100_000, 40_000),
1273            (50_000, None, 1, 100_000, 40_000, 40_000),
1274            (50_000, Some(70_000), 1, 100_000, 100_000, 50_000),
1275            (50_000, Some(30_000), 1, 100_000, 100_000, 30_000),
1276            (50_000, Some(70_000), 1, 100_000, 40_000, 50_000),
1277            (50_000, Some(30_000), 1, 0, 100_000, 30_000),
1278            (50_000, Some(30_000), 0, 0, 100_000, 30_000),
1279            (0, None, 1, 100_000, 100_000, 100_000),
1280            (0, Some(70_000), 1, 100_000, 40_000, 70_000),
1281        ] {
1282            let provider = MockEthProvider::default()
1283                .with_chain_spec(ChainSpecBuilder::mainnet().cancun_activated().build());
1284            provider.add_block(
1285                B256::repeat_byte(0x42),
1286                Block {
1287                    header: Header {
1288                        number: 1,
1289                        gas_limit: block_limit,
1290                        excess_blob_gas: Some(0),
1291                        ..Default::default()
1292                    },
1293                    body: BlockBody::default(),
1294                },
1295            );
1296            let api = build_test_eth_api_with_gas_cap(provider, gas_cap);
1297            let trace_api =
1298                crate::TraceApi::new(api.clone(), BlockingTaskGuard::new(1), EthConfig::default());
1299            let state_override = StateOverride::from_iter([
1300                (
1301                    sender,
1302                    AccountOverride {
1303                        balance: Some(U256::from(balance + 1_000)),
1304                        ..Default::default()
1305                    },
1306                ),
1307                (contract, AccountOverride { code: Some(code.clone()), ..Default::default() }),
1308            ]);
1309
1310            for dynamic_fee in [false, true] {
1311                let request = TransactionRequest {
1312                    gas,
1313                    gas_price: (!dynamic_fee).then_some(price),
1314                    max_fee_per_gas: dynamic_fee.then_some(price),
1315                    max_priority_fee_per_gas: dynamic_fee.then_some(price),
1316                    value: Some(U256::from(1_000)),
1317                    ..TransactionRequest::default().with_from(sender).with_to(contract)
1318                };
1319                let output = EthCall::call(
1320                    &api,
1321                    request.clone(),
1322                    Some(BlockId::latest()),
1323                    EvmOverrides::state(Some(state_override.clone())),
1324                )
1325                .await
1326                .unwrap();
1327                let traces = trace_api
1328                    .trace_call(TraceCallRequest {
1329                        call: request,
1330                        trace_types: std::iter::once(TraceType::Trace).collect(),
1331                        block_id: Some(BlockId::latest()),
1332                        state_overrides: Some(state_override.clone()),
1333                        block_overrides: None,
1334                    })
1335                    .await
1336                    .unwrap();
1337
1338                assert_eq!(U256::from_be_slice(&output[..32]), U256::from(budget - 21_002));
1339                assert_eq!(U256::from_be_slice(&output[32..]), U256::from(balance));
1340                assert_eq!(traces.output, output);
1341            }
1342        }
1343    }
1344
1345    #[tokio::test]
1346    async fn call_converts_request_once_as_sent() {
1347        static CONVERTED_GAS: std::sync::Mutex<Vec<Option<u64>>> =
1348            std::sync::Mutex::new(Vec::new());
1349
1350        // A signature that commits to the gas limit can recover a different caller or fee payer
1351        // from a request with another gas limit, so the request must be converted once, as sent.
1352        fn count_conversion(
1353            request: TransactionRequest,
1354            evm_env: &EvmEnvFor<EthEvmConfig>,
1355        ) -> Result<TxEnvFor<EthEvmConfig>, EthTxEnvError> {
1356            CONVERTED_GAS.lock().unwrap().push(request.gas);
1357            request.try_into_tx_env(evm_env)
1358        }
1359
1360        let sender = Address::repeat_byte(0x11);
1361        let contract = Address::repeat_byte(0xaa);
1362        // Return the gas remaining after intrinsic gas and the GAS opcode.
1363        let code = Bytes::from_static(&[0x5a, 0x60, 0x00, 0x52, 0x60, 0x20, 0x60, 0x00, 0xf3]);
1364        let provider = MockEthProvider::default()
1365            .with_chain_spec(ChainSpecBuilder::mainnet().cancun_activated().build());
1366        provider.add_block(
1367            B256::repeat_byte(0x42),
1368            Block {
1369                header: Header {
1370                    number: 1,
1371                    gas_limit: 100_000,
1372                    excess_blob_gas: Some(0),
1373                    ..Default::default()
1374                },
1375                body: BlockBody::default(),
1376            },
1377        );
1378        let api = EthApiBuilder::new(
1379            provider.clone(),
1380            testing_pool(),
1381            NoopNetwork::default(),
1382            EthEvmConfig::new(provider.chain_spec()),
1383        )
1384        .with_rpc_converter(
1385            EthRpcConverter::new(EthReceiptConverter::new(provider.chain_spec()))
1386                .with_tx_env_converter(
1387                    count_conversion
1388                        as fn(
1389                            TransactionRequest,
1390                            &EvmEnvFor<EthEvmConfig>,
1391                        )
1392                            -> Result<TxEnvFor<EthEvmConfig>, EthTxEnvError>,
1393                ),
1394        )
1395        .gas_cap(50_000u64.into())
1396        .build();
1397        let state_override = StateOverride::from_iter([
1398            (sender, AccountOverride { balance: Some(U256::from(101_000)), ..Default::default() }),
1399            (contract, AccountOverride { code: Some(code), ..Default::default() }),
1400        ]);
1401        // Omitted gas, and gas above the RPC cap.
1402        for (gas, expected_gas) in [(None, 50_000), (Some(70_000), 50_000), (Some(30_000), 30_000)]
1403        {
1404            let request = TransactionRequest {
1405                gas,
1406                gas_price: Some(1),
1407                value: Some(U256::from(1_000)),
1408                ..TransactionRequest::default().with_from(sender).with_to(contract)
1409            };
1410            CONVERTED_GAS.lock().unwrap().clear();
1411
1412            let output = EthCall::call(
1413                &api,
1414                request,
1415                Some(BlockId::latest()),
1416                EvmOverrides::state(Some(state_override.clone())),
1417            )
1418            .await
1419            .unwrap();
1420
1421            assert_eq!(U256::from_be_slice(&output), U256::from(expected_gas - 21_002));
1422            assert_eq!(*CONVERTED_GAS.lock().unwrap(), [gas]);
1423        }
1424    }
1425
1426    #[test]
1427    fn execution_errors_distinguish_reverts_from_failed_calls() {
1428        for stop in [
1429            evm2::interpreter::InstrStop::OutOfFunds,
1430            evm2::interpreter::InstrStop::CallTooDeep,
1431            evm2::interpreter::InstrStop::Revert,
1432        ] {
1433            let output = Bytes::from_static(b"revert payload");
1434            let result = evm2::TxResult::<evm2::BaseEvmTypes> {
1435                status: false,
1436                stop,
1437                output: output.clone(),
1438                ..Default::default()
1439            };
1440            let err = <EthApiError as reth_rpc_eth_types::error::FromEvmError<EthEvmConfig>>::ensure_success::<evm2::BaseEvmTypes>(result)
1441                .unwrap_err();
1442            match err.as_invalid_transaction().unwrap() {
1443                RpcInvalidTransactionError::Revert(_) => {
1444                    assert_eq!(stop, evm2::interpreter::InstrStop::Revert);
1445                }
1446                RpcInvalidTransactionError::EvmHalt(reason) => {
1447                    assert_ne!(stop, evm2::interpreter::InstrStop::Revert);
1448                    assert_eq!(reason, &format!("{stop:?}"));
1449                }
1450                other => panic!("unexpected error: {other}"),
1451            }
1452            let rpc: jsonrpsee::types::ErrorObjectOwned = err.into();
1453            if stop == evm2::interpreter::InstrStop::Revert {
1454                assert_eq!(rpc.code(), 3);
1455                assert_eq!(
1456                    serde_json::from_str::<Bytes>(rpc.data().unwrap().get()).unwrap(),
1457                    output
1458                );
1459            } else {
1460                assert_eq!(rpc.code(), -32003);
1461                assert!(rpc.data().is_none());
1462            }
1463        }
1464    }
1465
1466    #[tokio::test]
1467    async fn estimate_gas_respects_rpc_gas_cap() {
1468        const LOW_GAS_CAP: u64 = 50_000;
1469        const HIGH_GAS_CAP: u64 = 200_000;
1470        // Revert unless GAS > 60_000. Retrying above the RPC cap would succeed and
1471        // incorrectly turn the revert into an out-of-gas error.
1472        let code = Bytes::from_static(&[
1473            0x5a, 0x61, 0xea, 0x60, 0x10, 0x60, 0x0d, 0x57, 0x60, 0x00, 0x60, 0x00, 0xfd, 0x5b,
1474            0x00,
1475        ]);
1476        let sender = Address::repeat_byte(0x11);
1477        let contract = Address::repeat_byte(0xaa);
1478        let mut state_override = StateOverride::default();
1479        state_override.insert(contract, AccountOverride { code: Some(code), ..Default::default() });
1480        let overrides = EvmOverrides::state(Some(state_override));
1481        let at = BlockId::latest();
1482
1483        for chain_spec in [
1484            ChainSpecBuilder::mainnet().cancun_activated().build(),
1485            ChainSpecBuilder::mainnet().osaka_activated().build(),
1486            ChainSpecBuilder::mainnet().amsterdam_activated().build(),
1487        ] {
1488            let provider = MockEthProvider::default().with_chain_spec(chain_spec);
1489            provider.add_account(sender, ExtendedAccount::new(0, U256::MAX));
1490            provider.add_block(
1491                B256::repeat_byte(0x42),
1492                Block {
1493                    header: Header {
1494                        number: 1,
1495                        gas_limit: 30_000_000,
1496                        excess_blob_gas: Some(0),
1497                        ..Default::default()
1498                    },
1499                    body: BlockBody::default(),
1500                },
1501            );
1502
1503            for gas in [None, Some(1_000_000)] {
1504                let request = TransactionRequest {
1505                    gas,
1506                    ..TransactionRequest::default().with_from(sender).with_to(contract)
1507                };
1508                let capped = build_test_eth_api_with_gas_cap(provider.clone(), LOW_GAS_CAP);
1509                let err = EthCall::estimate_gas_at(&capped, request.clone(), at, overrides.clone())
1510                    .await
1511                    .expect_err("estimation above the RPC gas cap must fail");
1512                assert!(
1513                    matches!(
1514                        err.as_invalid_transaction(),
1515                        Some(RpcInvalidTransactionError::Revert(_))
1516                    ),
1517                    "{err}"
1518                );
1519
1520                for gas_cap in [HIGH_GAS_CAP, 0] {
1521                    let relaxed = build_test_eth_api_with_gas_cap(provider.clone(), gas_cap);
1522                    let estimated =
1523                        EthCall::estimate_gas_at(&relaxed, request.clone(), at, overrides.clone())
1524                            .await
1525                            .expect("same call fits under a higher or unlimited RPC gas cap");
1526                    assert!(estimated > U256::from(LOW_GAS_CAP), "{estimated}");
1527                    assert!(estimated <= U256::from(HIGH_GAS_CAP), "{estimated}");
1528                }
1529            }
1530        }
1531    }
1532
1533    #[tokio::test]
1534    async fn estimate_gas_fee_free_retries_and_transfer() {
1535        let sender = Address::repeat_byte(0x11);
1536        let target = Address::repeat_byte(0xaa);
1537        let provider = MockEthProvider::default()
1538            .with_chain_spec(ChainSpecBuilder::mainnet().cancun_activated().build());
1539        provider.add_block(
1540            B256::repeat_byte(0x42),
1541            Block {
1542                header: Header {
1543                    number: 1,
1544                    gas_limit: 100_000,
1545                    excess_blob_gas: Some(0),
1546                    ..Default::default()
1547                },
1548                body: BlockBody::default(),
1549            },
1550        );
1551        let api = build_test_eth_api_with_gas_cap(provider, 100_000);
1552        for dynamic_fee in [false, true] {
1553            for transfer in [false, true] {
1554                let request = TransactionRequest {
1555                    gas: Some(30_000),
1556                    gas_price: (!dynamic_fee).then_some(1),
1557                    max_fee_per_gas: dynamic_fee.then_some(1),
1558                    max_priority_fee_per_gas: dynamic_fee.then_some(1),
1559                    ..TransactionRequest::default().with_from(sender).with_to(target)
1560                };
1561                let overrides = StateOverride::from_iter([
1562                    (
1563                        sender,
1564                        AccountOverride {
1565                            balance: Some(U256::from(if transfer { 20_000 } else { 50_000 })),
1566                            ..Default::default()
1567                        },
1568                    ),
1569                    (
1570                        target,
1571                        AccountOverride {
1572                            code: Some(if transfer {
1573                                Bytes::new()
1574                            } else {
1575                                Bytes::from_static(&[0x60, 0x00, 0x60, 0x00, 0xfd])
1576                            }),
1577                            ..Default::default()
1578                        },
1579                    ),
1580                ]);
1581                let result = EthCall::estimate_gas_at(
1582                    &api,
1583                    request,
1584                    BlockId::latest(),
1585                    EvmOverrides::state(Some(overrides)),
1586                )
1587                .await;
1588                if transfer {
1589                    assert_eq!(result.unwrap(), U256::from(21_000));
1590                } else {
1591                    let err = result.unwrap_err();
1592                    assert!(
1593                        matches!(
1594                            err.as_invalid_transaction(),
1595                            Some(RpcInvalidTransactionError::Revert(_))
1596                        ),
1597                        "{err}"
1598                    );
1599                }
1600            }
1601        }
1602    }
1603
1604    #[tokio::test]
1605    async fn estimate_gas_transfer_respects_rpc_gas_cap() {
1606        let provider = MockEthProvider::default();
1607        provider.add_block(
1608            B256::repeat_byte(0x42),
1609            Block {
1610                header: Header { number: 1, gas_limit: 30_000_000, ..Default::default() },
1611                body: BlockBody::default(),
1612            },
1613        );
1614        let request = TransactionRequest::default().with_to(Address::repeat_byte(0xaa));
1615        let at = BlockId::latest();
1616
1617        let capped = build_test_eth_api_with_gas_cap(provider.clone(), 20_999);
1618        let err = EthCall::estimate_gas_at(&capped, request.clone(), at, EvmOverrides::default())
1619            .await
1620            .expect_err("the transfer shortcut must respect the RPC gas cap");
1621        assert!(
1622            matches!(
1623                err.as_invalid_transaction(),
1624                Some(RpcInvalidTransactionError::GasRequiredExceedsAllowance { gas_limit: 20_999 })
1625            ),
1626            "{err}"
1627        );
1628
1629        let sufficient = build_test_eth_api_with_gas_cap(provider, 21_000);
1630        let estimated = EthCall::estimate_gas_at(&sufficient, request, at, EvmOverrides::default())
1631            .await
1632            .unwrap();
1633        assert_eq!(estimated, U256::from(21_000));
1634    }
1635
1636    #[tokio::test]
1637    async fn header_responses_omit_size_while_blocks_keep_it() {
1638        let provider = MockEthProvider::default();
1639        let block = Block {
1640            header: Header { number: 1, ..Default::default() },
1641            body: BlockBody::default(),
1642        };
1643        let hash = block.header.hash_slow();
1644        let block_size = alloy_rlp::encode(&block).len();
1645        provider.add_block(hash, block);
1646
1647        let api = build_test_eth_api(provider);
1648        for block_id in [BlockId::number(1), BlockId::hash(hash)] {
1649            let header = EthBlocks::rpc_block_header(&api, block_id).await.unwrap().unwrap();
1650            let response = serde_json::to_value(&header).unwrap();
1651            assert!(response.get("size").is_none());
1652        }
1653
1654        for full in [false, true] {
1655            let block =
1656                EthBlocks::rpc_block(&api, BlockId::number(1), full).await.unwrap().unwrap();
1657            assert_eq!(block.header.size, Some(U256::from(block_size)));
1658        }
1659    }
1660
1661    #[tokio::test]
1662    async fn simulate_preserves_state_between_blocks() {
1663        let sender = Address::repeat_byte(0x11);
1664        let contract = Address::repeat_byte(0xaa);
1665        // Increment slot zero and return both the counter and the contract balance.
1666        let code = alloy_primitives::bytes!("60005460010180600055600052303160205260406000f3");
1667        let genesis =
1668            Genesis::default().with_gas_limit(30_000_000).with_base_fee(Some(0)).extend_accounts([
1669                (sender, GenesisAccount::default().with_balance(U256::from(1_000_000))),
1670                (contract, GenesisAccount::default().with_nonce(Some(1)).with_code(Some(code))),
1671            ]);
1672        let chain_spec =
1673            Arc::new(ChainSpecBuilder::mainnet().cancun_activated().genesis(genesis).build());
1674        let factory = create_test_provider_factory_with_chain_spec(chain_spec);
1675        init_genesis(&factory).unwrap();
1676        let provider = BlockchainProvider::new(factory).unwrap();
1677        let api = EthApiBuilder::new(
1678            provider.clone(),
1679            testing_pool(),
1680            NoopNetwork::default(),
1681            EthEvmConfig::new(provider.chain_spec()),
1682        )
1683        .compute_state_root_for_eth_simulate(true)
1684        .build();
1685        for trace_transfers in [false, true] {
1686            let payload = SimulatePayload {
1687                validation: true,
1688                trace_transfers,
1689                block_state_calls: vec![
1690                    SimBlock::default()
1691                        .call(
1692                            TransactionRequest::default()
1693                                .with_from(sender)
1694                                .with_to(contract)
1695                                .with_nonce(0)
1696                                .with_gas_limit(100_000)
1697                                .with_value(U256::from(1)),
1698                        )
1699                        .call(
1700                            // This recipient is only changed in the first block.
1701                            TransactionRequest::default()
1702                                .with_from(sender)
1703                                .with_to(Address::repeat_byte(0xbb))
1704                                .with_nonce(1)
1705                                .with_gas_limit(21_000)
1706                                .with_value(U256::from(1)),
1707                        ),
1708                    SimBlock::default().call(
1709                        TransactionRequest::default()
1710                            .with_from(sender)
1711                            .with_to(contract)
1712                            .with_nonce(2)
1713                            .with_gas_limit(100_000),
1714                    ),
1715                ],
1716                ..Default::default()
1717            };
1718            let combined = SimulatePayload {
1719                block_state_calls: vec![SimBlock::default().extend_calls(
1720                    payload.block_state_calls.iter().flat_map(|block| block.calls.clone()),
1721                )],
1722                ..payload.clone()
1723            };
1724            let expected = EthCall::simulate_v1(&api, combined, None).await.unwrap();
1725            let blocks = EthCall::simulate_v1(&api, payload, None).await.unwrap();
1726            assert_eq!(blocks[1].inner.header.state_root, expected[0].inner.header.state_root);
1727            assert_eq!(blocks.len(), 2);
1728            for (index, block) in blocks.iter().enumerate() {
1729                let result = &block.calls[0];
1730                assert!(result.status, "{result:?}");
1731                assert_eq!(U256::from_be_slice(&result.return_data[..32]), U256::from(index + 1));
1732                assert_eq!(U256::from_be_slice(&result.return_data[32..]), U256::from(1));
1733            }
1734        }
1735    }
1736
1737    #[tokio::test]
1738    async fn call_preserves_block_number_and_saturates_fee_overrides() {
1739        let contract = Address::repeat_byte(0xaa);
1740        let sender = Address::repeat_byte(0x11);
1741        let provider = MockEthProvider::default()
1742            .with_chain_spec(ChainSpecBuilder::mainnet().cancun_activated().build());
1743        provider.add_account(sender, ExtendedAccount::new(0, U256::MAX));
1744        provider.add_block(
1745            B256::repeat_byte(0x42),
1746            Block {
1747                header: Header {
1748                    number: 1,
1749                    gas_limit: 30_000_000,
1750                    excess_blob_gas: Some(0),
1751                    ..Default::default()
1752                },
1753                body: BlockBody::default(),
1754            },
1755        );
1756        let api = build_test_eth_api(provider);
1757        // Return NUMBER, BASEFEE, and BLOBBASEFEE.
1758        let overrides = EvmOverrides::state(Some(StateOverride::from_iter([(
1759            contract,
1760            AccountOverride {
1761                code: Some(alloy_primitives::bytes!("43600052486020524a60405260606000f3")),
1762                ..Default::default()
1763            },
1764        )])))
1765        .with_block(Box::new(BlockOverrides {
1766            number: Some(U256::MAX),
1767            base_fee: Some(U256::MAX),
1768            blob_base_fee: Some(U256::MAX),
1769            ..Default::default()
1770        }));
1771        let result = EthCall::call(
1772            &api,
1773            TransactionRequest {
1774                gas_price: Some(1),
1775                ..TransactionRequest::default()
1776                    .with_from(sender)
1777                    .with_to(contract)
1778                    .with_gas_limit(100_000)
1779            },
1780            None,
1781            overrides,
1782        )
1783        .await
1784        .unwrap();
1785        assert_eq!(result.len(), 96);
1786        assert_eq!(U256::from_be_slice(&result[..32]), U256::MAX);
1787        assert_eq!(U256::from_be_slice(&result[32..64]), U256::from(u64::MAX));
1788        assert_eq!(U256::from_be_slice(&result[64..]), U256::from(u128::MAX));
1789    }
1790
1791    #[tokio::test]
1792    async fn create_access_list_gas_includes_generated_list() {
1793        let provider = MockEthProvider::default()
1794            .with_chain_spec(ChainSpecBuilder::mainnet().berlin_activated().build());
1795        provider.add_block(
1796            B256::repeat_byte(0x42),
1797            Block {
1798                header: Header { number: 1, gas_limit: 30_000_000, ..Default::default() },
1799                body: BlockBody::default(),
1800            },
1801        );
1802        let sender = Address::repeat_byte(0x11);
1803        provider.add_account(sender, ExtendedAccount::new(7, U256::MAX));
1804        let contract = Address::repeat_byte(0xaa);
1805        let state_override = StateOverride::from_iter([(
1806            contract,
1807            AccountOverride {
1808                // PUSH1 0; SLOAD; STOP.
1809                code: Some(Bytes::from_static(&[0x60, 0x00, 0x54, 0x00])),
1810                ..Default::default()
1811            },
1812        )]);
1813        let api = build_test_eth_api_with_gas_cap(provider, 30_000);
1814        let mut request = TransactionRequest::default()
1815            .with_from(sender)
1816            .with_to(contract)
1817            .with_gas_limit(100_000);
1818        let at = BlockId::latest();
1819        let result = EthCall::create_access_list_at(
1820            &api,
1821            request.clone(),
1822            Some(at),
1823            Some(state_override.clone()),
1824        )
1825        .await
1826        .unwrap();
1827
1828        assert_eq!(result.error, None);
1829        assert_eq!(result.access_list.0.len(), 1);
1830        assert_eq!(result.access_list.0[0].address, contract);
1831        assert_eq!(result.access_list.0[0].storage_keys, vec![B256::ZERO]);
1832        // Intrinsic gas + address/key access-list charges + PUSH1 + warm SLOAD.
1833        assert_eq!(result.gas_used, U256::from(21_000 + 2_400 + 1_900 + 3 + 100));
1834
1835        request.set_access_list(result.access_list.clone());
1836        let repeated =
1837            EthCall::create_access_list_at(&api, request, Some(at), Some(state_override))
1838                .await
1839                .unwrap();
1840        assert_eq!(repeated, result);
1841    }
1842
1843    #[tokio::test]
1844    async fn create_access_list_excludes_authorization_authorities() {
1845        let provider = MockEthProvider::default()
1846            .with_chain_spec(ChainSpecBuilder::mainnet().prague_activated().build());
1847        provider.add_block(
1848            B256::repeat_byte(0x42),
1849            Block {
1850                header: Header { number: 1, gas_limit: 30_000_000, ..Default::default() },
1851                body: BlockBody::default(),
1852            },
1853        );
1854        let sender = Address::repeat_byte(0x11);
1855        provider.add_account(sender, ExtendedAccount::new(0, U256::MAX));
1856
1857        let authorization = Authorization {
1858            chain_id: U256::from(1),
1859            address: Address::repeat_byte(0xbb),
1860            nonce: 0,
1861        };
1862        let signature =
1863            sign_message(B256::repeat_byte(0x22), authorization.signature_hash()).unwrap();
1864        let authorization = authorization.into_signed(signature);
1865        let authority = authorization.recover_authority().unwrap();
1866
1867        let contract = Address::repeat_byte(0xaa);
1868        let state_override = StateOverride::from_iter([(
1869            contract,
1870            AccountOverride {
1871                // PUSH20 authority; BALANCE; STOP.
1872                code: Some([&[0x73][..], authority.as_slice(), &[0x31, 0x00]].concat().into()),
1873                ..Default::default()
1874            },
1875        )]);
1876        let api = build_test_eth_api(provider);
1877        let request = TransactionRequest {
1878            authorization_list: Some(vec![authorization]),
1879            ..TransactionRequest::default()
1880                .with_from(sender)
1881                .with_to(contract)
1882                .with_gas_limit(100_000)
1883        };
1884        let result = EthCall::create_access_list_at(
1885            &api,
1886            request,
1887            Some(BlockId::latest()),
1888            Some(state_override),
1889        )
1890        .await
1891        .unwrap();
1892
1893        assert_eq!(result.error, None);
1894        // The authority is warmed by authorization processing, so listing it only adds cost.
1895        assert!(result.access_list.0.is_empty(), "{:?}", result.access_list);
1896    }
1897
1898    #[tokio::test]
1899    async fn simulate_roots_include_overrides_across_blocks() {
1900        let sender = Address::repeat_byte(0x11);
1901        let contract = Address::repeat_byte(0xaa);
1902        let added = Address::repeat_byte(0xbb);
1903        let absent = Address::repeat_byte(0xcc);
1904        let slot = |n: u64| B256::from(U256::from(n));
1905        let genesis =
1906            Genesis::default().with_gas_limit(30_000_000).with_base_fee(Some(0)).extend_accounts([
1907                (sender, GenesisAccount::default().with_balance(U256::from(1_000_000))),
1908                (
1909                    contract,
1910                    GenesisAccount::default()
1911                        .with_nonce(Some(1))
1912                        .with_storage(Some([(slot(0), slot(1)), (slot(1), slot(2))].into())),
1913                ),
1914            ]);
1915        let chain_spec = Arc::new(
1916            ChainSpecBuilder::mainnet().cancun_activated().genesis(genesis.clone()).build(),
1917        );
1918        let factory = create_test_provider_factory_with_chain_spec(chain_spec);
1919        init_genesis(&factory).unwrap();
1920        let provider = BlockchainProvider::new(factory).unwrap();
1921        let api = EthApiBuilder::new(
1922            provider.clone(),
1923            testing_pool(),
1924            NoopNetwork::default(),
1925            EthEvmConfig::new(provider.chain_spec()),
1926        )
1927        .compute_state_root_for_eth_simulate(true)
1928        .build();
1929        // The first block leaves the overridden accounts untouched. The second replaces storage
1930        // (including a slot introduced by the first override), then execution overwrites slot zero.
1931        // The third executes against the same account again without overriding it.
1932        let code = alloy_primitives::bytes!("600960005500");
1933        let first = SimBlock {
1934            state_overrides: Some(StateOverride::from_iter([
1935                (
1936                    contract,
1937                    AccountOverride {
1938                        balance: Some(U256::from(7)),
1939                        nonce: Some(2),
1940                        code: Some(code.clone()),
1941                        state_diff: Some(std::iter::once((slot(2), slot(3))).collect()),
1942                        ..Default::default()
1943                    },
1944                ),
1945                (added, AccountOverride { balance: Some(U256::from(4)), ..Default::default() }),
1946                // An empty override leaves an absent account absent, so it must not reach the
1947                // root.
1948                (absent, AccountOverride::default()),
1949            ])),
1950            ..Default::default()
1951        };
1952        let second = SimBlock {
1953            state_overrides: Some(StateOverride::from_iter([(
1954                contract,
1955                AccountOverride {
1956                    state: Some(std::iter::once((slot(0), slot(5))).collect()),
1957                    ..Default::default()
1958                },
1959            )])),
1960            ..Default::default()
1961        }
1962        .call(
1963            TransactionRequest::default()
1964                .with_from(sender)
1965                .with_to(contract)
1966                .with_nonce(0)
1967                .with_gas_limit(100_000)
1968                .with_gas_price(0),
1969        );
1970        let third = SimBlock::default().call(
1971            TransactionRequest::default()
1972                .with_from(sender)
1973                .with_to(contract)
1974                .with_nonce(1)
1975                .with_gas_limit(100_000)
1976                .with_gas_price(0),
1977        );
1978        let blocks = EthCall::simulate_v1(
1979            &api,
1980            SimulatePayload {
1981                validation: true,
1982                block_state_calls: vec![first, second, third],
1983                ..Default::default()
1984            },
1985            None,
1986        )
1987        .await
1988        .unwrap();
1989        assert!(blocks[1].calls[0].status);
1990        assert!(blocks[2].calls[0].status);
1991
1992        // Genesis trie construction supplies an independent root for the expected full state.
1993        for (index, storage) in [
1994            [(slot(0), slot(1)), (slot(1), slot(2)), (slot(2), slot(3))].into_iter().collect(),
1995            std::iter::once((slot(0), slot(9))).collect(),
1996            std::iter::once((slot(0), slot(9))).collect(),
1997        ]
1998        .into_iter()
1999        .enumerate()
2000        {
2001            let expected = genesis.clone().extend_accounts([
2002                (
2003                    sender,
2004                    GenesisAccount::default()
2005                        .with_balance(U256::from(1_000_000))
2006                        .with_nonce(Some(index as u64)),
2007                ),
2008                (
2009                    contract,
2010                    GenesisAccount::default()
2011                        .with_balance(U256::from(7))
2012                        .with_nonce(Some(2))
2013                        .with_code(Some(code.clone()))
2014                        .with_storage(Some(storage)),
2015                ),
2016                (added, GenesisAccount::default().with_balance(U256::from(4))),
2017            ]);
2018            let expected = ChainSpecBuilder::mainnet().cancun_activated().genesis(expected).build();
2019            assert_eq!(blocks[index].inner.header.state_root, expected.genesis_header().state_root);
2020        }
2021    }
2022
2023    #[tokio::test]
2024    async fn blob_call_allowance_reserves_maximum_fee() {
2025        let sender = Address::repeat_byte(0x11);
2026        let provider = MockEthProvider::default()
2027            .with_chain_spec(ChainSpecBuilder::mainnet().cancun_activated().build());
2028        let api = build_test_eth_api(provider);
2029        let env = api.evm_config().evm_env(&Header::default()).unwrap();
2030        let allowance = |balance, value| {
2031            let mut db = CacheDB::default();
2032            db.insert_account_info(&sender, AccountInfo { balance, ..Default::default() });
2033            let request = TransactionRequest {
2034                max_fee_per_gas: Some(10),
2035                max_priority_fee_per_gas: Some(10),
2036                max_fee_per_blob_gas: Some(3),
2037                blob_versioned_hashes: Some(vec![B256::repeat_byte(1)]),
2038                value: Some(value),
2039                ..TransactionRequest::default()
2040                    .with_from(sender)
2041                    .with_to(Address::repeat_byte(0xaa))
2042            };
2043            let tx = api.create_txn_env(&env, request, &mut db).unwrap();
2044            api.caller_gas_allowance(&mut db, &env, &tx)
2045        };
2046        let value = U256::from(1_000);
2047        let blob_fee = U256::from(DATA_GAS_PER_BLOB * 3);
2048
2049        assert_eq!(
2050            allowance(U256::from(1_000_000), value).unwrap(),
2051            (1_000_000 - 1_000 - DATA_GAS_PER_BLOB * 3) / 10
2052        );
2053        for (balance, value) in [(value + blob_fee - U256::ONE, value), (U256::MAX, U256::MAX)] {
2054            let err = allowance(balance, value).unwrap_err();
2055            assert!(
2056                matches!(
2057                    err.as_invalid_transaction(),
2058                    Some(RpcInvalidTransactionError::InsufficientFunds { cost, balance: actual })
2059                        if *cost == value.saturating_add(blob_fee) && *actual == balance
2060                ),
2061                "{err}"
2062            );
2063        }
2064    }
2065}