fc_rpc/eth/
block.rs

1// This file is part of Frontier.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19use std::sync::Arc;
20
21use ethereum_types::{H256, U256};
22use jsonrpsee::core::RpcResult;
23// Substrate
24use 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;
30// Frontier
31use 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				// Get current in-pool transactions
143				let mut xts: Vec<<B as BlockT>::Extrinsic> = Vec::new();
144				// ready validated pool
145				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				// future validated pool
153				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			// get the pending transactions count
197			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}