referrerpolicy=no-referrer-when-downgrade

substrate_test_runtime/
substrate_test_pallet.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//! # substrate-test pallet
19//!
20//! Provides functionality used in unit-tests of numerous modules across substrate that require
21//! functioning runtime. Some calls are allowed to be submitted as unsigned extrinsics, however most
22//! of them requires signing. Refer to `pallet::Call` for further details.
23
24use alloc::{vec, vec::Vec};
25use frame_support::{pallet_prelude::*, storage};
26use sp_core::sr25519::Public;
27use sp_runtime::{
28	traits::Hash,
29	transaction_validity::{
30		InvalidTransaction, TransactionSource, TransactionValidity, ValidTransaction,
31	},
32};
33
34pub use self::pallet::*;
35
36const LOG_TARGET: &str = "substrate_test_pallet";
37
38#[frame_support::pallet(dev_mode)]
39pub mod pallet {
40	use super::*;
41	use crate::TransferData;
42	use frame_system::pallet_prelude::*;
43	use sp_core::storage::well_known_keys;
44	use sp_runtime::{traits::BlakeTwo256, transaction_validity::TransactionPriority, Perbill};
45
46	#[pallet::pallet]
47	#[pallet::without_storage_info]
48	pub struct Pallet<T>(_);
49
50	#[pallet::config]
51	pub trait Config: frame_system::Config {}
52
53	#[pallet::storage]
54	#[pallet::getter(fn authorities)]
55	pub type Authorities<T> = StorageValue<_, Vec<Public>, ValueQuery>;
56
57	#[pallet::genesis_config]
58	#[derive(frame_support::DefaultNoBound)]
59	pub struct GenesisConfig<T: Config> {
60		pub authorities: Vec<Public>,
61		#[serde(skip)]
62		pub _config: core::marker::PhantomData<T>,
63	}
64
65	#[pallet::genesis_build]
66	impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
67		fn build(&self) {
68			<Authorities<T>>::put(self.authorities.clone());
69		}
70	}
71
72	#[pallet::call]
73	impl<T: Config> Pallet<T> {
74		/// Legacy call used in transaction pool benchmarks.
75		#[pallet::call_index(0)]
76		#[pallet::weight(100)]
77		pub fn bench_call(_origin: OriginFor<T>, _transfer: TransferData) -> DispatchResult {
78			Ok(())
79		}
80
81		/// Implicitly fill a block body with some data.
82		#[pallet::call_index(1)]
83		#[pallet::weight(100)]
84		pub fn include_data(origin: OriginFor<T>, _data: Vec<u8>) -> DispatchResult {
85			frame_system::ensure_signed(origin)?;
86			Ok(())
87		}
88
89		/// Put/delete some data from storage. Intended to use as an unsigned extrinsic.
90		#[pallet::call_index(2)]
91		#[pallet::weight(100)]
92		pub fn storage_change(
93			_origin: OriginFor<T>,
94			key: Vec<u8>,
95			value: Option<Vec<u8>>,
96		) -> DispatchResult {
97			match value {
98				Some(value) => storage::unhashed::put_raw(&key, &value),
99				None => storage::unhashed::kill(&key),
100			}
101			Ok(())
102		}
103
104		/// Write a key value pair to the offchain database.
105		#[pallet::call_index(3)]
106		#[pallet::weight(100)]
107		pub fn offchain_index_set(
108			origin: OriginFor<T>,
109			key: Vec<u8>,
110			value: Vec<u8>,
111		) -> DispatchResult {
112			frame_system::ensure_signed(origin)?;
113			sp_io::offchain_index::set(&key, &value);
114			Ok(())
115		}
116
117		/// Remove a key and an associated value from the offchain database.
118		#[pallet::call_index(4)]
119		#[pallet::weight(100)]
120		pub fn offchain_index_clear(origin: OriginFor<T>, key: Vec<u8>) -> DispatchResult {
121			frame_system::ensure_signed(origin)?;
122			sp_io::offchain_index::clear(&key);
123			Ok(())
124		}
125
126		/// Create an index for this call.
127		#[pallet::call_index(5)]
128		#[pallet::weight(100)]
129		pub fn indexed_call(origin: OriginFor<T>, data: Vec<u8>) -> DispatchResult {
130			frame_system::ensure_signed(origin)?;
131			let content_hash = sp_io::hashing::blake2_256(&data);
132			let extrinsic_index: u32 =
133				storage::unhashed::get(well_known_keys::EXTRINSIC_INDEX).unwrap();
134			sp_io::transaction_index::index(extrinsic_index, data.len() as u32, content_hash);
135			Ok(())
136		}
137
138		/// Deposit given digest items into the system storage. They will be included in a header
139		/// during finalization.
140		#[pallet::call_index(6)]
141		#[pallet::weight(100)]
142		pub fn deposit_log_digest_item(
143			_origin: OriginFor<T>,
144			log: sp_runtime::generic::DigestItem,
145		) -> DispatchResult {
146			<frame_system::Pallet<T>>::deposit_log(log);
147			Ok(())
148		}
149
150		/// This call is validated as `ValidTransaction` with given priority.
151		#[pallet::call_index(7)]
152		#[pallet::weight(100)]
153		pub fn call_with_priority(
154			_origin: OriginFor<T>,
155			_priority: TransactionPriority,
156		) -> DispatchResult {
157			Ok(())
158		}
159
160		/// This call is validated as non-propagable `ValidTransaction`.
161		#[pallet::call_index(8)]
162		#[pallet::weight(100)]
163		pub fn call_do_not_propagate(_origin: OriginFor<T>) -> DispatchResult {
164			Ok(())
165		}
166
167		/// Fill the block weight up to the given ratio.
168		#[pallet::call_index(9)]
169		#[pallet::weight(*_ratio * T::BlockWeights::get().max_block)]
170		pub fn fill_block(origin: OriginFor<T>, _ratio: Perbill) -> DispatchResult {
171			ensure_signed(origin)?;
172			Ok(())
173		}
174
175		/// Read X times from the state some data.
176		///
177		/// Panics if it can not read `X` times.
178		#[pallet::call_index(10)]
179		#[pallet::weight(100)]
180		pub fn read(_origin: OriginFor<T>, count: u32) -> DispatchResult {
181			Self::execute_read(count, false)
182		}
183
184		/// Read X times from the state some data and then panic!
185		///
186		/// Returns `Ok` if it didn't read anything.
187		#[pallet::call_index(11)]
188		#[pallet::weight(100)]
189		pub fn read_and_panic(_origin: OriginFor<T>, count: u32) -> DispatchResult {
190			Self::execute_read(count, true)
191		}
192	}
193
194	impl<T: Config> Pallet<T> {
195		fn execute_read(read: u32, panic_at_end: bool) -> DispatchResult {
196			let mut next_key = vec![];
197			for _ in 0..(read as usize) {
198				if let Some(next) = sp_io::storage::next_key(&next_key) {
199					// Read the value
200					sp_io::storage::get(&next);
201
202					next_key = next;
203				} else {
204					if panic_at_end {
205						return Ok(())
206					} else {
207						panic!("Could not read {read} times from the state");
208					}
209				}
210			}
211
212			if panic_at_end {
213				panic!("BYE")
214			} else {
215				Ok(())
216			}
217		}
218	}
219
220	#[pallet::validate_unsigned]
221	impl<T: Config> ValidateUnsigned for Pallet<T> {
222		type Call = Call<T>;
223
224		fn validate_unsigned(_source: TransactionSource, call: &Self::Call) -> TransactionValidity {
225			log::trace!(target: LOG_TARGET, "validate_unsigned {call:?}");
226			match call {
227				// Some tests do not need to be complicated with signer and nonce, some need
228				// reproducible block hash (call signature can't be there).
229				// Offchain testing requires storage_change.
230				Call::deposit_log_digest_item { .. } |
231				Call::storage_change { .. } |
232				Call::read { .. } |
233				Call::read_and_panic { .. } => Ok(ValidTransaction {
234					provides: vec![BlakeTwo256::hash_of(&call).encode()],
235					..Default::default()
236				}),
237				_ => Err(TransactionValidityError::Invalid(InvalidTransaction::Call)),
238			}
239		}
240	}
241}
242
243pub fn validate_runtime_call<T: pallet::Config>(call: &pallet::Call<T>) -> TransactionValidity {
244	log::trace!(target: LOG_TARGET, "validate_runtime_call {call:?}");
245	match call {
246		Call::call_do_not_propagate {} =>
247			Ok(ValidTransaction { propagate: false, ..Default::default() }),
248		Call::call_with_priority { priority } =>
249			Ok(ValidTransaction { priority: *priority, ..Default::default() }),
250		_ => Ok(Default::default()),
251	}
252}