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/// Construct iterator to iterate over map items in `module` for the map called `item`.
31pub fn storage_iter<T: Decode + Sized>(module: &[u8], item: &[u8]) -> PrefixIterator<(Vec<u8>, T)> {
32	storage_iter_with_suffix(module, item, &[][..])
33}
34
35/// Construct iterator to iterate over map items in `module` for the map called `item`.
36pub 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
54/// Construct iterator to iterate over map items in `module` for the map called `item`.
55pub 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
62/// Construct iterator to iterate over map items in `module` for the map called `item`.
63pub 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
87/// Get a particular value in storage by the `module`, the map's `item` name and the key `hash`.
88pub fn have_storage_value(module: &[u8], item: &[u8], hash: &[u8]) -> bool {
89	get_storage_value::<()>(module, item, hash).is_some()
90}
91
92/// Get a particular value in storage by the `module`, the map's `item` name and the key `hash`.
93pub 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
101/// Take a particular value in storage by the `module`, the map's `item` name and the key `hash`.
102pub 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
110/// Put a particular value into storage by the `module`, the map's `item` name and the key `hash`.
111pub 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/// Remove all items under a storage prefix by the `module`, the map's `item` name and the key
120/// `hash`.
121#[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
130/// Attempt to remove all values under a storage prefix by the `module`, the map's `item` name and
131/// the key `hash`.
132///
133/// All values in the client overlay will be deleted, if `maybe_limit` is `Some` then up to
134/// that number of values are deleted from the client backend by seeking and reading that number of
135/// storage values plus one. If `maybe_limit` is `None` then all values in the client backend are
136/// deleted. This is potentially unsafe since it's an unbounded operation.
137///
138/// ## Cursors
139///
140/// The `maybe_cursor` parameter should be `None` for the first call to initial removal.
141/// If the resultant `maybe_cursor` is `Some`, then another call is required to complete the
142/// removal operation. This value must be passed in as the subsequent call's `maybe_cursor`
143/// parameter. If the resultant `maybe_cursor` is `None`, then the operation is complete and no
144/// items remain in storage provided that no items were added between the first calls and the
145/// final call.
146pub 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
160/// Take a particular item in storage by the `module`, the map's `item` name and the key `hash`.
161pub 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
169/// Move a storage from a pallet prefix to another pallet prefix.
170///
171/// Keys used in pallet storages always start with:
172/// `concat(twox_128(pallet_name), twox_128(storage_name))`.
173///
174/// This function will remove all value for which the key start with
175/// `concat(twox_128(old_pallet_name), twox_128(storage_name))` and insert them at the key with
176/// the start replaced by `concat(twox_128(new_pallet_name), twox_128(storage_name))`.
177///
178/// # Example
179///
180/// If a pallet named "my_example" has 2 storages named "Foo" and "Bar" and the pallet is renamed
181/// "my_new_example_name", a migration can be:
182/// ```
183/// # use frame_support::storage::migration::move_storage_from_pallet;
184/// # sp_io::TestExternalities::new_empty().execute_with(|| {
185/// move_storage_from_pallet(b"Foo", b"my_example", b"my_new_example_name");
186/// move_storage_from_pallet(b"Bar", b"my_example", b"my_new_example_name");
187/// # })
188/// ```
189pub 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
205/// Move all storages from a pallet prefix to another pallet prefix.
206///
207/// Keys used in pallet storages always start with:
208/// `concat(twox_128(pallet_name), twox_128(storage_name))`.
209///
210/// This function will remove all value for which the key start with `twox_128(old_pallet_name)`
211/// and insert them at the key with the start replaced by `twox_128(new_pallet_name)`.
212///
213/// NOTE: The value at the key `twox_128(old_pallet_name)` is not moved.
214///
215/// # Example
216///
217/// If a pallet named "my_example" has some storages and the pallet is renamed
218/// "my_new_example_name", a migration can be:
219/// ```
220/// # use frame_support::storage::migration::move_pallet;
221/// # sp_io::TestExternalities::new_empty().execute_with(|| {
222/// move_pallet(b"my_example", b"my_new_example_name");
223/// # })
224/// ```
225pub 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
229/// Move all `(key, value)` after some prefix to the another prefix
230///
231/// This function will remove all value for which the key start with `from_prefix`
232/// and insert them at the key with the start replaced by `to_prefix`.
233///
234/// NOTE: The value at the key `from_prefix` is not moved.
235pub 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			// Empty because storage iterator skips over the entry under the first key
379			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}