1use std::{marker::PhantomData, sync::Arc};
20
21use ethereum::EnvelopedEncodable;
22use ethereum_types::H256;
23use jsonrpsee::core::{async_trait, RpcResult};
24use rlp::Encodable;
25use sc_client_api::backend::{Backend, StorageProvider};
27use sp_api::ProvideRuntimeApi;
28use sp_blockchain::HeaderBackend;
29use sp_runtime::traits::Block as BlockT;
30use fc_rpc_core::{types::*, DebugApiServer};
32use fc_storage::StorageOverride;
33use fp_rpc::EthereumRuntimeRPCApi;
34
35use crate::{cache::EthBlockDataCacheTask, frontier_backend_client, internal_err};
36
37pub struct Debug<B: BlockT, C, BE> {
39 client: Arc<C>,
40 backend: Arc<dyn fc_api::Backend<B>>,
41 storage_override: Arc<dyn StorageOverride<B>>,
42 block_data_cache: Arc<EthBlockDataCacheTask<B>>,
43 _marker: PhantomData<BE>,
44}
45
46impl<B: BlockT, C, BE> Debug<B, C, BE> {
47 pub fn new(
48 client: Arc<C>,
49 backend: Arc<dyn fc_api::Backend<B>>,
50 storage_override: Arc<dyn StorageOverride<B>>,
51 block_data_cache: Arc<EthBlockDataCacheTask<B>>,
52 ) -> Self {
53 Self {
54 client,
55 backend,
56 storage_override,
57 block_data_cache,
58 _marker: PhantomData,
59 }
60 }
61
62 async fn block_by(&self, number: BlockNumberOrHash) -> RpcResult<Option<ethereum::BlockV3>>
63 where
64 C: HeaderBackend<B> + StorageProvider<B, BE> + 'static,
65 BE: Backend<B>,
66 {
67 let id = match frontier_backend_client::native_block_id::<B, C>(
68 self.client.as_ref(),
69 self.backend.as_ref(),
70 Some(number),
71 )
72 .await?
73 {
74 Some(id) => id,
75 None => return Ok(None),
76 };
77
78 let substrate_hash = self
79 .client
80 .expect_block_hash_from_id(&id)
81 .map_err(|_| internal_err(format!("Expect block number from id: {id}")))?;
82 let block = self.block_data_cache.current_block(substrate_hash).await;
83 Ok(block)
84 }
85
86 async fn transaction_by(
87 &self,
88 transaction_hash: H256,
89 ) -> RpcResult<Option<ethereum::TransactionV3>>
90 where
91 C: HeaderBackend<B> + StorageProvider<B, BE> + 'static,
92 BE: Backend<B>,
93 {
94 let (eth_block_hash, index) = match frontier_backend_client::load_transactions::<B, C>(
95 self.client.as_ref(),
96 self.backend.as_ref(),
97 transaction_hash,
98 true,
99 )
100 .await?
101 {
102 Some((hash, index)) => (hash, index as usize),
103 None => return Ok(None),
104 };
105
106 let substrate_hash = match frontier_backend_client::load_hash::<B, C>(
107 self.client.as_ref(),
108 self.backend.as_ref(),
109 eth_block_hash,
110 )
111 .await?
112 {
113 Some(hash) => hash,
114 None => return Ok(None),
115 };
116
117 let block = self.block_data_cache.current_block(substrate_hash).await;
118 if let Some(block) = block {
119 Ok(Some(block.transactions[index].clone()))
120 } else {
121 Ok(None)
122 }
123 }
124
125 async fn receipts_by(
126 &self,
127 number: BlockNumberOrHash,
128 ) -> RpcResult<Option<Vec<ethereum::ReceiptV4>>>
129 where
130 C: HeaderBackend<B> + StorageProvider<B, BE> + 'static,
131 BE: Backend<B>,
132 {
133 let id = match frontier_backend_client::native_block_id::<B, C>(
134 self.client.as_ref(),
135 self.backend.as_ref(),
136 Some(number),
137 )
138 .await?
139 {
140 Some(id) => id,
141 None => return Ok(None),
142 };
143
144 let substrate_hash = self
145 .client
146 .expect_block_hash_from_id(&id)
147 .map_err(|_| internal_err(format!("Expect block number from id: {id}")))?;
148
149 let receipts = self.storage_override.current_receipts(substrate_hash);
151 Ok(receipts)
152 }
153}
154
155#[async_trait]
156impl<B, C, BE> DebugApiServer for Debug<B, C, BE>
157where
158 B: BlockT,
159 C: ProvideRuntimeApi<B>,
160 C::Api: EthereumRuntimeRPCApi<B>,
161 C: HeaderBackend<B> + StorageProvider<B, BE> + 'static,
162 BE: Backend<B> + 'static,
163{
164 async fn raw_header(&self, number: BlockNumberOrHash) -> RpcResult<Option<Bytes>> {
165 let block = self.block_by(number).await?;
166 Ok(block.map(|block| Bytes::new(block.header.rlp_bytes().to_vec())))
167 }
168
169 async fn raw_block(&self, number: BlockNumberOrHash) -> RpcResult<Option<Bytes>> {
170 let block = self.block_by(number).await?;
171 Ok(block.map(|block| Bytes::new(block.rlp_bytes().to_vec())))
172 }
173
174 async fn raw_transaction(&self, hash: H256) -> RpcResult<Option<Bytes>> {
175 let transaction = self.transaction_by(hash).await?;
176 Ok(transaction.map(|transaction| Bytes::new(transaction.encode().to_vec())))
177 }
178
179 async fn raw_receipts(&self, number: BlockNumberOrHash) -> RpcResult<Vec<Bytes>> {
180 let receipts = self.receipts_by(number).await?.unwrap_or_default();
181 Ok(receipts
182 .into_iter()
183 .map(|receipt| Bytes::new(receipt.encode().to_vec()))
184 .collect::<Vec<_>>())
185 }
186
187 fn bad_blocks(&self, _number: BlockNumberOrHash) -> RpcResult<Vec<()>> {
188 Ok(vec![])
193 }
194}