1#[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
43pub struct Dev<Block: BlockT, Client> {
45 client: Arc<Client>,
46 _phantom: PhantomData<Block>,
47}
48
49impl<Block: BlockT, Client> Dev<Block, Client> {
50 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 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}