// Copyright 2017-2020 Parity Technologies (UK) Ltd. // This file is part of Substrate. // Substrate is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Substrate is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Substrate. If not, see . //! Stuff to do with the runtime's storage. use sp_std::{prelude::*, marker::PhantomData}; use codec::{FullCodec, FullEncode, Encode, EncodeAppend, EncodeLike, Decode}; use crate::{traits::Len, hash::{Twox128, StorageHasher}}; pub mod unhashed; pub mod hashed; pub mod child; #[doc(hidden)] pub mod generator; pub mod migration; /// A trait for working with macro-generated storage values under the substrate storage API. /// /// Details on implementation can be found at /// [`generator::StorageValue`] pub trait StorageValue { /// The type that get/take return. type Query; /// Get the storage key. fn hashed_key() -> [u8; 32]; /// Does the value (explicitly) exist in storage? fn exists() -> bool; /// Load the value from the provided storage instance. fn get() -> Self::Query; /// Try to get the underlying value from the provided storage instance; `Ok` if it exists, /// `Err` if not. fn try_get() -> Result; /// Translate a value from some previous type (`O`) to the current type. /// /// `f: F` is the translation function. /// /// Returns `Err` if the storage item could not be interpreted as the old type, and Ok, along /// with the new value if it could. /// /// NOTE: This operates from and to `Option<_>` types; no effort is made to respect the default /// value of the original type. /// /// # Warning /// /// This function must be used with care, before being updated the storage still contains the /// old type, thus other calls (such as `get`) will fail at decoding it. /// /// # Usage /// /// This would typically be called inside the module implementation of on_runtime_upgrade, while /// ensuring **no usage of this storage are made before the call to `on_runtime_upgrade`**. (More /// precisely prior initialized modules doesn't make use of this storage). fn translate) -> Option>(f: F) -> Result, ()>; /// Store a value under this key into the provided storage instance. fn put>(val: Arg); /// Store a value under this key into the provided storage instance; this uses the query /// type rather than the underlying value. fn set(val: Self::Query); /// Mutate the value fn mutate R>(f: F) -> R; /// Clear the storage value. fn kill(); /// Take a value from storage, removing it afterwards. fn take() -> Self::Query; /// Append the given item to the value in the storage. /// /// `T` is required to implement `codec::EncodeAppend`. fn append(items: Items) -> Result<(), &'static str> where Item: Encode, EncodeLikeItem: EncodeLike, T: EncodeAppend, Items: IntoIterator, Items::IntoIter: ExactSizeIterator; /// Append the given items to the value in the storage. /// /// `T` is required to implement `Codec::EncodeAppend`. /// /// Upon any failure, it replaces `items` as the new value (assuming that the previous stored /// data is simply corrupt and no longer usable). /// /// ### WARNING /// /// use with care; if your use-case is not _exactly_ as what this function is doing, /// you should use append and sensibly handle failure within the runtime code if it happens. fn append_or_put(items: Items) where Item: Encode, EncodeLikeItem: EncodeLike, T: EncodeAppend, Items: IntoIterator + Clone + EncodeLike, Items::IntoIter: ExactSizeIterator; /// Read the length of the value in a fast way, without decoding the entire value. /// /// `T` is required to implement `Codec::DecodeLength`. fn decode_len() -> Result where T: codec::DecodeLength + Len; } /// A strongly-typed map in storage. /// /// Details on implementation can be found at /// [`generator::StorageMap`] pub trait StorageMap { /// The type that get/take return. type Query; /// Get the storage key used to fetch a value corresponding to a specific key. fn hashed_key_for>(key: KeyArg) -> Vec; /// Does the value (explicitly) exist in storage? fn contains_key>(key: KeyArg) -> bool; /// Load the value associated with the given key from the map. fn get>(key: KeyArg) -> Self::Query; /// Swap the values of two keys. fn swap, KeyArg2: EncodeLike>(key1: KeyArg1, key2: KeyArg2); /// Store a value to be associated with the given key from the map. fn insert, ValArg: EncodeLike>(key: KeyArg, val: ValArg); /// Remove the value under a key. fn remove>(key: KeyArg); /// Mutate the value under a key. fn mutate, R, F: FnOnce(&mut Self::Query) -> R>(key: KeyArg, f: F) -> R; /// Mutate the item, only if an `Ok` value is returned. fn try_mutate, R, E, F: FnOnce(&mut Self::Query) -> Result>( key: KeyArg, f: F, ) -> Result; /// Mutate the value under a key. Deletes the item if mutated to a `None`. fn mutate_exists, R, F: FnOnce(&mut Option) -> R>(key: KeyArg, f: F) -> R; /// Mutate the item, only if an `Ok` value is returned. Deletes the item if mutated to a `None`. fn try_mutate_exists, R, E, F: FnOnce(&mut Option) -> Result>( key: KeyArg, f: F, ) -> Result; /// Take the value under a key. fn take>(key: KeyArg) -> Self::Query; /// Append the given items to the value in the storage. /// /// `V` is required to implement `codec::EncodeAppend`. fn append(key: KeyArg, items: Items) -> Result<(), &'static str> where KeyArg: EncodeLike, Item: Encode, EncodeLikeItem: EncodeLike, V: EncodeAppend, Items: IntoIterator, Items::IntoIter: ExactSizeIterator; /// Safely append the given items to the value in the storage. If a codec error occurs, then the /// old (presumably corrupt) value is replaced with the given `items`. /// /// `V` is required to implement `codec::EncodeAppend`. fn append_or_insert(key: KeyArg, items: Items) where KeyArg: EncodeLike, Item: Encode, EncodeLikeItem: EncodeLike, V: EncodeAppend, Items: IntoIterator + Clone + EncodeLike, Items::IntoIter: ExactSizeIterator; /// Read the length of the value in a fast way, without decoding the entire value. /// /// `T` is required to implement `Codec::DecodeLength`. /// /// Note that `0` is returned as the default value if no encoded value exists at the given key. /// Therefore, this function cannot be used as a sign of _existence_. use the `::contains_key()` /// function for this purpose. fn decode_len>(key: KeyArg) -> Result where V: codec::DecodeLength + Len; /// Migrate an item with the given `key` from a defunct `OldHasher` to the current hasher. /// /// If the key doesn't exist, then it's a no-op. If it does, then it returns its value. fn migrate_key>(key: KeyArg) -> Option; /// Migrate an item with the given `key` from a `blake2_256` hasher to the current hasher. /// /// If the key doesn't exist, then it's a no-op. If it does, then it returns its value. fn migrate_key_from_blake>(key: KeyArg) -> Option { Self::migrate_key::(key) } } /// A strongly-typed map in storage whose keys and values can be iterated over. pub trait IterableStorageMap: StorageMap { /// The type that iterates over all `(key, value)`. type Iterator: Iterator; /// Enumerate all elements in the map in no particular order. If you alter the map while doing /// this, you'll get undefined results. fn iter() -> Self::Iterator; /// Remove all elements from the map and iterate through them in no particular order. If you /// add elements to the map while doing this, you'll get undefined results. fn drain() -> Self::Iterator; /// Translate the values of all elements by a function `f`, in the map in no particular order. /// By returning `None` from `f` for an element, you'll remove it from the map. fn translate Option>(f: F); } /// A strongly-typed double map in storage whose secondary keys and values can be iterated over. pub trait IterableStorageDoubleMap< K1: FullCodec, K2: FullCodec, V: FullCodec >: StorageDoubleMap { /// The type that iterates over all `(key, value)`. type Iterator: Iterator; /// Enumerate all elements in the map with first key `k1` in no particular order. If you add or /// remove values whose first key is `k1` to the map while doing this, you'll get undefined /// results. fn iter(k1: impl EncodeLike) -> Self::Iterator; /// Remove all elements from the map with first key `k1` and iterate through them in no /// particular order. If you add elements with first key `k1` to the map while doing this, /// you'll get undefined results. fn drain(k1: impl EncodeLike) -> Self::Iterator; /// Translate the values of all elements by a function `f`, in the map in no particular order. /// By returning `None` from `f` for an element, you'll remove it from the map. fn translate Option>(f: F); } /// An implementation of a map with a two keys. /// /// It provides an important ability to efficiently remove all entries /// that have a common first key. /// /// Details on implementation can be found at /// [`generator::StorageDoubleMap`] pub trait StorageDoubleMap { /// The type that get/take returns. type Query; fn hashed_key_for(k1: KArg1, k2: KArg2) -> Vec where KArg1: EncodeLike, KArg2: EncodeLike; fn contains_key(k1: KArg1, k2: KArg2) -> bool where KArg1: EncodeLike, KArg2: EncodeLike; fn get(k1: KArg1, k2: KArg2) -> Self::Query where KArg1: EncodeLike, KArg2: EncodeLike; fn take(k1: KArg1, k2: KArg2) -> Self::Query where KArg1: EncodeLike, KArg2: EncodeLike; /// Swap the values of two key-pairs. fn swap(x_k1: XKArg1, x_k2: XKArg2, y_k1: YKArg1, y_k2: YKArg2) where XKArg1: EncodeLike, XKArg2: EncodeLike, YKArg1: EncodeLike, YKArg2: EncodeLike; fn insert(k1: KArg1, k2: KArg2, val: VArg) where KArg1: EncodeLike, KArg2: EncodeLike, VArg: EncodeLike; fn remove(k1: KArg1, k2: KArg2) where KArg1: EncodeLike, KArg2: EncodeLike; fn remove_prefix(k1: KArg1) where KArg1: ?Sized + EncodeLike; fn iter_prefix(k1: KArg1) -> PrefixIterator where KArg1: ?Sized + EncodeLike; fn mutate(k1: KArg1, k2: KArg2, f: F) -> R where KArg1: EncodeLike, KArg2: EncodeLike, F: FnOnce(&mut Self::Query) -> R; fn append( k1: KArg1, k2: KArg2, items: Items, ) -> Result<(), &'static str> where KArg1: EncodeLike, KArg2: EncodeLike, Item: Encode, EncodeLikeItem: EncodeLike, V: EncodeAppend, Items: IntoIterator, Items::IntoIter: ExactSizeIterator; fn append_or_insert( k1: KArg1, k2: KArg2, items: Items, ) where KArg1: EncodeLike, KArg2: EncodeLike, Item: Encode, EncodeLikeItem: EncodeLike, V: EncodeAppend, Items: IntoIterator + Clone + EncodeLike, Items::IntoIter: ExactSizeIterator; /// Read the length of the value in a fast way, without decoding the entire value. /// /// `V` is required to implement `Codec::DecodeLength`. /// /// Note that `0` is returned as the default value if no encoded value exists at the given key. /// Therefore, this function cannot be used as a sign of _existence_. use the `::contains_key()` /// function for this purpose. fn decode_len(key1: KArg1, key2: KArg2) -> Result where KArg1: EncodeLike, KArg2: EncodeLike, V: codec::DecodeLength + Len; /// Migrate an item with the given `key1` and `key2` from defunct `OldHasher1` and /// `OldHasher2` to the current hashers. /// /// If the key doesn't exist, then it's a no-op. If it does, then it returns its value. fn migrate_keys< OldHasher1: StorageHasher, OldHasher2: StorageHasher, KeyArg1: EncodeLike, KeyArg2: EncodeLike, >(key1: KeyArg1, key2: KeyArg2) -> Option; } /// Iterator for prefixed map. pub struct PrefixIterator { prefix: Vec, previous_key: Vec, phantom_data: PhantomData, } impl Iterator for PrefixIterator { type Item = Value; fn next(&mut self) -> Option { match sp_io::storage::next_key(&self.previous_key) .filter(|n| n.starts_with(&self.prefix[..])) { Some(next_key) => { let value = unhashed::get(&next_key); if value.is_none() { runtime_print!( "ERROR: returned next_key has no value:\nkey is {:?}\nnext_key is {:?}", &self.previous_key, &next_key, ); } self.previous_key = next_key; value }, _ => None, } } } /// Trait for maps that store all its value after a unique prefix. /// /// By default the final prefix is: /// ```nocompile /// Twox128(module_prefix) ++ Twox128(storage_prefix) /// ``` pub trait StoragePrefixedMap { /// Module prefix. Used for generating final key. fn module_prefix() -> &'static [u8]; /// Storage prefix. Used for generating final key. fn storage_prefix() -> &'static [u8]; /// Final full prefix that prefixes all keys. fn final_prefix() -> [u8; 32] { let mut final_key = [0u8; 32]; final_key[0..16].copy_from_slice(&Twox128::hash(Self::module_prefix())); final_key[16..32].copy_from_slice(&Twox128::hash(Self::storage_prefix())); final_key } /// Remove all value of the storage. fn remove_all() { sp_io::storage::clear_prefix(&Self::final_prefix()) } /// Iter over all value of the storage. fn iter_values() -> PrefixIterator { let prefix = Self::final_prefix(); PrefixIterator { prefix: prefix.to_vec(), previous_key: prefix.to_vec(), phantom_data: Default::default(), } } /// Translate the values from some previous `OldValue` to the current type. /// /// `TV` translates values. /// /// Returns `Err` if the map could not be interpreted as the old type, and Ok if it could. /// The `Err` contains the number of value that couldn't be interpreted, those value are /// removed from the map. /// /// # Warning /// /// This function must be used with care, before being updated the storage still contains the /// old type, thus other calls (such as `get`) will fail at decoding it. /// /// # Usage /// /// This would typically be called inside the module implementation of on_runtime_upgrade, while /// ensuring **no usage of this storage are made before the call to `on_runtime_upgrade`**. (More /// precisely prior initialized modules doesn't make use of this storage). fn translate_values(translate_val: TV) -> Result<(), u32> where OldValue: Decode, TV: Fn(OldValue) -> Value { let prefix = Self::final_prefix(); let mut previous_key = prefix.to_vec(); let mut errors = 0; while let Some(next_key) = sp_io::storage::next_key(&previous_key) .filter(|n| n.starts_with(&prefix[..])) { if let Some(value) = unhashed::get(&next_key) { unhashed::put(&next_key[..], &translate_val(value)); } else { // We failed to read the value. Remove the key and increment errors. unhashed::kill(&next_key[..]); errors += 1; } previous_key = next_key; } if errors == 0 { Ok(()) } else { Err(errors) } } } #[cfg(test)] mod test { use sp_core::hashing::twox_128; use sp_io::TestExternalities; use crate::storage::{unhashed, StoragePrefixedMap}; #[test] fn prefixed_map_works() { TestExternalities::default().execute_with(|| { struct MyStorage; impl StoragePrefixedMap for MyStorage { fn module_prefix() -> &'static [u8] { b"MyModule" } fn storage_prefix() -> &'static [u8] { b"MyStorage" } } let key_before = { let mut k = MyStorage::final_prefix(); let last = k.iter_mut().last().unwrap(); *last = last.checked_sub(1).unwrap(); k }; let key_after = { let mut k = MyStorage::final_prefix(); let last = k.iter_mut().last().unwrap(); *last = last.checked_add(1).unwrap(); k }; unhashed::put(&key_before[..], &32u64); unhashed::put(&key_after[..], &33u64); let k = [twox_128(b"MyModule"), twox_128(b"MyStorage")].concat(); assert_eq!(MyStorage::final_prefix().to_vec(), k); // test iteration assert_eq!(MyStorage::iter_values().collect::>(), vec![]); unhashed::put(&[&k[..], &vec![1][..]].concat(), &1u64); unhashed::put(&[&k[..], &vec![1, 1][..]].concat(), &2u64); unhashed::put(&[&k[..], &vec![8][..]].concat(), &3u64); unhashed::put(&[&k[..], &vec![10][..]].concat(), &4u64); assert_eq!(MyStorage::iter_values().collect::>(), vec![1, 2, 3, 4]); // test removal MyStorage::remove_all(); assert_eq!(MyStorage::iter_values().collect::>(), vec![]); // test migration unhashed::put(&[&k[..], &vec![1][..]].concat(), &1u32); unhashed::put(&[&k[..], &vec![8][..]].concat(), &2u32); assert_eq!(MyStorage::iter_values().collect::>(), vec![]); MyStorage::translate_values(|v: u32| v as u64).unwrap(); assert_eq!(MyStorage::iter_values().collect::>(), vec![1, 2]); MyStorage::remove_all(); // test migration 2 unhashed::put(&[&k[..], &vec![1][..]].concat(), &1u128); unhashed::put(&[&k[..], &vec![1, 1][..]].concat(), &2u64); unhashed::put(&[&k[..], &vec![8][..]].concat(), &3u128); unhashed::put(&[&k[..], &vec![10][..]].concat(), &4u32); // (contains some value that successfully decoded to u64) assert_eq!(MyStorage::iter_values().collect::>(), vec![1, 2, 3]); assert_eq!(MyStorage::translate_values(|v: u128| v as u64), Err(2)); assert_eq!(MyStorage::iter_values().collect::>(), vec![1, 3]); MyStorage::remove_all(); // test that other values are not modified. assert_eq!(unhashed::get(&key_before[..]), Some(32u64)); assert_eq!(unhashed::get(&key_after[..]), Some(33u64)); }); } }