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