Project Initiation - Hello World
An illustration to write the contract logic using rust
To execute Rust code on the Ontology blockchain, there's a process that needs to be followed. The steps are carried out in the following way:
WASM bytecode is generated by compiling the code.
The bytecode is deployed on to the chain.
Functions from the contract are invoked.
We will approach the development process from two different angles. In this section, we will first look at a template designed with the specific goal of getting you acquainted with the fundamentals of writing a WASM smart contract and working with a template. And then in the later sections, we will proceed to demonstrating how to start writing code from scratch.
To facilitate developers looking to work on Ontology WASM smart contracts we have made available a Rust template that developers can clone and start editing to speed things up. The code can be cloned from Github using the following command-
Project file hierarchy and specifics
The file hierarchy of the project is mapped below.
The config file in .cargo
directory contains the configuration settings which will be used when compiling the contract. The contents of the file-
[target.wasm32-unknown-unknown]
is the compile target. The target will directly be compiled to WASM using the low-level virtual machine (LLVM) back end. The resultant bytecode can be executed on Linux, Mac, and Windows system platforms. rustflags
is used to configure the link arguments and the default stack size to 32768 bytes, 32KB that is. This indicates the highest stack value that the contract is allowed to use.
cargo.toml
file contains a few configuration settings and other details regarding the contract. The content is as follows-
In the [lib]
configuration module, crate-type = ["cdylib"]
specifies the compilation DLL
that can be invoked using other languages.
path = "src/lib.rs"
sets the library file path.
[dependencies]
section is used to specify the project dependency details. Here, we import the ontio-std
library.
[features]
is used to toggle newly introduced features that are unstable. These features can be used with the nightly version compiler only.
The build.sh
file encapsulates functions that will be used to compile and optimize our contract. Executing this shell script will move the optimized bytecode to the output directory.
The src/lib.rs rust file is used to write the contract logic. The template contains the following code:
#![no_std]
annotation is used to indicate that the core library is to be used instead of the standard library, referred to as crate in rust. This will allow us to use Ontology's APIs.
#![no_mangle]
annotation indicates that when the code is compiled to WASM
bytecode, the compiler will not obscure the invoke method. The runtime module encapsulates the API that allows the contract to communicate with the blockchain. The runtime::ret()
method is used to return the result of contract invocation. Here, we are trying to implement a simple contract that returns "hello" when invoked.
Compiling the contract
The code can be compiled and the optimized bytecode can be fetched by running the build.sh
shell script.
If the console returns a "Permission denied" message, use sudo
on linux systems or run the command line as administrator on windows platforms and run the script again.
After the script successfully executes, it will create the output directory in the following way-
Two files are generated here. The WASM file is the bytecode generated by compiling the smart contract that we compiled, and the str file contains the hex encoding for the bytecode.
Deploying the contract
Once the code is compiled, it needs to be deployed on to the chain to be executed. The bytecode that we generated can be deployed on both the test net and the private net for testing. For now, let us look at how to deploy the contract on the private net.
First, we need to create a wallet account and run our private node. We use the following shell command to create an account-
After executing the above command, follow the instructions and set up and account with the default configuration. Then, use the following command in a new command line window to start a private node.
The --loglevel 1
parameter is used to set the log level to debug
. In case there is any debug information returned while testing the node, it will be displayed in the log files generated in the Log directory.
In a new window, access the Ontology master directory and execute the following command to deploy the contract. Enter the password for the account when prompted.
The parameters consist of the target path and some other information regarding the contract which is optional to fill in. The gaslimit
is set at the end.
Note: The gas limit is precise to 9 decimal places. Thus, 10^9 units of gas would be equivalent to 1 ONG token with the minimum valid value being 0.000000001. The gas cost, which basically means the cost to carry out a transaction on the chain, is calculated by taking the product of the gas price and the gas limit.
The result will be as follows-
If the system returns the error that the gaslimit is not enough, please change the gaslimit and enter a bigger value.
Test invocation
Next, we use the following command to invoke our smart contract. Here we use the contract address that was returned by the system earlier when we deployed the contract.
There are no parameters to be passed for this function, and the execution mode is --prepare
which indicates that the contract will be pre-executed, thereby allowing us to see the value that will be returned by the invoke
function.
The result is as follows-
We expected a "Hello" to show up, but the value returned by the system is 68656c6c6f. Why?
The reason is simple. All the data values returned by the system will be hex encoded. A simple hexadecimal to string conversion will show that 68656c6c6f is in fact "Hello".
You have successfully executed your first Ontology WASM contract.
Templates for reference
Please follow the following link to find the various templates made available by Ontology. The templates serve as examples that illustrate how token exchange and transaction protocols can be realized using rust.
Last updated