1mod state_full;
22mod utils;
23
24#[cfg(test)]
25mod tests;
26
27use crate::SubscriptionTaskExecutor;
28use jsonrpsee::{core::async_trait, Extensions, PendingSubscriptionSink};
29use sc_client_api::{
30 Backend, BlockBackend, BlockchainEvents, ExecutorProvider, ProofProvider, StorageProvider,
31};
32use sc_rpc_api::{check_if_safe, DenyUnsafe};
33use sc_tracing::block::TracingExecuteBlock;
34use sp_api::{CallApiAt, Metadata, ProvideRuntimeApi};
35use sp_blockchain::{HeaderBackend, HeaderMetadata};
36use sp_core::{
37 storage::{PrefixedStorageKey, StorageChangeSet, StorageData, StorageKey},
38 Bytes,
39};
40use sp_runtime::traits::Block as BlockT;
41use sp_version::RuntimeVersion;
42use std::sync::Arc;
43
44pub use sc_rpc_api::{child_state::*, state::*};
45
46const STORAGE_KEYS_PAGED_MAX_COUNT: u32 = 1000;
47
48#[async_trait]
50pub trait StateBackend<Block: BlockT, Client>: Send + Sync + 'static
51where
52 Block: BlockT + 'static,
53 Client: Send + Sync + 'static,
54{
55 fn call(
57 &self,
58 block: Option<Block::Hash>,
59 method: String,
60 call_data: Bytes,
61 ) -> Result<Bytes, Error>;
62
63 fn storage_keys(
65 &self,
66 block: Option<Block::Hash>,
67 prefix: StorageKey,
68 ) -> Result<Vec<StorageKey>, Error>;
69
70 fn storage_pairs(
72 &self,
73 block: Option<Block::Hash>,
74 prefix: StorageKey,
75 ) -> Result<Vec<(StorageKey, StorageData)>, Error>;
76
77 fn storage_keys_paged(
79 &self,
80 block: Option<Block::Hash>,
81 prefix: Option<StorageKey>,
82 count: u32,
83 start_key: Option<StorageKey>,
84 ) -> Result<Vec<StorageKey>, Error>;
85
86 fn storage(
88 &self,
89 block: Option<Block::Hash>,
90 key: StorageKey,
91 ) -> Result<Option<StorageData>, Error>;
92
93 fn storage_hash(
95 &self,
96 block: Option<Block::Hash>,
97 key: StorageKey,
98 ) -> Result<Option<Block::Hash>, Error>;
99
100 async fn storage_size(
105 &self,
106 block: Option<Block::Hash>,
107 key: StorageKey,
108 deny_unsafe: DenyUnsafe,
109 ) -> Result<Option<u64>, Error>;
110
111 fn metadata(&self, block: Option<Block::Hash>) -> Result<Bytes, Error>;
113
114 fn runtime_version(&self, block: Option<Block::Hash>) -> Result<RuntimeVersion, Error>;
116
117 fn query_storage(
123 &self,
124 from: Block::Hash,
125 to: Option<Block::Hash>,
126 keys: Vec<StorageKey>,
127 ) -> Result<Vec<StorageChangeSet<Block::Hash>>, Error>;
128
129 fn query_storage_at(
131 &self,
132 keys: Vec<StorageKey>,
133 at: Option<Block::Hash>,
134 ) -> Result<Vec<StorageChangeSet<Block::Hash>>, Error>;
135
136 fn read_proof(
138 &self,
139 block: Option<Block::Hash>,
140 keys: Vec<StorageKey>,
141 ) -> Result<ReadProof<Block::Hash>, Error>;
142
143 fn trace_block(
145 &self,
146 block: Block::Hash,
147 targets: Option<String>,
148 storage_keys: Option<String>,
149 methods: Option<String>,
150 ) -> Result<sp_rpc::tracing::TraceBlockResponse, Error>;
151
152 fn subscribe_runtime_version(&self, pending: PendingSubscriptionSink);
154
155 fn subscribe_storage(
157 &self,
158 pending: PendingSubscriptionSink,
159 keys: Option<Vec<StorageKey>>,
160 deny_unsafe: DenyUnsafe,
161 );
162}
163
164pub fn new_full<BE, Block: BlockT, Client>(
166 client: Arc<Client>,
167 executor: SubscriptionTaskExecutor,
168 execute_block: Option<Arc<dyn TracingExecuteBlock<Block>>>,
169) -> (State<Block, Client>, ChildState<Block, Client>)
170where
171 Block: BlockT + 'static,
172 Block::Hash: Unpin,
173 BE: Backend<Block> + 'static,
174 Client: ExecutorProvider<Block>
175 + StorageProvider<Block, BE>
176 + ProofProvider<Block>
177 + HeaderMetadata<Block, Error = sp_blockchain::Error>
178 + BlockchainEvents<Block>
179 + CallApiAt<Block>
180 + HeaderBackend<Block>
181 + BlockBackend<Block>
182 + ProvideRuntimeApi<Block>
183 + Send
184 + Sync
185 + 'static,
186 Client::Api: Metadata<Block>,
187{
188 let child_backend = Box::new(self::state_full::FullState::new(
189 client.clone(),
190 executor.clone(),
191 execute_block.clone(),
192 ));
193 let backend =
194 Box::new(self::state_full::FullState::new(client, executor, execute_block.clone()));
195 (State { backend }, ChildState { backend: child_backend })
196}
197
198pub struct State<Block, Client> {
200 backend: Box<dyn StateBackend<Block, Client>>,
201}
202
203#[async_trait]
204impl<Block, Client> StateApiServer<Block::Hash> for State<Block, Client>
205where
206 Block: BlockT + 'static,
207 Client: Send + Sync + 'static,
208{
209 fn call(
210 &self,
211 method: String,
212 data: Bytes,
213 block: Option<Block::Hash>,
214 ) -> Result<Bytes, Error> {
215 self.backend.call(block, method, data).map_err(Into::into)
216 }
217
218 fn storage_keys(
219 &self,
220 key_prefix: StorageKey,
221 block: Option<Block::Hash>,
222 ) -> Result<Vec<StorageKey>, Error> {
223 self.backend.storage_keys(block, key_prefix).map_err(Into::into)
224 }
225
226 fn storage_pairs(
227 &self,
228 ext: &Extensions,
229 key_prefix: StorageKey,
230 block: Option<Block::Hash>,
231 ) -> Result<Vec<(StorageKey, StorageData)>, Error> {
232 check_if_safe(ext)?;
233 self.backend.storage_pairs(block, key_prefix).map_err(Into::into)
234 }
235
236 fn storage_keys_paged(
237 &self,
238 prefix: Option<StorageKey>,
239 count: u32,
240 start_key: Option<StorageKey>,
241 block: Option<Block::Hash>,
242 ) -> Result<Vec<StorageKey>, Error> {
243 if count > STORAGE_KEYS_PAGED_MAX_COUNT {
244 return Err(Error::InvalidCount { value: count, max: STORAGE_KEYS_PAGED_MAX_COUNT })
245 }
246 self.backend
247 .storage_keys_paged(block, prefix, count, start_key)
248 .map_err(Into::into)
249 }
250
251 fn storage(
252 &self,
253 key: StorageKey,
254 block: Option<Block::Hash>,
255 ) -> Result<Option<StorageData>, Error> {
256 self.backend.storage(block, key).map_err(Into::into)
257 }
258
259 fn storage_hash(
260 &self,
261 key: StorageKey,
262 block: Option<Block::Hash>,
263 ) -> Result<Option<Block::Hash>, Error> {
264 self.backend.storage_hash(block, key).map_err(Into::into)
265 }
266
267 async fn storage_size(
268 &self,
269 ext: &Extensions,
270 key: StorageKey,
271 block: Option<Block::Hash>,
272 ) -> Result<Option<u64>, Error> {
273 let deny_unsafe = ext
274 .get::<DenyUnsafe>()
275 .cloned()
276 .expect("DenyUnsafe extension is always set by the substrate rpc server; qed");
277 self.backend.storage_size(block, key, deny_unsafe).await.map_err(Into::into)
278 }
279
280 fn metadata(&self, block: Option<Block::Hash>) -> Result<Bytes, Error> {
281 self.backend.metadata(block).map_err(Into::into)
282 }
283
284 fn runtime_version(&self, at: Option<Block::Hash>) -> Result<RuntimeVersion, Error> {
285 self.backend.runtime_version(at).map_err(Into::into)
286 }
287
288 fn query_storage(
289 &self,
290 ext: &Extensions,
291 keys: Vec<StorageKey>,
292 from: Block::Hash,
293 to: Option<Block::Hash>,
294 ) -> Result<Vec<StorageChangeSet<Block::Hash>>, Error> {
295 check_if_safe(ext)?;
296 self.backend.query_storage(from, to, keys).map_err(Into::into)
297 }
298
299 fn query_storage_at(
300 &self,
301 keys: Vec<StorageKey>,
302 at: Option<Block::Hash>,
303 ) -> Result<Vec<StorageChangeSet<Block::Hash>>, Error> {
304 self.backend.query_storage_at(keys, at).map_err(Into::into)
305 }
306
307 fn read_proof(
308 &self,
309 keys: Vec<StorageKey>,
310 block: Option<Block::Hash>,
311 ) -> Result<ReadProof<Block::Hash>, Error> {
312 self.backend.read_proof(block, keys).map_err(Into::into)
313 }
314
315 fn trace_block(
321 &self,
322 ext: &Extensions,
323 block: Block::Hash,
324 targets: Option<String>,
325 storage_keys: Option<String>,
326 methods: Option<String>,
327 ) -> Result<sp_rpc::tracing::TraceBlockResponse, Error> {
328 check_if_safe(ext)?;
329 self.backend
330 .trace_block(block, targets, storage_keys, methods)
331 .map_err(Into::into)
332 }
333
334 fn subscribe_runtime_version(&self, pending: PendingSubscriptionSink) {
335 self.backend.subscribe_runtime_version(pending)
336 }
337
338 fn subscribe_storage(
339 &self,
340 pending: PendingSubscriptionSink,
341 ext: &Extensions,
342 keys: Option<Vec<StorageKey>>,
343 ) {
344 let deny_unsafe = ext
345 .get::<DenyUnsafe>()
346 .cloned()
347 .expect("DenyUnsafe extension is always set by the substrate rpc server; qed");
348 self.backend.subscribe_storage(pending, keys, deny_unsafe)
349 }
350}
351
352pub trait ChildStateBackend<Block: BlockT, Client>: Send + Sync + 'static
354where
355 Block: BlockT + 'static,
356 Client: Send + Sync + 'static,
357{
358 fn read_child_proof(
360 &self,
361 block: Option<Block::Hash>,
362 storage_key: PrefixedStorageKey,
363 keys: Vec<StorageKey>,
364 ) -> Result<ReadProof<Block::Hash>, Error>;
365
366 fn storage_keys(
369 &self,
370 block: Option<Block::Hash>,
371 storage_key: PrefixedStorageKey,
372 prefix: StorageKey,
373 ) -> Result<Vec<StorageKey>, Error>;
374
375 fn storage_keys_paged(
377 &self,
378 block: Option<Block::Hash>,
379 storage_key: PrefixedStorageKey,
380 prefix: Option<StorageKey>,
381 count: u32,
382 start_key: Option<StorageKey>,
383 ) -> Result<Vec<StorageKey>, Error>;
384
385 fn storage(
387 &self,
388 block: Option<Block::Hash>,
389 storage_key: PrefixedStorageKey,
390 key: StorageKey,
391 ) -> Result<Option<StorageData>, Error>;
392
393 fn storage_entries(
395 &self,
396 block: Option<Block::Hash>,
397 storage_key: PrefixedStorageKey,
398 keys: Vec<StorageKey>,
399 ) -> Result<Vec<Option<StorageData>>, Error>;
400
401 fn storage_hash(
403 &self,
404 block: Option<Block::Hash>,
405 storage_key: PrefixedStorageKey,
406 key: StorageKey,
407 ) -> Result<Option<Block::Hash>, Error>;
408
409 fn storage_size(
411 &self,
412 block: Option<Block::Hash>,
413 storage_key: PrefixedStorageKey,
414 key: StorageKey,
415 ) -> Result<Option<u64>, Error> {
416 self.storage(block, storage_key, key).map(|x| x.map(|x| x.0.len() as u64))
417 }
418}
419
420pub struct ChildState<Block, Client> {
422 backend: Box<dyn ChildStateBackend<Block, Client>>,
423}
424
425impl<Block, Client> ChildStateApiServer<Block::Hash> for ChildState<Block, Client>
426where
427 Block: BlockT + 'static,
428 Client: Send + Sync + 'static,
429{
430 fn storage_keys(
431 &self,
432 storage_key: PrefixedStorageKey,
433 key_prefix: StorageKey,
434 block: Option<Block::Hash>,
435 ) -> Result<Vec<StorageKey>, Error> {
436 self.backend.storage_keys(block, storage_key, key_prefix).map_err(Into::into)
437 }
438
439 fn storage_keys_paged(
440 &self,
441 storage_key: PrefixedStorageKey,
442 prefix: Option<StorageKey>,
443 count: u32,
444 start_key: Option<StorageKey>,
445 block: Option<Block::Hash>,
446 ) -> Result<Vec<StorageKey>, Error> {
447 self.backend
448 .storage_keys_paged(block, storage_key, prefix, count, start_key)
449 .map_err(Into::into)
450 }
451
452 fn storage(
453 &self,
454 storage_key: PrefixedStorageKey,
455 key: StorageKey,
456 block: Option<Block::Hash>,
457 ) -> Result<Option<StorageData>, Error> {
458 self.backend.storage(block, storage_key, key).map_err(Into::into)
459 }
460
461 fn storage_entries(
462 &self,
463 storage_key: PrefixedStorageKey,
464 keys: Vec<StorageKey>,
465 block: Option<Block::Hash>,
466 ) -> Result<Vec<Option<StorageData>>, Error> {
467 self.backend.storage_entries(block, storage_key, keys).map_err(Into::into)
468 }
469
470 fn storage_hash(
471 &self,
472 storage_key: PrefixedStorageKey,
473 key: StorageKey,
474 block: Option<Block::Hash>,
475 ) -> Result<Option<Block::Hash>, Error> {
476 self.backend.storage_hash(block, storage_key, key).map_err(Into::into)
477 }
478
479 fn storage_size(
480 &self,
481 storage_key: PrefixedStorageKey,
482 key: StorageKey,
483 block: Option<Block::Hash>,
484 ) -> Result<Option<u64>, Error> {
485 self.backend.storage_size(block, storage_key, key).map_err(Into::into)
486 }
487
488 fn read_child_proof(
489 &self,
490 child_storage_key: PrefixedStorageKey,
491 keys: Vec<StorageKey>,
492 block: Option<Block::Hash>,
493 ) -> Result<ReadProof<Block::Hash>, Error> {
494 self.backend
495 .read_child_proof(block, child_storage_key, keys)
496 .map_err(Into::into)
497 }
498}
499
500fn client_err(err: sp_blockchain::Error) -> Error {
501 Error::Client(Box::new(err))
502}