cfxcore/consensus/consensus_graph/rpc_api/
execution_provider.rs1use super::super::ConsensusGraph;
2
3use crate::{
4 block_data_manager::BlockExecutionResultWithEpoch,
5 errors::Result as CoreResult,
6};
7use cfx_execute_helper::estimation::{EstimateExt, EstimateRequest};
8use cfx_executor::executive::ExecutionOutcome;
9use cfx_parameters::rpc::{
10 GAS_PRICE_BLOCK_SAMPLE_SIZE, GAS_PRICE_DEFAULT_VALUE,
11 GAS_PRICE_TRANSACTION_SAMPLE_SIZE,
12};
13use cfx_rpc_eth_types::EvmOverrides;
14use cfx_types::{Space, H256, U256};
15use primitives::{EpochNumber, SignedTransaction};
16
17impl ConsensusGraph {
18 pub fn gas_price(&self, space: Space) -> Option<U256> {
21 let inner = self.inner.read();
22 let mut last_epoch_number = inner.best_epoch_number();
23 let (
24 number_of_tx_to_sample,
25 mut number_of_blocks_to_sample,
26 block_gas_ratio,
27 ) = (
28 GAS_PRICE_TRANSACTION_SAMPLE_SIZE,
29 GAS_PRICE_BLOCK_SAMPLE_SIZE,
30 1,
31 );
32 let mut prices = Vec::new();
33 let mut total_block_gas_limit: u64 = 0;
34 let mut total_tx_gas_limit: u64 = 0;
35
36 loop {
37 if number_of_blocks_to_sample == 0 || last_epoch_number == 0 {
38 break;
39 }
40 if prices.len() == number_of_tx_to_sample {
41 break;
42 }
43 let mut hashes = inner
44 .block_hashes_by_epoch(last_epoch_number.into())
45 .unwrap();
46 hashes.reverse();
47 last_epoch_number -= 1;
48
49 for hash in hashes {
50 let block = self
51 .data_man
52 .block_by_hash(&hash, false )
53 .unwrap();
54 total_block_gas_limit +=
55 block.block_header.gas_limit().as_u64() * block_gas_ratio;
56 for tx in block.transactions.iter() {
57 if space == Space::Native && tx.space() != Space::Native {
58 continue;
60 }
61 total_tx_gas_limit += tx.transaction.gas().as_u64();
65 prices.push(tx.gas_price().clone());
66 if prices.len() == number_of_tx_to_sample {
67 break;
68 }
69 }
70 number_of_blocks_to_sample -= 1;
71 if number_of_blocks_to_sample == 0
72 || prices.len() == number_of_tx_to_sample
73 {
74 break;
75 }
76 }
77 }
78
79 prices.sort();
80 if prices.is_empty() || total_tx_gas_limit == 0 {
81 Some(U256::from(GAS_PRICE_DEFAULT_VALUE))
82 } else {
83 let average_gas_limit_multiple =
84 total_block_gas_limit / total_tx_gas_limit;
85 if average_gas_limit_multiple > 5 {
86 Some(U256::from(GAS_PRICE_DEFAULT_VALUE))
88 } else if average_gas_limit_multiple >= 2 {
89 Some(prices[prices.len() / 8])
91 } else {
92 Some(prices[prices.len() / 2])
94 }
95 }
96 }
97
98 pub fn get_block_execution_info(
99 &self, block_hash: &H256,
100 ) -> Option<(BlockExecutionResultWithEpoch, Option<H256>)> {
101 let results_with_epoch = self
102 .inner
103 .read_recursive()
104 .block_execution_results_by_hash(block_hash, true)?;
105
106 let pivot_hash = results_with_epoch.0;
107
108 let maybe_state_root = match self.executor.wait_for_result(pivot_hash) {
109 Ok(execution_commitment) => {
110 Some(
114 execution_commitment
115 .state_root_with_aux_info
116 .aux_info
117 .state_root_hash,
118 )
119 }
120 Err(msg) => {
121 warn!("get_transaction_receipt_and_block_info() gets the following error from ConsensusExecutor: {}", msg);
122 None
123 }
124 };
125
126 Some((results_with_epoch, maybe_state_root))
127 }
128
129 pub fn call_virtual(
130 &self, tx: &SignedTransaction, epoch: EpochNumber,
131 request: EstimateRequest, evm_overrides: EvmOverrides,
132 ) -> CoreResult<(ExecutionOutcome, EstimateExt)> {
133 self.validate_stated_epoch(&epoch)?;
135 let (epoch_id, epoch_size) = if let Ok(v) =
136 self.get_block_hashes_by_epoch(epoch)
137 {
138 (v.last().expect("pivot block always exist").clone(), v.len())
139 } else {
140 bail!("cannot get block hashes in the specified epoch, maybe it does not exist?");
141 };
142 self.executor.call_virtual(
143 tx,
144 &epoch_id,
145 epoch_size,
146 request,
147 evm_overrides,
148 )
149 }
150}