How To Build Your Own Blockchain Using Parity Substrate

1,884 reads

A brief getting started guide.

Substrate logo — © Parity Technologies

Parity Substrate is a blockchain development framework with many cool features like upgradable blockchains, modular architecture, customizable block execution logic, and hot-swappable consensus. For an overview of the Substrate framework, watch this talk from Dr. Gavin Wood (Web3 Summit, October 2018).

reactions

This article is about how you can get started with the Substrate framework to build your own blockchain. Let’s jump right in.

reactions

Installation

The first step towards getting started with Substrate is setting up your development environment. The Substrate team has created a bash script which installs all the dependencies and compiles the relevant packages as part of installing the Substrate framework.

reactions

Run the following command in your terminal, and it will set up your machine ready to hack on Substrate.

reactions

curl https://getsubstrate.io -sSf | bash

The command takes a few minutes to complete (depending on your hardware) as it also compiles all the Rust packages needed for the Substrate framework.

reactions

There is a faster option also available, but it installs only the dependencies and does not compile the Substrate packages. To use this option, run the following command.

reactions

curl https://getsubstrate.io -sSf | bash -s -- --fast

Note: In the faster option you will not have the Substrate CLI installed globally in your system.

reactions

Substrate Node Template

Once the install script finishes execution, along with the dependencies, you will also have a couple of commands installed on your machine.

reactions

One of these commands is the substrate-node-new command which helps you set up a template node. Think of this as a project scaffolding template. The command downloads a Rust code base and compiles it. This codebase packages together all the bootstrapping code needed to set up a Substrate runtime.

reactions

To create an instance of the node template, run the following command in your terminal.

reactions

substrate-node-new <project name> <author name>

The first parameter is a name for your blockchain project and the second (optional) parameter is the name of the author for this chain.

reactions

For example:

reactions

substrate-node-new substrate-demo demoauthor

Once this command completes, it will create the following directory structure inside the substrate-demo (or the project name you used) directory. It will also initialize a git repository in this directory.

reactions

substrate-node-template directory structure

The runtime sub-directory houses the blockchain runtime related logic. The runtime can be called the business logic for your blockchain. It is further divided into runtime modules and each module packages together it’s own state (storage) and behavior (logic). The runtime directory contains files for the runtime modules.

reactions

The src directory contains the low-level code which brings together all the components of the Substrate framework for execution of the runtime.

reactions

The node template contains a build.sh script which allows us to build the Substrate runtime for the Wasm (Web Assembly) environment.

reactions

Running the Substrate Node

Once the substrate-node-new command finishes execution, it would have also compiled the source code of the node template (takes a few mins). At this moment, you can already start the node, and it will begin producing blocks.

reactions

To start the Substrate node, run the following command, in the context of the node-template directory. The following command will start a Substrate node based on the node-template using the dev configuration. In essence, it is running the executable generated by the compilation of the node-template codebase.

reactions

cd substrate-demo // in case you haven't done this already

./target/release/substrate-demo --dev

The command will produce output similar to the following.

reactions

2019-04-08 17:28:31 Substrate Node 2019-04-08 17:28:31 version 1.0.0-x86_64-linux-gnu 2019-04-08 17:28:31 by demoauthor, 2017, 2018 2019-04-08 17:28:31 Chain specification: Development 2019-04-08 17:28:31 Node name: adorable-wind-3578 2019-04-08 17:28:31 Roles: AUTHORITY 2019-04-08 17:28:31 Initializing Genesis block/state (state: 0x4397…ab51, header-hash: 0x0353…30ef) 2019-04-08 17:28:31 Loaded block-time = 10 seconds from genesis on first-launch 2019-04-08 17:28:31 Best block: #0 2019-04-08 17:28:31 Local node address is: /ip4/0.0.0.0/tcp/30333/p2p/QmYsPTbsxQiKV8Dk3rWL19xFXxfpt2NrzFRd2P63AjRM3o 2019-04-08 17:28:31 Listening for new connections on 127.0.0.1:9944. 2019-04-08 17:28:31 Using authority key 5FA9nQDVg267DEd8m1ZypXLBnvN7SFxYwV7ndqSYGiN9TmTd 2019-04-08 17:28:40 Starting consensus session on top of parent 0x03534673f220e0514d5324acd179438094e05f4c2419f33226c42e33f5cf30ef 2019-04-08 17:28:40 Prepared block for proposing at 1 [hash: 0xdc6de1c9b04607fe51bf4abed8cfdbd6313a74e9eeda78e3db4f6d2b60e69903; parent_hash: 0x0353…30ef; extrinsics: [0x0421…0149]] 2019-04-08 17:28:40 Pre-sealed block for proposal at 1. Hash now 0x1e5375649660d9e8b8e41fde74c861185a1e55153285e4332111dd0aa240684a, previously 0xdc6de1c9b04607fe51bf4abed8cfdbd6313a74e9eeda78e3db4f6d2b60e69903. 2019-04-08 17:28:40 Imported #1 (0x1e53…684a)

As you can see, the node has started producing blocks.

reactions

Building a Substrate Runtime Module

Now that we are all set up with Substrate and our template node is working as expected, let’s build some custom logic for our blockchain.

reactions

The business logic for the blockchain resides in the runtime modules. A collection of runtime modules constitutes a runtime.

reactions

Let’s say we want to build a simple blockchain runtime for a token transfer functionality. To implement this, we would be needing the following:

reactions

State:

reactions

Total Supply of the token

Accounts and Balances mapping

Behavior:

reactions

Initialization of the token (total supply allocated to the owner account)

Transfer of token between accounts

As mentioned before, a Substrate runtime module packages together it’s own state and behavior. We would be creating a custom runtime module with the storage items and functions as mentioned above.

reactions

In the node-template directory which we created above, inside the runtime/src directory we will find two files — lib.rs and temaplate.rs.

reactions

The lib.rs is the Rust crate root for the runtime. It imports all the necessary dependencies and types. It also initializes the runtime modules using some Rust macros part of the Substrate framework.

reactions

The template.rs is a template of a Substrate runtime module which is included in the node-template. It contains some dummy state and behavior (with a description in code comments) and is fully functional runtime module in itself.

reactions

To implement our token functionality described above, let’s make some changes to the template.rs file.

reactions

Declaring Storage

Firstly, let’s declare the storage items needed for the token functionality. In the decl_storage! macro call, let’s add the following two items for total supply and balances mapping of the token.

reactions

TotalSupply get(total_supply): u64 = 21000000;

BalanceOf get(balance_of): map T::AccountId => u64;

In the first line, we are adding a storage item TotalSupply to save the total number of the tokens. We are also setting a value to this storage item (21000000).

reactions

In the second line, we are creating another storage item as a StorageMap with a mapping between an AccountId and the token balance associated with it. We are calling this storage item BalanceOf.

reactions

The full storage declaration code for this module looks like the following. (Note: We’ve removed the dummy storage items which came with the template module.)

reactions

// storage for this runtime module decl_storage! { trait Store for Module<T: Trait> as Template { TotalSupply get(total_supply): u64 = 21000000;

BalanceOf get(balance_of): map T::AccountId => u64; } }

Implementing the Runtime Logic

Now that we have the storage defined for our Substrate module let’s write some code to manipulate these storage items.

reactions

In Substrate modules, public dispatchable functions are defined using the decl_module! macro. We have two functions to implement the simple token transfer functionality in our module. These are the initialization of the token and the transfer function.

reactions

In the following snippet, these two dispatchable functions — init and transfer are defined in the decl_module! macro.

reactions

decl_module! { pub struct Module<T: Trait> for enum Call where origin: T::Origin {

// initialize the token // transfers the total_supply amout to the caller fn init(origin) -> Result { let sender = ensure_signed(origin)?; <BalanceOf<T>>::insert(sender, Self::total_supply()); Ok(()) }

// transfer tokens from one account to another fn transfer(_origin, to: T::AccountId, value: u64) -> Result { let sender = ensure_signed(_origin)?; let sender_balance = Self::balance_of(sender.clone()); ensure!(sender_balance >= value, "Not enough balance.");

let updated_from_balance = sender_balance.checked_sub(value) .ok_or("overflow in calculating balance")?; let receiver_balance = Self::balance_of(to.clone()); let updated_to_balance = receiver_balance.checked_add(value) .ok_or("overflow in calculating balance")?; // reduce sender's balance <BalanceOf<T>>::insert(sender, updated_from_balance);

// increase receiver's balance <BalanceOf<T>>::insert(to.clone(), updated_to_balance); Ok(()) } } }

Note how we are accessing the module’s storage withSelf::total_supply() and <BalanceOf<T>> to get and set values of these storage items.

reactions

Note: From a security perspective, these functions do need a bit more in terms of checks and validations. But to keep things simple, let’s skip them for now.

reactions

That’s it; we have now defined the state and behavior of our tiny blockchain runtime.

reactions

The full module code is available in the following GitHub gist. We have removed most of the code with came initially with the template.rs file and have only included the proper storage and functions needed for the token transfer functionality.

reactions

Building and Running the Substrate Node

Let’s now run the Substrate runtime we just created through the token transfer functions in the template.rs file.

reactions

Compiling

First, to compile the runtime for the Wasm environment, run the following command in the context of the repository directory.

reactions

./build.sh

Once the above command completed, run the following command to build the Substrate node for the native environment.

reactions

cargo build --release

Running the Node

Running the node is the same as how we did before, just after creating the node-template.

reactions

./target/release/substrate-demo --dev

This command should again have a similar output, and the node should be up and running, producing blocks.

reactions

Connecting the Substrate node with a User Interface

Now that we have the Substrate node running with the token transfer runtime, let’s connect it with a UI to see it working.

reactions

The simplest way would be to use the Polkadot Apps Portal. It is a hosted web app primarily made for connecting to the Polkadot network nodes but it can also connect to a local Substrate node.

reactions

To try it with the Polkadot Apps UI, follow the following steps,

reactions

Once the local node is running, open the following in your browser,

Go to the settings page and select Local Node in the remote node/endpoint to connect to input. Click Save & Reload .

The apps portal would be connected to your local Substrate node and if you go to the Explorer page, then it should show the blocks as they are produced. The following screenshot shows the Explorer view of the Polkadot Apps portal with a local node connected.

reactions

Calling the Dispatchable Functions from the UI

To initialize the token, call the init() function under the template section in the Extrinsicspage of the Apps portal. See the following screenshot for reference.

reactions

As you can see, there is a pre-selected account Alice and it will be used to sign the function call when the Submit Transaction button is clicked.

reactions

When this transaction is finalized in a block, the account Alice will have all the 21000000 tokens as per the logic in the init() function in our module.

reactions

Browse Storage Values from the UI

After calling the init() function from the UI, the account Alice should have the updated token balance of 21000000. Let’s verify that by checking the storage values from the UI.

reactions

Recall from the previous section that we used a storage item called BalanceOf to store token balances against AccountIds. Let’s check what is the balance stored with Alice’s AccountId.

reactions

You can use the Chain state page of the portal to query storage items. Navigate to this page, select template from the first drop-down menu (list of modules) and then select balanceOf(AccountId): u64 from the next menu. From the AccountId menu, select Alice. Now click on the + button. It will show you the updated value for Alice’s token balance (as shown in the following screenshot).

reactions

That’s it. We have built a simple blockchain runtime and connected it to a UI in less than 20 mins.

reactions

Yes, it is really that easy to get started with the Substrate framework.

reactions

This was just a tiny demo for kind of a “hello world” tutorial purposes. You can further extend this runtime module by implementing more functions like approval, transfer_from, etc (from the ERC20 interface).

reactions

Resources

Here are some resources to help you learn and build on Substrate.

reactions

Substrate Official Documentation — The go-to place for developers building on Substrate. Substrate Collectibles Tutorial — An in-depth tutorial covering all the basic concepts in an interactive, hands-on way. Substrate TCR Guide — A set of tutorials covering how to build an end-to-end solution with Substrate (runtime, UI, unit tests, storage patterns, etc.)

Tags