1use crate::{
10 hash::ReversibleStorageHasher,
11 storage::{storage_prefix, unhashed},
12 StorageHasher, Twox128,
13};
14use alloc::{vec, vec::Vec};
15use codec::{Decode, Encode};
16
17use super::PrefixIterator;
18
19pub struct StorageIterator<T> {
21 prefix: Vec<u8>,
22 previous_key: Vec<u8>,
23 drain: bool,
24 _phantom: ::core::marker::PhantomData<T>,
25}
26
27impl<T> StorageIterator<T> {
28 #[deprecated(note = "Will be removed after July 2023; Please use the storage_iter or \
30 storage_iter_with_suffix functions instead")]
31 pub fn new(module: &[u8], item: &[u8]) -> Self {
32 #[allow(deprecated)]
33 Self::with_suffix(module, item, &[][..])
34 }
35
36 #[deprecated(note = "Will be removed after July 2023; Please use the storage_iter or \
38 storage_iter_with_suffix functions instead")]
39 pub fn with_suffix(module: &[u8], item: &[u8], suffix: &[u8]) -> Self {
40 let mut prefix = Vec::new();
41 let storage_prefix = storage_prefix(module, item);
42 prefix.extend_from_slice(&storage_prefix);
43 prefix.extend_from_slice(suffix);
44 let previous_key = prefix.clone();
45 Self { prefix, previous_key, drain: false, _phantom: Default::default() }
46 }
47
48 pub fn drain(mut self) -> Self {
50 self.drain = true;
51 self
52 }
53}
54
55impl<T: Decode + Sized> Iterator for StorageIterator<T> {
56 type Item = (Vec<u8>, T);
57
58 fn next(&mut self) -> Option<(Vec<u8>, T)> {
59 loop {
60 let maybe_next = subsoil::io::storage::next_key(&self.previous_key)
61 .filter(|n| n.starts_with(&self.prefix));
62 break match maybe_next {
63 Some(next) => {
64 self.previous_key = next.clone();
65 let maybe_value = topsoil_core::storage::unhashed::get::<T>(&next);
66 match maybe_value {
67 Some(value) => {
68 if self.drain {
69 topsoil_core::storage::unhashed::kill(&next);
70 }
71 Some((self.previous_key[self.prefix.len()..].to_vec(), value))
72 },
73 None => continue,
74 }
75 },
76 None => None,
77 };
78 }
79 }
80}
81
82pub struct StorageKeyIterator<K, T, H: ReversibleStorageHasher> {
84 prefix: Vec<u8>,
85 previous_key: Vec<u8>,
86 drain: bool,
87 _phantom: ::core::marker::PhantomData<(K, T, H)>,
88}
89
90impl<K, T, H: ReversibleStorageHasher> StorageKeyIterator<K, T, H> {
91 #[deprecated(note = "Will be removed after July 2023; Please use the storage_key_iter or \
93 storage_key_iter_with_suffix functions instead")]
94 pub fn new(module: &[u8], item: &[u8]) -> Self {
95 #[allow(deprecated)]
96 Self::with_suffix(module, item, &[][..])
97 }
98
99 #[deprecated(note = "Will be removed after July 2023; Please use the storage_key_iter or \
101 storage_key_iter_with_suffix functions instead")]
102 pub fn with_suffix(module: &[u8], item: &[u8], suffix: &[u8]) -> Self {
103 let mut prefix = Vec::new();
104 let storage_prefix = storage_prefix(module, item);
105 prefix.extend_from_slice(&storage_prefix);
106 prefix.extend_from_slice(suffix);
107 let previous_key = prefix.clone();
108 Self { prefix, previous_key, drain: false, _phantom: Default::default() }
109 }
110
111 pub fn drain(mut self) -> Self {
113 self.drain = true;
114 self
115 }
116}
117
118impl<K: Decode + Sized, T: Decode + Sized, H: ReversibleStorageHasher> Iterator
119 for StorageKeyIterator<K, T, H>
120{
121 type Item = (K, T);
122
123 fn next(&mut self) -> Option<(K, T)> {
124 loop {
125 let maybe_next = subsoil::io::storage::next_key(&self.previous_key)
126 .filter(|n| n.starts_with(&self.prefix));
127 break match maybe_next {
128 Some(next) => {
129 self.previous_key = next.clone();
130 let mut key_material = H::reverse(&next[self.prefix.len()..]);
131 match K::decode(&mut key_material) {
132 Ok(key) => {
133 let maybe_value = topsoil_core::storage::unhashed::get::<T>(&next);
134 match maybe_value {
135 Some(value) => {
136 if self.drain {
137 topsoil_core::storage::unhashed::kill(&next);
138 }
139 Some((key, value))
140 },
141 None => continue,
142 }
143 },
144 Err(_) => continue,
145 }
146 },
147 None => None,
148 };
149 }
150 }
151}
152
153pub fn storage_iter<T: Decode + Sized>(module: &[u8], item: &[u8]) -> PrefixIterator<(Vec<u8>, T)> {
155 storage_iter_with_suffix(module, item, &[][..])
156}
157
158pub fn storage_iter_with_suffix<T: Decode + Sized>(
160 module: &[u8],
161 item: &[u8],
162 suffix: &[u8],
163) -> PrefixIterator<(Vec<u8>, T)> {
164 let mut prefix = Vec::new();
165 let storage_prefix = storage_prefix(module, item);
166 prefix.extend_from_slice(&storage_prefix);
167 prefix.extend_from_slice(suffix);
168 let previous_key = prefix.clone();
169 let closure = |raw_key_without_prefix: &[u8], mut raw_value: &[u8]| {
170 let value = T::decode(&mut raw_value)?;
171 Ok((raw_key_without_prefix.to_vec(), value))
172 };
173
174 PrefixIterator { prefix, previous_key, drain: false, closure, phantom: Default::default() }
175}
176
177pub fn storage_key_iter<K: Decode + Sized, T: Decode + Sized, H: ReversibleStorageHasher>(
179 module: &[u8],
180 item: &[u8],
181) -> PrefixIterator<(K, T)> {
182 storage_key_iter_with_suffix::<K, T, H>(module, item, &[][..])
183}
184
185pub fn storage_key_iter_with_suffix<
187 K: Decode + Sized,
188 T: Decode + Sized,
189 H: ReversibleStorageHasher,
190>(
191 module: &[u8],
192 item: &[u8],
193 suffix: &[u8],
194) -> PrefixIterator<(K, T)> {
195 let mut prefix = Vec::new();
196 let storage_prefix = storage_prefix(module, item);
197
198 prefix.extend_from_slice(&storage_prefix);
199 prefix.extend_from_slice(suffix);
200 let previous_key = prefix.clone();
201 let closure = |raw_key_without_prefix: &[u8], mut raw_value: &[u8]| {
202 let mut key_material = H::reverse(raw_key_without_prefix);
203 let key = K::decode(&mut key_material)?;
204 let value = T::decode(&mut raw_value)?;
205 Ok((key, value))
206 };
207 PrefixIterator { prefix, previous_key, drain: false, closure, phantom: Default::default() }
208}
209
210pub fn have_storage_value(module: &[u8], item: &[u8], hash: &[u8]) -> bool {
212 get_storage_value::<()>(module, item, hash).is_some()
213}
214
215pub fn get_storage_value<T: Decode + Sized>(module: &[u8], item: &[u8], hash: &[u8]) -> Option<T> {
217 let mut key = vec![0u8; 32 + hash.len()];
218 let storage_prefix = storage_prefix(module, item);
219 key[0..32].copy_from_slice(&storage_prefix);
220 key[32..].copy_from_slice(hash);
221 topsoil_core::storage::unhashed::get::<T>(&key)
222}
223
224pub fn take_storage_value<T: Decode + Sized>(module: &[u8], item: &[u8], hash: &[u8]) -> Option<T> {
226 let mut key = vec![0u8; 32 + hash.len()];
227 let storage_prefix = storage_prefix(module, item);
228 key[0..32].copy_from_slice(&storage_prefix);
229 key[32..].copy_from_slice(hash);
230 topsoil_core::storage::unhashed::take::<T>(&key)
231}
232
233pub fn put_storage_value<T: Encode>(module: &[u8], item: &[u8], hash: &[u8], value: T) {
235 let mut key = vec![0u8; 32 + hash.len()];
236 let storage_prefix = storage_prefix(module, item);
237 key[0..32].copy_from_slice(&storage_prefix);
238 key[32..].copy_from_slice(hash);
239 topsoil_core::storage::unhashed::put(&key, &value);
240}
241
242#[deprecated = "Use `clear_storage_prefix` instead"]
245pub fn remove_storage_prefix(module: &[u8], item: &[u8], hash: &[u8]) {
246 let mut key = vec![0u8; 32 + hash.len()];
247 let storage_prefix = storage_prefix(module, item);
248 key[0..32].copy_from_slice(&storage_prefix);
249 key[32..].copy_from_slice(hash);
250 let _ = topsoil_core::storage::unhashed::clear_prefix(&key, None, None);
251}
252
253pub fn clear_storage_prefix(
270 module: &[u8],
271 item: &[u8],
272 hash: &[u8],
273 maybe_limit: Option<u32>,
274 maybe_cursor: Option<&[u8]>,
275) -> subsoil::io::MultiRemovalResults {
276 let mut key = vec![0u8; 32 + hash.len()];
277 let storage_prefix = storage_prefix(module, item);
278 key[0..32].copy_from_slice(&storage_prefix);
279 key[32..].copy_from_slice(hash);
280 topsoil_core::storage::unhashed::clear_prefix(&key, maybe_limit, maybe_cursor)
281}
282
283pub fn take_storage_item<K: Encode + Sized, T: Decode + Sized, H: StorageHasher>(
285 module: &[u8],
286 item: &[u8],
287 key: K,
288) -> Option<T> {
289 take_storage_value(module, item, key.using_encoded(H::hash).as_ref())
290}
291
292pub fn move_storage_from_pallet(
313 storage_name: &[u8],
314 old_pallet_name: &[u8],
315 new_pallet_name: &[u8],
316) {
317 let new_prefix = storage_prefix(new_pallet_name, storage_name);
318 let old_prefix = storage_prefix(old_pallet_name, storage_name);
319
320 move_prefix(&old_prefix, &new_prefix);
321
322 if let Some(value) = unhashed::get_raw(&old_prefix) {
323 unhashed::put_raw(&new_prefix, &value);
324 unhashed::kill(&old_prefix);
325 }
326}
327
328pub fn move_pallet(old_pallet_name: &[u8], new_pallet_name: &[u8]) {
349 move_prefix(&Twox128::hash(old_pallet_name), &Twox128::hash(new_pallet_name))
350}
351
352pub fn move_prefix(from_prefix: &[u8], to_prefix: &[u8]) {
359 if from_prefix == to_prefix {
360 return;
361 }
362
363 let iter = PrefixIterator::<_> {
364 prefix: from_prefix.to_vec(),
365 previous_key: from_prefix.to_vec(),
366 drain: true,
367 closure: |key, value| Ok((key.to_vec(), value.to_vec())),
368 phantom: Default::default(),
369 };
370
371 for (key, value) in iter {
372 let full_key = [to_prefix, &key].concat();
373 unhashed::put_raw(&full_key, &value);
374 }
375}
376
377#[cfg(test)]
378mod tests {
379 use super::{
380 move_pallet, move_prefix, move_storage_from_pallet, storage_iter, storage_key_iter,
381 };
382 use crate::{
383 hash::StorageHasher,
384 pallet_prelude::{StorageMap, StorageValue, Twox128, Twox64Concat},
385 };
386 use subsoil::io::TestExternalities;
387
388 struct OldPalletStorageValuePrefix;
389 impl topsoil_core::traits::StorageInstance for OldPalletStorageValuePrefix {
390 const STORAGE_PREFIX: &'static str = "foo_value";
391 fn pallet_prefix() -> &'static str {
392 "my_old_pallet"
393 }
394 }
395 type OldStorageValue = StorageValue<OldPalletStorageValuePrefix, u32>;
396
397 struct OldPalletStorageMapPrefix;
398 impl topsoil_core::traits::StorageInstance for OldPalletStorageMapPrefix {
399 const STORAGE_PREFIX: &'static str = "foo_map";
400 fn pallet_prefix() -> &'static str {
401 "my_old_pallet"
402 }
403 }
404 type OldStorageMap = StorageMap<OldPalletStorageMapPrefix, Twox64Concat, u32, u32>;
405
406 struct NewPalletStorageValuePrefix;
407 impl topsoil_core::traits::StorageInstance for NewPalletStorageValuePrefix {
408 const STORAGE_PREFIX: &'static str = "foo_value";
409 fn pallet_prefix() -> &'static str {
410 "my_new_pallet"
411 }
412 }
413 type NewStorageValue = StorageValue<NewPalletStorageValuePrefix, u32>;
414
415 struct NewPalletStorageMapPrefix;
416 impl topsoil_core::traits::StorageInstance for NewPalletStorageMapPrefix {
417 const STORAGE_PREFIX: &'static str = "foo_map";
418 fn pallet_prefix() -> &'static str {
419 "my_new_pallet"
420 }
421 }
422 type NewStorageMap = StorageMap<NewPalletStorageMapPrefix, Twox64Concat, u32, u32>;
423
424 #[test]
425 fn test_move_prefix() {
426 TestExternalities::new_empty().execute_with(|| {
427 OldStorageValue::put(3);
428 OldStorageMap::insert(1, 2);
429 OldStorageMap::insert(3, 4);
430
431 move_prefix(&Twox128::hash(b"my_old_pallet"), &Twox128::hash(b"my_new_pallet"));
432
433 assert_eq!(OldStorageValue::get(), None);
434 assert_eq!(OldStorageMap::iter().collect::<Vec<_>>(), vec![]);
435 assert_eq!(NewStorageValue::get(), Some(3));
436 assert_eq!(NewStorageMap::iter().collect::<Vec<_>>(), vec![(1, 2), (3, 4)]);
437 })
438 }
439
440 #[test]
441 fn test_move_storage() {
442 TestExternalities::new_empty().execute_with(|| {
443 OldStorageValue::put(3);
444 OldStorageMap::insert(1, 2);
445 OldStorageMap::insert(3, 4);
446
447 move_storage_from_pallet(b"foo_map", b"my_old_pallet", b"my_new_pallet");
448
449 assert_eq!(OldStorageValue::get(), Some(3));
450 assert_eq!(OldStorageMap::iter().collect::<Vec<_>>(), vec![]);
451 assert_eq!(NewStorageValue::get(), None);
452 assert_eq!(NewStorageMap::iter().collect::<Vec<_>>(), vec![(1, 2), (3, 4)]);
453
454 move_storage_from_pallet(b"foo_value", b"my_old_pallet", b"my_new_pallet");
455
456 assert_eq!(OldStorageValue::get(), None);
457 assert_eq!(OldStorageMap::iter().collect::<Vec<_>>(), vec![]);
458 assert_eq!(NewStorageValue::get(), Some(3));
459 assert_eq!(NewStorageMap::iter().collect::<Vec<_>>(), vec![(1, 2), (3, 4)]);
460 })
461 }
462
463 #[test]
464 fn test_move_pallet() {
465 TestExternalities::new_empty().execute_with(|| {
466 OldStorageValue::put(3);
467 OldStorageMap::insert(1, 2);
468 OldStorageMap::insert(3, 4);
469
470 move_pallet(b"my_old_pallet", b"my_new_pallet");
471
472 assert_eq!(OldStorageValue::get(), None);
473 assert_eq!(OldStorageMap::iter().collect::<Vec<_>>(), vec![]);
474 assert_eq!(NewStorageValue::get(), Some(3));
475 assert_eq!(NewStorageMap::iter().collect::<Vec<_>>(), vec![(1, 2), (3, 4)]);
476 })
477 }
478
479 #[test]
480 fn test_storage_iter() {
481 TestExternalities::new_empty().execute_with(|| {
482 OldStorageValue::put(3);
483 OldStorageMap::insert(1, 2);
484 OldStorageMap::insert(3, 4);
485
486 assert_eq!(
487 storage_key_iter::<i32, i32, Twox64Concat>(b"my_old_pallet", b"foo_map")
488 .collect::<Vec<_>>(),
489 vec![(1, 2), (3, 4)],
490 );
491
492 assert_eq!(
493 storage_iter(b"my_old_pallet", b"foo_map")
494 .drain()
495 .map(|t| t.1)
496 .collect::<Vec<i32>>(),
497 vec![2, 4],
498 );
499 assert_eq!(OldStorageMap::iter().collect::<Vec<_>>(), vec![]);
500
501 assert_eq!(storage_iter::<i32>(b"my_old_pallet", b"foo_value").drain().next(), None);
503 assert_eq!(OldStorageValue::get(), Some(3));
504 });
505 }
506}