Skip to content
This repository was archived by the owner on Aug 27, 2024. It is now read-only.

Commit e41eb84

Browse files
committed
New Add a Pallet Tutorial with Nicks Pallet
1 parent b5e3ba6 commit e41eb84

File tree

12 files changed

+580
-4
lines changed

12 files changed

+580
-4
lines changed
Loading
Loading
Loading
Loading
49.2 KB
Loading
Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
---
2+
title: Configure the Nicks Pallet
3+
---
4+
5+
Every pallet has a configuration interface called `Trait` that FRAME developers must implement in
6+
order to configure that pallet with the parameters and types that it needs from the outer runtime.
7+
For instance, in the template pallet that is included in the Node Template, you will see the
8+
following `Trait` configuration interface:
9+
10+
```rust
11+
/// Configure the pallet by specifying the parameters and types on which it depends.
12+
pub trait Trait: frame_system::Trait {
13+
/// Because this pallet emits events, it depends on the runtime's definition of an event.
14+
type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;
15+
}
16+
```
17+
18+
As the comment states, we are using the `Event` type of the `Trait` configuration interface in order
19+
to allow the `TemplateModule` pallet to emit a type of event that is compatible with the outer
20+
runtime. The `Trait` configuration interface may also be used to tune parameters that control the
21+
resources required to interact with a pallet or even to limit the resources of the runtime that the
22+
pallet may consume. You will see examples of both such cases below when you implement the `Trait`
23+
configuration interface for the Nicks pallet.
24+
25+
To figure out what you need to implement for the Nicks pallet specifically, you can take a look at
26+
the
27+
[`pallet_nicks::Trait` documentation](https://substrate.dev/rustdocs/v2.0.0-rc6/pallet_nicks/trait.Trait.html)
28+
or the definition of the interface itself in
29+
[the source code](https://github.com/paritytech/substrate/blob/v2.0.0-rc6/frame/nicks/src/lib.rs) of
30+
the Nicks pallet. We have annotated the source code below with new comments that expand on those
31+
already included in the documentation so be sure to read them:
32+
33+
```rust
34+
pub trait Trait: frame_system::Trait {
35+
// The runtime must supply this pallet with an Event type that satisfies the pallet's requirements.
36+
type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;
37+
38+
// The currency type that will be used to place deposits on nicks.
39+
// It must implement ReservableCurrency.
40+
// https://substrate.dev/rustdocs/v2.0.0-rc6/frame_support/traits/trait.ReservableCurrency.html
41+
type Currency: ReservableCurrency<Self::AccountId>;
42+
43+
// The amount required to reserve a nick.
44+
type ReservationFee: Get<BalanceOf<Self>>;
45+
46+
// A callback that will be invoked when a deposit is forfeited.
47+
type Slashed: OnUnbalanced<NegativeImbalanceOf<Self>>;
48+
49+
// Origins are used to identify network participants and control access.
50+
// This is used to identify the pallet's admin.
51+
// https://substrate.dev/docs/en/knowledgebase/runtime/origin
52+
type ForceOrigin: EnsureOrigin<Self::Origin>;
53+
54+
// This parameter is used to configure a nick's minimum length.
55+
type MinLength: Get<usize>;
56+
57+
// This parameter is used to configure a nick's maximum length.
58+
// https://substrate.dev/docs/en/knowledgebase/runtime/storage#create-bounds
59+
type MaxLength: Get<usize>;
60+
}
61+
```
62+
63+
Just like we used the Balances pallet as a template for importing the Nicks pallet, let's use the
64+
Balances pallet as an example to help us understand how can implement the `Trait` interface for the
65+
Nicks pallet. You will notice that this implementation consists of two parts: a `parameter_types!`
66+
block where constant values are defined and an `impl` block where the types and values defined by
67+
the `Trait` interface are configured. This code block has also been annotated with additional
68+
comments that you should be sure to read:
69+
70+
**`runtime/src/lib.rs`**
71+
72+
```rust
73+
parameter_types! {
74+
// The u128 constant value 500 is aliased to a type named ExistentialDeposit.
75+
pub const ExistentialDeposit: u128 = 500;
76+
}
77+
78+
impl pallet_balances::Trait for Runtime {
79+
// The "Balance" that appears after the equal sign is an alias for the u128 type.
80+
type Balance = Balance;
81+
82+
// The empty value, (), is used to specify a no-op callback function.
83+
type DustRemoval = ();
84+
85+
// The previously defined parameter_type is used as a configuration parameter.
86+
type ExistentialDeposit = ExistentialDeposit;
87+
88+
// The FRAME runtime system is used to track the accounts that hold balances.
89+
type AccountStore = System;
90+
91+
// No weight information is supplied to the Balances pallet by the Node Template's runtime.
92+
type WeightInfo = ();
93+
94+
// The ubiquitous event type.
95+
type Event = Event;
96+
}
97+
```
98+
99+
The `impl balances::Trait` block allows runtime developers that are including the Balances pallet in
100+
their runtime to configure the types and parameters that are specified by the Balances pallet
101+
`Trait` configuration interface. For example, the `impl` block above configures the Balances pallet
102+
to use the `u128` type to track balances. If you were developing a chain where it was important to
103+
optimize storage, you could use any unsigned integer type that was at least 32-bits in size; this is
104+
because
105+
[the `Balance` type](https://substrate.dev/rustdocs/v2.0.0-rc6/pallet_balances/trait.Trait.html#associatedtype.Balance)
106+
for the Balances pallet `Trait` configuration interface specifies
107+
[the `AtLeast32BitUnsigned` interface](https://substrate.dev/rustdocs/v2.0.0-rc6/sp_arithmetic/traits/trait.AtLeast32BitUnsigned.html)
108+
(or "trait" in Rust terminology).
109+
110+
Now that you have an idea of the purpose behind the `Trait` configuration interface and how you can
111+
implement a FRAME pallet's `Trait` interface for your runtime, let's implement the `Trait`
112+
configuration interface for the Nicks pallet. Add the following code to `runtime/src/lib.rs`:
113+
114+
```rust
115+
parameter_types! {
116+
// Choose a fee that incentivizes desireable behavior.
117+
pub const NickReservationFee: u128 = 100;
118+
pub const MinNickLength: usize = 8;
119+
// Maximum bounds on storage are important to secure your chain.
120+
pub const MaxNickLength: usize = 32;
121+
}
122+
123+
impl pallet_nicks::Trait for Runtime {
124+
// The Balances pallet implements the ReservableCurrency trait.
125+
// https://substrate.dev/rustdocs/v2.0.0-rc6/pallet_balances/index.html#implementations-2
126+
type Currency = pallet_balances::Module<Runtime>;
127+
128+
// Use the NickReservationFee from the parameter_types block.
129+
type ReservationFee = NickReservationFee;
130+
131+
// No action is taken when deposits are forfeited.
132+
type Slashed = ();
133+
134+
// Configure the FRAME System Root origin as the Nick pallet admin.
135+
// https://substrate.dev/rustdocs/v2.0.0-rc6/frame_system/enum.RawOrigin.html#variant.Root
136+
type ForceOrigin = EnsureRoot<AccountId>;
137+
138+
// Use the MinNickLength from the parameter_types block.
139+
type MinLength = MinNickLength;
140+
141+
// Use the MaxNickLength from the parameter_types block.
142+
type MaxLength = MaxNickLength;
143+
144+
// The ubiquitous event type.
145+
type Event = Event;
146+
}
147+
```
148+
149+
In order to use the `EnsureRoot<AccountId>` type as the `ForceOrigin` for the Nicks pallet, you will
150+
need to add the following line along with the other `import` statements at the top of
151+
`runtime/src/lib.rs`:
152+
153+
```rust
154+
use frame_system::EnsureRoot;
155+
```
156+
157+
### Adding Nicks to the `construct_runtime!` Macro
158+
159+
Next, we need to add the Nicks pallet to the `construct_runtime!` macro. For this, we need to
160+
determine the types that the pallet exposes so that we can tell the our runtime that they exist. The
161+
complete list of possible types can be found in the
162+
[`construct_runtime!` macro documentation](https://substrate.dev/rustdocs/v2.0.0-rc6/frame_support/macro.construct_runtime.html).
163+
164+
If we look at the Nicks pallet in detail, we know it has:
165+
166+
- Module **Storage**: Because it uses the `decl_storage!` macro.
167+
- Module **Event**s: Because it uses the `decl_event!` macro.
168+
- **Call**able Functions: Because it has dispatchable functions in the `decl_module!` macro.
169+
- The **Module** type from the `decl_module!` macro.
170+
171+
Thus, when we add the pallet, it will look like this:
172+
173+
**`runtime/src/lib.rs`**
174+
175+
```rust
176+
construct_runtime!(
177+
pub enum Runtime where
178+
Block = Block,
179+
NodeBlock = opaque::Block,
180+
UncheckedExtrinsic = UncheckedExtrinsic
181+
{
182+
/* --snip-- */
183+
184+
/*** Add This Line ***/
185+
Nicks: pallet_nicks::{Module, Call, Storage, Event<T>},
186+
}
187+
);
188+
```
189+
190+
Note that not all pallets will expose all of these runtime types, and some may expose more! You
191+
should always look at the documentation or source code of a pallet to determine which of these types
192+
you need to expose.
193+
194+
This is another good time to check that your runtime compiles correctly so far. Use this command to
195+
check just the runtime.
196+
197+
```bash
198+
cargo check -p node-template-runtime
199+
```
Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
---
2+
title: Import the Nicks Pallet
3+
---
4+
5+
We will now modify the Substrate Developer Hub Node Template to include the Nicks pallet; this
6+
pallet allows blockchain users to pay a deposit to reserve a nickname and associate it with an
7+
account they control.
8+
9+
Open the Node Template in your favorite code editor. We will be editing two files:
10+
`runtime/src/lib.rs`, and `runtime/Cargo.toml`.
11+
12+
```
13+
substrate-node-template
14+
|
15+
+-- runtime
16+
| |
17+
| +-- Cargo.toml <-- One change in this file
18+
| |
19+
| +-- build.rs
20+
| |
21+
| +-- src
22+
| |
23+
| +-- lib.rs <-- Most changes in this file
24+
|
25+
+-- pallets
26+
|
27+
+-- scripts
28+
|
29+
+-- node
30+
|
31+
+-- ...
32+
```
33+
34+
## Importing a Pallet Crate
35+
36+
The first thing you need to do to add the Nicks pallet is to import the `pallet-nicks` crate in your
37+
runtime's `Cargo.toml` file. If you want a proper primer into Cargo References, you should check out
38+
[their official documentation](https://doc.rust-lang.org/cargo/reference/index.html).
39+
40+
Open `substrate-node-template/runtime/Cargo.toml` and you will see a list of all the dependencies
41+
your runtime has. For example, it depends on the
42+
[Balances pallet](https://substrate.dev/rustdocs/v2.0.0-rc6):
43+
44+
**`runtime/Cargo.toml`**
45+
46+
```TOML
47+
[dependencies.pallet-balances]
48+
default-features = false
49+
git = 'https://github.com/paritytech/substrate.git'
50+
tag = 'v2.0.0-rc6'
51+
version = '2.0.0-rc6'
52+
```
53+
54+
### Crate Features
55+
56+
One important thing we need to call out with importing pallet crates is making sure to set up the
57+
crate `features` correctly. In the code snippet above, you will notice that we set
58+
`default_features = false`. If you explore the `Cargo.toml` file even closer, you will find
59+
something like:
60+
61+
**`runtime/Cargo.toml`**
62+
63+
```TOML
64+
[features]
65+
default = ['std']
66+
std = [
67+
'codec/std',
68+
'frame-executive/std',
69+
'frame-support/std',
70+
'frame-system/std',
71+
'frame-system-rpc-runtime-api/std',
72+
'pallet-aura/std',
73+
'pallet-balances/std',
74+
#--snip--
75+
]
76+
```
77+
78+
This second line defines the `default` features of your runtime crate as `std`. You can imagine,
79+
each pallet crate has a similar configuration defining the default feature for the crate. Your
80+
feature will determine the features that should be used on downstream dependencies. For example, the
81+
snippet above should be read as:
82+
83+
> The default feature for this Substrate runtime is `std`. When `std` feature is enabled for the
84+
> runtime, `codec`, `frame-executive`, `frame-support`, and all the other listed dependencies should
85+
> use their `std` feature too.
86+
87+
This is important to enable the Substrate runtime to compile to both native binaries, which support
88+
Rust [`std`](https://doc.rust-lang.org/std/), and [Wasm](https://webassembly.org/) binaries, which
89+
do not (see: [`no_std`](https://rust-embedded.github.io/book/intro/no-std.html)).
90+
91+
The use of Wasm runtime binaries is one of Substrate's defining features. It allows the runtime code
92+
to become a part of a blockchain's evolving state; it also means that the definition of the runtime
93+
itself is subject to the cryptographic consensus mechanisms that ensure the security of the
94+
blockchain network. The usage of Wasm runtimes enables one of Substrate's most innovative features:
95+
forkless runtime upgrades, which means that Substrate blockchain nodes can stay up-to-date and even
96+
acquire new features without needing to be replaced with an updated application binary.
97+
98+
To see how the `std` and `no_std` features are actually used in the runtime code, we can open the
99+
project file:
100+
101+
**`runtime/src/lib.rs`**
102+
103+
```rust
104+
#![cfg_attr(not(feature = "std"), no_std)]
105+
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
106+
#![recursion_limit="256"]
107+
108+
// Make the WASM binary available.
109+
#[cfg(feature = "std")]
110+
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
111+
112+
// --snip--
113+
```
114+
115+
You can see that at the top of the file, we define that we will use `no_std` when we are _not_ using
116+
the `std` feature. A few lines lower you can see `#[cfg(feature = "std")]` above the
117+
`wasm_binary.rs` import, which is a flag saying to only import the Wasm binary when we have enabled
118+
the `std` feature.
119+
120+
### Importing the Nicks Pallet Crate
121+
122+
Okay, now that we have covered the basics of crate features, we can actually import the Nicks
123+
pallet. The Nicks pallet is one of the simpler pallets in FRAME, so it makes for a good example of
124+
the common points you need to consider when adding a pallet to your runtime.
125+
126+
First we will add the new dependency by simply copying an existing pallet and changing the values.
127+
So based on the `balances` import shown above, the `nicks` import will look like:
128+
129+
**`runtime/Cargo.toml`**
130+
131+
```TOML
132+
[dependencies.pallet-nicks]
133+
git = 'https://github.com/paritytech/substrate.git'
134+
default-features = false
135+
tag = 'v2.0.0-rc6'
136+
version = '2.0.0-rc6'
137+
```
138+
139+
As with other pallets, the Contracts pallet has an `std` feature. We should build its `std` feature
140+
when the runtime is built with its own `std` feature. Add the following line to the runtime's `std`
141+
feature.
142+
143+
**`runtime/Cargo.toml`**
144+
145+
```TOML
146+
[features]
147+
default = ["std"]
148+
std = [
149+
#--snip--
150+
'pallet-nicks/std',
151+
#--snip--
152+
]
153+
```
154+
155+
If you forget to set the feature, when building to your native binaries you will get errors like:
156+
157+
```rust
158+
error[E0425]: cannot find function `memory_teardown` in module `sandbox`
159+
--> ~/.cargo/git/checkouts/substrate-7e08433d4c370a21/83a6f1a/primitives/sandbox/src/../without_std.rs:53:12
160+
|
161+
53 | sandbox::memory_teardown(self.memory_idx);
162+
| ^^^^^^^^^^^^^^^ not found in `sandbox`
163+
164+
error[E0425]: cannot find function `memory_new` in module `sandbox`
165+
--> ~/.cargo/git/checkouts/substrate-7e08433d4c370a21/83a6f1a/primitives/sandbox/src/../without_std.rs:72:18
166+
|
167+
72 | match sandbox::memory_new(initial, maximum) {
168+
|
169+
170+
...
171+
```
172+
173+
Before moving on, check that the new dependencies resolve correctly by running:
174+
175+
```bash
176+
cargo check
177+
```

0 commit comments

Comments
 (0)