substrate_api_client/api/rpc_api/
state.rs

1/*
2   Copyright 2019 Supercomputing Systems AG
3   Licensed under the Apache License, Version 2.0 (the "License");
4   you may not use this file except in compliance with the License.
5   You may obtain a copy of the License at
6	   http://www.apache.org/licenses/LICENSE-2.0
7   Unless required by applicable law or agreed to in writing, software
8   distributed under the License is distributed on an "AS IS" BASIS,
9   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10   See the License for the specific language governing permissions and
11   limitations under the License.
12*/
13use crate::{
14	api::Result,
15	rpc::{Request, Subscribe},
16	Api, ReadProof,
17};
18use ac_compose_macros::rpc_params;
19use ac_node_api::MetadataError;
20use ac_primitives::config::Config;
21#[cfg(all(not(feature = "sync-api"), not(feature = "std")))]
22use alloc::boxed::Box;
23use alloc::{borrow::ToOwned, string::String, vec, vec::Vec};
24use codec::{Decode, Encode};
25use core::cmp;
26use log::*;
27use serde::de::DeserializeOwned;
28use sp_storage::{StorageChangeSet, StorageData, StorageKey};
29
30/// Default substrate value of maximum number of keys returned.
31// See https://github.com/paritytech/substrate/blob/9f6fecfeea15345c983629af275b1f1702a50004/client/rpc/src/state/mod.rs#L54
32const STORAGE_KEYS_PAGED_MAX_COUNT: u32 = 1000;
33
34pub type StorageChangeSetSubscriptionFor<Client, Hash> =
35	<Client as Subscribe>::Subscription<StorageChangeSet<Hash>>;
36
37/// Generic interface to substrate storage.
38#[maybe_async::maybe_async(?Send)]
39pub trait GetStorage {
40	type Hash;
41	/// Retrieve the storage value.
42	///
43	/// `at_block`: the state is queried at this block, set to `None` to get the state from the latest known block.
44	async fn get_storage<V: Decode>(
45		&self,
46		pallet: &'static str,
47		storage_item: &'static str,
48		at_block: Option<Self::Hash>,
49	) -> Result<Option<V>>;
50
51	/// Retrieve the storage value from a map for the given `map_key`.
52	///
53	/// `at_block`: the state is queried at this block, set to `None` to get the state from the latest known block.
54	async fn get_storage_map<K: Encode, V: Decode>(
55		&self,
56		pallet: &'static str,
57		storage_item: &'static str,
58		map_key: K,
59		at_block: Option<Self::Hash>,
60	) -> Result<Option<V>>;
61
62	/// Retrieve the key prefix for a storage map. This is the prefix needed for get_storage_keys_paged().
63	async fn get_storage_map_key_prefix(
64		&self,
65		pallet: &'static str,
66		storage_item: &'static str,
67	) -> Result<StorageKey>;
68
69	async fn get_storage_double_map_key_prefix<K: Encode>(
70		&self,
71		storage_prefix: &'static str,
72		storage_key_name: &'static str,
73		first: K,
74	) -> Result<StorageKey>;
75
76	/// Retrieve the storage value from a double map for the given keys: `first_double_map_key` and `second_double_map_key`.
77	///
78	/// `at_block`: the state is queried at this block, set to `None` to get the state from the latest known block.
79	async fn get_storage_double_map<K: Encode, Q: Encode, V: Decode>(
80		&self,
81		pallet: &'static str,
82		storage_item: &'static str,
83		first_double_map_key: K,
84		second_double_map_key: Q,
85		at_block: Option<Self::Hash>,
86	) -> Result<Option<V>>;
87
88	/// Retrieve the storage value from the given `storage_key`.
89	///
90	/// `at_block`: the state is queried at this block, set to `None` to get the state from the latest known block.
91	async fn get_storage_by_key<V: Decode>(
92		&self,
93		storage_key: StorageKey,
94		at_block: Option<Self::Hash>,
95	) -> Result<Option<V>>;
96
97	/// Retrieve the keys with prefix with pagination support.
98	/// Call the RPC substrate storage_keys_paged, which limits the number of returned keys.
99	///
100	/// Up to `count` keys will be returned. If `count` is too big, an error will be returned
101	/// If `start_key` is passed, return next keys in storage in lexicographic order.
102	///
103	/// `at_block`: the state is queried at this block, set to `None` to get the state from the latest known block.
104	// See https://github.com/paritytech/substrate/blob/9f6fecfeea15345c983629af275b1f1702a50004/client/rpc/src/state/mod.rs#L54
105	async fn get_storage_keys_paged_limited(
106		&self,
107		prefix: Option<StorageKey>,
108		count: u32,
109		start_key: Option<StorageKey>,
110		at_block: Option<Self::Hash>,
111	) -> Result<Vec<StorageKey>>;
112
113	/// Retrieve up to `count` keys. Support prefix and pagination support.
114	/// The number of keys returned is not limited. For big numbers, the rpc calls will be made several times.
115	/// Up to `count` keys will be returned.
116	/// If `start_key` is passed, return next keys in storage in lexicographic order.
117	///
118	/// `at_block`: the state is queried at this block, set to `None` to get the state from the latest known block.
119	async fn get_storage_keys_paged(
120		&self,
121		prefix: Option<StorageKey>,
122		count: u32,
123		start_key: Option<StorageKey>,
124		at_block: Option<Self::Hash>,
125	) -> Result<Vec<StorageKey>>;
126
127	/// Retrieve the raw storage for the given `storage_key`.
128	///
129	/// `at_block`: the state is queried at this block, set to `None` to get the state from the latest known block.
130	async fn get_opaque_storage_by_key(
131		&self,
132		storage_key: StorageKey,
133		at_block: Option<Self::Hash>,
134	) -> Result<Option<Vec<u8>>>;
135
136	/// Retrieve the storage proof of the corresponding storage value.
137	///
138	/// `at_block`: the state is queried at this block, set to `None` to get the state from the latest known block.
139	async fn get_storage_value_proof(
140		&self,
141		pallet: &'static str,
142		storage_item: &'static str,
143		at_block: Option<Self::Hash>,
144	) -> Result<Option<ReadProof<Self::Hash>>>;
145
146	/// Retrieve the storage proof of the corresponding storage map value.
147	///
148	/// `at_block`: the state is queried at this block, set to `None` to get the state from the latest known block.
149	async fn get_storage_map_proof<K: Encode>(
150		&self,
151		pallet: &'static str,
152		storage_item: &'static str,
153		map_key: K,
154		at_block: Option<Self::Hash>,
155	) -> Result<Option<ReadProof<Self::Hash>>>;
156
157	/// Retrieve the storage proof of the corresponding storage double map value.
158	///
159	/// `at_block`: the state is queried at this block, set to `None` to get the state from the latest known block.
160	async fn get_storage_double_map_proof<K: Encode, Q: Encode>(
161		&self,
162		pallet: &'static str,
163		storage_item: &'static str,
164		first_double_map_key: K,
165		second_double_map_key: Q,
166		at_block: Option<Self::Hash>,
167	) -> Result<Option<ReadProof<Self::Hash>>>;
168
169	/// Retrieve the proof of the corresponding storage entries.
170	///
171	/// `at_block`: the state is queried at this block, set to `None` to get the state from the latest known block.
172	async fn get_storage_proof_by_keys(
173		&self,
174		keys: Vec<StorageKey>,
175		at_block: Option<Self::Hash>,
176	) -> Result<Option<ReadProof<Self::Hash>>>;
177
178	async fn get_keys(
179		&self,
180		key: StorageKey,
181		at_block: Option<Self::Hash>,
182	) -> Result<Option<Vec<String>>>;
183
184	async fn get_constant<C: Decode>(
185		&self,
186		pallet: &'static str,
187		constant: &'static str,
188	) -> Result<C>;
189}
190
191#[maybe_async::maybe_async(?Send)]
192impl<T, Client> GetStorage for Api<T, Client>
193where
194	T: Config,
195	Client: Request,
196{
197	type Hash = T::Hash;
198
199	async fn get_storage<V: Decode>(
200		&self,
201		pallet: &'static str,
202		storage_item: &'static str,
203		at_block: Option<Self::Hash>,
204	) -> Result<Option<V>> {
205		let storagekey = self.metadata().storage_value_key(pallet, storage_item)?;
206		info!("storage key is: 0x{}", hex::encode(&storagekey));
207		self.get_storage_by_key(storagekey, at_block).await
208	}
209
210	async fn get_storage_map<K: Encode, V: Decode>(
211		&self,
212		pallet: &'static str,
213		storage_item: &'static str,
214		map_key: K,
215		at_block: Option<Self::Hash>,
216	) -> Result<Option<V>> {
217		let storagekey = self.metadata().storage_map_key::<K>(pallet, storage_item, map_key)?;
218		info!("storage key is: 0x{}", hex::encode(&storagekey));
219		self.get_storage_by_key(storagekey, at_block).await
220	}
221
222	async fn get_storage_map_key_prefix(
223		&self,
224		pallet: &'static str,
225		storage_item: &'static str,
226	) -> Result<StorageKey> {
227		self.metadata()
228			.storage_map_key_prefix(pallet, storage_item)
229			.map_err(|e| e.into())
230	}
231
232	async fn get_storage_double_map<K: Encode, Q: Encode, V: Decode>(
233		&self,
234		pallet: &'static str,
235		storage_item: &'static str,
236		first_double_map_key: K,
237		second_double_map_key: Q,
238		at_block: Option<Self::Hash>,
239	) -> Result<Option<V>> {
240		let storagekey = self.metadata().storage_double_map_key::<K, Q>(
241			pallet,
242			storage_item,
243			first_double_map_key,
244			second_double_map_key,
245		)?;
246		info!("storage key is: 0x{}", hex::encode(&storagekey));
247		self.get_storage_by_key(storagekey, at_block).await
248	}
249
250	async fn get_storage_double_map_key_prefix<K: Encode>(
251		&self,
252		storage_prefix: &'static str,
253		storage_key_name: &'static str,
254		first: K,
255	) -> Result<StorageKey> {
256		self.metadata()
257			.storage_double_map_key_prefix(storage_prefix, storage_key_name, first)
258			.map_err(|e| e.into())
259	}
260
261	async fn get_storage_by_key<V: Decode>(
262		&self,
263		storage_key: StorageKey,
264		at_block: Option<Self::Hash>,
265	) -> Result<Option<V>> {
266		let s = self.get_opaque_storage_by_key(storage_key, at_block).await?;
267		match s {
268			Some(storage) => Ok(Some(Decode::decode(&mut storage.as_slice())?)),
269			None => Ok(None),
270		}
271	}
272
273	async fn get_storage_keys_paged_limited(
274		&self,
275		storage_key_prefix: Option<StorageKey>,
276		count: u32,
277		start_key: Option<StorageKey>,
278		at_block: Option<Self::Hash>,
279	) -> Result<Vec<StorageKey>> {
280		let storage = self
281			.client()
282			.request(
283				"state_getKeysPaged",
284				rpc_params![storage_key_prefix, count, start_key, at_block],
285			)
286			.await?;
287		Ok(storage)
288	}
289
290	async fn get_storage_keys_paged(
291		&self,
292		storage_key_prefix: Option<StorageKey>,
293		count: u32,
294		start_key: Option<StorageKey>,
295		at_block: Option<Self::Hash>,
296	) -> Result<Vec<StorageKey>> {
297		let mut storage_keys: Vec<StorageKey> = Vec::new();
298		let mut keys_left_to_fetch = count;
299		let mut new_start_key = start_key;
300
301		while keys_left_to_fetch > 0 {
302			let new_count = cmp::min(STORAGE_KEYS_PAGED_MAX_COUNT, keys_left_to_fetch);
303			let mut keys = self
304				.get_storage_keys_paged_limited(
305					storage_key_prefix.clone(),
306					new_count,
307					new_start_key,
308					at_block,
309				)
310				.await?;
311			let num_keys = keys.len() as u32;
312			storage_keys.append(&mut keys);
313			if num_keys < new_count {
314				break
315			}
316			keys_left_to_fetch -= new_count;
317			new_start_key = keys.last().map(|x| x.to_owned());
318		}
319
320		Ok(storage_keys)
321	}
322
323	async fn get_opaque_storage_by_key(
324		&self,
325		storage_key: StorageKey,
326		at_block: Option<Self::Hash>,
327	) -> Result<Option<Vec<u8>>> {
328		let storage: Option<StorageData> = self
329			.client()
330			.request("state_getStorage", rpc_params![storage_key, at_block])
331			.await?;
332		Ok(storage.map(|storage_data| storage_data.0))
333	}
334
335	async fn get_storage_value_proof(
336		&self,
337		pallet: &'static str,
338		storage_item: &'static str,
339		at_block: Option<Self::Hash>,
340	) -> Result<Option<ReadProof<Self::Hash>>> {
341		let storagekey = self.metadata().storage_value_key(pallet, storage_item)?;
342		info!("storage key is: 0x{}", hex::encode(&storagekey));
343		self.get_storage_proof_by_keys(vec![storagekey], at_block).await
344	}
345
346	async fn get_storage_map_proof<K: Encode>(
347		&self,
348		pallet: &'static str,
349		storage_item: &'static str,
350		map_key: K,
351		at_block: Option<Self::Hash>,
352	) -> Result<Option<ReadProof<Self::Hash>>> {
353		let storagekey = self.metadata().storage_map_key::<K>(pallet, storage_item, map_key)?;
354		info!("storage key is: 0x{}", hex::encode(&storagekey));
355		self.get_storage_proof_by_keys(vec![storagekey], at_block).await
356	}
357
358	async fn get_storage_double_map_proof<K: Encode, Q: Encode>(
359		&self,
360		pallet: &'static str,
361		storage_item: &'static str,
362		first_double_map_key: K,
363		second_double_map_key: Q,
364		at_block: Option<Self::Hash>,
365	) -> Result<Option<ReadProof<Self::Hash>>> {
366		let storage_key = self.metadata().storage_double_map_key::<K, Q>(
367			pallet,
368			storage_item,
369			first_double_map_key,
370			second_double_map_key,
371		)?;
372		info!("storage key is: 0x{}", hex::encode(&storage_key));
373		self.get_storage_proof_by_keys(vec![storage_key], at_block).await
374	}
375
376	async fn get_storage_proof_by_keys(
377		&self,
378		storage_keys: Vec<StorageKey>,
379		at_block: Option<Self::Hash>,
380	) -> Result<Option<ReadProof<Self::Hash>>> {
381		let proof = self
382			.client()
383			.request("state_getReadProof", rpc_params![storage_keys, at_block])
384			.await?;
385		Ok(proof)
386	}
387
388	async fn get_keys(
389		&self,
390		storage_key: StorageKey,
391		at_block: Option<Self::Hash>,
392	) -> Result<Option<Vec<String>>> {
393		let keys = self
394			.client()
395			.request("state_getKeys", rpc_params![storage_key, at_block])
396			.await?;
397		Ok(keys)
398	}
399
400	async fn get_constant<C: Decode>(
401		&self,
402		pallet: &'static str,
403		constant: &'static str,
404	) -> Result<C> {
405		let c = self
406			.metadata()
407			.pallet_by_name_err(pallet)?
408			.constant_by_name(constant)
409			.ok_or(MetadataError::ConstantNotFound(constant))?;
410
411		Ok(Decode::decode(&mut c.value.as_slice())?)
412	}
413}
414
415#[maybe_async::maybe_async(?Send)]
416pub trait SubscribeState {
417	type Client: Subscribe;
418	type Hash: DeserializeOwned;
419
420	async fn subscribe_state(
421		&self,
422		pallet: &str,
423		storage_key: &str,
424	) -> Result<StorageChangeSetSubscriptionFor<Self::Client, Self::Hash>>;
425}
426
427#[maybe_async::maybe_async(?Send)]
428impl<T, Client> SubscribeState for Api<T, Client>
429where
430	T: Config,
431	Client: Subscribe,
432{
433	type Client = Client;
434	type Hash = T::Hash;
435
436	async fn subscribe_state(
437		&self,
438		pallet: &str,
439		storage_key_name: &str,
440	) -> Result<StorageChangeSetSubscriptionFor<Self::Client, Self::Hash>> {
441		debug!("subscribing to events");
442		let key = crate::storage_key(pallet, storage_key_name);
443		self.client()
444			.subscribe("state_subscribeStorage", rpc_params![vec![key]], "state_unsubscribeStorage")
445			.await
446			.map_err(|e| e.into())
447	}
448}