diff --git a/crates/rpc/rpc/src/eth/api/server.rs b/crates/rpc/rpc/src/eth/api/server.rs deleted file mode 100644 index c5db4cf78cb2..000000000000 --- a/crates/rpc/rpc/src/eth/api/server.rs +++ /dev/null @@ -1,762 +0,0 @@ -//! Implementation of the [`jsonrpsee`] generated [`reth_rpc_api::EthApiServer`] trait -//! Handles RPC requests for the `eth_` namespace. - -use jsonrpsee::core::RpcResult as Result; -use reth_evm::ConfigureEvm; -use reth_network_api::NetworkInfo; -use reth_primitives::{Address, BlockId, BlockNumberOrTag, Bytes, B256, B64, U256, U64}; -use reth_provider::{ - BlockIdReader, BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, - HeaderProvider, StateProviderFactory, -}; -use reth_rpc_api::EthApiServer; -use reth_rpc_types::{ - serde_helpers::JsonStorageKey, state::StateOverride, AccessListWithGasUsed, - AnyTransactionReceipt, BlockOverrides, Bundle, EIP1186AccountProofResponse, EthCallResponse, - FeeHistory, Header, Index, RichBlock, StateContext, SyncStatus, TransactionRequest, Work, -}; -use reth_transaction_pool::TransactionPool; -use serde_json::Value; -use tracing::trace; - -use crate::{ - eth::{ - api::{EthApi, EthTransactions}, - error::EthApiError, - revm_utils::EvmOverrides, - }, - result::{internal_rpc_err, ToRpcResult}, -}; - -use super::EthApiSpec; - -#[async_trait::async_trait] -impl EthApiServer for EthApi -where - Self: EthApiSpec + EthTransactions, - Pool: TransactionPool + 'static, - Provider: BlockReader - + BlockIdReader - + BlockReaderIdExt - + ChainSpecProvider - + HeaderProvider - + StateProviderFactory - + EvmEnvProvider - + 'static, - Network: NetworkInfo + Send + Sync + 'static, - EvmConfig: ConfigureEvm + 'static, -{ - /// Handler for: `eth_protocolVersion` - async fn protocol_version(&self) -> Result { - trace!(target: "rpc::eth", "Serving eth_protocolVersion"); - EthApiSpec::protocol_version(self).await.to_rpc_result() - } - - /// Handler for: `eth_syncing` - fn syncing(&self) -> Result { - trace!(target: "rpc::eth", "Serving eth_syncing"); - EthApiSpec::sync_status(self).to_rpc_result() - } - - /// Handler for: `eth_coinbase` - async fn author(&self) -> Result
{ - Err(internal_rpc_err("unimplemented")) - } - - /// Handler for: `eth_accounts` - fn accounts(&self) -> Result> { - trace!(target: "rpc::eth", "Serving eth_accounts"); - Ok(EthApiSpec::accounts(self)) - } - - /// Handler for: `eth_blockNumber` - fn block_number(&self) -> Result { - trace!(target: "rpc::eth", "Serving eth_blockNumber"); - Ok(U256::from( - EthApiSpec::chain_info(self).with_message("failed to read chain info")?.best_number, - )) - } - - /// Handler for: `eth_chainId` - async fn chain_id(&self) -> Result> { - trace!(target: "rpc::eth", "Serving eth_chainId"); - Ok(Some(EthApiSpec::chain_id(self))) - } - - /// Handler for: `eth_getBlockByHash` - async fn block_by_hash(&self, hash: B256, full: bool) -> Result> { - trace!(target: "rpc::eth", ?hash, ?full, "Serving eth_getBlockByHash"); - Ok(EthApi::rpc_block(self, hash, full).await?) - } - - /// Handler for: `eth_getBlockByNumber` - async fn block_by_number( - &self, - number: BlockNumberOrTag, - full: bool, - ) -> Result> { - trace!(target: "rpc::eth", ?number, ?full, "Serving eth_getBlockByNumber"); - Ok(EthApi::rpc_block(self, number, full).await?) - } - - /// Handler for: `eth_getBlockTransactionCountByHash` - async fn block_transaction_count_by_hash(&self, hash: B256) -> Result> { - trace!(target: "rpc::eth", ?hash, "Serving eth_getBlockTransactionCountByHash"); - Ok(EthApi::block_transaction_count(self, hash).await?.map(U256::from)) - } - - /// Handler for: `eth_getBlockTransactionCountByNumber` - async fn block_transaction_count_by_number( - &self, - number: BlockNumberOrTag, - ) -> Result> { - trace!(target: "rpc::eth", ?number, "Serving eth_getBlockTransactionCountByNumber"); - Ok(EthApi::block_transaction_count(self, number).await?.map(U256::from)) - } - - /// Handler for: `eth_getUncleCountByBlockHash` - async fn block_uncles_count_by_hash(&self, hash: B256) -> Result> { - trace!(target: "rpc::eth", ?hash, "Serving eth_getUncleCountByBlockHash"); - Ok(EthApi::ommers(self, hash)?.map(|ommers| U256::from(ommers.len()))) - } - - /// Handler for: `eth_getUncleCountByBlockNumber` - async fn block_uncles_count_by_number(&self, number: BlockNumberOrTag) -> Result> { - trace!(target: "rpc::eth", ?number, "Serving eth_getUncleCountByBlockNumber"); - Ok(EthApi::ommers(self, number)?.map(|ommers| U256::from(ommers.len()))) - } - - /// Handler for: `eth_getBlockReceipts` - async fn block_receipts( - &self, - block_id: BlockId, - ) -> Result>> { - trace!(target: "rpc::eth", ?block_id, "Serving eth_getBlockReceipts"); - Ok(EthApi::block_receipts(self, block_id).await?) - } - - /// Handler for: `eth_getUncleByBlockHashAndIndex` - async fn uncle_by_block_hash_and_index( - &self, - hash: B256, - index: Index, - ) -> Result> { - trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getUncleByBlockHashAndIndex"); - Ok(EthApi::ommer_by_block_and_index(self, hash, index).await?) - } - - /// Handler for: `eth_getUncleByBlockNumberAndIndex` - async fn uncle_by_block_number_and_index( - &self, - number: BlockNumberOrTag, - index: Index, - ) -> Result> { - trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getUncleByBlockNumberAndIndex"); - Ok(EthApi::ommer_by_block_and_index(self, number, index).await?) - } - - /// Handler for: `eth_getRawTransactionByHash` - async fn raw_transaction_by_hash(&self, hash: B256) -> Result> { - trace!(target: "rpc::eth", ?hash, "Serving eth_getRawTransactionByHash"); - Ok(EthTransactions::raw_transaction_by_hash(self, hash).await?) - } - - /// Handler for: `eth_getTransactionByHash` - async fn transaction_by_hash(&self, hash: B256) -> Result> { - trace!(target: "rpc::eth", ?hash, "Serving eth_getTransactionByHash"); - Ok(EthTransactions::transaction_by_hash(self, hash).await?.map(Into::into)) - } - - /// Handler for: `eth_getRawTransactionByBlockHashAndIndex` - async fn raw_transaction_by_block_hash_and_index( - &self, - hash: B256, - index: Index, - ) -> Result> { - trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getRawTransactionByBlockHashAndIndex"); - Ok(EthApi::raw_transaction_by_block_and_tx_index(self, hash, index).await?) - } - - /// Handler for: `eth_getTransactionByBlockHashAndIndex` - async fn transaction_by_block_hash_and_index( - &self, - hash: B256, - index: Index, - ) -> Result> { - trace!(target: "rpc::eth", ?hash, ?index, "Serving eth_getTransactionByBlockHashAndIndex"); - Ok(EthApi::transaction_by_block_and_tx_index(self, hash, index).await?) - } - - /// Handler for: `eth_getRawTransactionByBlockNumberAndIndex` - async fn raw_transaction_by_block_number_and_index( - &self, - number: BlockNumberOrTag, - index: Index, - ) -> Result> { - trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getRawTransactionByBlockNumberAndIndex"); - Ok(EthApi::raw_transaction_by_block_and_tx_index(self, number, index).await?) - } - - /// Handler for: `eth_getTransactionByBlockNumberAndIndex` - async fn transaction_by_block_number_and_index( - &self, - number: BlockNumberOrTag, - index: Index, - ) -> Result> { - trace!(target: "rpc::eth", ?number, ?index, "Serving eth_getTransactionByBlockNumberAndIndex"); - Ok(EthApi::transaction_by_block_and_tx_index(self, number, index).await?) - } - - /// Handler for: `eth_getTransactionReceipt` - async fn transaction_receipt(&self, hash: B256) -> Result> { - trace!(target: "rpc::eth", ?hash, "Serving eth_getTransactionReceipt"); - Ok(EthTransactions::transaction_receipt(self, hash).await?) - } - - /// Handler for: `eth_getBalance` - async fn balance(&self, address: Address, block_number: Option) -> Result { - trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getBalance"); - Ok(self.on_blocking_task(|this| async move { this.balance(address, block_number) }).await?) - } - - /// Handler for: `eth_getStorageAt` - async fn storage_at( - &self, - address: Address, - index: JsonStorageKey, - block_number: Option, - ) -> Result { - trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getStorageAt"); - Ok(self - .on_blocking_task(|this| async move { this.storage_at(address, index, block_number) }) - .await?) - } - - /// Handler for: `eth_getTransactionCount` - async fn transaction_count( - &self, - address: Address, - block_number: Option, - ) -> Result { - trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getTransactionCount"); - Ok(self - .on_blocking_task( - |this| async move { this.get_transaction_count(address, block_number) }, - ) - .await?) - } - - /// Handler for: `eth_getCode` - async fn get_code(&self, address: Address, block_number: Option) -> Result { - trace!(target: "rpc::eth", ?address, ?block_number, "Serving eth_getCode"); - Ok(self - .on_blocking_task(|this| async move { this.get_code(address, block_number) }) - .await?) - } - - /// Handler for: `eth_getHeaderByNumber` - async fn header_by_number(&self, block_number: BlockNumberOrTag) -> Result> { - trace!(target: "rpc::eth", ?block_number, "Serving eth_getHeaderByNumber"); - Ok(EthApi::rpc_block_header(self, block_number).await?) - } - - /// Handler for: `eth_getHeaderByHash` - async fn header_by_hash(&self, hash: B256) -> Result> { - trace!(target: "rpc::eth", ?hash, "Serving eth_getHeaderByHash"); - Ok(EthApi::rpc_block_header(self, hash).await?) - } - - /// Handler for: `eth_call` - async fn call( - &self, - request: TransactionRequest, - block_number: Option, - state_overrides: Option, - block_overrides: Option>, - ) -> Result { - trace!(target: "rpc::eth", ?request, ?block_number, ?state_overrides, ?block_overrides, "Serving eth_call"); - Ok(self - .call(request, block_number, EvmOverrides::new(state_overrides, block_overrides)) - .await?) - } - - /// Handler for: `eth_callMany` - async fn call_many( - &self, - bundle: Bundle, - state_context: Option, - state_override: Option, - ) -> Result> { - trace!(target: "rpc::eth", ?bundle, ?state_context, ?state_override, "Serving eth_callMany"); - Ok(EthApi::call_many(self, bundle, state_context, state_override).await?) - } - - /// Handler for: `eth_createAccessList` - async fn create_access_list( - &self, - request: TransactionRequest, - block_number: Option, - ) -> Result { - trace!(target: "rpc::eth", ?request, ?block_number, "Serving eth_createAccessList"); - let access_list_with_gas_used = self.create_access_list_at(request, block_number).await?; - - Ok(access_list_with_gas_used) - } - - /// Handler for: `eth_estimateGas` - async fn estimate_gas( - &self, - request: TransactionRequest, - block_number: Option, - state_override: Option, - ) -> Result { - trace!(target: "rpc::eth", ?request, ?block_number, "Serving eth_estimateGas"); - Ok(self.estimate_gas_at(request, block_number.unwrap_or_default(), state_override).await?) - } - - /// Handler for: `eth_gasPrice` - async fn gas_price(&self) -> Result { - trace!(target: "rpc::eth", "Serving eth_gasPrice"); - - let Some(rpc_url) = &self.provider().chain_spec().bitfinity_evm_url else { - return Ok(EthApi::gas_price(self).await?); - }; - - let client = ethereum_json_rpc_client::EthJsonRpcClient::new( - ethereum_json_rpc_client::reqwest::ReqwestClient::new(rpc_url.to_string()), - ); - - let gas_price = client.gas_price().await.map_err(|e| { - internal_rpc_err(format!("failed to forward gas_price request to {}: {}", rpc_url, e)) - })?; - - Ok(U256::from(gas_price.as_u128())) - } - - /// Handler for: `eth_maxPriorityFeePerGas` - async fn max_priority_fee_per_gas(&self) -> Result { - trace!(target: "rpc::eth", "Serving eth_maxPriorityFeePerGas"); - - let Some(rpc_url) = &self.provider().chain_spec().bitfinity_evm_url else { - return Ok(EthApi::suggested_priority_fee(self).await?); - }; - - let client = ethereum_json_rpc_client::EthJsonRpcClient::new( - ethereum_json_rpc_client::reqwest::ReqwestClient::new(rpc_url.to_string()), - ); - - let priority_fee = client.max_priority_fee_per_gas().await.map_err(|e| { - internal_rpc_err(format!("failed to forward max_priority_fee_per_gas request to {}: {}", rpc_url, e)) - })?; - - Ok(U256::from(priority_fee.as_u128())) - } - - /// Handler for: `eth_blobBaseFee` - async fn blob_base_fee(&self) -> Result { - trace!(target: "rpc::eth", "Serving eth_blobBaseFee"); - return Ok(EthApi::blob_base_fee(self).await?) - } - - // FeeHistory is calculated based on lazy evaluation of fees for historical blocks, and further - // caching of it in the LRU cache. - // When new RPC call is executed, the cache gets locked, we check it for the historical fees - // according to the requested block range, and fill any cache misses (in both RPC response - // and cache itself) with the actual data queried from the database. - // To minimize the number of database seeks required to query the missing data, we calculate the - // first non-cached block number and last non-cached block number. After that, we query this - // range of consecutive blocks from the database. - /// Handler for: `eth_feeHistory` - async fn fee_history( - &self, - block_count: u64, - newest_block: BlockNumberOrTag, - reward_percentiles: Option>, - ) -> Result { - trace!(target: "rpc::eth", ?block_count, ?newest_block, ?reward_percentiles, "Serving eth_feeHistory"); - return Ok(EthApi::fee_history(self, block_count, newest_block, reward_percentiles).await?) - } - - /// Handler for: `eth_mining` - async fn is_mining(&self) -> Result { - Err(internal_rpc_err("unimplemented")) - } - - /// Handler for: `eth_hashrate` - async fn hashrate(&self) -> Result { - Ok(U256::ZERO) - } - - /// Handler for: `eth_getWork` - async fn get_work(&self) -> Result { - Err(internal_rpc_err("unimplemented")) - } - - /// Handler for: `eth_submitHashrate` - async fn submit_hashrate(&self, _hashrate: U256, _id: B256) -> Result { - Ok(false) - } - - /// Handler for: `eth_submitWork` - async fn submit_work(&self, _nonce: B64, _pow_hash: B256, _mix_digest: B256) -> Result { - Err(internal_rpc_err("unimplemented")) - } - - /// Handler for: `eth_sendTransaction` - async fn send_transaction(&self, _request: TransactionRequest) -> Result { - Err(internal_rpc_err("eth_sendTransaction not supported")) - } - - /// Handler for: `eth_sendRawTransaction` - async fn send_raw_transaction(&self, tx: Bytes) -> Result { - let Some(rpc_url) = &self.provider().chain_spec().bitfinity_evm_url else { - return Err(internal_rpc_err("no url found for eth_sendRawTransaction")); - }; - trace!(target: "rpc::eth", ?rpc_url, "Serving eth_sendRawTransaction"); - - let client = ethereum_json_rpc_client::EthJsonRpcClient::new( - ethereum_json_rpc_client::reqwest::ReqwestClient::new(rpc_url.to_string()), - ); - - let tx_hash = client.send_raw_transaction_bytes(&tx).await.map_err(|e| { - internal_rpc_err(format!("failed to forward send_raw_transaction request to {}: {}", rpc_url, e)) - })?; - - Ok(tx_hash.0.into()) - } - - /// Handler for: `eth_sign` - async fn sign(&self, address: Address, message: Bytes) -> Result { - trace!(target: "rpc::eth", ?address, ?message, "Serving eth_sign"); - Ok(EthApi::sign(self, address, message).await?) - } - - /// Handler for: `eth_signTransaction` - async fn sign_transaction(&self, _transaction: TransactionRequest) -> Result { - Err(internal_rpc_err("unimplemented")) - } - - /// Handler for: `eth_signTypedData` - async fn sign_typed_data(&self, address: Address, data: Value) -> Result { - trace!(target: "rpc::eth", ?address, ?data, "Serving eth_signTypedData"); - Ok(EthApi::sign_typed_data(self, data, address)?) - } - - /// Handler for: `eth_getProof` - async fn get_proof( - &self, - address: Address, - keys: Vec, - block_number: Option, - ) -> Result { - trace!(target: "rpc::eth", ?address, ?keys, ?block_number, "Serving eth_getProof"); - let res = EthApi::get_proof(self, address, keys, block_number).await; - - Ok(res.map_err(|e| match e { - EthApiError::InvalidBlockRange => { - internal_rpc_err("eth_getProof is unimplemented for historical blocks") - } - _ => e.into(), - })?) - } -} - -#[cfg(test)] -mod tests { - use crate::{ - eth::{ - cache::EthStateCache, gas_oracle::GasPriceOracle, FeeHistoryCache, - FeeHistoryCacheConfig, - }, - EthApi, - }; - use jsonrpsee::types::error::INVALID_PARAMS_CODE; - use reth_evm_ethereum::EthEvmConfig; - use reth_interfaces::test_utils::{generators, generators::Rng}; - use reth_network_api::noop::NoopNetwork; - use reth_primitives::{ - constants::ETHEREUM_BLOCK_GAS_LIMIT, BaseFeeParams, Block, BlockNumberOrTag, Header, - TransactionSigned, B256, - }; - use reth_provider::{ - test_utils::{MockEthProvider, NoopProvider}, - BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, StateProviderFactory, - }; - use reth_rpc_api::EthApiServer; - use reth_rpc_types::FeeHistory; - use reth_tasks::pool::BlockingTaskPool; - use reth_transaction_pool::test_utils::{testing_pool, TestPool}; - - fn build_test_eth_api< - P: BlockReaderIdExt - + BlockReader - + ChainSpecProvider - + EvmEnvProvider - + StateProviderFactory - + Unpin - + Clone - + 'static, - >( - provider: P, - ) -> EthApi { - let evm_config = EthEvmConfig::default(); - let cache = EthStateCache::spawn(provider.clone(), Default::default(), evm_config); - let fee_history_cache = - FeeHistoryCache::new(cache.clone(), FeeHistoryCacheConfig::default()); - - EthApi::new( - provider.clone(), - testing_pool(), - NoopNetwork::default(), - cache.clone(), - GasPriceOracle::new(provider, Default::default(), cache), - ETHEREUM_BLOCK_GAS_LIMIT, - BlockingTaskPool::build().expect("failed to build tracing pool"), - fee_history_cache, - evm_config, - None, - ) - } - - // Function to prepare the EthApi with mock data - fn prepare_eth_api( - newest_block: u64, - mut oldest_block: Option, - block_count: u64, - mock_provider: MockEthProvider, - ) -> (EthApi, Vec, Vec) { - let mut rng = generators::rng(); - - // Build mock data - let mut gas_used_ratios = Vec::new(); - let mut base_fees_per_gas = Vec::new(); - let mut last_header = None; - let mut parent_hash = B256::default(); - - for i in (0..block_count).rev() { - let hash = rng.gen(); - let gas_limit: u64 = rng.gen(); - let gas_used: u64 = rng.gen(); - // Note: Generates a u32 to avoid overflows later - let base_fee_per_gas: Option = rng.gen::().then(|| rng.gen::() as u64); - - let header = Header { - number: newest_block - i, - gas_limit, - gas_used, - base_fee_per_gas, - parent_hash, - ..Default::default() - }; - last_header = Some(header.clone()); - parent_hash = hash; - - let mut transactions = vec![]; - for _ in 0..100 { - let random_fee: u128 = rng.gen(); - - if let Some(base_fee_per_gas) = header.base_fee_per_gas { - let transaction = TransactionSigned { - transaction: reth_primitives::Transaction::Eip1559( - reth_primitives::TxEip1559 { - max_priority_fee_per_gas: random_fee, - max_fee_per_gas: random_fee + base_fee_per_gas as u128, - ..Default::default() - }, - ), - ..Default::default() - }; - - transactions.push(transaction); - } else { - let transaction = TransactionSigned { - transaction: reth_primitives::Transaction::Legacy( - reth_primitives::TxLegacy { ..Default::default() }, - ), - ..Default::default() - }; - - transactions.push(transaction); - } - } - - mock_provider.add_block( - hash, - Block { header: header.clone(), body: transactions, ..Default::default() }, - ); - mock_provider.add_header(hash, header); - - oldest_block.get_or_insert(hash); - gas_used_ratios.push(gas_used as f64 / gas_limit as f64); - base_fees_per_gas.push(base_fee_per_gas.map(|fee| fee as u128).unwrap_or_default()); - } - - // Add final base fee (for the next block outside of the request) - let last_header = last_header.unwrap(); - base_fees_per_gas.push(BaseFeeParams::ethereum().next_block_base_fee( - last_header.gas_used as u128, - last_header.gas_limit as u128, - last_header.base_fee_per_gas.unwrap_or_default() as u128, - )); - - let eth_api = build_test_eth_api(mock_provider); - - (eth_api, base_fees_per_gas, gas_used_ratios) - } - - /// Invalid block range - #[tokio::test] - async fn test_fee_history_empty() { - let response = as EthApiServer>::fee_history( - &build_test_eth_api(NoopProvider::default()), - 1, - BlockNumberOrTag::Latest, - None, - ) - .await; - assert!(response.is_err()); - let error_object = response.unwrap_err(); - assert_eq!(error_object.code(), INVALID_PARAMS_CODE); - } - - #[tokio::test] - /// Invalid block range (request is before genesis) - async fn test_fee_history_invalid_block_range_before_genesis() { - let block_count = 10; - let newest_block = 1337; - let oldest_block = None; - - let (eth_api, _, _) = - prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default()); - - let response = as EthApiServer>::fee_history( - ð_api, - newest_block + 1, - newest_block.into(), - Some(vec![10.0]), - ) - .await; - - assert!(response.is_err()); - let error_object = response.unwrap_err(); - assert_eq!(error_object.code(), INVALID_PARAMS_CODE); - } - - #[tokio::test] - /// Invalid block range (request is in the future) - async fn test_fee_history_invalid_block_range_in_future() { - let block_count = 10; - let newest_block = 1337; - let oldest_block = None; - - let (eth_api, _, _) = - prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default()); - - let response = as EthApiServer>::fee_history( - ð_api, - 1, - (newest_block + 1000).into(), - Some(vec![10.0]), - ) - .await; - - assert!(response.is_err()); - let error_object = response.unwrap_err(); - assert_eq!(error_object.code(), INVALID_PARAMS_CODE); - } - - #[tokio::test] - /// Requesting no block should result in a default response - async fn test_fee_history_no_block_requested() { - let block_count = 10; - let newest_block = 1337; - let oldest_block = None; - - let (eth_api, _, _) = - prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default()); - - let response = as EthApiServer>::fee_history( - ð_api, - 0, - newest_block.into(), - None, - ) - .await - .unwrap(); - assert_eq!( - response, - FeeHistory::default(), - "none: requesting no block should yield a default response" - ); - } - - #[tokio::test] - /// Requesting a single block should return 1 block (+ base fee for the next block over) - async fn test_fee_history_single_block() { - let block_count = 10; - let newest_block = 1337; - let oldest_block = None; - - let (eth_api, base_fees_per_gas, gas_used_ratios) = - prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default()); - - let fee_history = eth_api.fee_history(1, newest_block.into(), None).await.unwrap(); - assert_eq!( - fee_history.base_fee_per_gas, - &base_fees_per_gas[base_fees_per_gas.len() - 2..], - "one: base fee per gas is incorrect" - ); - assert_eq!( - fee_history.base_fee_per_gas.len(), - 2, - "one: should return base fee of the next block as well" - ); - assert_eq!( - &fee_history.gas_used_ratio, - &gas_used_ratios[gas_used_ratios.len() - 1..], - "one: gas used ratio is incorrect" - ); - assert_eq!(fee_history.oldest_block, newest_block, "one: oldest block is incorrect"); - assert!( - fee_history.reward.is_none(), - "one: no percentiles were requested, so there should be no rewards result" - ); - } - - /// Requesting all blocks should be ok - #[tokio::test] - async fn test_fee_history_all_blocks() { - let block_count = 10; - let newest_block = 1337; - let oldest_block = None; - - let (eth_api, base_fees_per_gas, gas_used_ratios) = - prepare_eth_api(newest_block, oldest_block, block_count, MockEthProvider::default()); - - let fee_history = - eth_api.fee_history(block_count, newest_block.into(), None).await.unwrap(); - - assert_eq!( - &fee_history.base_fee_per_gas, &base_fees_per_gas, - "all: base fee per gas is incorrect" - ); - assert_eq!( - fee_history.base_fee_per_gas.len() as u64, - block_count + 1, - "all: should return base fee of the next block as well" - ); - assert_eq!( - &fee_history.gas_used_ratio, &gas_used_ratios, - "all: gas used ratio is incorrect" - ); - assert_eq!( - fee_history.oldest_block, - newest_block - block_count + 1, - "all: oldest block is incorrect" - ); - assert!( - fee_history.reward.is_none(), - "all: no percentiles were requested, so there should be no rewards result" - ); - } -}