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 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}