referrerpolicy=no-referrer-when-downgrade

frame_support/
macros.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//! Macros for the FRAME support library.
19
20/// Create new implementations of the [`Get`](crate::traits::Get) trait.
21///
22/// The so-called parameter type can be created in four different ways:
23///
24/// - Using `const` to create a parameter type that provides a `const` getter. It is required that
25///   the `value` is const.
26///
27/// - Declare the parameter type without `const` to have more freedom when creating the value.
28///
29/// - Using `storage` to create a storage parameter type. This type is special as it tries to load
30///   the value from the storage under a fixed key. If the value could not be found in the storage,
31///   the given default value will be returned. It is required that the value implements
32///   [`Encode`](codec::Encode) and [`Decode`](codec::Decode). The key for looking up the value in
33///   the storage is built using the following formula:
34///
35///   `twox_128(":" ++ NAME ++ ":")` where `NAME` is the name that is passed as type name.
36///
37/// - Using `static` to create a static parameter type. Its value is being provided by a static
38///   variable with the equivalent name in `UPPER_SNAKE_CASE`. An additional `set` function is
39///   provided in this case to alter the static variable. **This is intended for testing ONLY and is
40///   ONLY available when `std` is enabled.**
41///
42/// # Examples
43///
44/// ```
45/// # use frame_support::traits::Get;
46/// # use frame_support::parameter_types;
47/// // This function cannot be used in a const context.
48/// fn non_const_expression() -> u64 { 99 }
49///
50/// const FIXED_VALUE: u64 = 10;
51/// parameter_types! {
52///    pub const Argument: u64 = 42 + FIXED_VALUE;
53///    /// Visibility of the type is optional
54///    OtherArgument: u64 = non_const_expression();
55///    pub storage StorageArgument: u64 = 5;
56///    pub static StaticArgument: u32 = 7;
57/// }
58///
59/// trait Config {
60///    type Parameter: Get<u64>;
61///    type OtherParameter: Get<u64>;
62///    type StorageParameter: Get<u64>;
63///    type StaticParameter: Get<u32>;
64/// }
65///
66/// struct Runtime;
67/// impl Config for Runtime {
68///    type Parameter = Argument;
69///    type OtherParameter = OtherArgument;
70///    type StorageParameter = StorageArgument;
71///    type StaticParameter = StaticArgument;
72/// }
73///
74/// // In testing, `StaticArgument` can be altered later: `StaticArgument::set(8)`.
75/// ```
76///
77/// # Invalid example:
78///
79/// ```compile_fail
80/// # use frame_support::traits::Get;
81/// # use frame_support::parameter_types;
82/// // This function cannot be used in a const context.
83/// fn non_const_expression() -> u64 { 99 }
84///
85/// parameter_types! {
86///    pub const Argument: u64 = non_const_expression();
87/// }
88/// ```
89#[macro_export]
90macro_rules! parameter_types {
91	(
92		$( #[ $attr:meta ] )*
93		$vis:vis const $name:ident $(< $($ty_params:ident),* >)?: $type:ty = $value:expr;
94		$( $rest:tt )*
95	) => (
96		$( #[ $attr ] )*
97		$vis struct $name $(
98			< $($ty_params),* >( $(core::marker::PhantomData<$ty_params>),* )
99		)?;
100		$crate::parameter_types!(IMPL_CONST $name , $type , $value $( $(, $ty_params)* )?);
101		$crate::parameter_types!( $( $rest )* );
102	);
103	(
104		$( #[ $attr:meta ] )*
105		$vis:vis $name:ident $(< $($ty_params:ident),* >)?: $type:ty = $value:expr;
106		$( $rest:tt )*
107	) => (
108		$( #[ $attr ] )*
109		$vis struct $name $(
110			< $($ty_params),* >( $(core::marker::PhantomData<$ty_params>),* )
111		)?;
112		$crate::parameter_types!(IMPL $name, $type, $value $( $(, $ty_params)* )?);
113		$crate::parameter_types!( $( $rest )* );
114	);
115	(
116		$( #[ $attr:meta ] )*
117		$vis:vis storage $name:ident $(< $($ty_params:ident),* >)?: $type:ty = $value:expr;
118		$( $rest:tt )*
119	) => (
120		$( #[ $attr ] )*
121		$vis struct $name $(
122			< $($ty_params),* >( $(core::marker::PhantomData<$ty_params>),* )
123		)?;
124		$crate::parameter_types!(IMPL_STORAGE $name, $type, $value $( $(, $ty_params)* )?);
125		$crate::parameter_types!( $( $rest )* );
126	);
127	(
128		$( #[ $attr:meta ] )*
129		$vis:vis static $name:ident: $type:ty = $value:expr;
130		$( $rest:tt )*
131	) => (
132		$crate::parameter_types_impl_thread_local!(
133			$( #[ $attr ] )*
134			$vis static $name: $type = $value;
135		);
136		$crate::parameter_types!( $( $rest )* );
137	);
138	() => ();
139	(IMPL_CONST $name:ident, $type:ty, $value:expr $(, $ty_params:ident)*) => {
140		impl< $($ty_params),* > $name< $($ty_params),* > {
141			/// Returns the value of this parameter type.
142			pub const fn get() -> $type {
143				$value
144			}
145		}
146
147		impl<_I: From<$type> $(, $ty_params)*> $crate::traits::Get<_I> for $name< $($ty_params),* > {
148			fn get() -> _I {
149				_I::from(Self::get())
150			}
151		}
152
153		impl< $($ty_params),* > $crate::traits::TypedGet for $name< $($ty_params),* > {
154			type Type = $type;
155			fn get() -> $type {
156				Self::get()
157			}
158		}
159	};
160	(IMPL $name:ident, $type:ty, $value:expr $(, $ty_params:ident)*) => {
161		impl< $($ty_params),* > $name< $($ty_params),* > {
162			/// Returns the value of this parameter type.
163			pub fn get() -> $type {
164				$value
165			}
166		}
167
168		impl<_I: From<$type>, $(, $ty_params)*> $crate::traits::Get<_I> for $name< $($ty_params),* > {
169			fn get() -> _I {
170				_I::from(Self::get())
171			}
172		}
173
174		impl< $($ty_params),* > $crate::traits::TypedGet for $name< $($ty_params),* > {
175			type Type = $type;
176			fn get() -> $type {
177				Self::get()
178			}
179		}
180	};
181	(IMPL_STORAGE $name:ident, $type:ty, $value:expr $(, $ty_params:ident)*) => {
182		#[allow(unused)]
183		impl< $($ty_params),* > $name< $($ty_params),* > {
184			/// Returns the key for this parameter type.
185			pub fn key() -> [u8; 16] {
186				$crate::__private::sp_crypto_hashing_proc_macro::twox_128!(b":", $name, b":")
187			}
188
189			/// Set the value of this parameter type in the storage.
190			///
191			/// This needs to be executed in an externalities provided environment.
192			pub fn set(value: &$type) {
193				$crate::storage::unhashed::put(&Self::key(), value);
194			}
195
196			/// Returns the value of this parameter type.
197			///
198			/// This needs to be executed in an externalities provided environment.
199			#[allow(unused)]
200			pub fn get() -> $type {
201				$crate::storage::unhashed::get(&Self::key()).unwrap_or_else(|| $value)
202			}
203		}
204
205		impl<_I: From<$type> $(, $ty_params)*> $crate::traits::Get<_I> for $name< $($ty_params),* > {
206			fn get() -> _I {
207				_I::from(Self::get())
208			}
209		}
210
211		impl< $($ty_params),* > $crate::traits::TypedGet for $name< $($ty_params),* > {
212			type Type = $type;
213			fn get() -> $type {
214				Self::get()
215			}
216		}
217	};
218}
219
220#[cfg(not(feature = "std"))]
221#[macro_export]
222macro_rules! parameter_types_impl_thread_local {
223	( $( $any:tt )* ) => {
224		compile_error!("static parameter types is only available in std and for testing.");
225	};
226}
227
228#[cfg(feature = "std")]
229#[macro_export]
230macro_rules! parameter_types_impl_thread_local {
231	(
232		$(
233			$( #[ $attr:meta ] )*
234			$vis:vis static $name:ident: $type:ty = $value:expr;
235		)*
236	) => {
237		$crate::parameter_types_impl_thread_local!(
238			IMPL_THREAD_LOCAL $( $vis, $name, $type, $value, )*
239		);
240		$crate::__private::paste::item! {
241			$crate::parameter_types!(
242				$(
243					$( #[ $attr ] )*
244					$vis $name: $type = [<$name:snake:upper>].with(|v| v.borrow().clone());
245				)*
246			);
247			$(
248				impl $name {
249					/// Set the internal value.
250					pub fn set(t: $type) {
251						[<$name:snake:upper>].with(|v| *v.borrow_mut() = t);
252					}
253
254					/// Mutate the internal value in place.
255					#[allow(unused)]
256					pub fn mutate<R, F: FnOnce(&mut $type) -> R>(mutate: F) -> R{
257						let mut current = Self::get();
258						let result = mutate(&mut current);
259						Self::set(current);
260						result
261					}
262
263					/// Get current value and replace with initial value of the parameter type.
264					#[allow(unused)]
265					pub fn take() -> $type {
266						let current = Self::get();
267						Self::set($value);
268						current
269					}
270
271					/// Kill/reset the value to whatever was set at first.
272					#[allow(unused)]
273					pub fn reset() {
274						Self::set($value);
275					}
276				}
277			)*
278		}
279	};
280	(IMPL_THREAD_LOCAL $( $vis:vis, $name:ident, $type:ty, $value:expr, )* ) => {
281		$crate::__private::paste::item! {
282			thread_local! {
283				$(
284					pub static [<$name:snake:upper>]: std::cell::RefCell<$type> =
285						std::cell::RefCell::new($value);
286				)*
287			}
288		}
289	};
290}
291
292/// Macro for easily creating a new implementation of both the `Get` and `Contains` traits. Use
293/// exactly as with `parameter_types`, only the type must be `Ord`.
294#[macro_export]
295macro_rules! ord_parameter_types {
296	(
297		$( #[ $attr:meta ] )*
298		$vis:vis const $name:ident: $type:ty = $value:expr;
299		$( $rest:tt )*
300	) => (
301		$( #[ $attr ] )*
302		$vis struct $name;
303		$crate::parameter_types!{IMPL $name , $type , $value}
304		$crate::ord_parameter_types!{IMPL $name , $type , $value}
305		$crate::ord_parameter_types!{ $( $rest )* }
306	);
307	() => ();
308	(IMPL $name:ident , $type:ty , $value:expr) => {
309		impl $crate::traits::SortedMembers<$type> for $name {
310			fn contains(t: &$type) -> bool { &$value == t }
311			fn sorted_members() -> $crate::__private::Vec<$type> { vec![$value] }
312			fn count() -> usize { 1 }
313			#[cfg(feature = "runtime-benchmarks")]
314			fn add(_: &$type) {}
315		}
316		impl $crate::traits::Contains<$type> for $name {
317			fn contains(t: &$type) -> bool { &$value == t }
318		}
319	}
320}
321
322/// Print out a formatted message.
323///
324/// # Example
325///
326/// ```
327/// frame_support::runtime_print!("my value is {}", 3);
328/// ```
329#[macro_export]
330macro_rules! runtime_print {
331	($($arg:tt)+) => {
332		{
333			use core::fmt::Write;
334			let mut msg = $crate::__private::String::default();
335			let _ = core::write!(&mut msg, $($arg)+);
336			$crate::__private::sp_io::misc::print_utf8(msg.as_bytes())
337		}
338	}
339}
340
341/// Return Err of the expression: `return Err($expression);`.
342///
343/// Used as `fail!(expression)`.
344#[macro_export]
345macro_rules! fail {
346	( $y:expr ) => {{
347		return Err($y.into());
348	}};
349}
350
351/// Evaluate `$x:expr` and if not true return `Err($y:expr)`.
352///
353/// Used as `ensure!(expression_to_ensure, expression_to_return_on_false)`.
354#[macro_export]
355macro_rules! ensure {
356	( $x:expr, $y:expr $(,)? ) => {{
357		if !$x {
358			$crate::fail!($y);
359		}
360	}};
361}
362
363/// Evaluate an expression, assert it returns an expected `Err` value and that
364/// runtime storage has not been mutated (i.e. expression is a no-operation).
365///
366/// Used as `assert_noop(expression_to_assert, expected_error_expression)`.
367#[macro_export]
368macro_rules! assert_noop {
369	(
370		$x:expr,
371		$y:expr $(,)?
372	) => {
373		let h = $crate::__private::storage_root($crate::__private::StateVersion::V1);
374		$crate::assert_err!($x, $y);
375		assert_eq!(
376			h,
377			$crate::__private::storage_root($crate::__private::StateVersion::V1),
378			"storage has been mutated"
379		);
380	};
381}
382
383/// Evaluate any expression and assert that runtime storage has not been mutated
384/// (i.e. expression is a storage no-operation).
385///
386/// Used as `assert_storage_noop(expression_to_assert)`.
387#[macro_export]
388macro_rules! assert_storage_noop {
389	(
390		$x:expr
391	) => {
392		let h = $crate::__private::storage_root($crate::__private::StateVersion::V1);
393		$x;
394		assert_eq!(h, $crate::__private::storage_root($crate::__private::StateVersion::V1));
395	};
396}
397
398/// Assert an expression returns an error specified.
399///
400/// Used as `assert_err!(expression_to_assert, expected_error_expression)`
401#[macro_export]
402macro_rules! assert_err {
403	( $x:expr , $y:expr $(,)? ) => {
404		assert_eq!($x, Err($y.into()));
405	};
406}
407
408/// Assert an expression returns an error specified.
409///
410/// This can be used on `DispatchResultWithPostInfo` when the post info should
411/// be ignored.
412#[macro_export]
413macro_rules! assert_err_ignore_postinfo {
414	( $x:expr , $y:expr $(,)? ) => {
415		$crate::assert_err!($x.map(|_| ()).map_err(|e| e.error), $y);
416	};
417}
418
419/// Assert an expression returns error with the given weight.
420#[macro_export]
421macro_rules! assert_err_with_weight {
422	($call:expr, $err:expr, $weight:expr $(,)? ) => {
423		if let Err(dispatch_err_with_post) = $call {
424			$crate::assert_err!($call.map(|_| ()).map_err(|e| e.error), $err);
425			assert_eq!(dispatch_err_with_post.post_info.actual_weight, $weight);
426		} else {
427			::core::panic!("expected Err(_), got Ok(_).")
428		}
429	};
430}
431
432/// Panic if an expression doesn't evaluate to `Ok`.
433///
434/// Used as `assert_ok!(expression_to_assert, expected_ok_expression)`,
435/// or `assert_ok!(expression_to_assert)` which would assert against `Ok(())`.
436#[macro_export]
437macro_rules! assert_ok {
438	( $x:expr $(,)? ) => {
439		let is = $x;
440		match is {
441			Ok(_) => (),
442			_ => assert!(false, "Expected Ok(_). Got {:#?}", is),
443		}
444	};
445	( $x:expr, $y:expr $(,)? ) => {
446		assert_eq!($x, Ok($y));
447	};
448}
449
450/// Assert that the maximum encoding size does not exceed the value defined in
451/// [`MAX_MODULE_ERROR_ENCODED_SIZE`](crate::MAX_MODULE_ERROR_ENCODED_SIZE) during compilation.
452///
453/// This macro is intended to be used in conjunction with `tt_call!`.
454#[macro_export]
455macro_rules! assert_error_encoded_size {
456	{
457		path = [{ $($path:ident)::+ }]
458		runtime = [{ $runtime:ident }]
459		assert_message = [{ $assert_message:literal }]
460		error = [{ $error:ident }]
461	} => {
462		#[allow(deprecated)]
463		const _: () = assert!(
464			<
465				$($path::)+$error<$runtime> as $crate::traits::PalletError
466			>::MAX_ENCODED_SIZE <= $crate::MAX_MODULE_ERROR_ENCODED_SIZE,
467			$assert_message
468		);
469	};
470	{
471		path = [{ $($path:ident)::+ }]
472		runtime = [{ $runtime:ident }]
473		assert_message = [{ $assert_message:literal }]
474	} => {};
475}
476
477/// Do something hypothetically by rolling back any changes afterwards.
478///
479/// Returns the original result of the closure.
480#[macro_export]
481macro_rules! hypothetically {
482	( $e:expr ) => {
483		$crate::storage::transactional::with_transaction(|| -> $crate::__private::TransactionOutcome<::core::result::Result<_, $crate::__private::DispatchError>> {
484			$crate::__private::TransactionOutcome::Rollback(::core::result::Result::Ok($e))
485		},
486		).expect("Always returning Ok; qed")
487	};
488}
489
490/// Assert something to be *hypothetically* `Ok`, without actually committing it.
491///
492/// Reverts any storage changes made by the closure.
493#[macro_export]
494macro_rules! hypothetically_ok {
495	($e:expr $(, $args:expr)* $(,)?) => {
496		$crate::assert_ok!($crate::hypothetically!($e) $(, $args)*);
497	};
498}