Interact with Substrate Nodes using Light Clients in Rust

Reading Time: 3 minutes

Humankind is standing on the brink of another industrial revolution. Few technologies which are going to play a vital role in this are IoT, Artificial Intelligence, Blockchain and some more. This blog contemplates more on Blockchain based framework i.e. Substrate. So let’s get started.

In the last 2-3 years, Rust emerged as one of the best languages for Blockchain development as Rust gives Low-Level detail control. It archives safety and speed with some exciting features like Ownership, lifetimes and some more.  There is a lot of development happening around here. Last month Production Ready Polkadot finally launched which is built upon Substrate. The Substrate is a modular framework that enables you to create purpose-built blockchains by composing custom or pre-built components. It gives you a lot of exciting features and pre-built libraries to bring your Blockchain idea into existence.

In this blog, we are going to talk about one of Rust Based Light Client Library which is used to interact with Substrate Nodes. But, first, we are going to talk about Light Clients and why we need them.

Why Light Clients?

Light Client is one of the important features of Blockchain. It helps us to interact with blockchain in a secure and decentralised manner without having to sync the full blockchain. Unlike full nodes, Light Client does not have to read or write a lot of information on Blockchain. Rather than directly interacting with Blockchain, it interacts with full nodes instead. The benefit of the light client is that it requires fewer resources and storage compared to the entire node.
Now, I believe that the purpose of Light Client is clear. So let’s start exploring Light Client Lib by implementing it.

All dependencies which we are going to use for this project are:-

[dependencies]
substrate-api-client = { git = "https://github.com/scs/substrate-api-client.git" }
primitives = { git = "https://github.com/paritytech/substrate", rev = "3bf9540e72df5ecb3955845764dfee7dcdbb26b5", package = "substrate-primitives" }
codec = { package = "parity-scale-codec", features = ["derive"], version = "1.0.0", default-features = false }
sp-runtime = "2.0.0-rc6"

Now instantiate an API that connects to the given address:-

let url = "127.0.0.1:9944";
let from = AccountKeyring::Alice.pair();
let mut api = Api::new(format!("ws://{}", url)).set_signer(from);
let x = api.clone();

AccountKeyring module provides you with a few Keys for test purposes as it is needed to set a signer before sending Transaction (In case of Signed Transaction).

Print Full Substrate Metadata of Blockchain:

println!("{}", Metadata::pretty_format(&api.get_metadata()).unwrap_or_else(|| "pretty format failed".to_string()));

This will print metadata in JSON format.

Create an Extrinsic for any Module:

let xt: UncheckedExtrinsicV4<_> = compose_extrinsic!( api.clone(), "TemplateModule", "create_claim", &a);
println!("[+] Composed Extrinsic:\n {:?}\n", xt);

With the help of compose_extrinsic! Macro, we can create a transaction for any module present on Blockchain. It requires things like the details about API, module name, method name and payload.

let tx_hash = api
   .send_extrinsic(xt.hex_encode(), XtStatus::Finalized)
   .unwrap();

Using api.send_extrinsic, we send a transaction to the full node, and in return, it gives the Transaction’s Hash.

Get storage value from Blockchain:

Plain Storage

let result: u128 = api.get_storage_value("Balances", "TotalIssuance", None).unwrap();
println!("[+] TotalIssuance is {}", result);

let proof = api.get_storage_value_proof("Balances", "TotalIssuance", None).unwrap();
println!("[+] StorageValueProof: {:?}", proof);

StorageMap

let result: Hash = api.get_storage_map("System", "BlockHash", 1u32, None).or_else(|| Some(Hash::default())).unwrap();
println!("[+] block hash for blocknumber 42 is {:?}", result);

StorageMap key prefix

let result = api.get_storage_map_key_prefix("System", "BlockHash");
println!("[+] key prefix for System BlockHash map is {:?}", result);

StorageDoubleMap

let result: u32 = api.get_storage_double_map("TemplateModule", "SomeDoubleMap", 1_u32, 2_u32, None).or(Some(0)).unwrap();

That’s it! we are done. You can explore more about this library from here.

If you want to read more content like this?  Subscribe Rust Times Newsletter and receive insights and latest updates, bi-weekly, straight into your inbox. Subscribe Rust Times Newsletter: https://bit.ly/2Vdlld7.

Happy learning!!!

This image has an empty alt attribute; its file name is screenshot-from-2020-06-08-11-00-35.png


Knoldus-blog-footer-image

Leave a Reply