1use crate::{
21 hash::ReversibleStorageHasher,
22 storage::{storage_prefix, unhashed},
23 StorageHasher, Twox128,
24};
25use alloc::{vec, vec::Vec};
26use codec::{Decode, Encode};
27
28use super::PrefixIterator;
29
30pub fn storage_iter<T: Decode + Sized>(module: &[u8], item: &[u8]) -> PrefixIterator<(Vec<u8>, T)> {
32 storage_iter_with_suffix(module, item, &[][..])
33}
34
35pub fn storage_iter_with_suffix<T: Decode + Sized>(
37 module: &[u8],
38 item: &[u8],
39 suffix: &[u8],
40) -> PrefixIterator<(Vec<u8>, T)> {
41 let mut prefix = Vec::new();
42 let storage_prefix = storage_prefix(module, item);
43 prefix.extend_from_slice(&storage_prefix);
44 prefix.extend_from_slice(suffix);
45 let previous_key = prefix.clone();
46 let closure = |raw_key_without_prefix: &[u8], mut raw_value: &[u8]| {
47 let value = T::decode(&mut raw_value)?;
48 Ok((raw_key_without_prefix.to_vec(), value))
49 };
50
51 PrefixIterator { prefix, previous_key, drain: false, closure, phantom: Default::default() }
52}
53
54pub fn storage_key_iter<K: Decode + Sized, T: Decode + Sized, H: ReversibleStorageHasher>(
56 module: &[u8],
57 item: &[u8],
58) -> PrefixIterator<(K, T)> {
59 storage_key_iter_with_suffix::<K, T, H>(module, item, &[][..])
60}
61
62pub fn storage_key_iter_with_suffix<
64 K: Decode + Sized,
65 T: Decode + Sized,
66 H: ReversibleStorageHasher,
67>(
68 module: &[u8],
69 item: &[u8],
70 suffix: &[u8],
71) -> PrefixIterator<(K, T)> {
72 let mut prefix = Vec::new();
73 let storage_prefix = storage_prefix(module, item);
74
75 prefix.extend_from_slice(&storage_prefix);
76 prefix.extend_from_slice(suffix);
77 let previous_key = prefix.clone();
78 let closure = |raw_key_without_prefix: &[u8], mut raw_value: &[u8]| {
79 let mut key_material = H::reverse(raw_key_without_prefix);
80 let key = K::decode(&mut key_material)?;
81 let value = T::decode(&mut raw_value)?;
82 Ok((key, value))
83 };
84 PrefixIterator { prefix, previous_key, drain: false, closure, phantom: Default::default() }
85}
86
87pub fn have_storage_value(module: &[u8], item: &[u8], hash: &[u8]) -> bool {
89 get_storage_value::<()>(module, item, hash).is_some()
90}
91
92pub fn get_storage_value<T: Decode + Sized>(module: &[u8], item: &[u8], hash: &[u8]) -> Option<T> {
94 let mut key = vec![0u8; 32 + hash.len()];
95 let storage_prefix = storage_prefix(module, item);
96 key[0..32].copy_from_slice(&storage_prefix);
97 key[32..].copy_from_slice(hash);
98 frame_support::storage::unhashed::get::<T>(&key)
99}
100
101pub fn take_storage_value<T: Decode + Sized>(module: &[u8], item: &[u8], hash: &[u8]) -> Option<T> {
103 let mut key = vec![0u8; 32 + hash.len()];
104 let storage_prefix = storage_prefix(module, item);
105 key[0..32].copy_from_slice(&storage_prefix);
106 key[32..].copy_from_slice(hash);
107 frame_support::storage::unhashed::take::<T>(&key)
108}
109
110pub fn put_storage_value<T: Encode>(module: &[u8], item: &[u8], hash: &[u8], value: T) {
112 let mut key = vec![0u8; 32 + hash.len()];
113 let storage_prefix = storage_prefix(module, item);
114 key[0..32].copy_from_slice(&storage_prefix);
115 key[32..].copy_from_slice(hash);
116 frame_support::storage::unhashed::put(&key, &value);
117}
118
119#[deprecated = "Use `clear_storage_prefix` instead"]
122pub fn remove_storage_prefix(module: &[u8], item: &[u8], hash: &[u8]) {
123 let mut key = vec![0u8; 32 + hash.len()];
124 let storage_prefix = storage_prefix(module, item);
125 key[0..32].copy_from_slice(&storage_prefix);
126 key[32..].copy_from_slice(hash);
127 let _ = frame_support::storage::unhashed::clear_prefix(&key, None, None);
128}
129
130pub fn clear_storage_prefix(
147 module: &[u8],
148 item: &[u8],
149 hash: &[u8],
150 maybe_limit: Option<u32>,
151 maybe_cursor: Option<&[u8]>,
152) -> sp_io::MultiRemovalResults {
153 let mut key = vec![0u8; 32 + hash.len()];
154 let storage_prefix = storage_prefix(module, item);
155 key[0..32].copy_from_slice(&storage_prefix);
156 key[32..].copy_from_slice(hash);
157 frame_support::storage::unhashed::clear_prefix(&key, maybe_limit, maybe_cursor)
158}
159
160pub fn take_storage_item<K: Encode + Sized, T: Decode + Sized, H: StorageHasher>(
162 module: &[u8],
163 item: &[u8],
164 key: K,
165) -> Option<T> {
166 take_storage_value(module, item, key.using_encoded(H::hash).as_ref())
167}
168
169pub fn move_storage_from_pallet(
190 storage_name: &[u8],
191 old_pallet_name: &[u8],
192 new_pallet_name: &[u8],
193) {
194 let new_prefix = storage_prefix(new_pallet_name, storage_name);
195 let old_prefix = storage_prefix(old_pallet_name, storage_name);
196
197 move_prefix(&old_prefix, &new_prefix);
198
199 if let Some(value) = unhashed::get_raw(&old_prefix) {
200 unhashed::put_raw(&new_prefix, &value);
201 unhashed::kill(&old_prefix);
202 }
203}
204
205pub fn move_pallet(old_pallet_name: &[u8], new_pallet_name: &[u8]) {
226 move_prefix(&Twox128::hash(old_pallet_name), &Twox128::hash(new_pallet_name))
227}
228
229pub fn move_prefix(from_prefix: &[u8], to_prefix: &[u8]) {
236 if from_prefix == to_prefix {
237 return;
238 }
239
240 let iter = PrefixIterator::<_> {
241 prefix: from_prefix.to_vec(),
242 previous_key: from_prefix.to_vec(),
243 drain: true,
244 closure: |key, value| Ok((key.to_vec(), value.to_vec())),
245 phantom: Default::default(),
246 };
247
248 for (key, value) in iter {
249 let full_key = [to_prefix, &key].concat();
250 unhashed::put_raw(&full_key, &value);
251 }
252}
253
254#[cfg(test)]
255mod tests {
256 use super::{
257 move_pallet, move_prefix, move_storage_from_pallet, storage_iter, storage_key_iter,
258 };
259 use crate::{
260 hash::StorageHasher,
261 pallet_prelude::{StorageMap, StorageValue, Twox128, Twox64Concat},
262 };
263 use sp_io::TestExternalities;
264
265 struct OldPalletStorageValuePrefix;
266 impl frame_support::traits::StorageInstance for OldPalletStorageValuePrefix {
267 const STORAGE_PREFIX: &'static str = "foo_value";
268 fn pallet_prefix() -> &'static str {
269 "my_old_pallet"
270 }
271 }
272 type OldStorageValue = StorageValue<OldPalletStorageValuePrefix, u32>;
273
274 struct OldPalletStorageMapPrefix;
275 impl frame_support::traits::StorageInstance for OldPalletStorageMapPrefix {
276 const STORAGE_PREFIX: &'static str = "foo_map";
277 fn pallet_prefix() -> &'static str {
278 "my_old_pallet"
279 }
280 }
281 type OldStorageMap = StorageMap<OldPalletStorageMapPrefix, Twox64Concat, u32, u32>;
282
283 struct NewPalletStorageValuePrefix;
284 impl frame_support::traits::StorageInstance for NewPalletStorageValuePrefix {
285 const STORAGE_PREFIX: &'static str = "foo_value";
286 fn pallet_prefix() -> &'static str {
287 "my_new_pallet"
288 }
289 }
290 type NewStorageValue = StorageValue<NewPalletStorageValuePrefix, u32>;
291
292 struct NewPalletStorageMapPrefix;
293 impl frame_support::traits::StorageInstance for NewPalletStorageMapPrefix {
294 const STORAGE_PREFIX: &'static str = "foo_map";
295 fn pallet_prefix() -> &'static str {
296 "my_new_pallet"
297 }
298 }
299 type NewStorageMap = StorageMap<NewPalletStorageMapPrefix, Twox64Concat, u32, u32>;
300
301 #[test]
302 fn test_move_prefix() {
303 TestExternalities::new_empty().execute_with(|| {
304 OldStorageValue::put(3);
305 OldStorageMap::insert(1, 2);
306 OldStorageMap::insert(3, 4);
307
308 move_prefix(&Twox128::hash(b"my_old_pallet"), &Twox128::hash(b"my_new_pallet"));
309
310 assert_eq!(OldStorageValue::get(), None);
311 assert_eq!(OldStorageMap::iter().collect::<Vec<_>>(), vec![]);
312 assert_eq!(NewStorageValue::get(), Some(3));
313 assert_eq!(NewStorageMap::iter().collect::<Vec<_>>(), vec![(1, 2), (3, 4)]);
314 })
315 }
316
317 #[test]
318 fn test_move_storage() {
319 TestExternalities::new_empty().execute_with(|| {
320 OldStorageValue::put(3);
321 OldStorageMap::insert(1, 2);
322 OldStorageMap::insert(3, 4);
323
324 move_storage_from_pallet(b"foo_map", b"my_old_pallet", b"my_new_pallet");
325
326 assert_eq!(OldStorageValue::get(), Some(3));
327 assert_eq!(OldStorageMap::iter().collect::<Vec<_>>(), vec![]);
328 assert_eq!(NewStorageValue::get(), None);
329 assert_eq!(NewStorageMap::iter().collect::<Vec<_>>(), vec![(1, 2), (3, 4)]);
330
331 move_storage_from_pallet(b"foo_value", b"my_old_pallet", b"my_new_pallet");
332
333 assert_eq!(OldStorageValue::get(), None);
334 assert_eq!(OldStorageMap::iter().collect::<Vec<_>>(), vec![]);
335 assert_eq!(NewStorageValue::get(), Some(3));
336 assert_eq!(NewStorageMap::iter().collect::<Vec<_>>(), vec![(1, 2), (3, 4)]);
337 })
338 }
339
340 #[test]
341 fn test_move_pallet() {
342 TestExternalities::new_empty().execute_with(|| {
343 OldStorageValue::put(3);
344 OldStorageMap::insert(1, 2);
345 OldStorageMap::insert(3, 4);
346
347 move_pallet(b"my_old_pallet", b"my_new_pallet");
348
349 assert_eq!(OldStorageValue::get(), None);
350 assert_eq!(OldStorageMap::iter().collect::<Vec<_>>(), vec![]);
351 assert_eq!(NewStorageValue::get(), Some(3));
352 assert_eq!(NewStorageMap::iter().collect::<Vec<_>>(), vec![(1, 2), (3, 4)]);
353 })
354 }
355
356 #[test]
357 fn test_storage_iter() {
358 TestExternalities::new_empty().execute_with(|| {
359 OldStorageValue::put(3);
360 OldStorageMap::insert(1, 2);
361 OldStorageMap::insert(3, 4);
362
363 assert_eq!(
364 storage_key_iter::<i32, i32, Twox64Concat>(b"my_old_pallet", b"foo_map")
365 .collect::<Vec<_>>(),
366 vec![(1, 2), (3, 4)],
367 );
368
369 assert_eq!(
370 storage_iter(b"my_old_pallet", b"foo_map")
371 .drain()
372 .map(|t| t.1)
373 .collect::<Vec<i32>>(),
374 vec![2, 4],
375 );
376 assert_eq!(OldStorageMap::iter().collect::<Vec<_>>(), vec![]);
377
378 assert_eq!(storage_iter::<i32>(b"my_old_pallet", b"foo_value").drain().next(), None);
380 assert_eq!(OldStorageValue::get(), Some(3));
381 });
382 }
383}