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 call_recorded(
155 &self,
156 block: Block::Hash,
157 method: String,
158 call_data: Bytes,
159 ) -> Result<Bytes, Error>;
160
161 fn subscribe_runtime_version(&self, pending: PendingSubscriptionSink);
163
164 fn subscribe_storage(
166 &self,
167 pending: PendingSubscriptionSink,
168 keys: Option<Vec<StorageKey>>,
169 deny_unsafe: DenyUnsafe,
170 );
171}
172
173pub fn new_full<BE, Block: BlockT, Client>(
179 client: Arc<Client>,
180 executor: SubscriptionTaskExecutor,
181 execute_block: Option<Arc<dyn TracingExecuteBlock<Block>>>,
182) -> (State<Block, Client>, ChildState<Block, Client>)
183where
184 Block: BlockT + 'static,
185 Block::Hash: Unpin,
186 BE: Backend<Block> + 'static,
187 Client: ExecutorProvider<Block>
188 + StorageProvider<Block, BE>
189 + ProofProvider<Block>
190 + HeaderMetadata<Block, Error = sp_blockchain::Error>
191 + BlockchainEvents<Block>
192 + CallApiAt<Block>
193 + HeaderBackend<Block>
194 + BlockBackend<Block>
195 + ProvideRuntimeApi<Block>
196 + Send
197 + Sync
198 + 'static,
199 Client::Api: Metadata<Block>,
200{
201 let child_backend = Box::new(self::state_full::FullState::new(
202 client.clone(),
203 executor.clone(),
204 execute_block.clone(),
205 ));
206 let backend =
207 Box::new(self::state_full::FullState::new(client, executor, execute_block.clone()));
208 (State { backend }, ChildState { backend: child_backend })
209}
210
211pub struct State<Block, Client> {
213 backend: Box<dyn StateBackend<Block, Client>>,
214}
215
216#[async_trait]
217impl<Block, Client> StateApiServer<Block::Hash> for State<Block, Client>
218where
219 Block: BlockT + 'static,
220 Client: Send + Sync + 'static,
221{
222 fn call(
223 &self,
224 method: String,
225 data: Bytes,
226 block: Option<Block::Hash>,
227 ) -> Result<Bytes, Error> {
228 self.backend.call(block, method, data).map_err(Into::into)
229 }
230
231 fn storage_keys(
232 &self,
233 ext: &Extensions,
234 key_prefix: StorageKey,
235 block: Option<Block::Hash>,
236 ) -> Result<Vec<StorageKey>, Error> {
237 check_if_safe(ext)?;
238 self.backend.storage_keys(block, key_prefix).map_err(Into::into)
239 }
240
241 fn storage_pairs(
242 &self,
243 ext: &Extensions,
244 key_prefix: StorageKey,
245 block: Option<Block::Hash>,
246 ) -> Result<Vec<(StorageKey, StorageData)>, Error> {
247 check_if_safe(ext)?;
248 self.backend.storage_pairs(block, key_prefix).map_err(Into::into)
249 }
250
251 fn storage_keys_paged(
252 &self,
253 prefix: Option<StorageKey>,
254 count: u32,
255 start_key: Option<StorageKey>,
256 block: Option<Block::Hash>,
257 ) -> Result<Vec<StorageKey>, Error> {
258 if count > STORAGE_KEYS_PAGED_MAX_COUNT {
259 return Err(Error::InvalidCount { value: count, max: STORAGE_KEYS_PAGED_MAX_COUNT });
260 }
261 self.backend
262 .storage_keys_paged(block, prefix, count, start_key)
263 .map_err(Into::into)
264 }
265
266 fn storage(
267 &self,
268 key: StorageKey,
269 block: Option<Block::Hash>,
270 ) -> Result<Option<StorageData>, Error> {
271 self.backend.storage(block, key).map_err(Into::into)
272 }
273
274 fn storage_hash(
275 &self,
276 key: StorageKey,
277 block: Option<Block::Hash>,
278 ) -> Result<Option<Block::Hash>, Error> {
279 self.backend.storage_hash(block, key).map_err(Into::into)
280 }
281
282 async fn storage_size(
283 &self,
284 ext: &Extensions,
285 key: StorageKey,
286 block: Option<Block::Hash>,
287 ) -> Result<Option<u64>, Error> {
288 let deny_unsafe = ext
289 .get::<DenyUnsafe>()
290 .cloned()
291 .expect("DenyUnsafe extension is always set by the substrate rpc server; qed");
292 self.backend.storage_size(block, key, deny_unsafe).await.map_err(Into::into)
293 }
294
295 fn metadata(&self, block: Option<Block::Hash>) -> Result<Bytes, Error> {
296 self.backend.metadata(block).map_err(Into::into)
297 }
298
299 fn runtime_version(&self, at: Option<Block::Hash>) -> Result<RuntimeVersion, Error> {
300 self.backend.runtime_version(at).map_err(Into::into)
301 }
302
303 fn query_storage(
304 &self,
305 ext: &Extensions,
306 keys: Vec<StorageKey>,
307 from: Block::Hash,
308 to: Option<Block::Hash>,
309 ) -> Result<Vec<StorageChangeSet<Block::Hash>>, Error> {
310 check_if_safe(ext)?;
311 self.backend.query_storage(from, to, keys).map_err(Into::into)
312 }
313
314 fn query_storage_at(
315 &self,
316 keys: Vec<StorageKey>,
317 at: Option<Block::Hash>,
318 ) -> Result<Vec<StorageChangeSet<Block::Hash>>, Error> {
319 self.backend.query_storage_at(keys, at).map_err(Into::into)
320 }
321
322 fn read_proof(
323 &self,
324 keys: Vec<StorageKey>,
325 block: Option<Block::Hash>,
326 ) -> Result<ReadProof<Block::Hash>, Error> {
327 self.backend.read_proof(block, keys).map_err(Into::into)
328 }
329
330 fn trace_block(
336 &self,
337 ext: &Extensions,
338 block: Block::Hash,
339 targets: Option<String>,
340 storage_keys: Option<String>,
341 methods: Option<String>,
342 ) -> Result<sp_rpc::tracing::TraceBlockResponse, Error> {
343 check_if_safe(ext)?;
344 self.backend
345 .trace_block(block, targets, storage_keys, methods)
346 .map_err(Into::into)
347 }
348
349 fn call_recorded(
350 &self,
351 ext: &Extensions,
352 method: String,
353 data: Bytes,
354 block: Block::Hash,
355 ) -> Result<Bytes, Error> {
356 check_if_safe(ext).map_err(|_| Error::CallRecordedDenied)?;
357 self.backend.call_recorded(block, method, data).map_err(Into::into)
358 }
359
360 fn subscribe_runtime_version(&self, pending: PendingSubscriptionSink) {
361 self.backend.subscribe_runtime_version(pending)
362 }
363
364 fn subscribe_storage(
365 &self,
366 pending: PendingSubscriptionSink,
367 ext: &Extensions,
368 keys: Option<Vec<StorageKey>>,
369 ) {
370 let deny_unsafe = ext
371 .get::<DenyUnsafe>()
372 .cloned()
373 .expect("DenyUnsafe extension is always set by the substrate rpc server; qed");
374 self.backend.subscribe_storage(pending, keys, deny_unsafe)
375 }
376}
377
378pub trait ChildStateBackend<Block: BlockT, Client>: Send + Sync + 'static
380where
381 Block: BlockT + 'static,
382 Client: Send + Sync + 'static,
383{
384 fn read_child_proof(
386 &self,
387 block: Option<Block::Hash>,
388 storage_key: PrefixedStorageKey,
389 keys: Vec<StorageKey>,
390 ) -> Result<ReadProof<Block::Hash>, Error>;
391
392 fn storage_keys(
395 &self,
396 block: Option<Block::Hash>,
397 storage_key: PrefixedStorageKey,
398 prefix: StorageKey,
399 ) -> Result<Vec<StorageKey>, Error>;
400
401 fn storage_keys_paged(
403 &self,
404 block: Option<Block::Hash>,
405 storage_key: PrefixedStorageKey,
406 prefix: Option<StorageKey>,
407 count: u32,
408 start_key: Option<StorageKey>,
409 ) -> Result<Vec<StorageKey>, Error>;
410
411 fn storage(
413 &self,
414 block: Option<Block::Hash>,
415 storage_key: PrefixedStorageKey,
416 key: StorageKey,
417 ) -> Result<Option<StorageData>, Error>;
418
419 fn storage_entries(
421 &self,
422 block: Option<Block::Hash>,
423 storage_key: PrefixedStorageKey,
424 keys: Vec<StorageKey>,
425 ) -> Result<Vec<Option<StorageData>>, Error>;
426
427 fn storage_hash(
429 &self,
430 block: Option<Block::Hash>,
431 storage_key: PrefixedStorageKey,
432 key: StorageKey,
433 ) -> Result<Option<Block::Hash>, Error>;
434
435 fn storage_size(
437 &self,
438 block: Option<Block::Hash>,
439 storage_key: PrefixedStorageKey,
440 key: StorageKey,
441 ) -> Result<Option<u64>, Error> {
442 self.storage(block, storage_key, key).map(|x| x.map(|x| x.0.len() as u64))
443 }
444}
445
446pub struct ChildState<Block, Client> {
448 backend: Box<dyn ChildStateBackend<Block, Client>>,
449}
450
451impl<Block, Client> ChildStateApiServer<Block::Hash> for ChildState<Block, Client>
452where
453 Block: BlockT + 'static,
454 Client: Send + Sync + 'static,
455{
456 fn storage_keys(
457 &self,
458 ext: &Extensions,
459 storage_key: PrefixedStorageKey,
460 key_prefix: StorageKey,
461 block: Option<Block::Hash>,
462 ) -> Result<Vec<StorageKey>, Error> {
463 check_if_safe(ext)?;
464 self.backend.storage_keys(block, storage_key, key_prefix).map_err(Into::into)
465 }
466
467 fn storage_keys_paged(
468 &self,
469 storage_key: PrefixedStorageKey,
470 prefix: Option<StorageKey>,
471 count: u32,
472 start_key: Option<StorageKey>,
473 block: Option<Block::Hash>,
474 ) -> Result<Vec<StorageKey>, Error> {
475 self.backend
476 .storage_keys_paged(block, storage_key, prefix, count, start_key)
477 .map_err(Into::into)
478 }
479
480 fn storage(
481 &self,
482 storage_key: PrefixedStorageKey,
483 key: StorageKey,
484 block: Option<Block::Hash>,
485 ) -> Result<Option<StorageData>, Error> {
486 self.backend.storage(block, storage_key, key).map_err(Into::into)
487 }
488
489 fn storage_entries(
490 &self,
491 storage_key: PrefixedStorageKey,
492 keys: Vec<StorageKey>,
493 block: Option<Block::Hash>,
494 ) -> Result<Vec<Option<StorageData>>, Error> {
495 self.backend.storage_entries(block, storage_key, keys).map_err(Into::into)
496 }
497
498 fn storage_hash(
499 &self,
500 storage_key: PrefixedStorageKey,
501 key: StorageKey,
502 block: Option<Block::Hash>,
503 ) -> Result<Option<Block::Hash>, Error> {
504 self.backend.storage_hash(block, storage_key, key).map_err(Into::into)
505 }
506
507 fn storage_size(
508 &self,
509 storage_key: PrefixedStorageKey,
510 key: StorageKey,
511 block: Option<Block::Hash>,
512 ) -> Result<Option<u64>, Error> {
513 self.backend.storage_size(block, storage_key, key).map_err(Into::into)
514 }
515
516 fn read_child_proof(
517 &self,
518 child_storage_key: PrefixedStorageKey,
519 keys: Vec<StorageKey>,
520 block: Option<Block::Hash>,
521 ) -> Result<ReadProof<Block::Hash>, Error> {
522 self.backend
523 .read_child_proof(block, child_storage_key, keys)
524 .map_err(Into::into)
525 }
526}
527
528fn client_err(err: sp_blockchain::Error) -> Error {
529 Error::Client(Box::new(err))
530}