Using IN3 For Rust

Written by: Camilo Soto & Shoaib Ahmed, IN3 Software Developers

September 9, 2020

Share on:

Facebook share Linkedin share

Announcing IN3 For Rust

The popularity of Rust as a reliable and efficient programming language continues to rise. It has now become one of the most popular languages (including its use in blockchain programming), due to its focus on explicitness and correctness. As passionate technologists and geeks, the IN3 (Incubed) team at Blockchains wants to give the growing Rust community the opportunity to try it out for IN3!

What Is IN3?

IN3 is the first blockchain client of its kind. Also known as a “minimal verification client,” IN3 allows individuals to simultaneously connect their internet of things (IoT) devices to multiple blockchain networks, supporting the decentralization of application programming interfaces (APIs). At its core, the IN3 library implements a JSON-RPC client which delivers verifiable responses by leveraging the power of cryptographic proofs that are provided by IN3 nodes as defined by the IN3 protocol.

Why Rust?

According to the 2020 Stack Overflow developer survey, Rust is…”The Beloved.”

Rust held onto its spot as the most beloved language among the professional developers we surveyed.

Table Showing percent of developers using Rust at 86.1%

2020 Stack Overflow Developer Survey

In short, Rust is amazing and there are plenty of reasons for that claim to be true among the community:

  • Performance: blazingly fast and memory-efficient, with no runtime or garbage collector.
  • Reliability: rich type system and ownership model guarantee memory-safety and thread-safety.
  • Productivity: great documentation, a friendly compiler with useful error messages, and top-notch tooling.

With these features, Rust has also consolidated its position in the blockchain space. It is no mere coincidence that two of the most performant clients for Ethereum 1.0 and 2.0 are written in Rust.

Last but not least, Rust has recently become the first formal (and machine-checked) safety proof for a language representing a realistic subset of Rust as part of the project RustBelt: Logical Foundations for the Future of Safe Systems Programming from the Max Planck Institute for Software Systems (MPI-SWS) in Saarbruecken, Germany. This is a great milestone for programming languages and one of the hardest topics that is also part of the state of the art research in the blockchain community.

Can In3 Applications Be Written In Rust?

Yes, the first IN3 client was written in C, so we decided to support Rust and still keep our reliable and rigorously tested C source code.

Top-notch quality assurance is very important to us, the IN3 Rust API features these core milestones achieved:

  • Cross-platform support tested with cross-rs.
  • Unsafe code is isolated to a small subset of the API and should not be required for most use cases.
  • The C sources are bundled with the crate and we leverage the rust-bindgen and cmake-rs projects to auto-generate bindings.
  • The code is well-documented and carefully leak-free verified with Valgrind-memcheck.

How Were Rust Bindings Bult?

We followed best practices and patterns for writing idiomatic Rust to create low-level bindings and expose the greatness of our C client with an easy to use API. To achieve this we created two crates:

  • in3-sys: following the naming convention for crates that help Rust programs use C (“system”) libraries, e.g. libz-syskernel32-syslcms2-sys. With this, the in3-sys crate exposes a minimal low-level C interface to Rust FFI which tells Cargo how to link with the library.
  • in3-rs: idiomatic Rust IN3 Client API, featuring support for async transport, Ethereum, Bitcoin, IPFS, as well as all of the IN3 verification features.

What Is In This Release?

  • Well-documented API support for Ethereum, Bitcoin, and IPFS.
  • Customizable storage, transport, and signing.
  • All of IN3’s verification capabilities with examples and much more!

How Can We Use It To Develop Rust Applications?

Just follow the next few steps and you are good to go!

Cargo Manifest

Add IN3 and futures_executor (or just any executor of your choice) to your cargo manifest. The in3-rs API is asynchronous and Rust doesn’t have any built-in executors so we need to choose one, and we decided futures_executor is a very good option as it is lightweight and practical to use.

[package]
name = "in3-examples"
version = "0.1.0"
authors = ["BlockchainsLLC"]
edition = "2018"
[dependencies]
in3 = "0.1.7"
futures-executor = "0.3.5"

Getting Started

Let’s begin with the ‘hello-world’ equivalent of the Ethereum JSON-RPC API – eth_blockNumber. This call returns the number of the most recent block in the blockchain. Here’s the complete program:

use in3::eth1::Api;
use in3::prelude::*;

fn main() -> In3Result<()> {
let client = Client::new(chain::MAINNET);
let mut eth_api = Api::new(client);
let number = futures_executor::block_on(eth_api.block_number())?;
println!("Latest block number => {:?}", number);
Ok(())
}

Now, let’s go through this program line-by-line. We start by creating a JSON-RPC capable Incubed Client instance for the Ethereum mainnet chain.

let client = Client::new(chain::MAINNET);

This client is then used to instantiate an Ethereum Api instance which implements the Ethereum JSON-RPC API spec.

let mut eth_api = Api::new(client);

From here, getting the latest block number is as simple as calling the block_number() function on the Ethereum API instance. As specified before, we need to use futures_executor::block_on to run the future returned by block_number() to completion on the current thread.

let number = futures_executor::block_on(eth_api.block_number())?;

A complete list of supported functions can be found on the in3-rs crate documentation page at docs.rs.

Getting An Ethereum Block By Number

- eth_getBlockByNumber:

use in3::eth1::{Api, BlockNumber};
use in3::prelude::*;
fn main()-> In3Result<()> {
// configure client and API
let mut eth_api = Api::new(Client::new(chain::MAINNET));
// get latest block
let block: futures executor::block_on(eth_api.get_block_by_number(BlockNumber::Latest, false))?;
println!("Block => {:?}", block);
Ok(())
}

An Ethereum Contract Call

In this case, we are reading the number of nodes that are registered in the IN3 network deployed on the Ethereum Mainnet at 0x2736D225f85740f42D17987100dc8d58e9e16252.

use in3::eth1::{abi, abi::*, Api, BlockNumber, CallTransaction};
use in3::json_rpc::json;
use in3::prelude::*;
fn main() {
// configure client and API
let mut eth_api = Api::new(Client::new(chain::MAINNET));
// setup Incubed contract address
let contract: Address =
json::from_str(r#""0x2736D225f85740f42D17987100dc8d58e9e16252""#).unwrap(); // cannot fail
// instantiate an abi encoder for the contract call
let mut abi = abi::In3EthAbi::new();
// setup the signature to call in this case we are calling totalServers():uint256 from in3-nodes contract
let params = futures_executor::block_on(abi.encode("totalServers():uint256", json::json!([])))
.expect("failed to ABI encode params");
// setup the transaction with contract and signature data
let txn = CallTransaction {
to: Some(contract),
data: Some(params),
..Default::default()
};
// execute asynchronous api call
let output: Bytes =
futures_executor::block_on(eth_api.call(txn, BlockNumber::Latest))
.expect("ETH call failed");
// decode the Bytes output and get the result
let output =
futures_executor::block_on(abi.decode("uint256", output))
.expect("failed to ABI decode output");
let total_servers: U256 = json::from_value(output).unwrap(); // cannot fail if ABI decode succeeds
println!("{:?}", total_servers);
}

Store A String In IPFS

IPFS is a protocol and peer-to-peer network for storing and sharing data in a distributed file system.

use in3::ipfs::Api;
use in3::prelude::*;
fn main() {
let mut ipfs_api = Api::new(Client::new(chain::IPFS));
match futures_executor::block_on(ipfs_api.put("incubed meets rust".as_bytes().into())) {
Ok(res) => println!("The hash is {:?}", res),
Err(err) => println!("Failed with error: {:?}", err),
}
}

Ready-To-Run Example

Head over to our sample project on GitHub or simply run:

$ git clonehttps://github.com/blockchainsllc/in3-example-rust.git
$ cd in3-example-rust
$ cargo run

Other Examples

Head over to the Rust directory in the IN3-C repository on GitHub, you will find more examples to explore there.

Thank you for your interest in using IN3 for Rust. We hope you enjoy writing Rust IN3 applications and we cannot wait to hear from you. For questions and feedback, feel free to reach out to our Gitter IN3 channel.

If you are interested, we also provide IN3 clients for WasmJava, Android, .net, and Python.

For the complete IN3 technical documentation, visit ReadTheDocs.

Stay Connected

Tell us what opportunities or areas you’re interested in and be the first to hear the latest news from Blockchains.