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 key_prefix: StorageKey,
234 block: Option<Block::Hash>,
235 ) -> Result<Vec<StorageKey>, Error> {
236 self.backend.storage_keys(block, key_prefix).map_err(Into::into)
237 }
238
239 fn storage_pairs(
240 &self,
241 ext: &Extensions,
242 key_prefix: StorageKey,
243 block: Option<Block::Hash>,
244 ) -> Result<Vec<(StorageKey, StorageData)>, Error> {
245 check_if_safe(ext)?;
246 self.backend.storage_pairs(block, key_prefix).map_err(Into::into)
247 }
248
249 fn storage_keys_paged(
250 &self,
251 prefix: Option<StorageKey>,
252 count: u32,
253 start_key: Option<StorageKey>,
254 block: Option<Block::Hash>,
255 ) -> Result<Vec<StorageKey>, Error> {
256 if count > STORAGE_KEYS_PAGED_MAX_COUNT {
257 return Err(Error::InvalidCount { value: count, max: STORAGE_KEYS_PAGED_MAX_COUNT });
258 }
259 self.backend
260 .storage_keys_paged(block, prefix, count, start_key)
261 .map_err(Into::into)
262 }
263
264 fn storage(
265 &self,
266 key: StorageKey,
267 block: Option<Block::Hash>,
268 ) -> Result<Option<StorageData>, Error> {
269 self.backend.storage(block, key).map_err(Into::into)
270 }
271
272 fn storage_hash(
273 &self,
274 key: StorageKey,
275 block: Option<Block::Hash>,
276 ) -> Result<Option<Block::Hash>, Error> {
277 self.backend.storage_hash(block, key).map_err(Into::into)
278 }
279
280 async fn storage_size(
281 &self,
282 ext: &Extensions,
283 key: StorageKey,
284 block: Option<Block::Hash>,
285 ) -> Result<Option<u64>, Error> {
286 let deny_unsafe = ext
287 .get::<DenyUnsafe>()
288 .cloned()
289 .expect("DenyUnsafe extension is always set by the substrate rpc server; qed");
290 self.backend.storage_size(block, key, deny_unsafe).await.map_err(Into::into)
291 }
292
293 fn metadata(&self, block: Option<Block::Hash>) -> Result<Bytes, Error> {
294 self.backend.metadata(block).map_err(Into::into)
295 }
296
297 fn runtime_version(&self, at: Option<Block::Hash>) -> Result<RuntimeVersion, Error> {
298 self.backend.runtime_version(at).map_err(Into::into)
299 }
300
301 fn query_storage(
302 &self,
303 ext: &Extensions,
304 keys: Vec<StorageKey>,
305 from: Block::Hash,
306 to: Option<Block::Hash>,
307 ) -> Result<Vec<StorageChangeSet<Block::Hash>>, Error> {
308 check_if_safe(ext)?;
309 self.backend.query_storage(from, to, keys).map_err(Into::into)
310 }
311
312 fn query_storage_at(
313 &self,
314 keys: Vec<StorageKey>,
315 at: Option<Block::Hash>,
316 ) -> Result<Vec<StorageChangeSet<Block::Hash>>, Error> {
317 self.backend.query_storage_at(keys, at).map_err(Into::into)
318 }
319
320 fn read_proof(
321 &self,
322 keys: Vec<StorageKey>,
323 block: Option<Block::Hash>,
324 ) -> Result<ReadProof<Block::Hash>, Error> {
325 self.backend.read_proof(block, keys).map_err(Into::into)
326 }
327
328 fn trace_block(
334 &self,
335 ext: &Extensions,
336 block: Block::Hash,
337 targets: Option<String>,
338 storage_keys: Option<String>,
339 methods: Option<String>,
340 ) -> Result<sp_rpc::tracing::TraceBlockResponse, Error> {
341 check_if_safe(ext)?;
342 self.backend
343 .trace_block(block, targets, storage_keys, methods)
344 .map_err(Into::into)
345 }
346
347 fn call_recorded(
348 &self,
349 ext: &Extensions,
350 method: String,
351 data: Bytes,
352 block: Block::Hash,
353 ) -> Result<Bytes, Error> {
354 check_if_safe(ext).map_err(|_| Error::CallRecordedDenied)?;
355 self.backend.call_recorded(block, method, data).map_err(Into::into)
356 }
357
358 fn subscribe_runtime_version(&self, pending: PendingSubscriptionSink) {
359 self.backend.subscribe_runtime_version(pending)
360 }
361
362 fn subscribe_storage(
363 &self,
364 pending: PendingSubscriptionSink,
365 ext: &Extensions,
366 keys: Option<Vec<StorageKey>>,
367 ) {
368 let deny_unsafe = ext
369 .get::<DenyUnsafe>()
370 .cloned()
371 .expect("DenyUnsafe extension is always set by the substrate rpc server; qed");
372 self.backend.subscribe_storage(pending, keys, deny_unsafe)
373 }
374}
375
376pub trait ChildStateBackend<Block: BlockT, Client>: Send + Sync + 'static
378where
379 Block: BlockT + 'static,
380 Client: Send + Sync + 'static,
381{
382 fn read_child_proof(
384 &self,
385 block: Option<Block::Hash>,
386 storage_key: PrefixedStorageKey,
387 keys: Vec<StorageKey>,
388 ) -> Result<ReadProof<Block::Hash>, Error>;
389
390 fn storage_keys(
393 &self,
394 block: Option<Block::Hash>,
395 storage_key: PrefixedStorageKey,
396 prefix: StorageKey,
397 ) -> Result<Vec<StorageKey>, Error>;
398
399 fn storage_keys_paged(
401 &self,
402 block: Option<Block::Hash>,
403 storage_key: PrefixedStorageKey,
404 prefix: Option<StorageKey>,
405 count: u32,
406 start_key: Option<StorageKey>,
407 ) -> Result<Vec<StorageKey>, Error>;
408
409 fn storage(
411 &self,
412 block: Option<Block::Hash>,
413 storage_key: PrefixedStorageKey,
414 key: StorageKey,
415 ) -> Result<Option<StorageData>, Error>;
416
417 fn storage_entries(
419 &self,
420 block: Option<Block::Hash>,
421 storage_key: PrefixedStorageKey,
422 keys: Vec<StorageKey>,
423 ) -> Result<Vec<Option<StorageData>>, Error>;
424
425 fn storage_hash(
427 &self,
428 block: Option<Block::Hash>,
429 storage_key: PrefixedStorageKey,
430 key: StorageKey,
431 ) -> Result<Option<Block::Hash>, Error>;
432
433 fn storage_size(
435 &self,
436 block: Option<Block::Hash>,
437 storage_key: PrefixedStorageKey,
438 key: StorageKey,
439 ) -> Result<Option<u64>, Error> {
440 self.storage(block, storage_key, key).map(|x| x.map(|x| x.0.len() as u64))
441 }
442}
443
444pub struct ChildState<Block, Client> {
446 backend: Box<dyn ChildStateBackend<Block, Client>>,
447}
448
449impl<Block, Client> ChildStateApiServer<Block::Hash> for ChildState<Block, Client>
450where
451 Block: BlockT + 'static,
452 Client: Send + Sync + 'static,
453{
454 fn storage_keys(
455 &self,
456 storage_key: PrefixedStorageKey,
457 key_prefix: StorageKey,
458 block: Option<Block::Hash>,
459 ) -> Result<Vec<StorageKey>, Error> {
460 self.backend.storage_keys(block, storage_key, key_prefix).map_err(Into::into)
461 }
462
463 fn storage_keys_paged(
464 &self,
465 storage_key: PrefixedStorageKey,
466 prefix: Option<StorageKey>,
467 count: u32,
468 start_key: Option<StorageKey>,
469 block: Option<Block::Hash>,
470 ) -> Result<Vec<StorageKey>, Error> {
471 self.backend
472 .storage_keys_paged(block, storage_key, prefix, count, start_key)
473 .map_err(Into::into)
474 }
475
476 fn storage(
477 &self,
478 storage_key: PrefixedStorageKey,
479 key: StorageKey,
480 block: Option<Block::Hash>,
481 ) -> Result<Option<StorageData>, Error> {
482 self.backend.storage(block, storage_key, key).map_err(Into::into)
483 }
484
485 fn storage_entries(
486 &self,
487 storage_key: PrefixedStorageKey,
488 keys: Vec<StorageKey>,
489 block: Option<Block::Hash>,
490 ) -> Result<Vec<Option<StorageData>>, Error> {
491 self.backend.storage_entries(block, storage_key, keys).map_err(Into::into)
492 }
493
494 fn storage_hash(
495 &self,
496 storage_key: PrefixedStorageKey,
497 key: StorageKey,
498 block: Option<Block::Hash>,
499 ) -> Result<Option<Block::Hash>, Error> {
500 self.backend.storage_hash(block, storage_key, key).map_err(Into::into)
501 }
502
503 fn storage_size(
504 &self,
505 storage_key: PrefixedStorageKey,
506 key: StorageKey,
507 block: Option<Block::Hash>,
508 ) -> Result<Option<u64>, Error> {
509 self.backend.storage_size(block, storage_key, key).map_err(Into::into)
510 }
511
512 fn read_child_proof(
513 &self,
514 child_storage_key: PrefixedStorageKey,
515 keys: Vec<StorageKey>,
516 block: Option<Block::Hash>,
517 ) -> Result<ReadProof<Block::Hash>, Error> {
518 self.backend
519 .read_child_proof(block, child_storage_key, keys)
520 .map_err(Into::into)
521 }
522}
523
524fn client_err(err: sp_blockchain::Error) -> Error {
525 Error::Client(Box::new(err))
526}