referrerpolicy=no-referrer-when-downgrade

sc_rpc/dev/
mod.rs

1// This file is part of Substrate.
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
19//! Implementation of the [`DevApiServer`] trait providing debug utilities for Substrate based
20//! blockchains.
21
22#[cfg(test)]
23mod tests;
24
25use jsonrpsee::Extensions;
26use sc_client_api::{BlockBackend, HeaderBackend};
27use sc_rpc_api::{check_if_safe, dev::error::Error};
28use sp_api::{ApiExt, Core, ProvideRuntimeApi};
29use sp_core::Encode;
30use sp_runtime::{
31	generic::DigestItem,
32	traits::{Block as BlockT, Header},
33};
34use std::{
35	marker::{PhantomData, Send, Sync},
36	sync::Arc,
37};
38
39pub use sc_rpc_api::dev::{BlockStats, DevApiServer};
40
41type HasherOf<Block> = <<Block as BlockT>::Header as Header>::Hashing;
42
43/// The Dev API. All methods are unsafe.
44pub struct Dev<Block: BlockT, Client> {
45	client: Arc<Client>,
46	_phantom: PhantomData<Block>,
47}
48
49impl<Block: BlockT, Client> Dev<Block, Client> {
50	/// Create a new Dev API.
51	pub fn new(client: Arc<Client>) -> Self {
52		Self { client, _phantom: PhantomData::default() }
53	}
54}
55
56impl<Block, Client> DevApiServer<Block::Hash> for Dev<Block, Client>
57where
58	Block: BlockT + 'static,
59	Client: BlockBackend<Block>
60		+ HeaderBackend<Block>
61		+ ProvideRuntimeApi<Block>
62		+ Send
63		+ Sync
64		+ 'static,
65	Client::Api: Core<Block>,
66{
67	fn block_stats(
68		&self,
69		ext: &Extensions,
70		hash: Block::Hash,
71	) -> Result<Option<BlockStats>, Error> {
72		check_if_safe(ext)?;
73
74		let block = {
75			let block = self.client.block(hash).map_err(|e| Error::BlockQueryError(Box::new(e)))?;
76			if let Some(block) = block {
77				let (mut header, body) = block.block.deconstruct();
78				// Remove the `Seal` to ensure we have the number of digests as expected by the
79				// runtime.
80				header.digest_mut().logs.retain(|item| !matches!(item, DigestItem::Seal(_, _)));
81				Block::new(header, body)
82			} else {
83				return Ok(None)
84			}
85		};
86		let parent_header = {
87			let parent_hash = *block.header().parent_hash();
88			let parent_header = self
89				.client
90				.header(parent_hash)
91				.map_err(|e| Error::BlockQueryError(Box::new(e)))?;
92			if let Some(header) = parent_header {
93				header
94			} else {
95				return Ok(None)
96			}
97		};
98		let block_len = block.encoded_size() as u64;
99		let num_extrinsics = block.extrinsics().len() as u64;
100		let pre_root = *parent_header.state_root();
101		let mut runtime_api = self.client.runtime_api();
102		runtime_api.record_proof();
103		runtime_api
104			.execute_block(parent_header.hash(), block)
105			.map_err(|_| Error::BlockExecutionFailed)?;
106		let witness = runtime_api
107			.extract_proof()
108			.expect("We enabled proof recording. A proof must be available; qed");
109		let witness_len = witness.encoded_size() as u64;
110		let witness_compact_len = witness
111			.into_compact_proof::<HasherOf<Block>>(pre_root)
112			.map_err(|_| Error::WitnessCompactionFailed)?
113			.encoded_size() as u64;
114		Ok(Some(BlockStats { witness_len, witness_compact_len, block_len, num_extrinsics }))
115	}
116}