How to write a WebAssembly smart contract on the Ontology network? Part 1: Rust

How to write a WebAssembly smart contract on the Ontology network? Part 1: Rust

Ontology Wasm technology reduces the cost of migrating dApp smart contracts with complex business logic to the blockchain, thereby greatly enriching the dApp ecosystem.

Now Ontology Wasm Simultaneously supports both Rust and C++ development. The Rust language supports Wasm better, and the generated bytecode is simpler, which can further reduce the cost of contract calls. So, how to use Rust to develop a contract on the Ontology network?

Developing a WASM Contract with Rust

Create a contract

Job is a good project creation and package management tool for Rust development, which helps developers to better organize the interaction of code and third-party libraries. To create a new Ontology Wasm contract, simply run the following command:

How to write a WebAssembly smart contract on the Ontology network? Part 1: Rust

The project structure it generates:

How to write a WebAssembly smart contract on the Ontology network? Part 1: Rust

The Cargo.toml file is used to set up basic project information and dependent library information. The [lib] section of the file must be set to crate-type = ["cdylib"]. The lib.rs file is used to write the contract logic code. In addition, you need to add dependency parameters to the [dependencies] section of the Cargo.toml configuration file:

How to write a WebAssembly smart contract on the Ontology network? Part 1: Rust

With this dependency, developers can call interfaces that interact with the Ontology blockchain and tools such as the serialization parameter.

Contract entry function

Every program has an input function, like the main function we usually see, but the contract does not have a main function. When a Wasm contract is developed using Rust, the default invoke function is used as the input function to use the contract. The name of a function in Rust will be unclear when compiling Rust source code into bytecode that can be executed by a virtual machine. To prevent the compiler from generating redundant code and reduce the size of the contract, the invoke function adds the #[no_mangle] annotation.

How does the invoke function get parameters to execute a transaction?

The ontio_std library provides a runtime::input() function to get the parameters to execute a transaction. Developers can use ZeroCopySource to deserialize the resulting byte array. In which the first array of bytes read is the name of the invoke method, followed by the method parameters.

How is the result of the contract execution returned?

The runtime::ret function provided by the ontio_std library returns the result of a method execution.

The completed invoke function looks like this:

How to write a WebAssembly smart contract on the Ontology network? Part 1: Rust

Serializing and Deserializing Contract Data

In the process of developing contracts, developers always run into problems with serialization and deserialization, specifically with how to store a struct data type in the database and how to deserialize a byte array read from the database to get a struct data type.

The ontio_std library provides decoder and encoder interfaces for data serialization and deserialization. The fields of a struct also implement the decoder and encoder interfaces so that the structure can be serialized and deserialized. Instances of the Sink class are required when various data types are serialized. An instance of the Sink class has a set-type field buf that stores the byte type data, and all serialized data is stored in buf.

For fixed length data (eg: byte, u16, u32, u64, etc.), the data is directly converted to a byte array and then stored in buf; for data of non-fixed length, length must be serialized first, then Ddata (for example, unsigned integers of unknown size, including u16, u32, or u64, etc.).

Deserialization is the exact opposite. For every serialization method, there is a corresponding deserialization method. Deserialization requires the use of instances of the Source class. This class instance has two fields buf and pos. Buf is used to store the data to be deserialized and pos is used to store the current read position. When a particular type of data is being read, if you know its length, you can read it directly, for data of unknown lengthβ€”read the length first, then read the contents.

Access and update data in the chain

ontology-wasm-cdt-rust - encapsulated an operational method for working with data in the chain, which is convenient for developers to implement operations such as adding, deleting, changing and querying data in the chain as follows:

  • database::get(key) - is used to request data from the chain, and key requests the implementation of the AsRef interface;
  • database::put(key, value) - used to store data on the network. Key requests the implementation of the AsRef interface, and value requests the implementation of the Encoder interface;
  • database::delete(key) - is used to remove data from the chain, and key requests the implementation of the AsRef interface.

Contract testing

When the methods of a contract are implemented, we need access to the data on the chain and we need an appropriate virtual machine to execute the bytecode of the contract, so it is generally necessary to deploy the contract on the chain for testing. But this method of testing is problematic. To make it easier for developers to test contracts, the ontio_std library provides a mock module for testing. This module provides a simulation of the data in the circuit, making it easier for developers to unit test the methods in the contract. Specific examples can be found here.

Contract Debugging

console::debug(msg) displays debug information while debugging a contract. The msg information will be added to the node log file. A prerequisite is to set the log file level to debug mode when the local Ontology test node is running.

runtime::notify(msg) outputs the appropriate debug information while the contract is being debugged. This method will store the information entered into the chain and can be queried from the chain using the getSmartCodeEvent method.

The article was translated by the editors of Hashrate&Shares especially for OntologyRussia. ΠΊΠ»ΠΈΠΊ

Are you a developer? Join our tech community at Discord. Also, take a look at Developer Center on our website, where you can find developer tools, documentation, and more.

Ontology

Source: habr.com

Add a comment