referrerpolicy=no-referrer-when-downgrade

frame_support/storage/types/
value.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//! Storage value type. Implements StorageValue trait and its method directly.
19
20use crate::{
21	storage::{
22		generator::StorageValue as StorageValueT,
23		types::{OptionQuery, QueryKindTrait, StorageEntryMetadataBuilder},
24		StorageAppend, StorageDecodeLength, StorageTryAppend,
25	},
26	traits::{Get, GetDefault, StorageInfo, StorageInstance},
27};
28use alloc::{vec, vec::Vec};
29use codec::{Decode, Encode, EncodeLike, FullCodec, MaxEncodedLen};
30use frame_support::storage::StorageDecodeNonDedupLength;
31use sp_arithmetic::traits::SaturatedConversion;
32use sp_metadata_ir::{StorageEntryMetadataIR, StorageEntryTypeIR};
33
34/// A type representing a *value* in storage. A *storage value* is a single value of a given type
35/// stored on-chain.
36///
37/// For general information regarding the `#[pallet::storage]` attribute, refer to
38/// [`crate::pallet_macros::storage`].
39///
40/// # Example
41///
42/// ```
43/// #[frame_support::pallet]
44/// mod pallet {
45///     # use frame_support::pallet_prelude::*;
46///     # #[pallet::config]
47///     # pub trait Config: frame_system::Config {}
48///     # #[pallet::pallet]
49///     # pub struct Pallet<T>(_);
50/// 	/// A kitchen-sink StorageValue, with all possible additional attributes.
51///     #[pallet::storage]
52/// 	#[pallet::getter(fn foo)]
53/// 	#[pallet::storage_prefix = "OtherFoo"]
54/// 	#[pallet::unbounded]
55///     pub type Foo<T> = StorageValue<_, u32,ValueQuery>;
56///
57/// 	/// Named alternative syntax.
58///     #[pallet::storage]
59///     pub type Bar<T> = StorageValue<
60/// 		Value = u32,
61/// 		QueryKind = ValueQuery
62/// 	>;
63/// }
64/// ```
65pub struct StorageValue<Prefix, Value, QueryKind = OptionQuery, OnEmpty = GetDefault>(
66	core::marker::PhantomData<(Prefix, Value, QueryKind, OnEmpty)>,
67);
68
69impl<Prefix, Value, QueryKind, OnEmpty> crate::storage::generator::StorageValue<Value>
70	for StorageValue<Prefix, Value, QueryKind, OnEmpty>
71where
72	Prefix: StorageInstance,
73	Value: FullCodec,
74	QueryKind: QueryKindTrait<Value, OnEmpty>,
75	OnEmpty: Get<QueryKind::Query> + 'static,
76{
77	type Query = QueryKind::Query;
78	fn pallet_prefix() -> &'static [u8] {
79		Prefix::pallet_prefix().as_bytes()
80	}
81	fn storage_prefix() -> &'static [u8] {
82		Prefix::STORAGE_PREFIX.as_bytes()
83	}
84	fn from_optional_value_to_query(v: Option<Value>) -> Self::Query {
85		QueryKind::from_optional_value_to_query(v)
86	}
87	fn from_query_to_optional_value(v: Self::Query) -> Option<Value> {
88		QueryKind::from_query_to_optional_value(v)
89	}
90	fn storage_value_final_key() -> [u8; 32] {
91		Prefix::prefix_hash()
92	}
93}
94
95impl<Prefix, Value, QueryKind, OnEmpty> StorageValue<Prefix, Value, QueryKind, OnEmpty>
96where
97	Prefix: StorageInstance,
98	Value: FullCodec,
99	QueryKind: QueryKindTrait<Value, OnEmpty>,
100	OnEmpty: crate::traits::Get<QueryKind::Query> + 'static,
101{
102	/// Get the storage key.
103	pub fn hashed_key() -> [u8; 32] {
104		<Self as crate::storage::StorageValue<Value>>::hashed_key()
105	}
106
107	/// Does the value (explicitly) exist in storage?
108	pub fn exists() -> bool {
109		<Self as crate::storage::StorageValue<Value>>::exists()
110	}
111
112	/// Load the value from the provided storage instance.
113	pub fn get() -> QueryKind::Query {
114		<Self as crate::storage::StorageValue<Value>>::get()
115	}
116
117	/// Try to get the underlying value from the provided storage instance; `Ok` if it exists,
118	/// `Err` if not.
119	pub fn try_get() -> Result<Value, ()> {
120		<Self as crate::storage::StorageValue<Value>>::try_get()
121	}
122
123	/// Translate a value from some previous type (`O`) to the current type.
124	///
125	/// `f: F` is the translation function.
126	///
127	/// Returns `Err` if the storage item could not be interpreted as the old type, and Ok, along
128	/// with the new value if it could.
129	///
130	/// NOTE: This operates from and to `Option<_>` types; no effort is made to respect the default
131	/// value of the original type.
132	///
133	/// # Warning
134	///
135	/// This function must be used with care, before being updated the storage still contains the
136	/// old type, thus other calls (such as `get`) will fail at decoding it.
137	///
138	/// # Usage
139	///
140	/// This would typically be called inside the module implementation of on_runtime_upgrade,
141	/// while ensuring **no usage of this storage are made before the call to
142	/// `on_runtime_upgrade`**. (More precisely prior initialized modules doesn't make use of this
143	/// storage).
144	pub fn translate<O: Decode, F: FnOnce(Option<O>) -> Option<Value>>(
145		f: F,
146	) -> Result<Option<Value>, ()> {
147		<Self as crate::storage::StorageValue<Value>>::translate(f)
148	}
149
150	/// Store a value under this key into the provided storage instance.
151	pub fn put<Arg: EncodeLike<Value>>(val: Arg) {
152		<Self as crate::storage::StorageValue<Value>>::put(val)
153	}
154
155	/// Store a value under this key into the provided storage instance.
156	///
157	/// this uses the query type rather than the underlying value.
158	pub fn set(val: QueryKind::Query) {
159		<Self as crate::storage::StorageValue<Value>>::set(val)
160	}
161
162	/// Mutate the value
163	pub fn mutate<R, F: FnOnce(&mut QueryKind::Query) -> R>(f: F) -> R {
164		<Self as crate::storage::StorageValue<Value>>::mutate(f)
165	}
166
167	/// Mutate the value under a key iff it exists. Do nothing and return the default value if not.
168	pub fn mutate_extant<R: Default, F: FnOnce(&mut Value) -> R>(f: F) -> R {
169		<Self as crate::storage::StorageValue<Value>>::mutate_extant(f)
170	}
171
172	/// Mutate the value if closure returns `Ok`
173	pub fn try_mutate<R, E, F: FnOnce(&mut QueryKind::Query) -> Result<R, E>>(
174		f: F,
175	) -> Result<R, E> {
176		<Self as crate::storage::StorageValue<Value>>::try_mutate(f)
177	}
178
179	/// Mutate the value. Deletes the item if mutated to a `None`.
180	pub fn mutate_exists<R, F: FnOnce(&mut Option<Value>) -> R>(f: F) -> R {
181		<Self as crate::storage::StorageValue<Value>>::mutate_exists(f)
182	}
183
184	/// Mutate the value if closure returns `Ok`. Deletes the item if mutated to a `None`.
185	pub fn try_mutate_exists<R, E, F: FnOnce(&mut Option<Value>) -> Result<R, E>>(
186		f: F,
187	) -> Result<R, E> {
188		<Self as crate::storage::StorageValue<Value>>::try_mutate_exists(f)
189	}
190
191	/// Clear the storage value.
192	pub fn kill() {
193		<Self as crate::storage::StorageValue<Value>>::kill()
194	}
195
196	/// Take a value from storage, removing it afterwards.
197	pub fn take() -> QueryKind::Query {
198		<Self as crate::storage::StorageValue<Value>>::take()
199	}
200
201	/// Append the given item to the value in the storage.
202	///
203	/// `Value` is required to implement [`StorageAppend`].
204	///
205	/// # Warning
206	///
207	/// If the storage item is not encoded properly, the storage item will be overwritten
208	/// and set to `[item]`. Any default value set for the storage item will be ignored
209	/// on overwrite.
210	pub fn append<Item, EncodeLikeItem>(item: EncodeLikeItem)
211	where
212		Item: Encode,
213		EncodeLikeItem: EncodeLike<Item>,
214		Value: StorageAppend<Item>,
215	{
216		<Self as crate::storage::StorageValue<Value>>::append(item)
217	}
218
219	/// Read the length of the storage value without decoding the entire value.
220	///
221	/// `Value` is required to implement [`StorageDecodeLength`].
222	///
223	/// If the value does not exists or it fails to decode the length, `None` is returned.
224	/// Otherwise `Some(len)` is returned.
225	///
226	/// # Warning
227	///
228	/// `None` does not mean that `get()` does not return a value. The default value is completely
229	/// ignored by this function.
230	pub fn decode_len() -> Option<usize>
231	where
232		Value: StorageDecodeLength,
233	{
234		<Self as crate::storage::StorageValue<Value>>::decode_len()
235	}
236
237	/// Read the length of the storage value without decoding the entire value.
238	///
239	/// `Value` is required to implement [`StorageDecodeNonDedupLength`].
240	///
241	/// If the value does not exists or it fails to decode the length, `None` is returned.
242	/// Otherwise `Some(len)` is returned.
243	///
244	/// # Warning
245	///
246	///  - `None` does not mean that `get()` does not return a value. The default value is
247	///    completely
248	/// ignored by this function.
249	///
250	/// - The value returned is the non-deduplicated length of the underlying Vector in storage.This
251	/// means that any duplicate items are included.
252	pub fn decode_non_dedup_len() -> Option<usize>
253	where
254		Value: StorageDecodeNonDedupLength,
255	{
256		<Self as crate::storage::StorageValue<Value>>::decode_non_dedup_len()
257	}
258
259	/// Try and append the given item to the value in the storage.
260	///
261	/// Is only available if `Value` of the storage implements [`StorageTryAppend`].
262	pub fn try_append<Item, EncodeLikeItem>(item: EncodeLikeItem) -> Result<(), ()>
263	where
264		Item: Encode,
265		EncodeLikeItem: EncodeLike<Item>,
266		Value: StorageTryAppend<Item>,
267	{
268		<Self as crate::storage::TryAppendValue<Value, Item>>::try_append(item)
269	}
270}
271
272impl<Prefix, Value, QueryKind, OnEmpty> StorageEntryMetadataBuilder
273	for StorageValue<Prefix, Value, QueryKind, OnEmpty>
274where
275	Prefix: StorageInstance,
276	Value: FullCodec + scale_info::StaticTypeInfo,
277	QueryKind: QueryKindTrait<Value, OnEmpty>,
278	OnEmpty: crate::traits::Get<QueryKind::Query> + 'static,
279{
280	fn build_metadata(
281		deprecation_status: sp_metadata_ir::ItemDeprecationInfoIR,
282		docs: Vec<&'static str>,
283		entries: &mut Vec<StorageEntryMetadataIR>,
284	) {
285		let docs = if cfg!(feature = "no-metadata-docs") { vec![] } else { docs };
286
287		let entry = StorageEntryMetadataIR {
288			name: Prefix::STORAGE_PREFIX,
289			modifier: QueryKind::METADATA,
290			ty: StorageEntryTypeIR::Plain(scale_info::meta_type::<Value>()),
291			default: OnEmpty::get().encode(),
292			docs,
293			deprecation_info: deprecation_status,
294		};
295
296		entries.push(entry);
297	}
298}
299
300impl<Prefix, Value, QueryKind, OnEmpty> crate::traits::StorageInfoTrait
301	for StorageValue<Prefix, Value, QueryKind, OnEmpty>
302where
303	Prefix: StorageInstance,
304	Value: FullCodec + MaxEncodedLen,
305	QueryKind: QueryKindTrait<Value, OnEmpty>,
306	OnEmpty: crate::traits::Get<QueryKind::Query> + 'static,
307{
308	fn storage_info() -> Vec<StorageInfo> {
309		vec![StorageInfo {
310			pallet_name: Self::pallet_prefix().to_vec(),
311			storage_name: Self::storage_prefix().to_vec(),
312			prefix: Self::hashed_key().to_vec(),
313			max_values: Some(1),
314			max_size: Some(Value::max_encoded_len().saturated_into()),
315		}]
316	}
317}
318
319/// It doesn't require to implement `MaxEncodedLen` and give no information for `max_size`.
320impl<Prefix, Value, QueryKind, OnEmpty> crate::traits::PartialStorageInfoTrait
321	for StorageValue<Prefix, Value, QueryKind, OnEmpty>
322where
323	Prefix: StorageInstance,
324	Value: FullCodec,
325	QueryKind: QueryKindTrait<Value, OnEmpty>,
326	OnEmpty: crate::traits::Get<QueryKind::Query> + 'static,
327{
328	fn partial_storage_info() -> Vec<StorageInfo> {
329		vec![StorageInfo {
330			pallet_name: Self::pallet_prefix().to_vec(),
331			storage_name: Self::storage_prefix().to_vec(),
332			prefix: Self::hashed_key().to_vec(),
333			max_values: Some(1),
334			max_size: None,
335		}]
336	}
337}
338
339#[cfg(test)]
340mod test {
341	use super::*;
342	use crate::storage::types::ValueQuery;
343	use sp_io::{hashing::twox_128, TestExternalities};
344	use sp_metadata_ir::StorageEntryModifierIR;
345
346	struct Prefix;
347	impl StorageInstance for Prefix {
348		fn pallet_prefix() -> &'static str {
349			"test"
350		}
351		const STORAGE_PREFIX: &'static str = "foo";
352	}
353
354	struct ADefault;
355	impl crate::traits::Get<u32> for ADefault {
356		fn get() -> u32 {
357			97
358		}
359	}
360
361	#[test]
362	fn test() {
363		type A = StorageValue<Prefix, u32, OptionQuery>;
364		type AValueQueryWithAnOnEmpty = StorageValue<Prefix, u32, ValueQuery, ADefault>;
365		type B = StorageValue<Prefix, u16, ValueQuery>;
366		type WithLen = StorageValue<Prefix, Vec<u32>>;
367
368		TestExternalities::default().execute_with(|| {
369			assert_eq!(A::hashed_key().to_vec(), [twox_128(b"test"), twox_128(b"foo")].concat());
370			assert_eq!(A::exists(), false);
371			assert_eq!(A::get(), None);
372			assert_eq!(AValueQueryWithAnOnEmpty::get(), 97);
373			assert_eq!(A::try_get(), Err(()));
374
375			A::put(2);
376			assert_eq!(A::exists(), true);
377			assert_eq!(A::get(), Some(2));
378			assert_eq!(AValueQueryWithAnOnEmpty::get(), 2);
379			assert_eq!(A::try_get(), Ok(2));
380			assert_eq!(A::try_get(), Ok(2));
381
382			B::put(4);
383			A::translate::<u16, _>(|v| v.map(Into::into)).unwrap();
384			assert_eq!(A::try_get(), Ok(4));
385
386			A::set(None);
387			assert_eq!(A::try_get(), Err(()));
388
389			A::set(Some(2));
390			assert_eq!(A::try_get(), Ok(2));
391
392			A::mutate(|v| *v = Some(v.unwrap() * 2));
393			assert_eq!(A::try_get(), Ok(4));
394
395			A::set(Some(4));
396			let _: Result<(), ()> = A::try_mutate(|v| {
397				*v = Some(v.unwrap() * 2);
398				Ok(())
399			});
400			assert_eq!(A::try_get(), Ok(8));
401
402			let _: Result<(), ()> = A::try_mutate(|v| {
403				*v = Some(v.unwrap() * 2);
404				Err(())
405			});
406			assert_eq!(A::try_get(), Ok(8));
407
408			A::kill();
409			AValueQueryWithAnOnEmpty::mutate(|v| *v = *v * 2);
410			assert_eq!(AValueQueryWithAnOnEmpty::try_get(), Ok(97 * 2));
411
412			AValueQueryWithAnOnEmpty::kill();
413			let _: Result<(), ()> = AValueQueryWithAnOnEmpty::try_mutate(|v| {
414				*v = *v * 2;
415				Ok(())
416			});
417			assert_eq!(AValueQueryWithAnOnEmpty::try_get(), Ok(97 * 2));
418
419			A::kill();
420			assert_eq!(A::try_get(), Err(()));
421
422			let mut entries = vec![];
423			A::build_metadata(
424				sp_metadata_ir::ItemDeprecationInfoIR::NotDeprecated,
425				vec![],
426				&mut entries,
427			);
428			AValueQueryWithAnOnEmpty::build_metadata(
429				sp_metadata_ir::ItemDeprecationInfoIR::NotDeprecated,
430				vec![],
431				&mut entries,
432			);
433			assert_eq!(
434				entries,
435				vec![
436					StorageEntryMetadataIR {
437						name: "foo",
438						modifier: StorageEntryModifierIR::Optional,
439						ty: StorageEntryTypeIR::Plain(scale_info::meta_type::<u32>()),
440						default: Option::<u32>::None.encode(),
441						docs: vec![],
442						deprecation_info: sp_metadata_ir::ItemDeprecationInfoIR::NotDeprecated
443					},
444					StorageEntryMetadataIR {
445						name: "foo",
446						modifier: StorageEntryModifierIR::Default,
447						ty: StorageEntryTypeIR::Plain(scale_info::meta_type::<u32>()),
448						default: 97u32.encode(),
449						docs: vec![],
450						deprecation_info: sp_metadata_ir::ItemDeprecationInfoIR::NotDeprecated
451					}
452				]
453			);
454
455			WithLen::kill();
456			assert_eq!(WithLen::decode_len(), None);
457			WithLen::append(3);
458			assert_eq!(WithLen::decode_len(), Some(1));
459		});
460	}
461}