1use ethereum_types::U256;
20use jsonrpsee::core::RpcResult;
21use sc_client_api::backend::{Backend, StorageProvider};
23use sp_api::ProvideRuntimeApi;
24use sp_blockchain::HeaderBackend;
25use sp_runtime::{
26 traits::{Block as BlockT, UniqueSaturatedInto},
27 Permill,
28};
29use fc_rpc_core::types::*;
31use fp_rpc::EthereumRuntimeRPCApi;
32
33use crate::{eth::Eth, frontier_backend_client, internal_err};
34
35impl<B, C, P, CT, BE, CIDP, EC> Eth<B, C, P, CT, BE, CIDP, EC>
36where
37 B: BlockT,
38 C: ProvideRuntimeApi<B>,
39 C::Api: EthereumRuntimeRPCApi<B>,
40 C: HeaderBackend<B> + StorageProvider<B, BE> + 'static,
41 BE: Backend<B> + 'static,
42{
43 pub fn gas_price(&self) -> RpcResult<U256> {
44 let block_hash = self.client.info().best_hash;
45
46 self.client
47 .runtime_api()
48 .gas_price(block_hash)
49 .map_err(|err| internal_err(format!("fetch runtime chain id failed: {err:?}")))
50 }
51
52 pub async fn fee_history(
53 &self,
54 block_count: u64,
55 newest_block: BlockNumberOrHash,
56 reward_percentiles: Option<Vec<f64>>,
57 ) -> RpcResult<FeeHistory> {
58 let range_limit: u64 = 1024;
60 let block_count: u64 = u64::min(block_count, range_limit);
61
62 if let Some(id) = frontier_backend_client::native_block_id::<B, C>(
63 self.client.as_ref(),
64 self.backend.as_ref(),
65 Some(newest_block),
66 )
67 .await?
68 {
69 let Ok(number) = self.client.expect_block_number_from_id(&id) else {
70 return Err(internal_err(format!(
71 "Failed to retrieve block number at {id}"
72 )));
73 };
74 let highest = UniqueSaturatedInto::<u64>::unique_saturated_into(number);
76 let lowest = highest.saturating_sub(block_count.saturating_sub(1));
77 let best_number =
79 UniqueSaturatedInto::<u64>::unique_saturated_into(self.client.info().best_number);
80 if lowest < best_number.saturating_sub(self.fee_history_cache_limit) {
82 return Err(internal_err("Block range out of bounds."));
83 }
84 if let Ok(fee_history_cache) = &self.fee_history_cache.lock() {
85 let mut response = FeeHistory {
86 oldest_block: U256::from(lowest),
87 base_fee_per_gas: Vec::new(),
88 gas_used_ratio: Vec::new(),
89 reward: None,
90 };
91 let mut rewards = Vec::new();
92 for n in lowest..highest + 1 {
94 if let Some(block) = fee_history_cache.get(&n) {
95 response.base_fee_per_gas.push(U256::from(block.base_fee));
96 response.gas_used_ratio.push(block.gas_used_ratio);
97 if let Some(ref requested_percentiles) = reward_percentiles {
99 let mut block_rewards = Vec::new();
100 let resolution_per_percentile: f64 = 2.0;
102 for p in requested_percentiles {
104 let p = p.clamp(0.0, 100.0);
106 let index = ((p.round() / 2f64) * 2f64) * resolution_per_percentile;
107 let reward = if let Some(r) = block.rewards.get(index as usize) {
109 U256::from(*r)
110 } else {
111 U256::zero()
112 };
113 block_rewards.push(reward);
114 }
115 if !block_rewards.is_empty() {
117 rewards.push(block_rewards);
119 }
120 }
121 }
122 }
123 if rewards.len() > 0 {
124 response.reward = Some(rewards);
125 }
126 if let (Some(last_gas_used), Some(last_fee_per_gas)) = (
128 response.gas_used_ratio.last(),
129 response.base_fee_per_gas.last(),
130 ) {
131 let substrate_hash = self
132 .client
133 .expect_block_hash_from_id(&id)
134 .map_err(|_| internal_err(format!("Expect block number from id: {id}")))?;
135 let elasticity = self
136 .storage_override
137 .elasticity(substrate_hash)
138 .unwrap_or(Permill::from_parts(125_000))
139 .deconstruct();
140 let elasticity = elasticity as f64 / 1_000_000f64;
141 let last_fee_per_gas =
142 UniqueSaturatedInto::<u64>::unique_saturated_into(*last_fee_per_gas) as f64;
143 if last_gas_used > &0.5 {
144 let increase = ((last_gas_used - 0.5) * 2f64) * elasticity;
146 let new_base_fee =
147 (last_fee_per_gas + (last_fee_per_gas * increase)) as u64;
148 response.base_fee_per_gas.push(U256::from(new_base_fee));
149 } else if last_gas_used < &0.5 {
150 let increase = ((0.5 - last_gas_used) * 2f64) * elasticity;
152 let new_base_fee =
153 (last_fee_per_gas - (last_fee_per_gas * increase)) as u64;
154 response.base_fee_per_gas.push(U256::from(new_base_fee));
155 } else {
156 response
158 .base_fee_per_gas
159 .push(U256::from(last_fee_per_gas as u64));
160 }
161 }
162 return Ok(response);
163 } else {
164 return Err(internal_err("Failed to read fee history cache."));
165 }
166 }
167 Err(internal_err(format!(
168 "Failed to retrieve requested block {newest_block:?}."
169 )))
170 }
171
172 pub fn max_priority_fee_per_gas(&self) -> RpcResult<U256> {
173 let at_percentile = 60;
175 let block_count = 20;
176 let index = (at_percentile * 2) as usize;
177
178 let highest =
179 UniqueSaturatedInto::<u64>::unique_saturated_into(self.client.info().best_number);
180 let lowest = highest.saturating_sub(block_count - 1);
181
182 let mut rewards = Vec::new();
184 if let Ok(fee_history_cache) = &self.fee_history_cache.lock() {
185 for n in lowest..highest + 1 {
186 if let Some(block) = fee_history_cache.get(&n) {
187 let reward = if let Some(r) = block.rewards.get(index) {
188 U256::from(*r)
189 } else {
190 U256::zero()
191 };
192 rewards.push(reward);
193 }
194 }
195 } else {
196 return Err(internal_err("Failed to read fee oracle cache."));
197 }
198 Ok(*rewards.iter().min().unwrap_or(&U256::zero()))
199 }
200}