pallet_example_basic/lib.rs
1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: MIT-0
5
6// Permission is hereby granted, free of charge, to any person obtaining a copy of
7// this software and associated documentation files (the "Software"), to deal in
8// the Software without restriction, including without limitation the rights to
9// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
10// of the Software, and to permit persons to whom the Software is furnished to do
11// so, subject to the following conditions:
12
13// The above copyright notice and this permission notice shall be included in all
14// copies or substantial portions of the Software.
15
16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22// SOFTWARE.
23
24//! # Basic Example Pallet
25//!
26//! A pallet demonstrating concepts, APIs and structures common to most FRAME runtimes.
27//!
28//! **This pallet serves as an example and is not meant to be used in production.**
29//!
30//! > Made with *Substrate*, for *Polkadot*.
31//!
32//! [![github]](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/examples/basic)
33//! [![polkadot]](https://polkadot.com)
34//!
35//! [polkadot]: https://img.shields.io/badge/polkadot-E6007A?style=for-the-badge&logo=polkadot&logoColor=white
36//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
37//!
38//! ## Pallet API
39//!
40//! See the [`pallet`] module for more information about the interfaces this pallet exposes,
41//! including its configuration trait, dispatchables, storage items, events and errors.
42//!
43//! ## Overview
44//!
45//! This pallet provides basic examples of using:
46//!
47//! - A custom weight calculator able to classify a call's dispatch class (see:
48//! [`frame_support::dispatch::DispatchClass`])
49//! - Pallet hooks to implement some custom logic that's executed before and after a block is
50//! imported (see: [`frame_support::traits::Hooks`])
51//! - Inherited weight annotation for pallet calls, used to create less repetition for calls that
52//! use the [`Config::WeightInfo`] trait to calculate call weights. This can also be overridden,
53//! as demonstrated by [`Call::set_dummy`].
54//! - A private function that performs a storage update.
55//! - A simple transaction extension implementation (see:
56//! [`sp_runtime::traits::TransactionExtension`]) which increases the priority of the
57//! [`Call::set_dummy`] if it's present and drops any transaction with an encoded length higher
58//! than 200 bytes.
59
60// Ensure we're `no_std` when compiling for Wasm.
61#![cfg_attr(not(feature = "std"), no_std)]
62
63extern crate alloc;
64
65use alloc::vec::Vec;
66use codec::{Decode, DecodeWithMemTracking, Encode};
67use core::marker::PhantomData;
68use frame_support::{
69 dispatch::{ClassifyDispatch, DispatchClass, DispatchResult, Pays, PaysFee, WeighData},
70 pallet_prelude::TransactionSource,
71 traits::IsSubType,
72 weights::Weight,
73};
74use frame_system::ensure_signed;
75use log::info;
76use scale_info::TypeInfo;
77use sp_runtime::{
78 impl_tx_ext_default,
79 traits::{
80 Bounded, DispatchInfoOf, DispatchOriginOf, SaturatedConversion, Saturating,
81 TransactionExtension, ValidateResult,
82 },
83 transaction_validity::{InvalidTransaction, ValidTransaction},
84};
85
86// Re-export pallet items so that they can be accessed from the crate namespace.
87pub use pallet::*;
88
89#[cfg(test)]
90mod tests;
91
92mod benchmarking;
93pub mod weights;
94pub use weights::*;
95
96/// A type alias for the balance type from this pallet's point of view.
97type BalanceOf<T> = <T as pallet_balances::Config>::Balance;
98const MILLICENTS: u32 = 1_000_000_000;
99
100// A custom weight calculator tailored for the dispatch call `set_dummy()`. This actually examines
101// the arguments and makes a decision based upon them.
102//
103// The `WeightData<T>` trait has access to the arguments of the dispatch that it wants to assign a
104// weight to. Nonetheless, the trait itself cannot make any assumptions about what the generic type
105// of the arguments (`T`) is. Based on our needs, we could replace `T` with a more concrete type
106// while implementing the trait. The `pallet::weight` expects whatever implements `WeighData<T>` to
107// replace `T` with a tuple of the dispatch arguments. This is exactly how we will craft the
108// implementation below.
109//
110// The rules of `WeightForSetDummy` are as follows:
111// - The final weight of each dispatch is calculated as the argument of the call multiplied by the
112// parameter given to the `WeightForSetDummy`'s constructor.
113// - assigns a dispatch class `operational` if the argument of the call is more than 1000.
114//
115// More information can be read at:
116// - https://docs.substrate.io/main-docs/build/tx-weights-fees/
117//
118// Manually configuring weight is an advanced operation and what you really need may well be
119// fulfilled by running the benchmarking toolchain. Refer to `benchmarking.rs` file.
120struct WeightForSetDummy<T: pallet_balances::Config>(BalanceOf<T>);
121
122impl<T: pallet_balances::Config> WeighData<(&BalanceOf<T>,)> for WeightForSetDummy<T> {
123 fn weigh_data(&self, target: (&BalanceOf<T>,)) -> Weight {
124 let multiplier = self.0;
125 // *target.0 is the amount passed into the extrinsic
126 let cents = *target.0 / <BalanceOf<T>>::from(MILLICENTS);
127 Weight::from_parts((cents * multiplier).saturated_into::<u64>(), 0)
128 }
129}
130
131impl<T: pallet_balances::Config> ClassifyDispatch<(&BalanceOf<T>,)> for WeightForSetDummy<T> {
132 fn classify_dispatch(&self, target: (&BalanceOf<T>,)) -> DispatchClass {
133 if *target.0 > <BalanceOf<T>>::from(1000u32) {
134 DispatchClass::Operational
135 } else {
136 DispatchClass::Normal
137 }
138 }
139}
140
141impl<T: pallet_balances::Config> PaysFee<(&BalanceOf<T>,)> for WeightForSetDummy<T> {
142 fn pays_fee(&self, _target: (&BalanceOf<T>,)) -> Pays {
143 Pays::Yes
144 }
145}
146
147// Definition of the pallet logic, to be aggregated at runtime definition through
148// `construct_runtime`.
149#[frame_support::pallet]
150pub mod pallet {
151 // Import various types used to declare pallet in scope.
152 use super::*;
153 use frame_support::pallet_prelude::*;
154 use frame_system::pallet_prelude::*;
155
156 /// Our pallet's configuration trait. All our types and constants go in here. If the
157 /// pallet is dependent on specific other pallets, then their configuration traits
158 /// should be added to our implied traits list.
159 ///
160 /// `frame_system::Config` should always be included.
161 #[pallet::config]
162 pub trait Config: pallet_balances::Config + frame_system::Config {
163 // Setting a constant config parameter from the runtime
164 #[pallet::constant]
165 type MagicNumber: Get<Self::Balance>;
166
167 /// Type representing the weight of this pallet
168 type WeightInfo: WeightInfo;
169 }
170
171 // Simple declaration of the `Pallet` type. It is placeholder we use to implement traits and
172 // method.
173 #[pallet::pallet]
174 pub struct Pallet<T>(_);
175
176 // This pallet implements the [`frame_support::traits::Hooks`] trait to define some logic to
177 // execute in some context.
178 #[pallet::hooks]
179 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
180 // `on_initialize` is executed at the beginning of the block before any extrinsic are
181 // dispatched.
182 //
183 // This function must return the weight consumed by `on_initialize` and `on_finalize`.
184 fn on_initialize(_n: BlockNumberFor<T>) -> Weight {
185 // Anything that needs to be done at the start of the block.
186 // We don't do anything here.
187 Weight::zero()
188 }
189
190 // `on_finalize` is executed at the end of block after all extrinsic are dispatched.
191 fn on_finalize(_n: BlockNumberFor<T>) {
192 // Perform necessary data/state clean up here.
193 }
194
195 // A runtime code run after every block and have access to extended set of APIs.
196 //
197 // For instance you can generate extrinsics for the upcoming produced block.
198 fn offchain_worker(_n: BlockNumberFor<T>) {
199 // We don't do anything here.
200 // but we could dispatch extrinsic (transaction/unsigned/inherent) using
201 // sp_io::submit_extrinsic.
202 // To see example on offchain worker, please refer to example-offchain-worker pallet
203 // accompanied in this repository.
204 }
205 }
206
207 // The call declaration. This states the entry points that we handle. The
208 // macro takes care of the marshalling of arguments and dispatch.
209 //
210 // Anyone can have these functions execute by signing and submitting
211 // an extrinsic. Ensure that calls into each of these execute in a time, memory and
212 // using storage space proportional to any costs paid for by the caller or otherwise the
213 // difficulty of forcing the call to happen.
214 //
215 // Generally you'll want to split these into three groups:
216 // - Public calls that are signed by an external account.
217 // - Root calls that are allowed to be made only by the governance system.
218 // - Unsigned calls that can be of two kinds:
219 // * "Inherent extrinsics" that are opinions generally held by the block authors that build
220 // child blocks.
221 // * Unsigned Transactions that are of intrinsic recognizable utility to the network, and are
222 // validated by the runtime.
223 //
224 // Information about where this dispatch initiated from is provided as the first argument
225 // "origin". As such functions must always look like:
226 //
227 // `fn foo(origin: OriginFor<T>, bar: Bar, baz: Baz) -> DispatchResultWithPostInfo { ... }`
228 //
229 // The `DispatchResultWithPostInfo` is required as part of the syntax (and can be found at
230 // `pallet_prelude::DispatchResultWithPostInfo`).
231 //
232 // There are three entries in the `frame_system::Origin` enum that correspond
233 // to the above bullets: `::Signed(AccountId)`, `::Root` and `::None`. You should always match
234 // against them as the first thing you do in your function. There are three convenience calls
235 // in system that do the matching for you and return a convenient result: `ensure_signed`,
236 // `ensure_root` and `ensure_none`.
237 #[pallet::call(weight(<T as Config>::WeightInfo))]
238 impl<T: Config> Pallet<T> {
239 /// This is your public interface. Be extremely careful.
240 /// This is just a simple example of how to interact with the pallet from the external
241 /// world.
242 // This just increases the value of `Dummy` by `increase_by`.
243 //
244 // Since this is a dispatched function there are two extremely important things to
245 // remember:
246 //
247 // - MUST NOT PANIC: Under no circumstances (save, perhaps, storage getting into an
248 // irreparably damaged state) must this function panic.
249 // - NO SIDE-EFFECTS ON ERROR: This function must either complete totally (and return
250 // `Ok(())` or it must have no side-effects on storage and return `Err('Some reason')`.
251 //
252 // The first is relatively easy to audit for - just ensure all panickers are removed from
253 // logic that executes in production (which you do anyway, right?!). To ensure the second
254 // is followed, you should do all tests for validity at the top of your function. This
255 // is stuff like checking the sender (`origin`) or that state is such that the operation
256 // makes sense.
257 //
258 // Once you've determined that it's all good, then enact the operation and change storage.
259 // If you can't be certain that the operation will succeed without substantial computation
260 // then you have a classic blockchain attack scenario. The normal way of managing this is
261 // to attach a bond to the operation. As the first major alteration of storage, reserve
262 // some value from the sender's account (`Balances` Pallet has a `reserve` function for
263 // exactly this scenario). This amount should be enough to cover any costs of the
264 // substantial execution in case it turns out that you can't proceed with the operation.
265 //
266 // If it eventually transpires that the operation is fine and, therefore, that the
267 // expense of the checks should be borne by the network, then you can refund the reserved
268 // deposit. If, however, the operation turns out to be invalid and the computation is
269 // wasted, then you can burn it or repatriate elsewhere.
270 //
271 // Security bonds ensure that attackers can't game it by ensuring that anyone interacting
272 // with the system either progresses it or pays for the trouble of faffing around with
273 // no progress.
274 //
275 // If you don't respect these rules, it is likely that your chain will be attackable.
276 //
277 // Each transaction must define a `#[pallet::weight(..)]` attribute to convey a set of
278 // static information about its dispatch. FRAME System and FRAME Executive pallet then use
279 // this information to properly execute the transaction, whilst keeping the total load of
280 // the chain in a moderate rate.
281 //
282 // The parenthesized value of the `#[pallet::weight(..)]` attribute can be any type that
283 // implements a set of traits, namely [`WeighData`], [`ClassifyDispatch`], and
284 // [`PaysFee`]. The first conveys the weight (a numeric representation of pure
285 // execution time and difficulty) of the transaction and the second demonstrates the
286 // [`DispatchClass`] of the call, the third gives whereas extrinsic must pay fees or not.
287 // A higher weight means a larger transaction (less of which can be placed in a single
288 // block).
289 //
290 // The weight for this extrinsic we rely on the auto-generated `WeightInfo` from the
291 // benchmark toolchain.
292 #[pallet::call_index(0)]
293 pub fn accumulate_dummy(origin: OriginFor<T>, increase_by: T::Balance) -> DispatchResult {
294 // This is a public call, so we ensure that the origin is some signed account.
295 let _sender = ensure_signed(origin)?;
296
297 // Read the value of dummy from storage.
298 // let dummy = Dummy::<T>::get();
299
300 // Calculate the new value.
301 // let new_dummy = dummy.map_or(increase_by, |dummy| dummy + increase_by);
302
303 // Put the new value into storage.
304 // <Dummy<T>>::put(new_dummy);
305 // Will also work with a reference:
306 // <Dummy<T>>::put(&new_dummy);
307
308 // Here's the new one of read and then modify the value.
309 <Dummy<T>>::mutate(|dummy| {
310 // Using `saturating_add` instead of a regular `+` to avoid overflowing
311 let new_dummy = dummy.map_or(increase_by, |d| d.saturating_add(increase_by));
312 *dummy = Some(new_dummy);
313 });
314
315 // Let's deposit an event to let the outside world know this happened.
316 Self::deposit_event(Event::AccumulateDummy { balance: increase_by });
317
318 // All good, no refund.
319 Ok(())
320 }
321
322 /// A privileged call; in this case it resets our dummy value to something new.
323 // Implementation of a privileged call. The `origin` parameter is ROOT because
324 // it's not (directly) from an extrinsic, but rather the system as a whole has decided
325 // to execute it. Different runtimes have different reasons for allow privileged
326 // calls to be executed - we don't need to care why. Because it's privileged, we can
327 // assume it's a one-off operation and substantial processing/storage/memory can be used
328 // without worrying about gameability or attack scenarios.
329 //
330 // The weight for this extrinsic we use our own weight object `WeightForSetDummy` to
331 // determine its weight
332 #[pallet::call_index(1)]
333 #[pallet::weight(WeightForSetDummy::<T>(<BalanceOf<T>>::from(100u32)))]
334 pub fn set_dummy(
335 origin: OriginFor<T>,
336 #[pallet::compact] new_value: T::Balance,
337 ) -> DispatchResult {
338 ensure_root(origin)?;
339
340 // Print out log or debug message in the console via log::{error, warn, info, debug,
341 // trace}, accepting format strings similar to `println!`.
342 // https://paritytech.github.io/substrate/master/sp_io/logging/fn.log.html
343 // https://paritytech.github.io/substrate/master/frame_support/constant.LOG_TARGET.html
344 info!("New value is now: {:?}", new_value);
345
346 // Put the new value into storage.
347 <Dummy<T>>::put(new_value);
348
349 Self::deposit_event(Event::SetDummy { balance: new_value });
350
351 // All good, no refund.
352 Ok(())
353 }
354 }
355
356 /// Events are a simple means of reporting specific conditions and
357 /// circumstances that have happened that users, Dapps and/or chain explorers would find
358 /// interesting and otherwise difficult to detect.
359 #[pallet::event]
360 /// This attribute generate the function `deposit_event` to deposit one of this pallet event,
361 /// it is optional, it is also possible to provide a custom implementation.
362 #[pallet::generate_deposit(pub(super) fn deposit_event)]
363 pub enum Event<T: Config> {
364 // Just a normal `enum`, here's a dummy event to ensure it compiles.
365 /// Dummy event, just here so there's a generic type that's used.
366 AccumulateDummy {
367 balance: BalanceOf<T>,
368 },
369 SetDummy {
370 balance: BalanceOf<T>,
371 },
372 SetBar {
373 account: T::AccountId,
374 balance: BalanceOf<T>,
375 },
376 }
377
378 // pallet::storage attributes allow for type-safe usage of the Substrate storage database,
379 // so you can keep things around between blocks.
380 //
381 // Any storage must be one of `StorageValue`, `StorageMap` or `StorageDoubleMap`.
382 // The first generic holds the prefix to use and is generated by the macro.
383 // The query kind is either `OptionQuery` (the default) or `ValueQuery`.
384 // - for `type Foo<T> = StorageValue<_, u32, OptionQuery>`:
385 // - `Foo::put(1); Foo::get()` returns `Some(1)`;
386 // - `Foo::kill(); Foo::get()` returns `None`.
387 // - for `type Foo<T> = StorageValue<_, u32, ValueQuery>`:
388 // - `Foo::put(1); Foo::get()` returns `1`;
389 // - `Foo::kill(); Foo::get()` returns `0` (u32::default()).
390 #[pallet::storage]
391 pub(super) type Dummy<T: Config> = StorageValue<_, T::Balance>;
392
393 // A map that has enumerable entries.
394 #[pallet::storage]
395 pub(super) type Bar<T: Config> = StorageMap<_, Blake2_128Concat, T::AccountId, T::Balance>;
396
397 // this one uses the query kind: `ValueQuery`, we'll demonstrate the usage of 'mutate' API.
398 #[pallet::storage]
399 pub(super) type Foo<T: Config> = StorageValue<_, T::Balance, ValueQuery>;
400
401 #[pallet::storage]
402 pub type CountedMap<T> = CountedStorageMap<_, Blake2_128Concat, u8, u16>;
403
404 // The genesis config type.
405 #[pallet::genesis_config]
406 #[derive(frame_support::DefaultNoBound)]
407 pub struct GenesisConfig<T: Config> {
408 pub dummy: T::Balance,
409 pub bar: Vec<(T::AccountId, T::Balance)>,
410 pub foo: T::Balance,
411 }
412
413 // The build of genesis for the pallet.
414 #[pallet::genesis_build]
415 impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
416 fn build(&self) {
417 <Dummy<T>>::put(&self.dummy);
418 for (a, b) in &self.bar {
419 <Bar<T>>::insert(a, b);
420 }
421 <Foo<T>>::put(&self.foo);
422 }
423 }
424}
425
426// The main implementation block for the pallet. Functions here fall into three broad
427// categories:
428// - Public interface. These are functions that are `pub` and generally fall into inspector
429// functions that do not write to storage and operation functions that do.
430// - Private functions. These are your usual private utilities unavailable to other pallets.
431impl<T: Config> Pallet<T> {
432 // Add public immutables and private mutables.
433 #[allow(dead_code)]
434 fn accumulate_foo(origin: T::RuntimeOrigin, increase_by: T::Balance) -> DispatchResult {
435 let _sender = ensure_signed(origin)?;
436
437 let prev = Foo::<T>::get();
438 // Because Foo has 'default', the type of 'foo' in closure is the raw type instead of an
439 // Option<> type.
440 let result = Foo::<T>::mutate(|foo| {
441 *foo = foo.saturating_add(increase_by);
442 *foo
443 });
444 assert!(prev + increase_by == result);
445
446 Ok(())
447 }
448}
449
450// Similar to other FRAME pallets, your pallet can also define a transaction extension and perform
451// some checks and [pre/post]processing [before/after] the transaction. A transaction extension can
452// be any decodable type that implements `TransactionExtension`. See the trait definition for the
453// full list of bounds. As a convention, you can follow this approach to create an extension for
454// your pallet:
455// - If the extension does not carry any data, then use a tuple struct with just a `marker`
456// (needed for the compiler to accept `T: Config`) will suffice.
457// - Otherwise, create a tuple struct which contains the external data. Of course, for the entire
458// struct to be decodable, each individual item also needs to be decodable.
459//
460// Note that a transaction extension can also indicate that a particular data must be present in the
461// _signing payload_ of a transaction by providing an implementation for the `implicit` method. This
462// example will not cover this type of extension. See `CheckSpecVersion` in [FRAME
463// System](https://github.com/paritytech/polkadot-sdk/tree/master/substrate/frame/system#signed-extensions)
464// for an example.
465//
466// Using the extension, you can add some hooks to the life cycle of each transaction. Note that by
467// default, an extension is applied to all `Call` functions (i.e. all transactions). the `Call` enum
468// variant is given to each function of `TransactionExtension`. Hence, you can filter based on
469// pallet or a particular call if needed.
470//
471// Some extra information, such as encoded length, some static dispatch info like weight and the
472// sender of the transaction (if signed) are also provided.
473//
474// The full list of hooks that can be added to a transaction extension can be found in the
475// `TransactionExtension` trait definition.
476//
477// The transaction extensions are aggregated in the runtime file of a substrate chain. All
478// extensions should be aggregated in a tuple and passed to the `CheckedExtrinsic` and
479// `UncheckedExtrinsic` types defined in the runtime. Lookup `pub type TxExtension = (...)` in
480// `node/runtime` and `node-template` for an example of this.
481
482/// A simple transaction extension that checks for the `set_dummy` call. In that case, it increases
483/// the priority and prints some log.
484///
485/// Additionally, it drops any transaction with an encoded length higher than 200 bytes. No
486/// particular reason why, just to demonstrate the power of transaction extensions.
487#[derive(Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, TypeInfo)]
488#[scale_info(skip_type_params(T))]
489pub struct WatchDummy<T: Config + Send + Sync>(PhantomData<T>);
490
491impl<T: Config + Send + Sync> core::fmt::Debug for WatchDummy<T> {
492 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
493 write!(f, "WatchDummy")
494 }
495}
496
497impl<T: Config + Send + Sync> TransactionExtension<<T as frame_system::Config>::RuntimeCall>
498 for WatchDummy<T>
499where
500 <T as frame_system::Config>::RuntimeCall: IsSubType<Call<T>>,
501{
502 const IDENTIFIER: &'static str = "WatchDummy";
503 type Implicit = ();
504 type Pre = ();
505 type Val = ();
506
507 fn validate(
508 &self,
509 origin: DispatchOriginOf<<T as frame_system::Config>::RuntimeCall>,
510 call: &<T as frame_system::Config>::RuntimeCall,
511 _info: &DispatchInfoOf<<T as frame_system::Config>::RuntimeCall>,
512 len: usize,
513 _self_implicit: Self::Implicit,
514 _inherited_implication: &impl Encode,
515 _source: TransactionSource,
516 ) -> ValidateResult<Self::Val, <T as frame_system::Config>::RuntimeCall> {
517 // if the transaction is too big, just drop it.
518 if len > 200 {
519 return Err(InvalidTransaction::ExhaustsResources.into())
520 }
521
522 // check for `set_dummy`
523 let validity = match call.is_sub_type() {
524 Some(Call::set_dummy { .. }) => {
525 sp_runtime::print("set_dummy was received.");
526
527 let valid_tx =
528 ValidTransaction { priority: Bounded::max_value(), ..Default::default() };
529 valid_tx
530 },
531 _ => Default::default(),
532 };
533 Ok((validity, (), origin))
534 }
535 impl_tx_ext_default!(<T as frame_system::Config>::RuntimeCall; weight prepare);
536}