frame_support/storage/generator/
nmap.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//! Generator for `StorageNMap` used by `decl_storage` and storage types.
19//!
20//! By default each key value is stored at:
21//! ```nocompile
22//! Twox128(pallet_prefix) ++ Twox128(storage_prefix)
23//!     ++ Hasher1(encode(key1)) ++ Hasher2(encode(key2)) ++ ... ++ HasherN(encode(keyN))
24//! ```
25//!
26//! # Warning
27//!
28//! If the keys are not trusted (e.g. can be set by a user), a cryptographic `hasher` such as
29//! `blake2_256` must be used.  Otherwise, other values in storage with the same prefix can
30//! be compromised.
31
32use crate::{
33	storage::{
34		self, storage_prefix,
35		types::{
36			EncodeLikeTuple, HasKeyPrefix, HasReversibleKeyPrefix, KeyGenerator,
37			ReversibleKeyGenerator, TupleToEncodedIter,
38		},
39		unhashed, KeyPrefixIterator, PrefixIterator, StorageAppend,
40	},
41	Never,
42};
43use alloc::vec::Vec;
44use codec::{Decode, Encode, EncodeLike, FullCodec};
45
46/// Generator for `StorageNMap` used by `decl_storage` and storage types.
47///
48/// By default each key value is stored at:
49/// ```nocompile
50/// Twox128(pallet_prefix) ++ Twox128(storage_prefix)
51///     ++ Hasher1(encode(key1)) ++ Hasher2(encode(key2)) ++ ... ++ HasherN(encode(keyN))
52/// ```
53///
54/// # Warning
55///
56/// If the keys are not trusted (e.g. can be set by a user), a cryptographic `hasher` such as
57/// `blake2_256` must be used.  Otherwise, other values in storage with the same prefix can
58/// be compromised.
59pub trait StorageNMap<K: KeyGenerator, V: FullCodec> {
60	/// The type that get/take returns.
61	type Query;
62
63	/// Pallet prefix. Used for generating final key.
64	fn pallet_prefix() -> &'static [u8];
65
66	/// Storage prefix. Used for generating final key.
67	fn storage_prefix() -> &'static [u8];
68
69	/// The full prefix; just the hash of `pallet_prefix` concatenated to the hash of
70	/// `storage_prefix`.
71	fn prefix_hash() -> [u8; 32];
72
73	/// Convert an optional value retrieved from storage to the type queried.
74	fn from_optional_value_to_query(v: Option<V>) -> Self::Query;
75
76	/// Convert a query to an optional value into storage.
77	fn from_query_to_optional_value(v: Self::Query) -> Option<V>;
78
79	/// Generate a partial key used in top storage.
80	fn storage_n_map_partial_key<KP>(key: KP) -> Vec<u8>
81	where
82		K: HasKeyPrefix<KP>,
83	{
84		let storage_prefix = storage_prefix(Self::pallet_prefix(), Self::storage_prefix());
85		let key_hashed = <K as HasKeyPrefix<KP>>::partial_key(key);
86
87		let mut final_key = Vec::with_capacity(storage_prefix.len() + key_hashed.len());
88
89		final_key.extend_from_slice(&storage_prefix);
90		final_key.extend_from_slice(key_hashed.as_ref());
91
92		final_key
93	}
94
95	/// Generate the full key used in top storage.
96	fn storage_n_map_final_key<KG, KArg>(key: KArg) -> Vec<u8>
97	where
98		KG: KeyGenerator,
99		KArg: EncodeLikeTuple<KG::KArg> + TupleToEncodedIter,
100	{
101		let storage_prefix = storage_prefix(Self::pallet_prefix(), Self::storage_prefix());
102		let key_hashed = KG::final_key(key);
103
104		let mut final_key = Vec::with_capacity(storage_prefix.len() + key_hashed.len());
105
106		final_key.extend_from_slice(&storage_prefix);
107		final_key.extend_from_slice(key_hashed.as_ref());
108
109		final_key
110	}
111}
112
113impl<K, V, G> storage::StorageNMap<K, V> for G
114where
115	K: KeyGenerator,
116	V: FullCodec,
117	G: StorageNMap<K, V>,
118{
119	type Query = G::Query;
120
121	fn hashed_key_for<KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter>(key: KArg) -> Vec<u8> {
122		Self::storage_n_map_final_key::<K, _>(key)
123	}
124
125	fn contains_key<KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter>(key: KArg) -> bool {
126		unhashed::exists(&Self::storage_n_map_final_key::<K, _>(key))
127	}
128
129	fn get<KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter>(key: KArg) -> Self::Query {
130		G::from_optional_value_to_query(unhashed::get(&Self::storage_n_map_final_key::<K, _>(key)))
131	}
132
133	fn try_get<KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter>(key: KArg) -> Result<V, ()> {
134		unhashed::get(&Self::storage_n_map_final_key::<K, _>(key)).ok_or(())
135	}
136
137	fn set<KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter>(key: KArg, q: Self::Query) {
138		match G::from_query_to_optional_value(q) {
139			Some(v) => Self::insert(key, v),
140			None => Self::remove(key),
141		}
142	}
143
144	fn take<KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter>(key: KArg) -> Self::Query {
145		let final_key = Self::storage_n_map_final_key::<K, _>(key);
146
147		let value = unhashed::take(&final_key);
148		G::from_optional_value_to_query(value)
149	}
150
151	fn swap<KOther, KArg1, KArg2>(key1: KArg1, key2: KArg2)
152	where
153		KOther: KeyGenerator,
154		KArg1: EncodeLikeTuple<K::KArg> + TupleToEncodedIter,
155		KArg2: EncodeLikeTuple<KOther::KArg> + TupleToEncodedIter,
156	{
157		let final_x_key = Self::storage_n_map_final_key::<K, _>(key1);
158		let final_y_key = Self::storage_n_map_final_key::<KOther, _>(key2);
159
160		let v1 = unhashed::get_raw(&final_x_key);
161		if let Some(val) = unhashed::get_raw(&final_y_key) {
162			unhashed::put_raw(&final_x_key, &val);
163		} else {
164			unhashed::kill(&final_x_key);
165		}
166		if let Some(val) = v1 {
167			unhashed::put_raw(&final_y_key, &val);
168		} else {
169			unhashed::kill(&final_y_key);
170		}
171	}
172
173	fn insert<KArg, VArg>(key: KArg, val: VArg)
174	where
175		KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter,
176		VArg: EncodeLike<V>,
177	{
178		unhashed::put(&Self::storage_n_map_final_key::<K, _>(key), &val);
179	}
180
181	fn remove<KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter>(key: KArg) {
182		unhashed::kill(&Self::storage_n_map_final_key::<K, _>(key));
183	}
184
185	fn remove_prefix<KP>(partial_key: KP, limit: Option<u32>) -> sp_io::KillStorageResult
186	where
187		K: HasKeyPrefix<KP>,
188	{
189		unhashed::clear_prefix(&Self::storage_n_map_partial_key(partial_key), limit, None).into()
190	}
191
192	fn clear_prefix<KP>(
193		partial_key: KP,
194		limit: u32,
195		maybe_cursor: Option<&[u8]>,
196	) -> sp_io::MultiRemovalResults
197	where
198		K: HasKeyPrefix<KP>,
199	{
200		unhashed::clear_prefix(
201			&Self::storage_n_map_partial_key(partial_key),
202			Some(limit),
203			maybe_cursor,
204		)
205	}
206
207	fn contains_prefix<KP>(partial_key: KP) -> bool
208	where
209		K: HasKeyPrefix<KP>,
210	{
211		unhashed::contains_prefixed_key(&Self::storage_n_map_partial_key(partial_key))
212	}
213
214	fn iter_prefix_values<KP>(partial_key: KP) -> PrefixIterator<V>
215	where
216		K: HasKeyPrefix<KP>,
217	{
218		let prefix = Self::storage_n_map_partial_key(partial_key);
219		PrefixIterator {
220			prefix: prefix.clone(),
221			previous_key: prefix,
222			drain: false,
223			closure: |_raw_key, mut raw_value| V::decode(&mut raw_value),
224			phantom: Default::default(),
225		}
226	}
227
228	fn mutate<KArg, R, F>(key: KArg, f: F) -> R
229	where
230		KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter,
231		F: FnOnce(&mut Self::Query) -> R,
232	{
233		Self::try_mutate(key, |v| Ok::<R, Never>(f(v)))
234			.expect("`Never` can not be constructed; qed")
235	}
236
237	fn try_mutate<KArg, R, E, F>(key: KArg, f: F) -> Result<R, E>
238	where
239		KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter,
240		F: FnOnce(&mut Self::Query) -> Result<R, E>,
241	{
242		let final_key = Self::storage_n_map_final_key::<K, _>(key);
243		let mut val = G::from_optional_value_to_query(unhashed::get(final_key.as_ref()));
244
245		let ret = f(&mut val);
246		if ret.is_ok() {
247			match G::from_query_to_optional_value(val) {
248				Some(ref val) => unhashed::put(final_key.as_ref(), val),
249				None => unhashed::kill(final_key.as_ref()),
250			}
251		}
252		ret
253	}
254
255	fn mutate_exists<KArg, R, F>(key: KArg, f: F) -> R
256	where
257		KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter,
258		F: FnOnce(&mut Option<V>) -> R,
259	{
260		Self::try_mutate_exists(key, |v| Ok::<R, Never>(f(v)))
261			.expect("`Never` can not be constructed; qed")
262	}
263
264	fn try_mutate_exists<KArg, R, E, F>(key: KArg, f: F) -> Result<R, E>
265	where
266		KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter,
267		F: FnOnce(&mut Option<V>) -> Result<R, E>,
268	{
269		let final_key = Self::storage_n_map_final_key::<K, _>(key);
270		let mut val = unhashed::get(final_key.as_ref());
271
272		let ret = f(&mut val);
273		if ret.is_ok() {
274			match val {
275				Some(ref val) => unhashed::put(final_key.as_ref(), val),
276				None => unhashed::kill(final_key.as_ref()),
277			}
278		}
279		ret
280	}
281
282	fn append<Item, EncodeLikeItem, KArg>(key: KArg, item: EncodeLikeItem)
283	where
284		KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter,
285		Item: Encode,
286		EncodeLikeItem: EncodeLike<Item>,
287		V: StorageAppend<Item>,
288	{
289		let final_key = Self::storage_n_map_final_key::<K, _>(key);
290		sp_io::storage::append(&final_key, item.encode());
291	}
292
293	fn migrate_keys<KArg>(key: KArg, hash_fns: K::HArg) -> Option<V>
294	where
295		KArg: EncodeLikeTuple<K::KArg> + TupleToEncodedIter,
296	{
297		let old_key = {
298			let storage_prefix = storage_prefix(Self::pallet_prefix(), Self::storage_prefix());
299			let key_hashed = K::migrate_key(&key, hash_fns);
300
301			let mut final_key = Vec::with_capacity(storage_prefix.len() + key_hashed.len());
302
303			final_key.extend_from_slice(&storage_prefix);
304			final_key.extend_from_slice(key_hashed.as_ref());
305
306			final_key
307		};
308		unhashed::take(old_key.as_ref()).inspect(|value| {
309			unhashed::put(Self::storage_n_map_final_key::<K, _>(key).as_ref(), &value);
310		})
311	}
312}
313
314impl<K: ReversibleKeyGenerator, V: FullCodec, G: StorageNMap<K, V>>
315	storage::IterableStorageNMap<K, V> for G
316{
317	type KeyIterator = KeyPrefixIterator<K::Key>;
318	type Iterator = PrefixIterator<(K::Key, V)>;
319
320	fn iter_prefix<KP>(kp: KP) -> PrefixIterator<(<K as HasKeyPrefix<KP>>::Suffix, V)>
321	where
322		K: HasReversibleKeyPrefix<KP>,
323	{
324		let prefix = G::storage_n_map_partial_key(kp);
325		PrefixIterator {
326			prefix: prefix.clone(),
327			previous_key: prefix,
328			drain: false,
329			closure: |raw_key_without_prefix, mut raw_value| {
330				let partial_key = K::decode_partial_key(raw_key_without_prefix)?;
331				Ok((partial_key, V::decode(&mut raw_value)?))
332			},
333			phantom: Default::default(),
334		}
335	}
336
337	fn iter_prefix_from<KP>(
338		kp: KP,
339		starting_raw_key: Vec<u8>,
340	) -> PrefixIterator<(<K as HasKeyPrefix<KP>>::Suffix, V)>
341	where
342		K: HasReversibleKeyPrefix<KP>,
343	{
344		let mut iter = Self::iter_prefix(kp);
345		iter.set_last_raw_key(starting_raw_key);
346		iter
347	}
348
349	fn iter_key_prefix<KP>(kp: KP) -> KeyPrefixIterator<<K as HasKeyPrefix<KP>>::Suffix>
350	where
351		K: HasReversibleKeyPrefix<KP>,
352	{
353		let prefix = G::storage_n_map_partial_key(kp);
354		KeyPrefixIterator {
355			prefix: prefix.clone(),
356			previous_key: prefix,
357			drain: false,
358			closure: K::decode_partial_key,
359		}
360	}
361
362	fn iter_key_prefix_from<KP>(
363		kp: KP,
364		starting_raw_key: Vec<u8>,
365	) -> KeyPrefixIterator<<K as HasKeyPrefix<KP>>::Suffix>
366	where
367		K: HasReversibleKeyPrefix<KP>,
368	{
369		let mut iter = Self::iter_key_prefix(kp);
370		iter.set_last_raw_key(starting_raw_key);
371		iter
372	}
373
374	fn drain_prefix<KP>(kp: KP) -> PrefixIterator<(<K as HasKeyPrefix<KP>>::Suffix, V)>
375	where
376		K: HasReversibleKeyPrefix<KP>,
377	{
378		let mut iter = Self::iter_prefix(kp);
379		iter.drain = true;
380		iter
381	}
382
383	fn iter() -> Self::Iterator {
384		Self::iter_from(G::prefix_hash().to_vec())
385	}
386
387	fn iter_from(starting_raw_key: Vec<u8>) -> Self::Iterator {
388		let prefix = G::prefix_hash().to_vec();
389		Self::Iterator {
390			prefix,
391			previous_key: starting_raw_key,
392			drain: false,
393			closure: |raw_key_without_prefix, mut raw_value| {
394				let (final_key, _) = K::decode_final_key(raw_key_without_prefix)?;
395				Ok((final_key, V::decode(&mut raw_value)?))
396			},
397			phantom: Default::default(),
398		}
399	}
400
401	fn iter_keys() -> Self::KeyIterator {
402		Self::iter_keys_from(G::prefix_hash().to_vec())
403	}
404
405	fn iter_keys_from(starting_raw_key: Vec<u8>) -> Self::KeyIterator {
406		let prefix = G::prefix_hash().to_vec();
407		Self::KeyIterator {
408			prefix,
409			previous_key: starting_raw_key,
410			drain: false,
411			closure: |raw_key_without_prefix| {
412				let (final_key, _) = K::decode_final_key(raw_key_without_prefix)?;
413				Ok(final_key)
414			},
415		}
416	}
417
418	fn drain() -> Self::Iterator {
419		let mut iterator = Self::iter();
420		iterator.drain = true;
421		iterator
422	}
423
424	fn translate<O: Decode, F: FnMut(K::Key, O) -> Option<V>>(mut f: F) {
425		let prefix = G::prefix_hash().to_vec();
426		let mut previous_key = prefix.clone();
427		while let Some(next) =
428			sp_io::storage::next_key(&previous_key).filter(|n| n.starts_with(&prefix))
429		{
430			previous_key = next;
431			let value = match unhashed::get::<O>(&previous_key) {
432				Some(value) => value,
433				None => {
434					log::error!("Invalid translate: fail to decode old value");
435					continue
436				},
437			};
438
439			let final_key = match K::decode_final_key(&previous_key[prefix.len()..]) {
440				Ok((final_key, _)) => final_key,
441				Err(_) => {
442					log::error!("Invalid translate: fail to decode key");
443					continue
444				},
445			};
446
447			match f(final_key, value) {
448				Some(new) => unhashed::put::<V>(&previous_key, &new),
449				None => unhashed::kill(&previous_key),
450			}
451		}
452	}
453}
454
455/// Test iterators for StorageNMap
456#[cfg(test)]
457mod test_iterators {
458	use crate::{
459		hash::StorageHasher,
460		storage::{
461			generator::{tests::*, StorageNMap},
462			unhashed,
463		},
464	};
465	use alloc::vec;
466	use codec::Encode;
467
468	#[test]
469	fn n_map_iter_from() {
470		sp_io::TestExternalities::default().execute_with(|| {
471			use crate::{hash::Identity, storage::Key as NMapKey};
472			#[crate::storage_alias]
473			type MyNMap = StorageNMap<
474				MyModule,
475				(NMapKey<Identity, u64>, NMapKey<Identity, u64>, NMapKey<Identity, u64>),
476				u64,
477			>;
478
479			MyNMap::insert((1, 1, 1), 11);
480			MyNMap::insert((1, 1, 2), 21);
481			MyNMap::insert((1, 1, 3), 31);
482			MyNMap::insert((1, 2, 1), 12);
483			MyNMap::insert((1, 2, 2), 22);
484			MyNMap::insert((1, 2, 3), 32);
485			MyNMap::insert((1, 3, 1), 13);
486			MyNMap::insert((1, 3, 2), 23);
487			MyNMap::insert((1, 3, 3), 33);
488			MyNMap::insert((2, 0, 0), 200);
489
490			type Key = (NMapKey<Identity, u64>, NMapKey<Identity, u64>, NMapKey<Identity, u64>);
491
492			let starting_raw_key = MyNMap::storage_n_map_final_key::<Key, _>((1, 2, 2));
493			let iter = MyNMap::iter_key_prefix_from((1,), starting_raw_key);
494			assert_eq!(iter.collect::<Vec<_>>(), vec![(2, 3), (3, 1), (3, 2), (3, 3)]);
495
496			let starting_raw_key = MyNMap::storage_n_map_final_key::<Key, _>((1, 3, 1));
497			let iter = MyNMap::iter_prefix_from((1, 3), starting_raw_key);
498			assert_eq!(iter.collect::<Vec<_>>(), vec![(2, 23), (3, 33)]);
499
500			let starting_raw_key = MyNMap::storage_n_map_final_key::<Key, _>((1, 3, 2));
501			let iter = MyNMap::iter_keys_from(starting_raw_key);
502			assert_eq!(iter.collect::<Vec<_>>(), vec![(1, 3, 3), (2, 0, 0)]);
503
504			let starting_raw_key = MyNMap::storage_n_map_final_key::<Key, _>((1, 3, 3));
505			let iter = MyNMap::iter_from(starting_raw_key);
506			assert_eq!(iter.collect::<Vec<_>>(), vec![((2, 0, 0), 200)]);
507		});
508	}
509
510	#[test]
511	fn n_map_double_map_identical_key() {
512		sp_io::TestExternalities::default().execute_with(|| {
513			use crate::hash::{Blake2_128Concat, Twox64Concat};
514
515			type NMap = self::frame_system::NMap<Runtime>;
516
517			NMap::insert((1, 2), 50);
518			let key_hash = NMap::hashed_key_for((1, 2));
519
520			{
521				#[crate::storage_alias]
522				type NMap = StorageDoubleMap<System, Blake2_128Concat, u16, Twox64Concat, u32, u64>;
523
524				assert_eq!(NMap::get(1, 2), Some(50));
525				assert_eq!(NMap::hashed_key_for(1, 2), key_hash);
526			}
527		});
528	}
529
530	#[test]
531	fn n_map_reversible_reversible_iteration() {
532		sp_io::TestExternalities::default().execute_with(|| {
533			type NMap = self::frame_system::NMap<Runtime>;
534
535			// All map iterator
536			let prefix = NMap::prefix_hash().to_vec();
537
538			unhashed::put(&key_before_prefix(prefix.clone()), &1u64);
539			unhashed::put(&key_after_prefix(prefix.clone()), &1u64);
540
541			for i in 0..4 {
542				NMap::insert((i as u16, i as u32), i as u64);
543			}
544
545			assert_eq!(
546				NMap::iter().collect::<Vec<_>>(),
547				vec![((3, 3), 3), ((0, 0), 0), ((2, 2), 2), ((1, 1), 1)],
548			);
549
550			assert_eq!(NMap::iter_keys().collect::<Vec<_>>(), vec![(3, 3), (0, 0), (2, 2), (1, 1)]);
551
552			assert_eq!(NMap::iter_values().collect::<Vec<_>>(), vec![3, 0, 2, 1]);
553
554			assert_eq!(
555				NMap::drain().collect::<Vec<_>>(),
556				vec![((3, 3), 3), ((0, 0), 0), ((2, 2), 2), ((1, 1), 1)],
557			);
558
559			assert_eq!(NMap::iter().collect::<Vec<_>>(), vec![]);
560			assert_eq!(unhashed::get(&key_before_prefix(prefix.clone())), Some(1u64));
561			assert_eq!(unhashed::get(&key_after_prefix(prefix.clone())), Some(1u64));
562
563			// Prefix iterator
564			let k1 = 3 << 8;
565			let prefix = NMap::storage_n_map_partial_key((k1,));
566
567			unhashed::put(&key_before_prefix(prefix.clone()), &1u64);
568			unhashed::put(&key_after_prefix(prefix.clone()), &1u64);
569
570			for i in 0..4 {
571				NMap::insert((k1, i as u32), i as u64);
572			}
573
574			assert_eq!(
575				NMap::iter_prefix((k1,)).collect::<Vec<_>>(),
576				vec![(1, 1), (2, 2), (0, 0), (3, 3)],
577			);
578
579			assert_eq!(NMap::iter_key_prefix((k1,)).collect::<Vec<_>>(), vec![1, 2, 0, 3]);
580
581			assert_eq!(NMap::iter_prefix_values((k1,)).collect::<Vec<_>>(), vec![1, 2, 0, 3]);
582
583			assert_eq!(
584				NMap::drain_prefix((k1,)).collect::<Vec<_>>(),
585				vec![(1, 1), (2, 2), (0, 0), (3, 3)],
586			);
587
588			assert_eq!(NMap::iter_prefix((k1,)).collect::<Vec<_>>(), vec![]);
589			assert_eq!(unhashed::get(&key_before_prefix(prefix.clone())), Some(1u64));
590			assert_eq!(unhashed::get(&key_after_prefix(prefix.clone())), Some(1u64));
591
592			// Translate
593			let prefix = NMap::prefix_hash().to_vec();
594
595			unhashed::put(&key_before_prefix(prefix.clone()), &1u64);
596			unhashed::put(&key_after_prefix(prefix.clone()), &1u64);
597			for i in 0..4 {
598				NMap::insert((i as u16, i as u32), i as u64);
599			}
600
601			// Wrong key1
602			unhashed::put(&[prefix.clone(), vec![1, 2, 3]].concat(), &3u64.encode());
603
604			// Wrong key2
605			unhashed::put(
606				&[prefix.clone(), crate::Blake2_128Concat::hash(&1u16.encode())].concat(),
607				&3u64.encode(),
608			);
609
610			// Wrong value
611			unhashed::put(
612				&[
613					prefix.clone(),
614					crate::Blake2_128Concat::hash(&1u16.encode()),
615					crate::Twox64Concat::hash(&2u32.encode()),
616				]
617				.concat(),
618				&vec![1],
619			);
620
621			NMap::translate(|(_k1, _k2), v: u64| Some(v * 2));
622			assert_eq!(
623				NMap::iter().collect::<Vec<_>>(),
624				vec![((3, 3), 6), ((0, 0), 0), ((2, 2), 4), ((1, 1), 2)],
625			);
626		})
627	}
628}