cfx_rpc_eth_impl/
eth.rs

1use crate::helpers::{FeeHistoryCache, MAX_FEE_HISTORY_CACHE_BLOCK_COUNT};
2use async_trait::async_trait;
3use cfx_execute_helper::estimation::EstimateRequest;
4use cfx_executor::executive::{
5    Executed, ExecutionError, ExecutionOutcome, ToRepackError, TxDropError,
6};
7use cfx_parameters::rpc::GAS_PRICE_DEFAULT_VALUE;
8use cfx_rpc_cfx_types::{
9    traits::BlockProvider, PhantomBlock, RpcImplConfiguration,
10};
11use cfx_rpc_eth_api::EthApiServer;
12use cfx_rpc_eth_types::{
13    AccessListResult, AccountOverride, AccountPendingTransactions, Block,
14    BlockId, BlockOverrides, Bundle, Error, EthCallResponse, EthRpcLogFilter,
15    EthRpcLogFilter as Filter, EvmOverrides, FeeHistory, Header, Log, LogData,
16    Receipt, RpcStateOverride, SimulatePayload, SimulatedBlock, StateContext,
17    SyncInfo, SyncStatus, Transaction, TransactionRequest,
18};
19use cfx_rpc_primitives::{Bytes, Index, U64 as HexU64};
20use cfx_rpc_utils::{
21    error::{
22        errors::{EthApiError, RpcInvalidTransactionError, RpcPoolError},
23        jsonrpc_error_helpers::{
24            geth_call_execution_error, request_rejected_in_catch_up_mode,
25            unknown_block,
26        },
27        jsonrpsee_error_helpers::{
28            internal_error, internal_error_with_data, invalid_input_rpc_err,
29            invalid_params, invalid_params_rpc_err,
30        },
31    },
32    helpers::SpawnBlocking,
33};
34use cfx_statedb::StateDbExt;
35use cfx_tasks::{TaskExecutor, TaskSpawner};
36use cfx_types::{
37    Address, AddressSpaceUtil, BigEndianHash, Space, H160, H256, H64, U256, U64,
38};
39use cfx_util_macros::bail;
40use cfx_vm_types::Error as VmError;
41use cfxcore::{
42    errors::{Error as CoreError, Result as CoreResult},
43    ConsensusGraph, SharedConsensusGraph, SharedSynchronizationService,
44    SharedTransactionPool,
45};
46use cfxcore_errors::ProviderBlockError;
47use jsonrpsee::{core::RpcResult, types::ErrorObjectOwned as RpcError};
48use primitives::{
49    filter::LogFilter, receipt::EVM_SPACE_SUCCESS, Action, EpochNumber,
50    StorageKey, StorageValue, TransactionStatus, TransactionWithSignature,
51};
52use rustc_hex::ToHex;
53use solidity_abi::string_revert_reason_decode;
54use std::{collections::HashMap, future::Future};
55
56type BlockNumber = BlockId;
57type BlockNumberOrTag = BlockId;
58
59type JsonStorageKey = U256;
60type RpcBlock = Block;
61
62#[derive(Clone)]
63pub struct EthApi {
64    config: RpcImplConfiguration,
65    consensus: SharedConsensusGraph,
66    sync: SharedSynchronizationService,
67    tx_pool: SharedTransactionPool,
68    fee_history_cache: FeeHistoryCache,
69    executor: TaskExecutor,
70}
71
72impl EthApi {
73    pub fn new(
74        config: RpcImplConfiguration, consensus: SharedConsensusGraph,
75        sync: SharedSynchronizationService, tx_pool: SharedTransactionPool,
76        executor: TaskExecutor,
77    ) -> Self {
78        EthApi {
79            config,
80            consensus,
81            sync,
82            tx_pool,
83            fee_history_cache: FeeHistoryCache::new(),
84            executor,
85        }
86    }
87
88    pub fn consensus_graph(&self) -> &ConsensusGraph { &self.consensus }
89
90    pub fn tx_pool(&self) -> &SharedTransactionPool { &self.tx_pool }
91
92    pub fn fetch_block_by_height(
93        &self, height: u64,
94    ) -> Result<PhantomBlock, ProviderBlockError> {
95        self.consensus_graph()
96            .get_phantom_block_by_number(
97                EpochNumber::Number(height),
98                None,
99                false,
100            )?
101            .ok_or(
102                format!("Specified block does not exist, height={}", height)
103                    .into(),
104            )
105    }
106
107    pub fn fetch_block_by_hash(
108        &self, hash: &H256,
109    ) -> Result<PhantomBlock, ProviderBlockError> {
110        self.consensus_graph()
111            .get_phantom_block_by_hash(hash, false)?
112            .ok_or(
113                format!("Specified block does not exist, hash={:?}", hash)
114                    .into(),
115            )
116    }
117
118    fn convert_block_number_to_epoch_number(
119        &self, block_number: BlockNumber,
120    ) -> Result<EpochNumber, String> {
121        if let BlockNumber::Hash { hash, .. } = block_number {
122            let consensus_graph = self.consensus_graph();
123            match consensus_graph.get_block_epoch_number(&hash) {
124                Some(num) => {
125                    // do not expose non-pivot blocks in eth RPC
126                    let pivot = consensus_graph
127                        .get_block_hashes_by_epoch(EpochNumber::Number(num))?
128                        .last()
129                        .cloned();
130
131                    if Some(hash) != pivot {
132                        return Err(format!("Block {} not found", hash));
133                    }
134
135                    Ok(EpochNumber::Number(num))
136                }
137                None => return Err(format!("Block {} not found", hash)),
138            }
139        } else {
140            block_number.try_into().map_err(|e: Error| e.to_string())
141        }
142    }
143
144    pub fn exec_transaction(
145        &self, mut request: TransactionRequest,
146        block_number_or_hash: Option<BlockNumber>,
147        state_overrides: Option<RpcStateOverride>,
148        block_overrides: Option<Box<BlockOverrides>>,
149    ) -> CoreResult<(Executed, U256)> {
150        let consensus_graph = self.consensus_graph();
151
152        if request.gas_price.is_some()
153            && request.max_priority_fee_per_gas.is_some()
154        {
155            return Err(RpcError::from(
156                EthApiError::ConflictingFeeFieldsInRequest,
157            )
158            .into());
159        }
160
161        if request.max_fee_per_gas.is_some()
162            && request.max_priority_fee_per_gas.is_some()
163        {
164            if request.max_fee_per_gas.unwrap()
165                < request.max_priority_fee_per_gas.unwrap()
166            {
167                return Err(RpcError::from(
168                    RpcInvalidTransactionError::TipAboveFeeCap,
169                )
170                .into());
171            }
172        }
173
174        let state_overrides = match state_overrides {
175            Some(states) => {
176                let mut state_overrides = HashMap::new();
177                for (address, rpc_account_override) in states {
178                    let account_override =
179                        AccountOverride::try_from(rpc_account_override)
180                            .map_err(|err| {
181                                CoreError::InvalidParam(
182                                    err.into(),
183                                    Default::default(),
184                                )
185                            })?;
186                    state_overrides.insert(address, account_override);
187                }
188                Some(state_overrides)
189            }
190            None => None,
191        };
192        let evm_overrides = EvmOverrides::new(state_overrides, block_overrides);
193
194        let epoch = self.convert_block_number_to_epoch_number(
195            block_number_or_hash.unwrap_or_default(),
196        )?;
197
198        // if gas_price and gas is zero, it is considered as not set
199        request.unset_zero_gas_and_price();
200
201        let estimate_request = EstimateRequest {
202            has_sender: request.from.is_some(),
203            has_gas_limit: request.gas.is_some(),
204            has_gas_price: request.has_gas_price(),
205            has_nonce: request.nonce.is_some(),
206            has_storage_limit: false,
207        };
208
209        let chain_id = self.consensus.best_chain_id();
210
211        let max_gas = self.config.max_estimation_gas_limit;
212        let signed_tx = request.sign_call(chain_id.in_evm_space(), max_gas)?;
213
214        let (execution_outcome, estimation) = consensus_graph.call_virtual(
215            &signed_tx,
216            epoch,
217            estimate_request,
218            evm_overrides,
219        )?;
220
221        let executed = match execution_outcome {
222            ExecutionOutcome::NotExecutedDrop(TxDropError::OldNonce(
223                expected,
224                got,
225            )) => bail!(invalid_input_rpc_err(
226                format! {"nonce is too old expected {:?} got {:?}", expected, got}
227            )),
228            ExecutionOutcome::NotExecutedDrop(
229                TxDropError::InvalidRecipientAddress(recipient),
230            ) => bail!(invalid_input_rpc_err(
231                format! {"invalid recipient address {:?}", recipient}
232            )),
233            ExecutionOutcome::NotExecutedDrop(
234                TxDropError::NotEnoughGasLimit { expected, got },
235            ) => bail!(invalid_input_rpc_err(
236                format! {"not enough gas limit with respected to tx size: expected {:?} got {:?}", expected, got}
237            )),
238            ExecutionOutcome::NotExecutedDrop(TxDropError::SenderWithCode(
239                address,
240            )) => bail!(invalid_input_rpc_err(
241                format! {"tx sender has contract code: {:?}", address}
242            )),
243            ExecutionOutcome::NotExecutedToReconsiderPacking(
244                ToRepackError::SenderDoesNotExist,
245            ) => {
246                bail!(RpcError::from(
247                    RpcInvalidTransactionError::InsufficientFunds
248                ))
249            }
250            ExecutionOutcome::NotExecutedToReconsiderPacking(e) => {
251                bail!(invalid_input_rpc_err(format! {"err: {:?}", e}))
252            }
253            ExecutionOutcome::ExecutionErrorBumpNonce(
254                ExecutionError::NotEnoughCash { .. },
255                _executed,
256            ) => {
257                bail!(RpcError::from(
258                    RpcInvalidTransactionError::InsufficientFunds
259                ))
260            }
261            ExecutionOutcome::ExecutionErrorBumpNonce(
262                ExecutionError::NonceOverflow(addr),
263                _executed,
264            ) => {
265                bail!(geth_call_execution_error(
266                    format!("address nonce overflow: {})", addr),
267                    "".into()
268                ))
269            }
270            ExecutionOutcome::ExecutionErrorBumpNonce(
271                ExecutionError::VmError(VmError::Reverted),
272                executed,
273            ) => bail!(geth_call_execution_error(
274                format!(
275                    "execution reverted: revert: {}",
276                    string_revert_reason_decode(&executed.output)
277                ),
278                format!("0x{}", executed.output.to_hex::<String>())
279            )),
280            ExecutionOutcome::ExecutionErrorBumpNonce(
281                ExecutionError::VmError(e),
282                _executed,
283            ) => bail!(geth_call_execution_error(
284                format!("execution reverted: {}", e),
285                "".into()
286            )),
287            ExecutionOutcome::Finished(executed) => executed,
288        };
289
290        Ok((executed, estimation.estimated_gas_limit))
291    }
292
293    pub fn send_transaction_with_signature(
294        &self, tx: TransactionWithSignature,
295    ) -> CoreResult<H256> {
296        if self.sync.catch_up_mode() {
297            bail!(request_rejected_in_catch_up_mode(None));
298        }
299        let (signed_trans, failed_trans) =
300            self.tx_pool.insert_new_transactions(vec![tx]);
301        if signed_trans.len() + failed_trans.len() > 1 {
302            // This should never happen
303            Ok(H256::zero().into())
304        } else if signed_trans.len() + failed_trans.len() == 0 {
305            // For tx in transactions_pubkey_cache, we simply ignore them
306            bail!(RpcError::from(EthApiError::PoolError(
307                RpcPoolError::AlreadyKnown
308            )));
309        } else if signed_trans.is_empty() {
310            let tx_err = failed_trans.into_iter().next().expect("Not empty").1;
311            bail!(RpcError::from(EthApiError::from(tx_err)))
312        } else {
313            let tx_hash = signed_trans[0].hash();
314            self.sync.append_received_transactions(signed_trans);
315            Ok(tx_hash.into())
316        }
317    }
318
319    pub fn construct_rpc_receipt(
320        &self, b: &PhantomBlock, idx: usize, prior_log_index: &mut usize,
321    ) -> CoreResult<Receipt> {
322        if b.transactions.len() != b.receipts.len() {
323            return Err(internal_error_with_data(
324                "Inconsistent state: transactions and receipts length mismatch",
325            )
326            .into());
327        }
328
329        if b.transactions.len() != b.errors.len() {
330            return Err(internal_error_with_data(
331                "Inconsistent state: transactions and errors length mismatch",
332            )
333            .into());
334        }
335
336        if idx >= b.transactions.len() {
337            return Err(internal_error_with_data(
338                "Inconsistent state: tx index out of bound",
339            )
340            .into());
341        }
342
343        let tx = &b.transactions[idx];
344        let receipt = &b.receipts[idx];
345
346        if receipt.logs.iter().any(|l| l.space != Space::Ethereum) {
347            return Err(internal_error_with_data(
348                "Inconsistent state: native tx in phantom block",
349            )
350            .into());
351        }
352
353        let contract_address = match receipt.outcome_status {
354            TransactionStatus::Success => {
355                Transaction::deployed_contract_address(tx)
356            }
357            _ => None,
358        };
359
360        let transaction_hash = tx.hash();
361        let transaction_index: U256 = idx.into();
362        let block_hash = b.pivot_header.hash();
363        let block_height: U256 = b.pivot_header.height().into();
364
365        let logs: Vec<_> = receipt
366            .logs
367            .iter()
368            .cloned()
369            .enumerate()
370            .map(|(idx, log)| Log {
371                inner: LogData {
372                    address: log.address,
373                    topics: log.topics,
374                    data: log.data.into(),
375                },
376                block_hash,
377                block_number: block_height,
378                transaction_hash,
379                transaction_index,
380                block_timestamp: Some(b.pivot_header.timestamp().into()),
381                log_index: Some((*prior_log_index + idx).into()),
382                transaction_log_index: Some(idx.into()),
383                removed: false,
384            })
385            .collect();
386
387        *prior_log_index += logs.len();
388
389        let gas_used = match idx {
390            0 => receipt.accumulated_gas_used,
391            idx => {
392                receipt.accumulated_gas_used
393                    - b.receipts[idx - 1].accumulated_gas_used
394            }
395        };
396
397        let tx_exec_error_msg = if b.errors[idx].is_empty() {
398            None
399        } else {
400            Some(b.errors[idx].clone())
401        };
402
403        let effective_gas_price =
404            if let Some(base_price) = b.pivot_header.base_price() {
405                let base_price = base_price[tx.space()];
406                if *tx.gas_price() < base_price {
407                    *tx.gas_price()
408                } else {
409                    tx.effective_gas_price(&base_price)
410                }
411            } else {
412                *tx.gas_price()
413            };
414
415        Ok(Receipt {
416            transaction_hash,
417            transaction_index,
418            block_hash,
419            from: tx.sender().address,
420            to: match tx.action() {
421                Action::Create => None,
422                Action::Call(addr) => Some(addr),
423            },
424            block_number: block_height,
425            cumulative_gas_used: receipt.accumulated_gas_used,
426            gas_used,
427            gas_fee: receipt.gas_fee,
428            contract_address,
429            logs,
430            logs_bloom: receipt.log_bloom,
431            status_code: receipt
432                .outcome_status
433                .in_space(Space::Ethereum)
434                .into(),
435            effective_gas_price,
436            tx_exec_error_msg,
437            transaction_type: receipt
438                .burnt_gas_fee
439                .is_some()
440                .then_some(U64::from(tx.type_id())),
441            burnt_gas_fee: receipt.burnt_gas_fee,
442        })
443    }
444
445    pub fn get_tx_from_txpool(&self, hash: H256) -> Option<Transaction> {
446        let tx = self.tx_pool.get_transaction(&hash)?;
447
448        if tx.space() == Space::Ethereum {
449            Some(Transaction::from_signed(
450                &tx,
451                (None, None, None),
452                (None, None),
453            ))
454        } else {
455            None
456        }
457    }
458
459    pub fn get_block_receipts(
460        &self, block_num: BlockNumber,
461    ) -> CoreResult<Vec<Receipt>> {
462        let b = {
463            let phantom_block = self.phantom_block_by_number(block_num)?;
464
465            match phantom_block {
466                None => return Err(unknown_block().into()),
467                Some(b) => b,
468            }
469        };
470
471        let mut block_receipts = vec![];
472        let mut prior_log_index = 0;
473
474        for idx in 0..b.receipts.len() {
475            block_receipts.push(self.construct_rpc_receipt(
476                &b,
477                idx,
478                &mut prior_log_index,
479            )?);
480        }
481
482        return Ok(block_receipts);
483    }
484
485    pub fn block_tx_by_index(
486        phantom_block: Option<PhantomBlock>, idx: usize,
487    ) -> Option<Transaction> {
488        match phantom_block {
489            None => None,
490            Some(pb) => match pb.transactions.get(idx) {
491                None => None,
492                Some(tx) => {
493                    let block_number = Some(pb.pivot_header.height().into());
494                    let receipt = pb.receipts.get(idx).unwrap();
495                    let status =
496                        receipt.outcome_status.in_space(Space::Ethereum);
497                    let contract_address = match status == EVM_SPACE_SUCCESS {
498                        true => Transaction::deployed_contract_address(&tx),
499                        false => None,
500                    };
501                    Some(Transaction::from_signed(
502                        &tx,
503                        (
504                            Some(pb.pivot_header.hash()),
505                            block_number,
506                            Some(idx.into()),
507                        ),
508                        (Some(status.into()), contract_address),
509                    ))
510                }
511            },
512        }
513    }
514
515    pub fn sync_status(&self) -> SyncStatus {
516        if self.sync.catch_up_mode() {
517            SyncStatus::Info(SyncInfo {
518                starting_block: U256::from(self.consensus.block_count()),
519                current_block: U256::from(self.consensus.block_count()),
520                highest_block: U256::from(
521                    self.sync.get_synchronization_graph().block_count(),
522                ),
523                warp_chunks_amount: None,
524                warp_chunks_processed: None,
525            })
526        } else {
527            SyncStatus::None
528        }
529    }
530
531    pub fn chain_id(&self) -> u32 {
532        self.consensus.best_chain_id().in_evm_space()
533    }
534
535    pub fn gas_price(&self) -> U256 {
536        let (_, maybe_base_price) =
537            self.tx_pool.get_best_info_with_parent_base_price();
538        if let Some(base_price) = maybe_base_price {
539            return base_price[Space::Ethereum];
540        }
541
542        let consensus_gas_price = self
543            .consensus_graph()
544            .gas_price(Space::Ethereum)
545            .unwrap_or(GAS_PRICE_DEFAULT_VALUE.into());
546        std::cmp::max(
547            consensus_gas_price,
548            self.tx_pool.config.min_eth_tx_price.into(),
549        )
550    }
551
552    pub fn latest_block_number(&self) -> CoreResult<U256> {
553        let consensus_graph = self.consensus_graph();
554        let epoch_num = EpochNumber::LatestState;
555        match consensus_graph.get_height_from_epoch_number(epoch_num.into()) {
556            Ok(height) => Ok(height.into()),
557            Err(e) => Err(invalid_params_rpc_err(e, None::<()>).into()),
558        }
559    }
560
561    pub fn best_epoch_number(&self) -> u64 {
562        self.consensus.best_epoch_number()
563    }
564
565    pub fn user_balance(
566        &self, address: H160, num: Option<BlockNumber>,
567    ) -> CoreResult<U256> {
568        let epoch_num =
569            self.convert_block_number_to_epoch_number(num.unwrap_or_default())?;
570        let state_db = self
571            .consensus
572            .get_eth_state_db_by_epoch_number(epoch_num, "num")?;
573        let acc = state_db
574            .get_account(&address.with_evm_space())
575            .map_err(|err| CoreError::from(err))?;
576
577        Ok(acc.map_or(U256::zero(), |acc| acc.balance).into())
578    }
579
580    pub fn storage_at(
581        &self, address: H160, position: U256, block_num: Option<BlockNumber>,
582    ) -> CoreResult<H256> {
583        let epoch_num = self.convert_block_number_to_epoch_number(
584            block_num.unwrap_or_default(),
585        )?;
586
587        let state_db = self
588            .consensus
589            .get_eth_state_db_by_epoch_number(epoch_num, "epoch_number")?;
590
591        let position: H256 = H256::from_uint(&position);
592
593        let key = StorageKey::new_storage_key(&address, position.as_ref())
594            .with_evm_space();
595
596        Ok(
597            match state_db
598                .get::<StorageValue>(key)
599                .map_err(|err| CoreError::from(err))?
600            {
601                Some(entry) => H256::from_uint(&entry.value).into(),
602                None => H256::zero(),
603            },
604        )
605    }
606
607    pub fn phantom_block_by_hash(
608        &self, hash: H256,
609    ) -> CoreResult<Option<PhantomBlock>> {
610        self.phantom_block_by_number(BlockNumber::Hash {
611            hash,
612            require_canonical: None,
613        })
614    }
615
616    pub fn phantom_block_by_number(
617        &self, block_num: BlockNumber,
618    ) -> CoreResult<Option<PhantomBlock>> {
619        let phantom_block = {
620            // keep read lock to ensure consistent view
621            let _inner = self.consensus_graph().inner.read();
622
623            match block_num {
624                BlockNumber::Hash { hash, .. } => {
625                    self.consensus_graph()
626                        .get_phantom_block_by_hash(
627                            &hash, false, /* include_traces */
628                        )
629                        .map_err(|e| invalid_params_rpc_err(e, None::<()>))?
630                }
631                _ => {
632                    match self.consensus_graph().get_phantom_block_by_number(
633                        block_num.try_into()?,
634                        None,
635                        false, /* include_traces */
636                    ) {
637                        Ok(pb) => pb,
638                        Err(e) => match e {
639                            ProviderBlockError::Common(e) => {
640                                return Err(invalid_params_rpc_err(
641                                    e, None::<()>,
642                                )
643                                .into());
644                            }
645                            ProviderBlockError::EpochNumberTooLarge => None,
646                        },
647                    }
648                }
649            }
650        };
651
652        Ok(phantom_block)
653    }
654
655    pub fn block_by_hash(
656        &self, hash: H256, include_txs: bool,
657    ) -> CoreResult<Option<RpcBlock>> {
658        let phantom_block = self.phantom_block_by_hash(hash)?;
659
660        match phantom_block {
661            None => Ok(None),
662            Some(pb) => Ok(Some(RpcBlock::from_phantom(&pb, include_txs))),
663        }
664    }
665
666    pub fn block_by_number(
667        &self, block_num: BlockNumber, include_txs: bool,
668    ) -> CoreResult<Option<RpcBlock>> {
669        let phantom_block = self.phantom_block_by_number(block_num)?;
670
671        match phantom_block {
672            None => Ok(None),
673            Some(pb) => Ok(Some(RpcBlock::from_phantom(&pb, include_txs))),
674        }
675    }
676
677    pub fn next_nonce(
678        &self, address: H160, num: Option<BlockNumber>,
679    ) -> CoreResult<U256> {
680        let nonce = match num {
681            Some(BlockNumber::Pending) => {
682                self.tx_pool.get_next_nonce(&address.with_evm_space())
683            }
684            _ => self.consensus_graph().next_nonce(
685                address.with_evm_space(),
686                num.unwrap_or_default().into(),
687                "num",
688            )?,
689        };
690
691        Ok(nonce)
692    }
693
694    pub fn block_transaction_count_by_hash(
695        &self, hash: H256,
696    ) -> CoreResult<Option<U256>> {
697        let phantom_block = self.phantom_block_by_hash(hash)?;
698
699        match phantom_block {
700            None => Ok(None),
701            Some(pb) => Ok(Some(pb.transactions.len().into())),
702        }
703    }
704
705    pub fn block_transaction_count_by_number(
706        &self, block_num: BlockNumber,
707    ) -> CoreResult<Option<U256>> {
708        let phantom_block = self.phantom_block_by_number(block_num)?;
709
710        match phantom_block {
711            None => Ok(None),
712            Some(pb) => Ok(Some(pb.transactions.len().into())),
713        }
714    }
715
716    pub fn block_uncles_count_by_hash(
717        &self, hash: H256,
718    ) -> CoreResult<Option<U256>> {
719        let epoch_num = match self.consensus.get_block_epoch_number(&hash) {
720            None => return Ok(None),
721            Some(n) => n,
722        };
723
724        let maybe_pivot_hash = self
725            .consensus
726            .get_block_hashes_by_epoch(epoch_num.into())
727            .ok()
728            .and_then(|hs| hs.last().cloned());
729
730        match maybe_pivot_hash {
731            Some(h) if h == hash => Ok(Some(0.into())),
732            _ => Ok(None),
733        }
734    }
735
736    pub fn block_uncles_count_by_number(
737        &self, block_num: BlockNumber,
738    ) -> CoreResult<Option<U256>> {
739        let epoch_num = self.convert_block_number_to_epoch_number(block_num)?;
740        let maybe_epoch =
741            self.consensus.get_block_hashes_by_epoch(epoch_num).ok();
742
743        Ok(maybe_epoch.map(|_| 0.into()))
744    }
745
746    pub fn code_at(
747        &self, address: H160, block_num: Option<BlockNumber>,
748    ) -> CoreResult<Bytes> {
749        let epoch_num = self.convert_block_number_to_epoch_number(
750            block_num.unwrap_or_default(),
751        )?;
752
753        let state_db = self
754            .consensus
755            .get_eth_state_db_by_epoch_number(epoch_num, "num")?;
756
757        let address = address.with_evm_space();
758
759        let code = match state_db
760            .get_account(&address)
761            .map_err(|err| CoreError::from(err))?
762        {
763            Some(acc) => match state_db
764                .get_code(&address, &acc.code_hash)
765                .map_err(|err| CoreError::from(err))?
766            {
767                Some(code) => (*code.code).clone(),
768                _ => vec![],
769            },
770            None => vec![],
771        };
772
773        Ok(Bytes::new(code))
774    }
775
776    pub fn fee_history(
777        &self, mut block_count: HexU64, newest_block: BlockNumber,
778        reward_percentiles: Option<Vec<f64>>,
779    ) -> CoreResult<FeeHistory> {
780        if block_count.as_u64() == 0 || newest_block == BlockNumber::Pending {
781            return Ok(FeeHistory::new());
782        }
783
784        if block_count.as_u64() > MAX_FEE_HISTORY_CACHE_BLOCK_COUNT {
785            block_count = HexU64::from(MAX_FEE_HISTORY_CACHE_BLOCK_COUNT);
786        }
787
788        if let Some(percentiles) = &reward_percentiles {
789            if percentiles.windows(2).any(|w| w[0] > w[1] || w[0] > 100.) {
790                return Err(RpcError::from(
791                    EthApiError::InvalidRewardPercentiles,
792                )
793                .into());
794            }
795        }
796        let reward_percentiles = reward_percentiles.unwrap_or_default();
797
798        // keep read lock to ensure consistent view
799        let _consensus = self.consensus_graph().inner.read();
800
801        let epoch_num =
802            self.convert_block_number_to_epoch_number(newest_block)?;
803        let newest_height: u64 = self
804            .consensus_graph()
805            .get_height_from_epoch_number(epoch_num)
806            .map_err(|e| invalid_params_rpc_err(e, None::<()>))?;
807
808        if newest_block == BlockNumber::Latest {
809            let fetch_block_by_hash = |height| {
810                self.fetch_block_by_hash(&height).map_err(|e| e.to_string())
811            };
812
813            let latest_block = self
814                .fetch_block_by_height(newest_height)
815                .map_err(|e| internal_error_with_data(e.to_string()))?;
816
817            self.fee_history_cache
818                .update_to_latest_block(
819                    newest_height,
820                    latest_block.pivot_header.hash(),
821                    block_count.as_u64(),
822                    fetch_block_by_hash,
823                )
824                .map_err(|e| internal_error_with_data(e.to_string()))?;
825        }
826
827        let mut fee_history = FeeHistory::new();
828
829        let end_block = newest_height;
830        let start_block = if end_block >= block_count.as_u64() {
831            end_block - block_count.as_u64() + 1
832        } else {
833            0
834        };
835
836        let mut cached_fee_history_entries = self
837            .fee_history_cache
838            .get_history_with_missing_info(start_block, end_block);
839
840        cached_fee_history_entries.reverse();
841        for (i, entry) in cached_fee_history_entries.into_iter().enumerate() {
842            if entry.is_none() {
843                let height = end_block - i as u64;
844                let block = self
845                    .fetch_block_by_height(height)
846                    .map_err(|e| invalid_params_rpc_err(e, None::<()>))?;
847
848                // Internal error happens only if the fetch header has
849                // inconsistent block height
850                fee_history
851                    .push_front_block(
852                        Space::Ethereum,
853                        &reward_percentiles,
854                        &block.pivot_header,
855                        block.transactions.iter().map(|x| &**x),
856                    )
857                    .map_err(|_| internal_error())?;
858            } else {
859                fee_history
860                    .push_front_entry(&entry.unwrap(), &reward_percentiles)
861                    .expect("always success");
862            }
863        }
864
865        let last_hash = self
866            .consensus_graph()
867            .get_hash_from_epoch_number((end_block + 1).into())?;
868        let last_header = self
869            .consensus_graph()
870            .data_manager()
871            .block_header_by_hash(&last_hash)
872            .ok_or_else(|| {
873                format!("last block missing, height={}", end_block + 1)
874            })?;
875
876        fee_history.finish(
877            start_block,
878            last_header.base_price().as_ref(),
879            Space::Ethereum,
880        );
881
882        Ok(fee_history)
883    }
884
885    pub fn transaction_by_hash(
886        &self, hash: H256,
887    ) -> CoreResult<Option<Transaction>> {
888        let tx_index = match self
889            .consensus
890            .data_manager()
891            .transaction_index_by_hash(&hash, false /* update_cache */)
892        {
893            None => return Ok(self.get_tx_from_txpool(hash)),
894            Some(tx_index) => tx_index,
895        };
896
897        let epoch_num =
898            match self.consensus.get_block_epoch_number(&tx_index.block_hash) {
899                None => return Ok(self.get_tx_from_txpool(hash)),
900                Some(n) => n,
901            };
902
903        let maybe_block = self
904            .consensus_graph()
905            .get_phantom_block_by_number(
906                EpochNumber::Number(epoch_num),
907                None,
908                false, /* include_traces */
909            )
910            .map_err(|e| invalid_params_rpc_err(e, None::<()>))?;
911
912        let phantom_block = match maybe_block {
913            None => return Ok(self.get_tx_from_txpool(hash)),
914            Some(b) => b,
915        };
916
917        for (idx, tx) in phantom_block.transactions.iter().enumerate() {
918            if tx.hash() == hash {
919                let tx = Self::block_tx_by_index(Some(phantom_block), idx);
920                if let Some(tx_ref) = &tx {
921                    if tx_ref.status
922                        == Some(
923                            TransactionStatus::Skipped
924                                .in_space(Space::Ethereum)
925                                .into(),
926                        )
927                    {
928                        // A skipped transaction is not available to clients if
929                        // accessed by its hash.
930                        return Ok(None);
931                    }
932                }
933                return Ok(tx);
934            }
935        }
936
937        Ok(self.get_tx_from_txpool(hash))
938    }
939
940    pub fn transaction_receipt(
941        &self, tx_hash: H256,
942    ) -> CoreResult<Option<Receipt>> {
943        let tx_index =
944            match self.consensus.data_manager().transaction_index_by_hash(
945                &tx_hash, false, /* update_cache */
946            ) {
947                None => return Ok(None),
948                Some(tx_index) => tx_index,
949            };
950
951        let epoch_num =
952            match self.consensus.get_block_epoch_number(&tx_index.block_hash) {
953                None => return Ok(None),
954                Some(n) => n,
955            };
956
957        if epoch_num > self.consensus_graph().best_executed_state_epoch_number()
958        {
959            // The receipt is only visible to optimistic execution.
960            return Ok(None);
961        }
962
963        let maybe_block = self
964            .consensus_graph()
965            .get_phantom_block_by_number(
966                EpochNumber::Number(epoch_num),
967                None,
968                false, /* include_traces */
969            )
970            .map_err(|e| invalid_params_rpc_err(e, None::<()>))?;
971
972        let phantom_block = match maybe_block {
973            None => return Ok(None),
974            Some(b) => b,
975        };
976
977        let mut prior_log_index = 0;
978
979        for (idx, tx) in phantom_block.transactions.iter().enumerate() {
980            if tx.hash() == tx_hash {
981                let receipt = self.construct_rpc_receipt(
982                    &phantom_block,
983                    idx,
984                    &mut prior_log_index,
985                )?;
986                // A skipped transaction is not available to clients if accessed
987                // by its hash.
988                if receipt.status_code
989                    == TransactionStatus::Skipped
990                        .in_space(Space::Ethereum)
991                        .into()
992                {
993                    return Ok(None);
994                }
995
996                return Ok(Some(receipt));
997            }
998
999            // if the if-branch was not entered, we do the bookkeeping here
1000            prior_log_index += phantom_block.receipts[idx].logs.len();
1001        }
1002
1003        Ok(None)
1004    }
1005
1006    pub fn logs(&self, filter: EthRpcLogFilter) -> CoreResult<Vec<Log>> {
1007        let filter: LogFilter = filter.into_primitive(self)?;
1008
1009        let logs = self
1010            .consensus_graph()
1011            .logs(filter)
1012            .map_err(|err| CoreError::from(err))?;
1013
1014        // If the results does not fit into `max_limit`, report an error
1015        if let Some(max_limit) = self.config.get_logs_filter_max_limit {
1016            if logs.len() > max_limit {
1017                bail!(invalid_params("filter", Some(format!("This query results in too many logs, max limitation is {}, please use a smaller block range", max_limit))));
1018            }
1019        }
1020
1021        Ok(logs
1022            .iter()
1023            .cloned()
1024            .map(|l| Log::try_from_localized(l, self, false))
1025            .collect::<Result<_, _>>()?)
1026    }
1027
1028    pub fn max_priority_fee_per_gas(&self) -> CoreResult<U256> {
1029        let evm_ratio =
1030            self.tx_pool.machine().params().evm_transaction_block_ratio
1031                as usize;
1032
1033        let fee_history = self.fee_history(
1034            HexU64::from(300),
1035            BlockNumber::Latest,
1036            Some(vec![50f64]),
1037        )?;
1038
1039        let total_reward: U256 = fee_history
1040            .reward()
1041            .iter()
1042            .map(|x| x.first().unwrap())
1043            .fold(U256::zero(), |x, y| x + *y);
1044
1045        Ok(total_reward * evm_ratio / 300)
1046    }
1047
1048    pub fn account_pending_transactions(
1049        &self, address: Address, maybe_start_nonce: Option<U256>,
1050        maybe_limit: Option<U64>,
1051    ) -> CoreResult<AccountPendingTransactions> {
1052        let (pending_txs, tx_status, pending_count) = self
1053            .tx_pool()
1054            .get_account_pending_transactions(
1055                &Address::from(address).with_evm_space(),
1056                maybe_start_nonce,
1057                maybe_limit.map(|limit| limit.as_usize()),
1058                self.best_epoch_number(),
1059            )
1060            .map_err(|e| CoreError::from(e))?;
1061        Ok(AccountPendingTransactions {
1062            pending_transactions: pending_txs
1063                .into_iter()
1064                .map(|tx| {
1065                    Transaction::from_signed(
1066                        &tx,
1067                        (None, None, None),
1068                        (None, None),
1069                    )
1070                })
1071                .collect(),
1072            first_tx_status: tx_status,
1073            pending_count: pending_count.into(),
1074        })
1075    }
1076}
1077
1078impl SpawnBlocking for EthApi {
1079    fn io_task_spawner(&self) -> impl TaskSpawner { self.executor.clone() }
1080}
1081
1082impl EthApi {
1083    pub fn async_transaction_by_hash(
1084        &self, hash: H256,
1085    ) -> impl Future<Output = Result<Option<Transaction>, RpcError>> + Send
1086    {
1087        let self_clone = self.clone();
1088        async move {
1089            let resp = self_clone
1090                .spawn_blocking_io(move |this| {
1091                    this.transaction_by_hash(hash).map_err(|err| err.into())
1092                })
1093                .await;
1094            resp
1095        }
1096    }
1097}
1098
1099impl BlockProvider for &EthApi {
1100    fn get_block_epoch_number(&self, hash: &H256) -> Option<u64> {
1101        self.consensus_graph().get_block_epoch_number(hash)
1102    }
1103
1104    fn get_block_hashes_by_epoch(
1105        &self, epoch_number: EpochNumber,
1106    ) -> Result<Vec<H256>, String> {
1107        self.consensus_graph()
1108            .get_block_hashes_by_epoch(epoch_number)
1109            .map_err(|e| e.to_string())
1110    }
1111}
1112
1113#[async_trait]
1114impl EthApiServer for EthApi {
1115    /// Returns the protocol version encoded as a string.
1116    async fn protocol_version(&self) -> RpcResult<U64> { Ok(U64::from(65)) }
1117
1118    /// Returns an object with data about the sync status or false.
1119    fn syncing(&self) -> RpcResult<SyncStatus> { Ok(self.sync_status()) }
1120
1121    /// Returns the client coinbase address.
1122    async fn author(&self) -> RpcResult<Address> { Ok(H160::zero()) }
1123
1124    /// Returns a list of addresses owned by client.
1125    fn accounts(&self) -> RpcResult<Vec<Address>> { Ok(vec![]) }
1126
1127    /// Returns the number of most recent block.
1128    fn block_number(&self) -> RpcResult<U256> {
1129        self.latest_block_number().map_err(|err| err.into())
1130    }
1131
1132    /// Returns the chain ID of the current network.
1133    async fn chain_id(&self) -> RpcResult<Option<U64>> {
1134        Ok(Some(self.chain_id().into()))
1135    }
1136
1137    /// Returns information about a block by hash.
1138    async fn block_by_hash(
1139        &self, hash: H256, full: bool,
1140    ) -> RpcResult<Option<Block>> {
1141        self.block_by_hash(hash, full).map_err(|err| err.into())
1142    }
1143
1144    /// Returns information about a block by number.
1145    async fn block_by_number(
1146        &self, number: BlockNumberOrTag, full: bool,
1147    ) -> RpcResult<Option<Block>> {
1148        self.block_by_number(number, full).map_err(|err| err.into())
1149    }
1150
1151    /// Returns the number of transactions in a block from a block matching the
1152    /// given block hash.
1153    async fn block_transaction_count_by_hash(
1154        &self, hash: H256,
1155    ) -> RpcResult<Option<U256>> {
1156        self.block_transaction_count_by_hash(hash)
1157            .map_err(|err| err.into())
1158    }
1159
1160    /// Returns the number of transactions in a block matching the given block
1161    /// number.
1162    async fn block_transaction_count_by_number(
1163        &self, number: BlockNumberOrTag,
1164    ) -> RpcResult<Option<U256>> {
1165        self.block_transaction_count_by_number(number)
1166            .map_err(|err| err.into())
1167    }
1168
1169    /// Returns the number of uncles in a block from a block matching the given
1170    /// block hash.
1171    async fn block_uncles_count_by_hash(
1172        &self, hash: H256,
1173    ) -> RpcResult<Option<U256>> {
1174        self.block_uncles_count_by_hash(hash)
1175            .map_err(|err| err.into())
1176    }
1177
1178    /// Returns the number of uncles in a block with given block number.
1179    async fn block_uncles_count_by_number(
1180        &self, number: BlockNumberOrTag,
1181    ) -> RpcResult<Option<U256>> {
1182        self.block_uncles_count_by_number(number)
1183            .map_err(|err| err.into())
1184    }
1185
1186    /// Returns all transaction receipts for a given block.
1187    async fn block_receipts(
1188        &self, block_id: BlockId,
1189    ) -> RpcResult<Option<Vec<Receipt>>> {
1190        self.get_block_receipts(block_id)
1191            .map(|val| Some(val))
1192            .map_err(|e| e.into())
1193    }
1194
1195    /// Returns an uncle block of the given block and index.
1196    async fn uncle_by_block_hash_and_index(
1197        &self, hash: H256, index: Index,
1198    ) -> RpcResult<Option<Block>> {
1199        let _ = (hash, index);
1200        Ok(None)
1201    }
1202
1203    /// Returns an uncle block of the given block and index.
1204    async fn uncle_by_block_number_and_index(
1205        &self, number: BlockNumberOrTag, index: Index,
1206    ) -> RpcResult<Option<Block>> {
1207        let _ = (number, index);
1208        Ok(None)
1209    }
1210
1211    /// Returns the EIP-2718 encoded transaction if it exists.
1212    ///
1213    /// If this is a EIP-4844 transaction that is in the pool it will include
1214    /// the sidecar.
1215    async fn raw_transaction_by_hash(
1216        &self, hash: H256,
1217    ) -> RpcResult<Option<Bytes>> {
1218        let _ = hash;
1219        Err(internal_error_with_data("Not implemented"))
1220    }
1221
1222    /// Returns the information about a transaction requested by transaction
1223    /// hash.
1224    async fn transaction_by_hash(
1225        &self, hash: H256,
1226    ) -> RpcResult<Option<Transaction>> {
1227        self.async_transaction_by_hash(hash).await
1228    }
1229
1230    /// Returns information about a raw transaction by block hash and
1231    /// transaction index position.
1232    async fn raw_transaction_by_block_hash_and_index(
1233        &self, hash: H256, index: Index,
1234    ) -> RpcResult<Option<Bytes>> {
1235        let _ = (hash, index);
1236        Err(internal_error_with_data("Not implemented"))
1237    }
1238
1239    /// Returns information about a transaction by block hash and transaction
1240    /// index position.
1241    async fn transaction_by_block_hash_and_index(
1242        &self, hash: H256, index: Index,
1243    ) -> RpcResult<Option<Transaction>> {
1244        let phantom_block = self.phantom_block_by_hash(hash)?;
1245
1246        Ok(EthApi::block_tx_by_index(phantom_block, index.value()))
1247    }
1248
1249    /// Returns information about a raw transaction by block number and
1250    /// transaction index position.
1251    async fn raw_transaction_by_block_number_and_index(
1252        &self, number: BlockNumberOrTag, index: Index,
1253    ) -> RpcResult<Option<Bytes>> {
1254        let _ = (number, index);
1255        Err(internal_error_with_data("Not implemented"))
1256    }
1257
1258    /// Returns information about a transaction by block number and transaction
1259    /// index position.
1260    async fn transaction_by_block_number_and_index(
1261        &self, number: BlockNumberOrTag, index: Index,
1262    ) -> RpcResult<Option<Transaction>> {
1263        let phantom_block = self.phantom_block_by_number(number)?;
1264
1265        Ok(EthApi::block_tx_by_index(phantom_block, index.value()))
1266    }
1267
1268    /// Returns information about a transaction by sender and nonce.
1269    async fn transaction_by_sender_and_nonce(
1270        &self, address: Address, nonce: U64,
1271    ) -> RpcResult<Option<Transaction>> {
1272        let _ = (address, nonce);
1273        Err(internal_error_with_data("Not implemented"))
1274    }
1275
1276    /// Returns the receipt of a transaction by transaction hash.
1277    async fn transaction_receipt(
1278        &self, hash: H256,
1279    ) -> RpcResult<Option<Receipt>> {
1280        self.transaction_receipt(hash).map_err(|err| err.into())
1281    }
1282
1283    /// Returns the balance of the account of given address.
1284    async fn balance(
1285        &self, address: Address, block_number: Option<BlockId>,
1286    ) -> RpcResult<U256> {
1287        self.user_balance(address, block_number)
1288            .map_err(|err| err.into())
1289    }
1290
1291    /// Returns the value from a storage position at a given address
1292    async fn storage_at(
1293        &self, address: Address, index: JsonStorageKey,
1294        block_number: Option<BlockId>,
1295    ) -> RpcResult<H256> {
1296        self.storage_at(address, index, block_number)
1297            .map_err(|err| err.into())
1298    }
1299
1300    /// Returns the number of transactions sent from an address at given block
1301    /// number.
1302    async fn transaction_count(
1303        &self, address: Address, block_number: Option<BlockId>,
1304    ) -> RpcResult<U256> {
1305        self.next_nonce(address, block_number)
1306            .map_err(|err| err.into())
1307    }
1308
1309    /// Returns code at a given address at given block number.
1310    async fn get_code(
1311        &self, address: Address, block_number: Option<BlockId>,
1312    ) -> RpcResult<Bytes> {
1313        self.code_at(address, block_number)
1314            .map_err(|err| err.into())
1315    }
1316
1317    /// Returns the block's header at given number.
1318    async fn header_by_number(
1319        &self, hash: BlockNumberOrTag,
1320    ) -> RpcResult<Option<Header>> {
1321        let _ = hash;
1322        Err(internal_error_with_data("Not implemented"))
1323    }
1324
1325    /// Returns the block's header at given hash.
1326    async fn header_by_hash(&self, hash: H256) -> RpcResult<Option<Header>> {
1327        let _ = hash;
1328        Err(internal_error_with_data("Not implemented"))
1329    }
1330
1331    /// `eth_simulateV1` executes an arbitrary number of transactions on top of
1332    /// the requested state. The transactions are packed into individual
1333    /// blocks. Overrides can be provided.
1334    async fn simulate_v1(
1335        &self, opts: SimulatePayload, block_number: Option<BlockId>,
1336    ) -> RpcResult<Vec<SimulatedBlock>> {
1337        let _ = block_number;
1338        let _ = opts;
1339        Err(internal_error_with_data("Not implemented"))
1340    }
1341
1342    /// Executes a new message call immediately without creating a transaction
1343    /// on the block chain.
1344    async fn call(
1345        &self, request: TransactionRequest, block_number: Option<BlockId>,
1346        state_overrides: Option<RpcStateOverride>,
1347        block_overrides: Option<Box<BlockOverrides>>,
1348    ) -> RpcResult<Bytes> {
1349        let (execution, _estimation) = self.exec_transaction(
1350            request,
1351            block_number,
1352            state_overrides,
1353            block_overrides,
1354        )?;
1355
1356        Ok(execution.output.into())
1357    }
1358
1359    /// Simulate arbitrary number of transactions at an arbitrary blockchain
1360    /// index, with the optionality of state overrides
1361    async fn call_many(
1362        &self, bundle: Bundle, state_context: Option<StateContext>,
1363        state_override: Option<RpcStateOverride>,
1364    ) -> RpcResult<Vec<EthCallResponse>> {
1365        let _ = bundle;
1366        let _ = state_context;
1367        let _ = state_override;
1368        Err(internal_error_with_data("Not implemented"))
1369    }
1370
1371    /// Generates an access list for a transaction.
1372    ///
1373    /// This method creates an [EIP2930](https://eips.ethereum.org/EIPS/eip-2930) type accessList based on a given Transaction.
1374    ///
1375    /// An access list contains all storage slots and addresses touched by the
1376    /// transaction, except for the sender account and the chain's
1377    /// precompiles.
1378    ///
1379    /// It returns list of addresses and storage keys used by the transaction,
1380    /// plus the gas consumed when the access list is added. That is, it
1381    /// gives you the list of addresses and storage keys that will be used
1382    /// by that transaction, plus the gas consumed if the access
1383    /// list is included. Like eth_estimateGas, this is an estimation; the list
1384    /// could change when the transaction is actually mined. Adding an
1385    /// accessList to your transaction does not necessary result in lower
1386    /// gas usage compared to a transaction without an access list.
1387    async fn create_access_list(
1388        &self, request: TransactionRequest, block_number: Option<BlockId>,
1389    ) -> RpcResult<AccessListResult> {
1390        let _ = block_number;
1391        let _ = request;
1392        Err(internal_error_with_data("Not implemented"))
1393    }
1394
1395    /// Generates and returns an estimate of how much gas is necessary to allow
1396    /// the transaction to complete.
1397    async fn estimate_gas(
1398        &self, request: TransactionRequest, block_number: Option<BlockId>,
1399        state_overrides: Option<RpcStateOverride>,
1400    ) -> RpcResult<U256> {
1401        let (_, estimated_gas) = self.exec_transaction(
1402            request,
1403            block_number,
1404            state_overrides,
1405            None,
1406        )?;
1407
1408        Ok(estimated_gas)
1409    }
1410
1411    /// Returns the current price per gas in wei.
1412    async fn gas_price(&self) -> RpcResult<U256> { Ok(self.gas_price()) }
1413
1414    /// Returns the account details by specifying an address and a block
1415    /// number/tag
1416    // async fn get_account(
1417    //     &self,
1418    //     address: Address,
1419    //     block: BlockId,
1420    // ) -> RpcResult<Option<reth_rpc_types::Account>>;
1421
1422    /// Introduced in EIP-1559, returns suggestion for the priority for dynamic
1423    /// fee transactions.
1424    async fn max_priority_fee_per_gas(&self) -> RpcResult<U256> {
1425        self.max_priority_fee_per_gas().map_err(|err| err.into())
1426    }
1427
1428    /// Introduced in EIP-4844, returns the current blob base fee in wei.
1429    // async fn blob_base_fee(&self) -> RpcResult<U256>;
1430
1431    /// Returns the Transaction fee history
1432    ///
1433    /// Introduced in EIP-1559 for getting information on the appropriate
1434    /// priority fee to use.
1435    ///
1436    /// Returns transaction base fee per gas and effective priority fee per gas
1437    /// for the requested/supported block range. The returned Fee history
1438    /// for the returned block range can be a subsection of the requested
1439    /// range if not all blocks are available.
1440    async fn fee_history(
1441        &self, block_count: U64, newest_block: BlockNumberOrTag,
1442        reward_percentiles: Option<Vec<f64>>,
1443    ) -> RpcResult<FeeHistory> {
1444        self.fee_history(
1445            block_count.as_u64().into(),
1446            newest_block,
1447            reward_percentiles,
1448        )
1449        .map_err(|err| err.into())
1450    }
1451
1452    /// Returns whether the client is actively mining new blocks.
1453    async fn is_mining(&self) -> RpcResult<bool> { Ok(false) }
1454
1455    /// Returns the number of hashes per second that the node is mining with.
1456    async fn hashrate(&self) -> RpcResult<U256> { Ok(U256::zero()) }
1457
1458    /// Returns the hash of the current block, the seedHash, and the boundary
1459    /// condition to be met (“target”)
1460    // async fn get_work(&self) -> RpcResult<Work>;
1461
1462    /// Used for submitting mining hashrate.
1463    ///
1464    /// Can be used for remote miners to submit their hash rate.
1465    /// It accepts the miner hash rate and an identifier which must be unique
1466    /// between nodes. Returns `true` if the block was successfully
1467    /// submitted, `false` otherwise.
1468    async fn submit_hashrate(
1469        &self, hashrate: U256, id: H256,
1470    ) -> RpcResult<bool> {
1471        let _ = (hashrate, id);
1472        Ok(false)
1473    }
1474
1475    /// Used for submitting a proof-of-work solution.
1476    async fn submit_work(
1477        &self, nonce: H64, pow_hash: H256, mix_digest: H256,
1478    ) -> RpcResult<bool> {
1479        let _ = (nonce, pow_hash, mix_digest);
1480        Ok(false)
1481    }
1482
1483    /// Sends transaction; will block waiting for signer to return the
1484    /// transaction hash.
1485    async fn send_transaction(
1486        &self, request: TransactionRequest,
1487    ) -> RpcResult<H256> {
1488        let _ = request;
1489        Err(internal_error_with_data("Not implemented"))
1490    }
1491
1492    /// Sends signed transaction, returning its hash.
1493    async fn send_raw_transaction(&self, bytes: Bytes) -> RpcResult<H256> {
1494        let tx = if let Ok(tx) =
1495            TransactionWithSignature::from_raw(&bytes.into_vec())
1496        {
1497            tx
1498        } else {
1499            bail!(EthApiError::FailedToDecodeSignedTransaction)
1500        };
1501
1502        if tx.space() != Space::Ethereum {
1503            bail!(EthApiError::Other(
1504                "Incorrect transaction space".to_string()
1505            ));
1506        }
1507
1508        if tx.recover_public().is_err() {
1509            bail!(EthApiError::InvalidTransactionSignature);
1510        }
1511
1512        let r = self.send_transaction_with_signature(tx)?;
1513        Ok(r)
1514    }
1515
1516    async fn submit_transaction(&self, raw: Bytes) -> RpcResult<H256> {
1517        self.send_raw_transaction(raw).await
1518    }
1519
1520    /// Returns an Ethereum specific signature with:
1521    /// sign(keccak256("\x19Ethereum Signed Message:\n"
1522    /// + len(message) + message))).
1523    async fn sign(&self, address: Address, message: Bytes) -> RpcResult<Bytes> {
1524        let _ = (address, message);
1525        Err(internal_error_with_data("Not implemented"))
1526    }
1527
1528    /// Signs a transaction that can be submitted to the network at a later time
1529    /// using with `sendRawTransaction.`
1530    async fn sign_transaction(
1531        &self, transaction: TransactionRequest,
1532    ) -> RpcResult<Bytes> {
1533        let _ = transaction;
1534        Err(internal_error_with_data("Not implemented"))
1535    }
1536
1537    async fn logs(&self, filter: Filter) -> RpcResult<Vec<Log>> {
1538        self.logs(filter).map_err(|err| err.into())
1539    }
1540
1541    async fn account_pending_transactions(
1542        &self, address: Address, maybe_start_nonce: Option<U256>,
1543        maybe_limit: Option<U64>,
1544    ) -> RpcResult<AccountPendingTransactions> {
1545        self.account_pending_transactions(
1546            address,
1547            maybe_start_nonce,
1548            maybe_limit,
1549        )
1550        .map_err(|err| err.into())
1551    }
1552}