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 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 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 Ok(H256::zero().into())
304 } else if signed_trans.len() + failed_trans.len() == 0 {
305 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 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, )
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, ) {
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 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 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 )
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, )
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 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, ) {
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 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, )
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 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 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 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 async fn protocol_version(&self) -> RpcResult<U64> { Ok(U64::from(65)) }
1117
1118 fn syncing(&self) -> RpcResult<SyncStatus> { Ok(self.sync_status()) }
1120
1121 async fn author(&self) -> RpcResult<Address> { Ok(H160::zero()) }
1123
1124 fn accounts(&self) -> RpcResult<Vec<Address>> { Ok(vec![]) }
1126
1127 fn block_number(&self) -> RpcResult<U256> {
1129 self.latest_block_number().map_err(|err| err.into())
1130 }
1131
1132 async fn chain_id(&self) -> RpcResult<Option<U64>> {
1134 Ok(Some(self.chain_id().into()))
1135 }
1136
1137 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 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 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 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 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 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 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 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 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 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 async fn transaction_by_hash(
1225 &self, hash: H256,
1226 ) -> RpcResult<Option<Transaction>> {
1227 self.async_transaction_by_hash(hash).await
1228 }
1229
1230 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 async fn gas_price(&self) -> RpcResult<U256> { Ok(self.gas_price()) }
1413
1414 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 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 async fn is_mining(&self) -> RpcResult<bool> { Ok(false) }
1454
1455 async fn hashrate(&self) -> RpcResult<U256> { Ok(U256::zero()) }
1457
1458 async fn submit_hashrate(
1469 &self, hashrate: U256, id: H256,
1470 ) -> RpcResult<bool> {
1471 let _ = (hashrate, id);
1472 Ok(false)
1473 }
1474
1475 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 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 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 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 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}