1use std::sync::Arc;
20
21use ethereum_types::{H256, U256};
22use jsonrpsee::core::RpcResult;
23use sc_client_api::backend::{Backend, StorageProvider};
25use sc_transaction_pool_api::{InPoolTransaction, TransactionPool};
26use sp_api::ProvideRuntimeApi;
27use sp_blockchain::HeaderBackend;
28use sp_core::hashing::keccak_256;
29use sp_runtime::traits::Block as BlockT;
30use fc_rpc_core::types::*;
32use fp_rpc::EthereumRuntimeRPCApi;
33
34use crate::{
35 eth::{rich_block_build, BlockInfo, Eth},
36 frontier_backend_client, internal_err,
37};
38
39impl<B, C, P, CT, BE, CIDP, EC> Eth<B, C, P, CT, BE, CIDP, EC>
40where
41 B: BlockT,
42 C: ProvideRuntimeApi<B>,
43 C::Api: EthereumRuntimeRPCApi<B>,
44 C: HeaderBackend<B> + StorageProvider<B, BE> + 'static,
45 BE: Backend<B> + 'static,
46 P: TransactionPool<Block = B, Hash = B::Hash> + 'static,
47{
48 pub async fn block_by_hash(&self, hash: H256, full: bool) -> RpcResult<Option<RichBlock>> {
49 let BlockInfo {
50 block,
51 statuses,
52 substrate_hash,
53 base_fee,
54 ..
55 } = self.block_info_by_eth_block_hash(hash).await?;
56
57 match (block, statuses) {
58 (Some(block), Some(statuses)) => {
59 let mut rich_block = rich_block_build(
60 block,
61 statuses.into_iter().map(Option::Some).collect(),
62 Some(hash),
63 full,
64 Some(base_fee),
65 false,
66 );
67
68 let substrate_hash = H256::from_slice(substrate_hash.as_ref());
69 if let Some(parent_hash) = self
70 .forced_parent_hashes
71 .as_ref()
72 .and_then(|parent_hashes| parent_hashes.get(&substrate_hash).cloned())
73 {
74 rich_block.inner.header.parent_hash = parent_hash
75 }
76
77 Ok(Some(rich_block))
78 }
79 _ => Ok(None),
80 }
81 }
82
83 pub async fn block_by_number(
84 &self,
85 number_or_hash: BlockNumberOrHash,
86 full: bool,
87 ) -> RpcResult<Option<RichBlock>> {
88 let client = Arc::clone(&self.client);
89 let block_data_cache = Arc::clone(&self.block_data_cache);
90 let backend = Arc::clone(&self.backend);
91 let graph = Arc::clone(&self.graph);
92
93 match frontier_backend_client::native_block_id::<B, C>(
94 client.as_ref(),
95 backend.as_ref(),
96 Some(number_or_hash),
97 )
98 .await?
99 {
100 Some(id) => {
101 let substrate_hash = client
102 .expect_block_hash_from_id(&id)
103 .map_err(|_| internal_err(format!("Expect block number from id: {id}")))?;
104
105 let block = block_data_cache.current_block(substrate_hash).await;
106 let statuses = block_data_cache
107 .current_transaction_statuses(substrate_hash)
108 .await;
109
110 let base_fee = client.runtime_api().gas_price(substrate_hash).ok();
111
112 match (block, statuses) {
113 (Some(block), Some(statuses)) => {
114 let hash = H256::from(keccak_256(&rlp::encode(&block.header)));
115 let mut rich_block = rich_block_build(
116 block,
117 statuses.into_iter().map(Option::Some).collect(),
118 Some(hash),
119 full,
120 base_fee,
121 false,
122 );
123
124 let substrate_hash = H256::from_slice(substrate_hash.as_ref());
125 if let Some(parent_hash) = self
126 .forced_parent_hashes
127 .as_ref()
128 .and_then(|parent_hashes| parent_hashes.get(&substrate_hash).cloned())
129 {
130 rich_block.inner.header.parent_hash = parent_hash
131 }
132
133 Ok(Some(rich_block))
134 }
135 _ => Ok(None),
136 }
137 }
138 None if number_or_hash == BlockNumberOrHash::Pending => {
139 let api = client.runtime_api();
140 let best_hash = client.info().best_hash;
141
142 let mut xts: Vec<<B as BlockT>::Extrinsic> = Vec::new();
144 xts.extend(
146 graph
147 .ready()
148 .map(|in_pool_tx| in_pool_tx.data().as_ref().clone())
149 .collect::<Vec<<B as BlockT>::Extrinsic>>(),
150 );
151
152 xts.extend(
154 graph
155 .futures()
156 .iter()
157 .map(|in_pool_tx| in_pool_tx.data().as_ref().clone())
158 .collect::<Vec<<B as BlockT>::Extrinsic>>(),
159 );
160
161 let (block, statuses) = api
162 .pending_block(best_hash, xts)
163 .map_err(|_| internal_err(format!("Runtime access error at {best_hash}")))?;
164
165 let base_fee = api.gas_price(best_hash).ok();
166
167 match (block, statuses) {
168 (Some(block), Some(statuses)) => Ok(Some(rich_block_build(
169 block,
170 statuses.into_iter().map(Option::Some).collect(),
171 None,
172 full,
173 base_fee,
174 true,
175 ))),
176 _ => Ok(None),
177 }
178 }
179 None => Ok(None),
180 }
181 }
182
183 pub async fn block_transaction_count_by_hash(&self, hash: H256) -> RpcResult<Option<U256>> {
184 let blockinfo = self.block_info_by_eth_block_hash(hash).await?;
185 match blockinfo.block {
186 Some(block) => Ok(Some(U256::from(block.transactions.len()))),
187 None => Ok(None),
188 }
189 }
190
191 pub async fn block_transaction_count_by_number(
192 &self,
193 number_or_hash: BlockNumberOrHash,
194 ) -> RpcResult<Option<U256>> {
195 if let BlockNumberOrHash::Pending = number_or_hash {
196 return Ok(Some(U256::from(self.graph.ready().count())));
198 }
199
200 let block_info = self.block_info_by_number(number_or_hash).await?;
201 match block_info.block {
202 Some(block) => Ok(Some(U256::from(block.transactions.len()))),
203 None => Ok(None),
204 }
205 }
206
207 pub async fn block_transaction_receipts(
208 &self,
209 number_or_hash: BlockNumberOrHash,
210 ) -> RpcResult<Option<Vec<Receipt>>> {
211 let block_info = self.block_info_by_number(number_or_hash).await?;
212 let Some(statuses) = block_info.clone().statuses else {
213 return Ok(None);
214 };
215
216 let mut receipts = Vec::new();
217 let transactions: Vec<(H256, usize)> = statuses
218 .iter()
219 .map(|tx| (tx.transaction_hash, tx.transaction_index as usize))
220 .collect();
221 for (hash, index) in transactions {
222 if let Some(receipt) = self.transaction_receipt(&block_info, hash, index).await? {
223 receipts.push(receipt);
224 }
225 }
226
227 Ok(Some(receipts))
228 }
229
230 pub fn block_uncles_count_by_hash(&self, _: H256) -> RpcResult<U256> {
231 Ok(U256::zero())
232 }
233
234 pub fn block_uncles_count_by_number(&self, _: BlockNumberOrHash) -> RpcResult<U256> {
235 Ok(U256::zero())
236 }
237
238 pub fn uncle_by_block_hash_and_index(&self, _: H256, _: Index) -> RpcResult<Option<RichBlock>> {
239 Ok(None)
240 }
241
242 pub fn uncle_by_block_number_and_index(
243 &self,
244 _: BlockNumberOrHash,
245 _: Index,
246 ) -> RpcResult<Option<RichBlock>> {
247 Ok(None)
248 }
249}