Exploring Substrate
Hi there! welcome back, this will be the first post of a new serie exploring the Substrate framework. We will be using the tutorials and recipes from the Substrate Developer Hub as our road map to exploring and learning.
As the landing page of the hub says, Substrate is a modular framework that enables you to create purpose-built blockchains by composing custom or pre-built components.
, that means that you can create your first Substrate Chain by using the pre-built components that the framework offer. And that is what the first tutorial is about.
You can follow the first tutorial for detailed instructions, but make sure to review the installation page for setup your environment.
Let's continue with the exploration, assuming that you already cloned the needed templates
, first we need to build the node
(in release mode).
# node
$ cargo build --release
And then you can run both front-end and node
in different terminals
First the node
using the --dev
and --tmp
flags
$ ./target/release/node-template --dev --tmp
2021-09-03 19:39:37 Running in --dev mode, RPC CORS has been disabled.
2021-09-03 19:39:37 Substrate Node
2021-09-03 19:39:37 ✌️ version 3.0.0-monthly-2021-08-cd936fc-x86_64-macos
2021-09-03 19:39:37 ❤️ by Substrate DevHub <https://github.com/substrate-developer-hub>, 2017-2021
2021-09-03 19:39:37 📋 Chain specification: Development
2021-09-03 19:39:37 🏷 Node name: efficacious-cart-4351
And the front-end
# front-end
yarn i
yarn start
...
You can now view substrate-front-end-template in the browser.
Local: http://localhost:8000/substrate-front-end-template
On Your Network: http://192.168.0.175:8000/substrate-front-end-template
You will get a nice UI that allow you to interact with your first Substrate Chain :)
And even you can interact and make transfers between the test accounts :)
Great!! we complete the first tutorial, we can also explore other options un the UI and interact with our first chain :)
Let's now continue, we will first add add the nicks
pallet
following the next tutorial. But first a little definition from the KB page:
Pallets are a special kind of Rust module made up of a set of types, trait implementations and functions from which Substrate runtimes can be composed. FRAME not only provides a library of commonly used Substrate pallets but also a framework to build custom domain-specific pallets, giving runtime engineers the flexibility to define their runtime's behaviour according to their target use case. The result: each pallet has its own discrete logic which can modify the features and functionality of your blockchain's state transition functions.
You can follow the detailed explanation in the tutorial, but in a nutshell to add the pallet
you need to modify two files. First you need to add the dep
to the runtime
crate.
// runtime/Cargo.toml
(...)
[dependencies.pallet-nicks]
default-features = false
git = 'https://github.com/paritytech/substrate.git'
tag = 'monthly-2021-08'
version = '4.0.0-dev'
Note: The version
and tag
may be outdate, you can check the latest ones.
And also we need to add the feature
to the std
features of the runtime
crate ( you can read in the tutorial for a nice explanation)
// runtime/Cargo.toml
std = [
(...)
'pallet-balances/std',
'pallet-nicks/std',
(...)
Great! Now is time to configure
the pallet
, since every pallet
needs to implement the Config
trait in order to be included in the runtime (by the construct_runtime
macro).
We can here use the help
of the rust-analyzer to get the skeleton of the needed members.
// runtime/src/lib.rs
impl pallet_nicks::Config for Runtime {
type Event;
type Currency;
type ReservationFee;
type Slashed;
type ForceOrigin;
type MinLength;
type MaxLength;
}
And, also detailed in the tutorial, we had another macro (parameter_types
) to help us defined constant values. Let use this macro to define some constants needed in the configuration.
// runtime/src/lib.rs
parameter_types! {
pub const NickReservationFee: u128 = 100;
pub const MinNickLength: usize = 8;
pub const MaxNickLength: usize = 16;
}
And now let go to the trait implementation block and complete the needed config (using the code from the tutorial).
// runtime/src/lib.rs
// The Balances pallet implements the ReservableCurrency trait.
// `Balances` is defined in `construct_runtimes!` macro. See below.
// https://substrate.dev/rustdocs/latest/pallet_balances/index.html#implementations-2
type Currency = Balances;
// Use the NickReservationFee from the parameter_types block.
type ReservationFee = NickReservationFee;
// No action is taken when deposits are forfeited.
type Slashed = ();
// Configure the FRAME System Root origin as the Nick pallet admin.
// https://substrate.dev/rustdocs/latest/frame_system/enum.RawOrigin.html#variant.Root
type ForceOrigin = frame_system::EnsureRoot<AccountId>;
// Use the MinNickLength from the parameter_types block.
type MinLength = MinNickLength;
// Use the MaxNickLength from the parameter_types block.
type MaxLength = MaxNickLength;
// The ubiquitous event type.
type Event = Event;
Last, we need to add the pallet
to the runtime
by adding to the construct_runtime
macro call.
// runtime/src/lib.rs
construct_runtime!(
pub enum Runtime where
Block = Block,
NodeBlock = opaque::Block,
UncheckedExtrinsic = UncheckedExtrinsic
{
System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
RandomnessCollectiveFlip: pallet_randomness_collective_flip::{Pallet, Storage},
Timestamp: pallet_timestamp::{Pallet, Call, Storage, Inherent},
Aura: pallet_aura::{Pallet, Config<T>},
Grandpa: pallet_grandpa::{Pallet, Call, Storage, Config, Event},
Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
TransactionPayment: pallet_transaction_payment::{Pallet, Storage},
Sudo: pallet_sudo::{Pallet, Call, Config<T>, Storage, Event<T>},
// Include the custom logic from the pallet-template in the runtime.
TemplateModule: pallet_template::{Pallet, Call, Storage, Event<T>},
// add nicks pallet
Nicks: pallet_nicks::{Pallet, Call, Storage, Event<T>},
}
);
Awesome! Time to compile again and see it in action :)
$ cargo build --release
And we get an error, the trait From<usize>
is not implemented for u32
.
We can look at the Get trait in the substrate repo for more details in the implementation, but for now let go to our code and change the usize
to u32
.
// runtime/src/lib.rs
parameter_types! {
pub const NickReservationFee: u128 = 100;
pub const MinNickLength: u32 = 8;
pub const MaxNickLength: u32 = 16;
}
Let try to compile again...
$ cargo build --release
(...)
Finished release [optimized] target(s) in 18m 57s
Nice! we can run again and interact with the nicks
pallet.
$ ./target/release/node-template --dev --tmp
Set the nick of Alice address
Wait, looking at the Events
there is an error in the execution
system:ExtrinsicFailed:: (phase={"applyExtrinsic":1})-2
DispatchError: {"module":{"index":9,"error":1}}, DispatchInfo: {"weight":50000000,"class":"Normal","paysFee":"Yes"}
An extrinsic failed. \[error, info\]
After looking how to read this errors I found a nice explanation in this so answer
For future occasions there it goes a tip when a dispatch error happens. index:9 and error:0 are the index of the pallet in construct_runtime! which is throwing the error, and the index of the error in the #[pallet::error] definition of the pallet concerned.
So, in our case index:9
is the nicks
pallet and we error:1
is TooLong
(defined in this line), since remember we set the MaxNickLength
to 16. Let's try with a nick
with an accepted length(between 8 and 16).
Nice! works as expected! We can also check by query
ing the nameOf
using the address of Alice.
Great! we get the Alice'snick
(hex-encoded) and amount used for reserve the nick.
That's all for today, we followed the first two tutorials of the Substrate Developer Hub and make our first interactions with the framework :)
As always, I write this as a learning journal and any feedback is welcome 🙌. In the next post I will try to write a simple pallet
and integrate with our current chain, stay tune 😃
Thanks!