Intelligent contract written in Rust | Hello, Ink!

By Li Dagu/By Zhang Handong


What is the WASM Smart Contract?

In the past, when we talked about smart contracts, it was the Solidity Smart Contract based on EVM.

Now, with the development of smart contract technology, a new possibility has emerged: The WASM smart Contract,

WASM is not a new programming language, but rather an entirely new low-level binary syntax.

WASM (WebAssembly) is a new bytecode format. It is a new low-level binary syntax that compiles code instructions that are small, portable, fast to load, and compatible with new WEB formats. WASM can be written in multiple languages such as C/C++/RUST/GO, and there are rich underlying standard libraries available for calling.

Advantages of WASM:

As a kind of brand-new bytecode format, WASM through its own innovation and optimization, makes the support in using the language to write code instruction has small volume, can be in memory, hard disk storage, get more bandwidth of optimization, the saved block chain network resources, also obviously improve the efficiency of network transmission.

Using WASM on smart contracts will have the same characteristics, most notably fewer resources, faster and more stable contracts, and more efficient network transmission. This will enable more smart contracts to be deployed on the blockchain network, and will enable users to have a better experience when using smart contracts.

– WASM intelligence advantage analysis: zhuanlan.zhihu.com/p/344347968

Based on the current trend, Substrate, ETH 2.0 and other public chains have indicated that they will support the WASM smart contract.

In what languages can I write a WASM smart contract?

Wasm extends the family of languages available to smart contract developers, including Rust, C/C++, C#, Typescript, Haxe, and Kotlin. That means you can write smart contracts in any language you’re familiar with.

In terms of adaptation, Rust currently has better adaptation with WASM smart contracts, a more complete toolchain, and a more secure written smart contract.

So, this series will start with Subtrate on Ink! For example, start WASM smart Contract 101.

In this paper, the Ink! Official tutorial reference:

Substrate. The dev/substrate – c…

Rust Configuration

1. Configure the Rust environment

On A Linux operating system such as MacOS or Ubuntu, Rust can be easily installed with a one-line command:

Curl, proto '= HTTPS' - tlsv1.2 - sSf https://sh.rustup.rs | shCopy the code

In addition to this, install nightly version:

rustup install nightly
Copy the code

For Windows installation, see:

https://forge.rust-lang.org/infra/other-installation-methods.html
Copy the code

2. Add Rust to the environment

Add the following statement to ~/.bashrc or ~/.zshrc:

export PATH=~/.cargo/bin:$PATH
Copy the code

And then:

source ~/.bashrc # source ~/.zshrc
Copy the code

3. Change the source

We switched the Rust source to domestic by setting the following environment variables:

export RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static
export RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup
Copy the code

In the ~/.cargo/config file, write the following:

[source.crates-io]
registry = "https://github.com/rust-lang/crates.io-index"
replace-with = 'ustc'
[source.ustc]
registry = "git://mirrors.ustc.edu.cn/crates.io-index"
Copy the code

Ink! Environment configuration

After configuring the basic Rust environment, we can configure Ink! The required development environment.

# for substrate
rustup component add rust-src --toolchain nightly
rustup target add wasm32-unknown-unknown --toolchain stable
# for canvas node Cargo install canvas - node - git https://github.com/paritytech/canvas-node.git - tag v0.1.4 - force - locked# for ink! CLICargo install cargo-contract --vers 0.10.0 --force --lockedCopy the code

We also need to install/upgrade Binaryen, which is the WebAssembly compiler.

Install on Mac:

# for mac
brew upgrade binaryen Brew install if not installed
Copy the code

Install on Linux:

Create an ink! project

Run the following command:

cargo contract new flipper
Copy the code

After the creation, enter the folder:

cd flipper/
Copy the code

Contract Project Directory Structure:

flipper
|
+-- lib.rs                <-- Contract Source Code
|
+-- Cargo.toml            <-- Rust Dependencies and ink! Configuration
|
+-- .gitignore
Copy the code

Contract tests

cargo +nightly test
Copy the code

If all goes well, the output looks like this:

$ cargo +nightly test
    running 2 tests
    test flipper::tests::it_works ... ok
    test flipper::tests::default_works ... ok

    test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out
Copy the code

Contract compiling

cargo +nightly contract build
Copy the code

If successful, a target/ink folder will be generated within the directory containing the following files:

Where flipper. Contract is the contract file for deployment and can be thought of as the bin file in the Solidity contract.

Json is metadata and can be thought of as an ABI file in the Solidity contract.

Contract deployment

Launch a locally running development node from Canvas!

canvas --dev --tmp
Copy the code

Open the following url and the page will automatically connect to the locally launched development node:

Upload the file flipper. Contract:

One-click deployment:

Contract is called

Click on the Execute:

Select get():bool and click “Call” :

Return the result of the call:

Flipper source code interpretation

// Copyright 2018-2020 Parity Technologies (UK) Ltd.
//
Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
/ / http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#! [cfg_attr(not(feature ="std"), no_std)]

use ink_lang as ink;

#[ink::contract]
pub mod flipper {
    #[ink(storage)]
    pub struct Flipper {
        value: bool,}impl Flipper {
        /// Creates a new flipper smart contract initialized with the given value.
        #[ink(constructor)]
        pub fn new(init_value: bool) - >Self {
            Self { value: init_value }
        }

        /// Creates a new flipper smart contract initialized to `false`.
        #[ink(constructor)]
        pub fn default() - >Self {
            Self::new(Default::default())
        }

        /// Flips the current value of the Flipper's bool.
        #[ink(message)]
        pub fn flip(&mut self) {
            self.value = !self.value;
        }

        /// Returns the current value of the Flipper's bool.
        #[ink(message)]
        pub fn get(&self) - >bool {
            self.value
        }
    }

    #[cfg(test)]
    mod tests {
        use super::*;

        #[test]
        fn default_works() {
            let flipper = Flipper::default();
            assert_eq!(flipper.get(), false);
        }

        #[test]
        fn it_works() {
            let mut flipper = Flipper::new(false);
            assert_eq!(flipper.get(), false);
            flipper.flip();
            assert_eq!(flipper.get(), true); }}}Copy the code

1. cfgandcfg_attrThe use of

CFG is a special property in Rust that allows us to compile tag-based code and pass it to the compiler.

In this Agreement, we shall see that:

#[cfg(test)]
Copy the code

This identifier means that the following code is a unit test.

2. The IMPL keyword

Implement some functionality for a type.

Do a function implementation for a type.

The standard template is:

Struct Example {number: i32, # struct Example {number: i32, # } impl Example { fn boo() { println! ("boo! Example::boo() was called!" ); } fn answer(&mut self) { self.number += 42; } # Many functions... }Copy the code

To apply to this contract, we first define the struct of this contract:

Pub struct Flipper {value: bool, # contains a variable value}Copy the code

The struct is then implemented in a complementary way:

Impl Flipper {... }Copy the code

3. #[ink(constructor)]with#[ink(message)]

#[ink(constructor)] indicates that this line of statement function is the constructor of the contract, equivalent to constructor in solidity contract.

Docs.soliditylang.org/en/v0.7.2/c…

#[ink(message)] indicates that the following functions are normal contract functions, such as the get function in this example:

/// Returns the current value of the Flipper's bool.
#[ink(message)]
pub fn get(&self) -> bool {
	self.value
}
Copy the code

About the author:

Li Dashu (Li Xiaohua), deputy Director of Blockchain Technology and Application Research Center of Shanghai University of International Business and Economics, CTO of Bailian Education, Blockchain certified lecturer of FISCO BCOS (Webank Blockchain Framework), 5-year blockchain engineer, master of Peking University. Research areas include: blockchain systems, consensus mechanisms, smart contracts, blockchain applications, digital identity, etc.

Contents: March issue of Rust Chinese (Rust_Magazine)