Skip to main content

topsoil_core/storage/generator/
map.rs

1// This file is part of Soil.
2
3// Copyright (C) Soil contributors.
4// Copyright (C) Parity Technologies (UK) Ltd.
5// SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later WITH Classpath-exception-2.0
6
7use crate::{
8	hash::{ReversibleStorageHasher, StorageHasher},
9	storage::{self, storage_prefix, unhashed, KeyPrefixIterator, PrefixIterator, StorageAppend},
10	Never,
11};
12use alloc::vec::Vec;
13use codec::{Decode, Encode, EncodeLike, FullCodec, FullEncode};
14
15/// Generator for `StorageMap` used by `decl_storage`.
16///
17/// By default each key value is stored at:
18/// ```nocompile
19/// Twox128(pallet_prefix) ++ Twox128(storage_prefix) ++ Hasher(encode(key))
20/// ```
21///
22/// # Warning
23///
24/// If the keys are not trusted (e.g. can be set by a user), a cryptographic `hasher` such as
25/// `blake2_256` must be used.  Otherwise, other values in storage can be compromised.
26pub trait StorageMap<K: FullEncode, V: FullCodec> {
27	/// The type that get/take returns.
28	type Query;
29
30	/// Hasher. Used for generating final key.
31	type Hasher: StorageHasher;
32
33	/// Pallet prefix. Used for generating final key.
34	fn pallet_prefix() -> &'static [u8];
35
36	/// Storage prefix. Used for generating final key.
37	fn storage_prefix() -> &'static [u8];
38
39	/// The full prefix; just the hash of `pallet_prefix` concatenated to the hash of
40	/// `storage_prefix`.
41	fn prefix_hash() -> [u8; 32];
42
43	/// Convert an optional value retrieved from storage to the type queried.
44	fn from_optional_value_to_query(v: Option<V>) -> Self::Query;
45
46	/// Convert a query to an optional value into storage.
47	fn from_query_to_optional_value(v: Self::Query) -> Option<V>;
48
49	/// Generate the full key used in top storage.
50	fn storage_map_final_key<KeyArg>(key: KeyArg) -> Vec<u8>
51	where
52		KeyArg: EncodeLike<K>,
53	{
54		let storage_prefix = storage_prefix(Self::pallet_prefix(), Self::storage_prefix());
55		let key_hashed = key.using_encoded(Self::Hasher::hash);
56
57		let mut final_key = Vec::with_capacity(storage_prefix.len() + key_hashed.as_ref().len());
58
59		final_key.extend_from_slice(&storage_prefix);
60		final_key.extend_from_slice(key_hashed.as_ref());
61
62		final_key
63	}
64}
65
66impl<K: FullCodec, V: FullCodec, G: StorageMap<K, V>> storage::IterableStorageMap<K, V> for G
67where
68	G::Hasher: ReversibleStorageHasher,
69{
70	type Iterator = PrefixIterator<(K, V)>;
71	type KeyIterator = KeyPrefixIterator<K>;
72
73	/// Enumerate all elements in the map.
74	fn iter() -> Self::Iterator {
75		let prefix = G::prefix_hash().to_vec();
76		PrefixIterator {
77			prefix: prefix.clone(),
78			previous_key: prefix,
79			drain: false,
80			closure: |raw_key_without_prefix, mut raw_value| {
81				let mut key_material = G::Hasher::reverse(raw_key_without_prefix);
82				Ok((K::decode(&mut key_material)?, V::decode(&mut raw_value)?))
83			},
84			phantom: Default::default(),
85		}
86	}
87
88	/// Enumerate all elements in the map after a given key.
89	fn iter_from(starting_raw_key: Vec<u8>) -> Self::Iterator {
90		let mut iter = Self::iter();
91		iter.set_last_raw_key(starting_raw_key);
92		iter
93	}
94
95	/// Enumerate all keys in the map.
96	fn iter_keys() -> Self::KeyIterator {
97		let prefix = G::prefix_hash().to_vec();
98		KeyPrefixIterator {
99			prefix: prefix.clone(),
100			previous_key: prefix,
101			drain: false,
102			closure: |raw_key_without_prefix| {
103				let mut key_material = G::Hasher::reverse(raw_key_without_prefix);
104				K::decode(&mut key_material)
105			},
106		}
107	}
108
109	/// Enumerate all keys in the map after a given key.
110	fn iter_keys_from(starting_raw_key: Vec<u8>) -> Self::KeyIterator {
111		let mut iter = Self::iter_keys();
112		iter.set_last_raw_key(starting_raw_key);
113		iter
114	}
115
116	/// Enumerate all elements in the map.
117	fn drain() -> Self::Iterator {
118		let mut iterator = Self::iter();
119		iterator.drain = true;
120		iterator
121	}
122
123	fn translate<O: Decode, F: FnMut(K, O) -> Option<V>>(mut f: F) {
124		let mut previous_key = None;
125		loop {
126			previous_key = Self::translate_next(previous_key, &mut f);
127			if previous_key.is_none() {
128				break;
129			}
130		}
131	}
132
133	fn translate_next<O: Decode, F: FnMut(K, O) -> Option<V>>(
134		previous_key: Option<Vec<u8>>,
135		mut f: F,
136	) -> Option<Vec<u8>> {
137		let prefix = G::prefix_hash().to_vec();
138		let previous_key = previous_key.unwrap_or_else(|| prefix.clone());
139
140		let current_key =
141			subsoil::io::storage::next_key(&previous_key).filter(|n| n.starts_with(&prefix))?;
142
143		let value = match unhashed::get::<O>(&current_key) {
144			Some(value) => value,
145			None => {
146				crate::defensive!(
147					"Invalid translation: failed to decode old value for key",
148					array_bytes::bytes2hex("0x", &current_key)
149				);
150				return Some(current_key);
151			},
152		};
153
154		let mut key_material = G::Hasher::reverse(&current_key[prefix.len()..]);
155		let key = match K::decode(&mut key_material) {
156			Ok(key) => key,
157			Err(_) => {
158				crate::defensive!(
159					"Invalid translation: failed to decode key",
160					array_bytes::bytes2hex("0x", &current_key)
161				);
162				return Some(current_key);
163			},
164		};
165
166		match f(key, value) {
167			Some(new) => unhashed::put::<V>(&current_key, &new),
168			None => unhashed::kill(&current_key),
169		}
170
171		Some(current_key)
172	}
173}
174
175impl<K: FullEncode, V: FullCodec, G: StorageMap<K, V>> storage::StorageMap<K, V> for G {
176	type Query = G::Query;
177
178	fn hashed_key_for<KeyArg: EncodeLike<K>>(key: KeyArg) -> Vec<u8> {
179		Self::storage_map_final_key(key)
180	}
181
182	fn swap<KeyArg1: EncodeLike<K>, KeyArg2: EncodeLike<K>>(key1: KeyArg1, key2: KeyArg2) {
183		let k1 = Self::storage_map_final_key(key1);
184		let k2 = Self::storage_map_final_key(key2);
185
186		let v1 = unhashed::get_raw(k1.as_ref());
187		if let Some(val) = unhashed::get_raw(k2.as_ref()) {
188			unhashed::put_raw(k1.as_ref(), &val);
189		} else {
190			unhashed::kill(k1.as_ref())
191		}
192		if let Some(val) = v1 {
193			unhashed::put_raw(k2.as_ref(), &val);
194		} else {
195			unhashed::kill(k2.as_ref())
196		}
197	}
198
199	fn contains_key<KeyArg: EncodeLike<K>>(key: KeyArg) -> bool {
200		unhashed::exists(Self::storage_map_final_key(key).as_ref())
201	}
202
203	fn get<KeyArg: EncodeLike<K>>(key: KeyArg) -> Self::Query {
204		G::from_optional_value_to_query(unhashed::get(Self::storage_map_final_key(key).as_ref()))
205	}
206
207	fn try_get<KeyArg: EncodeLike<K>>(key: KeyArg) -> Result<V, ()> {
208		unhashed::get(Self::storage_map_final_key(key).as_ref()).ok_or(())
209	}
210
211	fn set<KeyArg: EncodeLike<K>>(key: KeyArg, q: Self::Query) {
212		match G::from_query_to_optional_value(q) {
213			Some(v) => Self::insert(key, v),
214			None => Self::remove(key),
215		}
216	}
217
218	fn insert<KeyArg: EncodeLike<K>, ValArg: EncodeLike<V>>(key: KeyArg, val: ValArg) {
219		unhashed::put(Self::storage_map_final_key(key).as_ref(), &val)
220	}
221
222	fn remove<KeyArg: EncodeLike<K>>(key: KeyArg) {
223		unhashed::kill(Self::storage_map_final_key(key).as_ref())
224	}
225
226	fn mutate<KeyArg: EncodeLike<K>, R, F: FnOnce(&mut Self::Query) -> R>(key: KeyArg, f: F) -> R {
227		Self::try_mutate(key, |v| Ok::<R, Never>(f(v)))
228			.expect("`Never` can not be constructed; qed")
229	}
230
231	fn mutate_exists<KeyArg: EncodeLike<K>, R, F: FnOnce(&mut Option<V>) -> R>(
232		key: KeyArg,
233		f: F,
234	) -> R {
235		Self::try_mutate_exists(key, |v| Ok::<R, Never>(f(v)))
236			.expect("`Never` can not be constructed; qed")
237	}
238
239	fn try_mutate<KeyArg: EncodeLike<K>, R, E, F: FnOnce(&mut Self::Query) -> Result<R, E>>(
240		key: KeyArg,
241		f: F,
242	) -> Result<R, E> {
243		let final_key = Self::storage_map_final_key(key);
244		let mut val = G::from_optional_value_to_query(unhashed::get(final_key.as_ref()));
245
246		let ret = f(&mut val);
247		if ret.is_ok() {
248			match G::from_query_to_optional_value(val) {
249				Some(ref val) => unhashed::put(final_key.as_ref(), &val),
250				None => unhashed::kill(final_key.as_ref()),
251			}
252		}
253		ret
254	}
255
256	fn try_mutate_exists<KeyArg: EncodeLike<K>, R, E, F: FnOnce(&mut Option<V>) -> Result<R, E>>(
257		key: KeyArg,
258		f: F,
259	) -> Result<R, E> {
260		let final_key = Self::storage_map_final_key(key);
261		let mut val = unhashed::get(final_key.as_ref());
262
263		let ret = f(&mut val);
264		if ret.is_ok() {
265			match val {
266				Some(ref val) => unhashed::put(final_key.as_ref(), &val),
267				None => unhashed::kill(final_key.as_ref()),
268			}
269		}
270		ret
271	}
272
273	fn take<KeyArg: EncodeLike<K>>(key: KeyArg) -> Self::Query {
274		let key = Self::storage_map_final_key(key);
275		let value = unhashed::take(key.as_ref());
276		G::from_optional_value_to_query(value)
277	}
278
279	fn append<Item, EncodeLikeItem, EncodeLikeKey>(key: EncodeLikeKey, item: EncodeLikeItem)
280	where
281		EncodeLikeKey: EncodeLike<K>,
282		Item: Encode,
283		EncodeLikeItem: EncodeLike<Item>,
284		V: StorageAppend<Item>,
285	{
286		let key = Self::storage_map_final_key(key);
287		subsoil::io::storage::append(&key, item.encode());
288	}
289
290	fn migrate_key<OldHasher: StorageHasher, KeyArg: EncodeLike<K>>(key: KeyArg) -> Option<V> {
291		let old_key = {
292			let storage_prefix = storage_prefix(Self::pallet_prefix(), Self::storage_prefix());
293			let key_hashed = key.using_encoded(OldHasher::hash);
294
295			let mut final_key =
296				Vec::with_capacity(storage_prefix.len() + key_hashed.as_ref().len());
297
298			final_key.extend_from_slice(&storage_prefix);
299			final_key.extend_from_slice(key_hashed.as_ref());
300
301			final_key
302		};
303		unhashed::take(old_key.as_ref()).inspect(|value| {
304			unhashed::put(Self::storage_map_final_key(key).as_ref(), &value);
305		})
306	}
307}
308
309/// Test iterators for StorageMap
310#[cfg(test)]
311mod test_iterators {
312	use crate::{
313		hash::StorageHasher,
314		storage::{
315			generator::{tests::*, StorageMap},
316			unhashed,
317		},
318	};
319	use alloc::vec;
320	use codec::Encode;
321
322	#[test]
323	fn map_iter_from() {
324		subsoil::io::TestExternalities::default().execute_with(|| {
325			use crate::hash::Identity;
326			#[crate::storage_alias]
327			type MyMap = StorageMap<MyModule, Identity, u64, u64>;
328
329			MyMap::insert(1, 10);
330			MyMap::insert(2, 20);
331			MyMap::insert(3, 30);
332			MyMap::insert(4, 40);
333			MyMap::insert(5, 50);
334
335			let starting_raw_key = MyMap::storage_map_final_key(3);
336			let iter = MyMap::iter_from(starting_raw_key);
337			assert_eq!(iter.collect::<Vec<_>>(), vec![(4, 40), (5, 50)]);
338
339			let starting_raw_key = MyMap::storage_map_final_key(2);
340			let iter = MyMap::iter_keys_from(starting_raw_key);
341			assert_eq!(iter.collect::<Vec<_>>(), vec![3, 4, 5]);
342		});
343	}
344
345	#[cfg(debug_assertions)]
346	#[test]
347	#[should_panic]
348	fn map_translate_with_bad_key_in_debug_mode() {
349		subsoil::io::TestExternalities::default().execute_with(|| {
350			type Map = topsoil_system::Map<Runtime>;
351			let prefix = Map::prefix_hash().to_vec();
352
353			// Wrong key
354			unhashed::put(&[prefix.clone(), vec![1, 2, 3]].concat(), &3u64.encode());
355
356			// debug_assert should cause a
357			Map::translate(|_k1, v: u64| Some(v * 2));
358			assert_eq!(Map::iter().collect::<Vec<_>>(), vec![(3, 6), (0, 0), (2, 4), (1, 2)]);
359		})
360	}
361
362	#[cfg(debug_assertions)]
363	#[test]
364	#[should_panic]
365	fn map_translate_with_bad_value_in_debug_mode() {
366		subsoil::io::TestExternalities::default().execute_with(|| {
367			type Map = topsoil_system::Map<Runtime>;
368			let prefix = Map::prefix_hash().to_vec();
369
370			// Wrong value
371			unhashed::put(
372				&[prefix.clone(), crate::Blake2_128Concat::hash(&6u16.encode())].concat(),
373				&vec![1],
374			);
375
376			Map::translate(|_k1, v: u64| Some(v * 2));
377			assert_eq!(Map::iter().collect::<Vec<_>>(), vec![(3, 6), (0, 0), (2, 4), (1, 2)]);
378		})
379	}
380
381	#[cfg(not(debug_assertions))]
382	#[test]
383	fn map_translate_with_bad_key_in_production_mode() {
384		subsoil::io::TestExternalities::default().execute_with(|| {
385			type Map = topsoil_system::Map<Runtime>;
386			let prefix = Map::prefix_hash().to_vec();
387
388			// Wrong key
389			unhashed::put(&[prefix.clone(), vec![1, 2, 3]].concat(), &3u64.encode());
390
391			Map::translate(|_k1, v: u64| Some(v * 2));
392			assert_eq!(Map::iter().collect::<Vec<_>>(), vec![]);
393		})
394	}
395
396	#[cfg(not(debug_assertions))]
397	#[test]
398	fn map_translate_with_bad_value_in_production_mode() {
399		subsoil::io::TestExternalities::default().execute_with(|| {
400			type Map = topsoil_system::Map<Runtime>;
401			let prefix = Map::prefix_hash().to_vec();
402
403			// Wrong value
404			unhashed::put(
405				&[prefix.clone(), crate::Blake2_128Concat::hash(&6u16.encode())].concat(),
406				&vec![1],
407			);
408
409			Map::translate(|_k1, v: u64| Some(v * 2));
410			assert_eq!(Map::iter().collect::<Vec<_>>(), vec![]);
411		})
412	}
413
414	#[test]
415	fn map_reversible_reversible_iteration() {
416		subsoil::io::TestExternalities::default().execute_with(|| {
417			type Map = topsoil_system::Map<Runtime>;
418
419			// All map iterator
420			let prefix = Map::prefix_hash().to_vec();
421
422			unhashed::put(&key_before_prefix(prefix.clone()), &1u64);
423			unhashed::put(&key_after_prefix(prefix.clone()), &1u64);
424
425			for i in 0..4 {
426				Map::insert(i as u16, i as u64);
427			}
428
429			assert_eq!(Map::iter().collect::<Vec<_>>(), vec![(3, 3), (0, 0), (2, 2), (1, 1)]);
430
431			assert_eq!(Map::iter_keys().collect::<Vec<_>>(), vec![3, 0, 2, 1]);
432
433			assert_eq!(Map::iter_values().collect::<Vec<_>>(), vec![3, 0, 2, 1]);
434
435			assert_eq!(Map::drain().collect::<Vec<_>>(), vec![(3, 3), (0, 0), (2, 2), (1, 1)]);
436
437			assert_eq!(Map::iter().collect::<Vec<_>>(), vec![]);
438			assert_eq!(unhashed::get(&key_before_prefix(prefix.clone())), Some(1u64));
439			assert_eq!(unhashed::get(&key_after_prefix(prefix.clone())), Some(1u64));
440
441			// Translate
442			let prefix = Map::prefix_hash().to_vec();
443
444			unhashed::put(&key_before_prefix(prefix.clone()), &1u64);
445			unhashed::put(&key_after_prefix(prefix.clone()), &1u64);
446			for i in 0..4 {
447				Map::insert(i as u16, i as u64);
448			}
449
450			Map::translate(|_k1, v: u64| Some(v * 2));
451			assert_eq!(Map::iter().collect::<Vec<_>>(), vec![(3, 6), (0, 0), (2, 4), (1, 2)]);
452		})
453	}
454}