substrate_constructor/
storage_query.rs

1use external_memory_tools::ExternalMemory;
2use frame_metadata::v14::{
3    PalletStorageMetadata, StorageEntryMetadata, StorageEntryType, StorageHasher,
4};
5use parity_scale_codec::Encode;
6use scale_info::{form::PortableForm, interner::UntrackedSymbol};
7use sp_crypto_hashing::{blake2_128, blake2_256, twox_128, twox_256, twox_64};
8use substrate_parser::{
9    cards::Documented, decoding_sci::Ty, error::RegistryError, propagated::Propagated,
10};
11
12use std::any::TypeId;
13
14use crate::error::StorageRegistryError;
15use crate::fill_prepare::{prepare_type, TypeToFill};
16use crate::finalize::{Finalize, TypeContent};
17use crate::traits::{AsFillMetadata, AsPalletMetadata};
18
19#[derive(Clone, Debug)]
20#[allow(clippy::large_enum_variant)]
21pub enum EntrySelector {
22    Empty,
23    Functional(EntrySelectorFunctional),
24}
25
26impl EntrySelector {
27    pub fn init<E: ExternalMemory, M: AsFillMetadata<E>>(
28        available_entries: &[StorageEntryMetadata<PortableForm>],
29        ext_memory: &mut E,
30        registry: &M::TypeRegistry,
31    ) -> Result<Self, RegistryError<E>> {
32        if available_entries.is_empty() {
33            Ok(Self::Empty)
34        } else {
35            Ok(Self::Functional(EntrySelectorFunctional::new_at::<E, M>(
36                available_entries,
37                ext_memory,
38                registry,
39                0usize,
40            )?))
41        }
42    }
43}
44
45#[derive(Clone, Debug)]
46pub struct EntrySelectorFunctional {
47    pub available_entries: Vec<StorageEntryMetadata<PortableForm>>,
48    pub selected_entry: StorageEntry,
49}
50
51impl EntrySelectorFunctional {
52    pub fn new_at<E: ExternalMemory, M: AsFillMetadata<E>>(
53        available_entries: &[StorageEntryMetadata<PortableForm>],
54        ext_memory: &mut E,
55        registry: &M::TypeRegistry,
56        selector_index: usize,
57    ) -> Result<Self, RegistryError<E>> {
58        let selected_entry_metadata = &available_entries[selector_index];
59        let name = selected_entry_metadata.name.to_owned();
60        let docs = selected_entry_metadata.collect_docs();
61        let type_to_fill = match &selected_entry_metadata.ty {
62            StorageEntryType::Plain(ty) => StorageEntryTypeToFill::Plain(*ty),
63            StorageEntryType::Map {
64                hashers,
65                key,
66                value,
67            } => {
68                let key_to_fill = prepare_type::<E, M>(
69                    &Ty::Symbol(key),
70                    ext_memory,
71                    registry,
72                    Propagated::new(),
73                )?;
74                StorageEntryTypeToFill::Map {
75                    hashers: hashers.to_vec(),
76                    key_to_fill,
77                    value: *value,
78                }
79            }
80        };
81        Ok(Self {
82            available_entries: available_entries.to_owned(),
83            selected_entry: StorageEntry {
84                selector_index_entry: selector_index,
85                name,
86                type_to_fill,
87                docs,
88            },
89        })
90    }
91
92    pub fn selector_up<E: ExternalMemory, M: AsFillMetadata<E>>(
93        &mut self,
94        ext_memory: &mut E,
95        registry: &M::TypeRegistry,
96    ) -> Result<(), RegistryError<E>> {
97        let new_selector_index = {
98            if self.selected_entry.selector_index_entry + 1 == self.available_entries.len() {
99                0
100            } else {
101                self.selected_entry.selector_index_entry + 1
102            }
103        };
104        *self = EntrySelectorFunctional::new_at::<E, M>(
105            &self.available_entries,
106            ext_memory,
107            registry,
108            new_selector_index,
109        )?;
110        Ok(())
111    }
112
113    pub fn selector_down<E: ExternalMemory, M: AsFillMetadata<E>>(
114        &mut self,
115        ext_memory: &mut E,
116        registry: &M::TypeRegistry,
117    ) -> Result<(), RegistryError<E>> {
118        let new_selector_index = {
119            if self.selected_entry.selector_index_entry == 0 {
120                self.available_entries.len() - 1
121            } else {
122                self.selected_entry.selector_index_entry - 1
123            }
124        };
125        *self = EntrySelectorFunctional::new_at::<E, M>(
126            &self.available_entries,
127            ext_memory,
128            registry,
129            new_selector_index,
130        )?;
131        Ok(())
132    }
133}
134
135#[derive(Clone, Debug)]
136pub struct StorageEntry {
137    pub selector_index_entry: usize,
138    pub name: String,
139    pub type_to_fill: StorageEntryTypeToFill,
140    pub docs: String,
141}
142
143#[derive(Clone, Debug)]
144#[allow(clippy::large_enum_variant)]
145pub enum StorageEntryTypeToFill {
146    Plain(UntrackedSymbol<TypeId>),
147    Map {
148        hashers: Vec<StorageHasher>,
149        key_to_fill: TypeToFill,
150        value: UntrackedSymbol<TypeId>,
151    },
152}
153
154#[derive(Clone, Debug)]
155#[allow(clippy::large_enum_variant)]
156pub enum StorageSelector {
157    Empty,
158    Functional(StorageSelectorFunctional),
159}
160
161impl StorageSelector {
162    pub fn init<E: ExternalMemory, M: AsFillMetadata<E>>(
163        ext_memory: &mut E,
164        metadata: &M,
165    ) -> Result<Self, RegistryError<E>> {
166        let mut available_pallets: Vec<PalletStorageMetadata<PortableForm>> = Vec::new();
167        for pallet in metadata.pallets().into_iter() {
168            if let Some(pallet_storage_metadata) = pallet.storage() {
169                available_pallets.push(pallet_storage_metadata)
170            }
171        }
172        if available_pallets.is_empty() {
173            Ok(Self::Empty)
174        } else {
175            Ok(Self::Functional(StorageSelectorFunctional::new_at::<E, M>(
176                &available_pallets,
177                ext_memory,
178                &metadata.types(),
179                0usize,
180            )?))
181        }
182    }
183}
184
185#[derive(Clone, Debug)]
186pub struct StorageSelectorFunctional {
187    pub available_pallets: Vec<PalletStorageMetadata<PortableForm>>,
188    pub query: StorageQuery,
189}
190
191impl StorageSelectorFunctional {
192    pub fn new_at<E: ExternalMemory, M: AsFillMetadata<E>>(
193        available_pallets: &[PalletStorageMetadata<PortableForm>],
194        ext_memory: &mut E,
195        registry: &M::TypeRegistry,
196        selector_index: usize,
197    ) -> Result<Self, RegistryError<E>> {
198        // TODO case bad index
199        let selected_pallet_metadata = &available_pallets[selector_index];
200
201        let query = StorageQuery {
202            selector_index_pallet: selector_index,
203            prefix: selected_pallet_metadata.prefix.to_owned(),
204            entry_selector: EntrySelector::init::<E, M>(
205                &selected_pallet_metadata.entries,
206                ext_memory,
207                registry,
208            )?,
209        };
210
211        Ok(Self {
212            available_pallets: available_pallets.to_owned(),
213            query,
214        })
215    }
216
217    pub fn selector_up<E: ExternalMemory, M: AsFillMetadata<E>>(
218        &mut self,
219        ext_memory: &mut E,
220        registry: &M::TypeRegistry,
221    ) -> Result<(), RegistryError<E>> {
222        let new_selector_index = {
223            if self.query.selector_index_pallet + 1 == self.available_pallets.len() {
224                0
225            } else {
226                self.query.selector_index_pallet + 1
227            }
228        };
229        *self = StorageSelectorFunctional::new_at::<E, M>(
230            &self.available_pallets,
231            ext_memory,
232            registry,
233            new_selector_index,
234        )?;
235        Ok(())
236    }
237
238    pub fn selector_down<E: ExternalMemory, M: AsFillMetadata<E>>(
239        &mut self,
240        ext_memory: &mut E,
241        registry: &M::TypeRegistry,
242    ) -> Result<(), RegistryError<E>> {
243        let new_selector_index = {
244            if self.query.selector_index_pallet == 0 {
245                self.available_pallets.len() - 1
246            } else {
247                self.query.selector_index_pallet - 1
248            }
249        };
250        *self = StorageSelectorFunctional::new_at::<E, M>(
251            &self.available_pallets,
252            ext_memory,
253            registry,
254            new_selector_index,
255        )?;
256        Ok(())
257    }
258}
259
260#[derive(Clone, Debug)]
261pub struct StorageQuery {
262    pub selector_index_pallet: usize,
263    pub prefix: String,
264    pub entry_selector: EntrySelector,
265}
266
267#[derive(Clone, Debug)]
268pub struct FinalizedStorageQuery {
269    pub key: String,
270    pub value_ty: UntrackedSymbol<TypeId>,
271}
272
273impl StorageQuery {
274    pub fn finalize(&self) -> Result<Option<FinalizedStorageQuery>, StorageRegistryError> {
275        if let EntrySelector::Functional(entry_selector_functional) = &self.entry_selector {
276            let mut key = format!(
277                "0x{}{}",
278                hex::encode(twox_128(self.prefix.as_bytes())),
279                hex::encode(twox_128(
280                    entry_selector_functional.selected_entry.name.as_bytes()
281                ))
282            );
283            match &entry_selector_functional.selected_entry.type_to_fill {
284                StorageEntryTypeToFill::Plain(value_ty) => Ok(Some(FinalizedStorageQuery {
285                    key,
286                    value_ty: *value_ty,
287                })),
288                StorageEntryTypeToFill::Map {
289                    hashers,
290                    key_to_fill,
291                    value,
292                } => {
293                    if let Some(type_content) = key_to_fill.finalize() {
294                        if hashers.len() == 1 {
295                            key.push_str(&hex::encode(hashed_key_element(
296                                &type_content.encode(),
297                                &hashers[0],
298                            )));
299                            Ok(Some(FinalizedStorageQuery {
300                                key,
301                                value_ty: *value,
302                            }))
303                        } else if let TypeContent::Tuple(tuple_elements) = type_content {
304                            if tuple_elements.len() == hashers.len() {
305                                let imax = tuple_elements.len();
306                                for i in 0..imax {
307                                    key.push_str(&hex::encode(hashed_key_element(
308                                        &tuple_elements[i].encode(),
309                                        &hashers[i],
310                                    )));
311                                }
312                                Ok(Some(FinalizedStorageQuery {
313                                    key,
314                                    value_ty: *value,
315                                }))
316                            } else {
317                                Err(StorageRegistryError::MapHashesNumberMismatch)
318                            }
319                        } else {
320                            Err(StorageRegistryError::MapHashesNotATuple)
321                        }
322                    } else {
323                        Ok(None)
324                    }
325                }
326            }
327        } else {
328            Ok(None)
329        }
330    }
331}
332
333pub fn hashed_key_element(data: &[u8], hasher: &StorageHasher) -> Vec<u8> {
334    match hasher {
335        StorageHasher::Blake2_128 => blake2_128(data).to_vec(),
336        StorageHasher::Blake2_256 => blake2_256(data).to_vec(),
337        StorageHasher::Blake2_128Concat => [blake2_128(data).to_vec(), data.to_vec()].concat(),
338        StorageHasher::Twox128 => twox_128(data).to_vec(),
339        StorageHasher::Twox256 => twox_256(data).to_vec(),
340        StorageHasher::Twox64Concat => [twox_64(data).to_vec(), data.to_vec()].concat(),
341        StorageHasher::Identity => data.to_vec(),
342    }
343}