
Ontology Wasm technology reduces the cost of transferring smart contracts for dApps with complex business logic to the blockchain, significantly enriching the dApp ecosystem.
Currently simultaneously supports development in both Rust and C++. The Rust language has better support for Wasm, and the generated bytecode is simpler, which can further reduce the cost of contract calls. So, how to use Rust to develop a contract in the Ontology network?
Developing a WASM contract using Rust
Creating a contract
is a great project creation and package management tool for Rust programming that helps developers better organize the interaction of code and third-party libraries. To create a new Ontology Wasm contract, simply run the following command:
![]()
The project structure it generates:

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

With this dependency, developers can call interfaces that interact with the Ontology blockchain, and tools such as serialization parameters.
Contract entry function
Every program has an entry function, like the main function we usually see, but a contract does not have a main function. When developing a Wasm contract using Rust, the invoke function is used by default as the entry function for using the contract. The function name in Rust will be unclear when compiling the Rust source code into bytecode that can be executed by the virtual machine. To prevent the compiler from generating redundant code and to reduce the size of the contract, the invoke function adds the #[no_mangle] annotation.
How does the invoke function receive parameters for executing a transaction?
The ontio_std library provides the runtime::input() function to obtain parameters for executing a transaction. Developers can use ZeroCopySource for deserializing the received byte array. The first byte array read is the invoke method name, 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 the method execution.
The completed invoke function looks as follows:

Serialization and deserialization of contract data
During contract development, developers often encounter issues with serialization and deserialization, specifically how to save struct data types to a database and how to deserialize a byte array read from a database to retrieve a struct data type.
The ontio_std library provides decoder and encoder interfaces for the serialization and deserialization of data. The fields of a struct also implement decoder and encoder interfaces, allowing the struct to be serialized and deserialized. Instances of the Sink class are required when serializing different data types. An instance of the Sink class has a set-type field buf, which stores byte-type data, and all serialized data is stored in buf.
For fixed-length data (for example: byte, u16, u32, u64, etc.), the data is directly converted into a byte array and then stored in buf; for variable-length data, the length must first be serialized, followed by the data (such as unsigned integers of unknown size, including u16, u32, or u64, etc.).
Deserialization is the direct opposite. For each 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 for storing data to be deserialized, while pos is used to store the current read position. When reading a specific data type, if you know its length, you can read it directly; for data of unknown length, first read the length, then read the content.
Accessing and updating data on the chain
Ontology-wasm-cdt-rust — encapsulates the operational method of working with data in the chain, which is convenient for developers to implement operations such as adding, deleting, modifying, and querying data in the chain as follows:
- database::get(key) — used to request data from the chain, where key requests the implementation of the AsRef interface;
- database::put(key, value) — used to store data in the network. Key requests the implementation of the AsRef interface, while value requests the implementation of the Encoder interface;
- database::delete(key) — used to delete data from the chain, where key requests the implementation of the AsRef interface.
Contract Testing
When contract methods are implemented, we need access to data in the chain and we require the appropriate virtual machine to execute the contract bytecode; therefore, it is usually necessary to deploy the contract in the chain for testing. However, this method of testing can be problematic. To simplify contract testing for developers, the ontio_std library provides a mock module for testing. This module simulates data in the chain, making unit testing of methods in the contract easier for developers. Specific examples can be found .
Contract Debugging
console::debug(msg) outputs debugging information during contract debugging. The information msg will be logged in the node's log file. A prerequisite is setting the log level to debug mode when running a local test node of Ontology.
runtime::notify(msg) outputs relevant debugging information during contract debugging. This method will save the information into the chain and can be queried from the chain using the getSmartCodeEvent method.
This article was translated by the Hashrate&Shares editorial team specifically for OntologyRussia.
Are you a developer? Join our technical community on . Also, check out the on our website, where you can find developer tools, documentation, and much more.
Ontology
- /
- Telegram /
- /
Source: habr.com
