referrerpolicy=no-referrer-when-downgrade

frame_support/storage/
migration.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! Some utilities for helping access storage with arbitrary key types.
19
20use 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
30/// Utility to iterate through raw items in storage.
31pub struct StorageIterator<T> {
32	prefix: Vec<u8>,
33	previous_key: Vec<u8>,
34	drain: bool,
35	_phantom: ::core::marker::PhantomData<T>,
36}
37
38impl<T> StorageIterator<T> {
39	/// Construct iterator to iterate over map items in `module` for the map called `item`.
40	#[deprecated(note = "Will be removed after July 2023; Please use the storage_iter or \
41		storage_iter_with_suffix functions instead")]
42	pub fn new(module: &[u8], item: &[u8]) -> Self {
43		#[allow(deprecated)]
44		Self::with_suffix(module, item, &[][..])
45	}
46
47	/// Construct iterator to iterate over map items in `module` for the map called `item`.
48	#[deprecated(note = "Will be removed after July 2023; Please use the storage_iter or \
49		storage_iter_with_suffix functions instead")]
50	pub fn with_suffix(module: &[u8], item: &[u8], suffix: &[u8]) -> Self {
51		let mut prefix = Vec::new();
52		let storage_prefix = storage_prefix(module, item);
53		prefix.extend_from_slice(&storage_prefix);
54		prefix.extend_from_slice(suffix);
55		let previous_key = prefix.clone();
56		Self { prefix, previous_key, drain: false, _phantom: Default::default() }
57	}
58
59	/// Mutate this iterator into a draining iterator; items iterated are removed from storage.
60	pub fn drain(mut self) -> Self {
61		self.drain = true;
62		self
63	}
64}
65
66impl<T: Decode + Sized> Iterator for StorageIterator<T> {
67	type Item = (Vec<u8>, T);
68
69	fn next(&mut self) -> Option<(Vec<u8>, T)> {
70		loop {
71			let maybe_next = sp_io::storage::next_key(&self.previous_key)
72				.filter(|n| n.starts_with(&self.prefix));
73			break match maybe_next {
74				Some(next) => {
75					self.previous_key = next.clone();
76					let maybe_value = frame_support::storage::unhashed::get::<T>(&next);
77					match maybe_value {
78						Some(value) => {
79							if self.drain {
80								frame_support::storage::unhashed::kill(&next);
81							}
82							Some((self.previous_key[self.prefix.len()..].to_vec(), value))
83						},
84						None => continue,
85					}
86				},
87				None => None,
88			}
89		}
90	}
91}
92
93/// Utility to iterate through raw items in storage.
94pub struct StorageKeyIterator<K, T, H: ReversibleStorageHasher> {
95	prefix: Vec<u8>,
96	previous_key: Vec<u8>,
97	drain: bool,
98	_phantom: ::core::marker::PhantomData<(K, T, H)>,
99}
100
101impl<K, T, H: ReversibleStorageHasher> StorageKeyIterator<K, T, H> {
102	/// Construct iterator to iterate over map items in `module` for the map called `item`.
103	#[deprecated(note = "Will be removed after July 2023; Please use the storage_key_iter or \
104		storage_key_iter_with_suffix functions instead")]
105	pub fn new(module: &[u8], item: &[u8]) -> Self {
106		#[allow(deprecated)]
107		Self::with_suffix(module, item, &[][..])
108	}
109
110	/// Construct iterator to iterate over map items in `module` for the map called `item`.
111	#[deprecated(note = "Will be removed after July 2023; Please use the storage_key_iter or \
112		storage_key_iter_with_suffix functions instead")]
113	pub fn with_suffix(module: &[u8], item: &[u8], suffix: &[u8]) -> Self {
114		let mut prefix = Vec::new();
115		let storage_prefix = storage_prefix(module, item);
116		prefix.extend_from_slice(&storage_prefix);
117		prefix.extend_from_slice(suffix);
118		let previous_key = prefix.clone();
119		Self { prefix, previous_key, drain: false, _phantom: Default::default() }
120	}
121
122	/// Mutate this iterator into a draining iterator; items iterated are removed from storage.
123	pub fn drain(mut self) -> Self {
124		self.drain = true;
125		self
126	}
127}
128
129impl<K: Decode + Sized, T: Decode + Sized, H: ReversibleStorageHasher> Iterator
130	for StorageKeyIterator<K, T, H>
131{
132	type Item = (K, T);
133
134	fn next(&mut self) -> Option<(K, T)> {
135		loop {
136			let maybe_next = sp_io::storage::next_key(&self.previous_key)
137				.filter(|n| n.starts_with(&self.prefix));
138			break match maybe_next {
139				Some(next) => {
140					self.previous_key = next.clone();
141					let mut key_material = H::reverse(&next[self.prefix.len()..]);
142					match K::decode(&mut key_material) {
143						Ok(key) => {
144							let maybe_value = frame_support::storage::unhashed::get::<T>(&next);
145							match maybe_value {
146								Some(value) => {
147									if self.drain {
148										frame_support::storage::unhashed::kill(&next);
149									}
150									Some((key, value))
151								},
152								None => continue,
153							}
154						},
155						Err(_) => continue,
156					}
157				},
158				None => None,
159			}
160		}
161	}
162}
163
164/// Construct iterator to iterate over map items in `module` for the map called `item`.
165pub fn storage_iter<T: Decode + Sized>(module: &[u8], item: &[u8]) -> PrefixIterator<(Vec<u8>, T)> {
166	storage_iter_with_suffix(module, item, &[][..])
167}
168
169/// Construct iterator to iterate over map items in `module` for the map called `item`.
170pub fn storage_iter_with_suffix<T: Decode + Sized>(
171	module: &[u8],
172	item: &[u8],
173	suffix: &[u8],
174) -> PrefixIterator<(Vec<u8>, T)> {
175	let mut prefix = Vec::new();
176	let storage_prefix = storage_prefix(module, item);
177	prefix.extend_from_slice(&storage_prefix);
178	prefix.extend_from_slice(suffix);
179	let previous_key = prefix.clone();
180	let closure = |raw_key_without_prefix: &[u8], mut raw_value: &[u8]| {
181		let value = T::decode(&mut raw_value)?;
182		Ok((raw_key_without_prefix.to_vec(), value))
183	};
184
185	PrefixIterator { prefix, previous_key, drain: false, closure, phantom: Default::default() }
186}
187
188/// Construct iterator to iterate over map items in `module` for the map called `item`.
189pub fn storage_key_iter<K: Decode + Sized, T: Decode + Sized, H: ReversibleStorageHasher>(
190	module: &[u8],
191	item: &[u8],
192) -> PrefixIterator<(K, T)> {
193	storage_key_iter_with_suffix::<K, T, H>(module, item, &[][..])
194}
195
196/// Construct iterator to iterate over map items in `module` for the map called `item`.
197pub fn storage_key_iter_with_suffix<
198	K: Decode + Sized,
199	T: Decode + Sized,
200	H: ReversibleStorageHasher,
201>(
202	module: &[u8],
203	item: &[u8],
204	suffix: &[u8],
205) -> PrefixIterator<(K, T)> {
206	let mut prefix = Vec::new();
207	let storage_prefix = storage_prefix(module, item);
208
209	prefix.extend_from_slice(&storage_prefix);
210	prefix.extend_from_slice(suffix);
211	let previous_key = prefix.clone();
212	let closure = |raw_key_without_prefix: &[u8], mut raw_value: &[u8]| {
213		let mut key_material = H::reverse(raw_key_without_prefix);
214		let key = K::decode(&mut key_material)?;
215		let value = T::decode(&mut raw_value)?;
216		Ok((key, value))
217	};
218	PrefixIterator { prefix, previous_key, drain: false, closure, phantom: Default::default() }
219}
220
221/// Get a particular value in storage by the `module`, the map's `item` name and the key `hash`.
222pub fn have_storage_value(module: &[u8], item: &[u8], hash: &[u8]) -> bool {
223	get_storage_value::<()>(module, item, hash).is_some()
224}
225
226/// Get a particular value in storage by the `module`, the map's `item` name and the key `hash`.
227pub fn get_storage_value<T: Decode + Sized>(module: &[u8], item: &[u8], hash: &[u8]) -> Option<T> {
228	let mut key = vec![0u8; 32 + hash.len()];
229	let storage_prefix = storage_prefix(module, item);
230	key[0..32].copy_from_slice(&storage_prefix);
231	key[32..].copy_from_slice(hash);
232	frame_support::storage::unhashed::get::<T>(&key)
233}
234
235/// Take a particular value in storage by the `module`, the map's `item` name and the key `hash`.
236pub fn take_storage_value<T: Decode + Sized>(module: &[u8], item: &[u8], hash: &[u8]) -> Option<T> {
237	let mut key = vec![0u8; 32 + hash.len()];
238	let storage_prefix = storage_prefix(module, item);
239	key[0..32].copy_from_slice(&storage_prefix);
240	key[32..].copy_from_slice(hash);
241	frame_support::storage::unhashed::take::<T>(&key)
242}
243
244/// Put a particular value into storage by the `module`, the map's `item` name and the key `hash`.
245pub fn put_storage_value<T: Encode>(module: &[u8], item: &[u8], hash: &[u8], value: T) {
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	frame_support::storage::unhashed::put(&key, &value);
251}
252
253/// Remove all items under a storage prefix by the `module`, the map's `item` name and the key
254/// `hash`.
255#[deprecated = "Use `clear_storage_prefix` instead"]
256pub fn remove_storage_prefix(module: &[u8], item: &[u8], hash: &[u8]) {
257	let mut key = vec![0u8; 32 + hash.len()];
258	let storage_prefix = storage_prefix(module, item);
259	key[0..32].copy_from_slice(&storage_prefix);
260	key[32..].copy_from_slice(hash);
261	let _ = frame_support::storage::unhashed::clear_prefix(&key, None, None);
262}
263
264/// Attempt to remove all values under a storage prefix by the `module`, the map's `item` name and
265/// the key `hash`.
266///
267/// All values in the client overlay will be deleted, if `maybe_limit` is `Some` then up to
268/// that number of values are deleted from the client backend by seeking and reading that number of
269/// storage values plus one. If `maybe_limit` is `None` then all values in the client backend are
270/// deleted. This is potentially unsafe since it's an unbounded operation.
271///
272/// ## Cursors
273///
274/// The `maybe_cursor` parameter should be `None` for the first call to initial removal.
275/// If the resultant `maybe_cursor` is `Some`, then another call is required to complete the
276/// removal operation. This value must be passed in as the subsequent call's `maybe_cursor`
277/// parameter. If the resultant `maybe_cursor` is `None`, then the operation is complete and no
278/// items remain in storage provided that no items were added between the first calls and the
279/// final call.
280pub fn clear_storage_prefix(
281	module: &[u8],
282	item: &[u8],
283	hash: &[u8],
284	maybe_limit: Option<u32>,
285	maybe_cursor: Option<&[u8]>,
286) -> sp_io::MultiRemovalResults {
287	let mut key = vec![0u8; 32 + hash.len()];
288	let storage_prefix = storage_prefix(module, item);
289	key[0..32].copy_from_slice(&storage_prefix);
290	key[32..].copy_from_slice(hash);
291	frame_support::storage::unhashed::clear_prefix(&key, maybe_limit, maybe_cursor)
292}
293
294/// Take a particular item in storage by the `module`, the map's `item` name and the key `hash`.
295pub fn take_storage_item<K: Encode + Sized, T: Decode + Sized, H: StorageHasher>(
296	module: &[u8],
297	item: &[u8],
298	key: K,
299) -> Option<T> {
300	take_storage_value(module, item, key.using_encoded(H::hash).as_ref())
301}
302
303/// Move a storage from a pallet prefix to another pallet prefix.
304///
305/// Keys used in pallet storages always start with:
306/// `concat(twox_128(pallet_name), twox_128(storage_name))`.
307///
308/// This function will remove all value for which the key start with
309/// `concat(twox_128(old_pallet_name), twox_128(storage_name))` and insert them at the key with
310/// the start replaced by `concat(twox_128(new_pallet_name), twox_128(storage_name))`.
311///
312/// # Example
313///
314/// If a pallet named "my_example" has 2 storages named "Foo" and "Bar" and the pallet is renamed
315/// "my_new_example_name", a migration can be:
316/// ```
317/// # use frame_support::storage::migration::move_storage_from_pallet;
318/// # sp_io::TestExternalities::new_empty().execute_with(|| {
319/// move_storage_from_pallet(b"Foo", b"my_example", b"my_new_example_name");
320/// move_storage_from_pallet(b"Bar", b"my_example", b"my_new_example_name");
321/// # })
322/// ```
323pub fn move_storage_from_pallet(
324	storage_name: &[u8],
325	old_pallet_name: &[u8],
326	new_pallet_name: &[u8],
327) {
328	let new_prefix = storage_prefix(new_pallet_name, storage_name);
329	let old_prefix = storage_prefix(old_pallet_name, storage_name);
330
331	move_prefix(&old_prefix, &new_prefix);
332
333	if let Some(value) = unhashed::get_raw(&old_prefix) {
334		unhashed::put_raw(&new_prefix, &value);
335		unhashed::kill(&old_prefix);
336	}
337}
338
339/// Move all storages from a pallet prefix to another pallet prefix.
340///
341/// Keys used in pallet storages always start with:
342/// `concat(twox_128(pallet_name), twox_128(storage_name))`.
343///
344/// This function will remove all value for which the key start with `twox_128(old_pallet_name)`
345/// and insert them at the key with the start replaced by `twox_128(new_pallet_name)`.
346///
347/// NOTE: The value at the key `twox_128(old_pallet_name)` is not moved.
348///
349/// # Example
350///
351/// If a pallet named "my_example" has some storages and the pallet is renamed
352/// "my_new_example_name", a migration can be:
353/// ```
354/// # use frame_support::storage::migration::move_pallet;
355/// # sp_io::TestExternalities::new_empty().execute_with(|| {
356/// move_pallet(b"my_example", b"my_new_example_name");
357/// # })
358/// ```
359pub fn move_pallet(old_pallet_name: &[u8], new_pallet_name: &[u8]) {
360	move_prefix(&Twox128::hash(old_pallet_name), &Twox128::hash(new_pallet_name))
361}
362
363/// Move all `(key, value)` after some prefix to the another prefix
364///
365/// This function will remove all value for which the key start with `from_prefix`
366/// and insert them at the key with the start replaced by `to_prefix`.
367///
368/// NOTE: The value at the key `from_prefix` is not moved.
369pub fn move_prefix(from_prefix: &[u8], to_prefix: &[u8]) {
370	if from_prefix == to_prefix {
371		return
372	}
373
374	let iter = PrefixIterator::<_> {
375		prefix: from_prefix.to_vec(),
376		previous_key: from_prefix.to_vec(),
377		drain: true,
378		closure: |key, value| Ok((key.to_vec(), value.to_vec())),
379		phantom: Default::default(),
380	};
381
382	for (key, value) in iter {
383		let full_key = [to_prefix, &key].concat();
384		unhashed::put_raw(&full_key, &value);
385	}
386}
387
388#[cfg(test)]
389mod tests {
390	use super::{
391		move_pallet, move_prefix, move_storage_from_pallet, storage_iter, storage_key_iter,
392	};
393	use crate::{
394		hash::StorageHasher,
395		pallet_prelude::{StorageMap, StorageValue, Twox128, Twox64Concat},
396	};
397	use sp_io::TestExternalities;
398
399	struct OldPalletStorageValuePrefix;
400	impl frame_support::traits::StorageInstance for OldPalletStorageValuePrefix {
401		const STORAGE_PREFIX: &'static str = "foo_value";
402		fn pallet_prefix() -> &'static str {
403			"my_old_pallet"
404		}
405	}
406	type OldStorageValue = StorageValue<OldPalletStorageValuePrefix, u32>;
407
408	struct OldPalletStorageMapPrefix;
409	impl frame_support::traits::StorageInstance for OldPalletStorageMapPrefix {
410		const STORAGE_PREFIX: &'static str = "foo_map";
411		fn pallet_prefix() -> &'static str {
412			"my_old_pallet"
413		}
414	}
415	type OldStorageMap = StorageMap<OldPalletStorageMapPrefix, Twox64Concat, u32, u32>;
416
417	struct NewPalletStorageValuePrefix;
418	impl frame_support::traits::StorageInstance for NewPalletStorageValuePrefix {
419		const STORAGE_PREFIX: &'static str = "foo_value";
420		fn pallet_prefix() -> &'static str {
421			"my_new_pallet"
422		}
423	}
424	type NewStorageValue = StorageValue<NewPalletStorageValuePrefix, u32>;
425
426	struct NewPalletStorageMapPrefix;
427	impl frame_support::traits::StorageInstance for NewPalletStorageMapPrefix {
428		const STORAGE_PREFIX: &'static str = "foo_map";
429		fn pallet_prefix() -> &'static str {
430			"my_new_pallet"
431		}
432	}
433	type NewStorageMap = StorageMap<NewPalletStorageMapPrefix, Twox64Concat, u32, u32>;
434
435	#[test]
436	fn test_move_prefix() {
437		TestExternalities::new_empty().execute_with(|| {
438			OldStorageValue::put(3);
439			OldStorageMap::insert(1, 2);
440			OldStorageMap::insert(3, 4);
441
442			move_prefix(&Twox128::hash(b"my_old_pallet"), &Twox128::hash(b"my_new_pallet"));
443
444			assert_eq!(OldStorageValue::get(), None);
445			assert_eq!(OldStorageMap::iter().collect::<Vec<_>>(), vec![]);
446			assert_eq!(NewStorageValue::get(), Some(3));
447			assert_eq!(NewStorageMap::iter().collect::<Vec<_>>(), vec![(1, 2), (3, 4)]);
448		})
449	}
450
451	#[test]
452	fn test_move_storage() {
453		TestExternalities::new_empty().execute_with(|| {
454			OldStorageValue::put(3);
455			OldStorageMap::insert(1, 2);
456			OldStorageMap::insert(3, 4);
457
458			move_storage_from_pallet(b"foo_map", b"my_old_pallet", b"my_new_pallet");
459
460			assert_eq!(OldStorageValue::get(), Some(3));
461			assert_eq!(OldStorageMap::iter().collect::<Vec<_>>(), vec![]);
462			assert_eq!(NewStorageValue::get(), None);
463			assert_eq!(NewStorageMap::iter().collect::<Vec<_>>(), vec![(1, 2), (3, 4)]);
464
465			move_storage_from_pallet(b"foo_value", b"my_old_pallet", b"my_new_pallet");
466
467			assert_eq!(OldStorageValue::get(), None);
468			assert_eq!(OldStorageMap::iter().collect::<Vec<_>>(), vec![]);
469			assert_eq!(NewStorageValue::get(), Some(3));
470			assert_eq!(NewStorageMap::iter().collect::<Vec<_>>(), vec![(1, 2), (3, 4)]);
471		})
472	}
473
474	#[test]
475	fn test_move_pallet() {
476		TestExternalities::new_empty().execute_with(|| {
477			OldStorageValue::put(3);
478			OldStorageMap::insert(1, 2);
479			OldStorageMap::insert(3, 4);
480
481			move_pallet(b"my_old_pallet", b"my_new_pallet");
482
483			assert_eq!(OldStorageValue::get(), None);
484			assert_eq!(OldStorageMap::iter().collect::<Vec<_>>(), vec![]);
485			assert_eq!(NewStorageValue::get(), Some(3));
486			assert_eq!(NewStorageMap::iter().collect::<Vec<_>>(), vec![(1, 2), (3, 4)]);
487		})
488	}
489
490	#[test]
491	fn test_storage_iter() {
492		TestExternalities::new_empty().execute_with(|| {
493			OldStorageValue::put(3);
494			OldStorageMap::insert(1, 2);
495			OldStorageMap::insert(3, 4);
496
497			assert_eq!(
498				storage_key_iter::<i32, i32, Twox64Concat>(b"my_old_pallet", b"foo_map")
499					.collect::<Vec<_>>(),
500				vec![(1, 2), (3, 4)],
501			);
502
503			assert_eq!(
504				storage_iter(b"my_old_pallet", b"foo_map")
505					.drain()
506					.map(|t| t.1)
507					.collect::<Vec<i32>>(),
508				vec![2, 4],
509			);
510			assert_eq!(OldStorageMap::iter().collect::<Vec<_>>(), vec![]);
511
512			// Empty because storage iterator skips over the entry under the first key
513			assert_eq!(storage_iter::<i32>(b"my_old_pallet", b"foo_value").drain().next(), None);
514			assert_eq!(OldStorageValue::get(), Some(3));
515		});
516	}
517}