Exploring Substrate

pepoviola

Javier Viola

Posted on September 5, 2021

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

You will get a nice UI that allow you to interact with your first Substrate Chain :)

Substrate UI

And even you can interact and make transfers between the test accounts :)

Transfer UI image

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'
Enter fullscreen mode Exit fullscreen mode

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',
(...)
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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>},
    }
);
Enter fullscreen mode Exit fullscreen mode

Awesome! Time to compile again and see it in action :)

$ cargo build --release
Enter fullscreen mode Exit fullscreen mode

And we get an error, the trait From<usize> is not implemented for u32.
error compiling

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. Update: there is already a PR in the tutorial repo to fix this and use u32.


// runtime/src/lib.rs
parameter_types! {
    pub const NickReservationFee: u128 = 100;
    pub const MinNickLength: u32 = 8;
    pub const MaxNickLength: u32 = 16;
}
Enter fullscreen mode Exit fullscreen mode

Let try to compile again...

$ cargo build --release
(...)
Finished release [optimized] target(s) in 18m 57s
Enter fullscreen mode Exit fullscreen mode

Nice! we can run again and interact with the nicks pallet.

$ ./target/release/node-template --dev --tmp
Enter fullscreen mode Exit fullscreen mode

Set the nick of Alice address

set nick

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\]
Enter fullscreen mode Exit fullscreen mode

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).

image

Nice! works as expected! We can also check by querying the nameOf using the address of Alice.

image

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!

💖 💪 🙅 🚩
pepoviola
Javier Viola

Posted on September 5, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Exploring Substrate
substrate Exploring Substrate

September 5, 2021