Contract Fundamentals
Data Serialization and Deserialization of Data in Ontology WASM Contract
Some common aspects of smart contract development process are:
Parameter processing upon contract invocation
Storing the user-defined data structures on the blockchain
Fetching and reading the on-chain data and processing and resolving them to original data types
Transferring the parameters to the target contract when carrying out cross-contract invocation
Most of these aspects involve serialization and deserialization of data. Here we talk about data serialization and deserialization in Ontology WASM contracts.
A template contract has been made available here on Github for the developers to make WASM contract development in Rust convenient. The template provides a script to compile the contract and a basic structure to start working with.
Encoder and Decoder Interfaces
The Encoder and Decoder interfaces define serialization and deserialization methods respectively for different data types. For the specific implementation logic, please refer to the sink.rs
file. The ontology-wasm-cdt-rust
library supports most commonly used data types, for e.g. &str, u8, u16, u32, u64, u128, bool, H256, Address, Vec, String, and tuple. Sample code for serialization and deserialization of different data types:
All the parameters passed to the sink.write()
method support all the data types that implement the Encoder interface. Their data types need to be declared when serializing, for example 1u128
. The source.read()
method can fetch and read all the data types that implement the Decoder interface. The target data type needs to be specified when deserializing as follows:
The data type needs to be specified after res1
. Here, the data type is u8
.
Since reading is carried out using the the read_byte
method it is not necessary to specify the data type.
Processing Contract Invocation Parameters
The contract fetches the invocation parameters using the runtime::input()
method. But, this method can only fetch parameters of the bytearray
type. This parameter can be deserialized to the corresponding method name and method parameters. Sample code for serialization and deserialization:
Rust supports type derivation. For most cases, type declaration is not necessary. For example, ont::transfer()
method declares the data type for from
, to
, and amount
variables, and so data type declaration is not required for these variables.
Deserialization for the Vec<&str>
data type can be carried out in the following way:
Deserialization for the Vec<(&str, U128, Address)>
data type can be carried out in the following way:
ONT and ONG Transfers
The WASM contract development tools already encapsulate methods that can used to invoke ONT and ONG native contracts. The contract
module contains these methods, and can be invoked in the following fashion:
Serializing the User-defined Data Structures
While developing smart contracts we often need to serialize and deserialize data of type struct
. To achieve this function, #[derive(Encoder, Decoder)]
can be conveniently added above the struct declaration statement. Refer to the code:
When using this feature to carry out serialization and deserialization, it is important to ensure that all the fields of struct
implement the Encoder
and Decoder
interface.
Fetching On-chain Data of Specific Data Types
The different types of data that are handled in a contract can be stored on the blockchain. But these different data types first need to be converted to bytearray
type using serialization. Similarly, the data that is fetched from the blockchain is in the bytearray
form and needs to be deserialized to obtain results in specific data types. The database
module provides several simple API methods that are available for the developer to use.
The T
data type is saved based on the key
, and the type T
is to implement the Encoder interface.
Sample code
From the above example it is clear that when using the database::put
method, first we serialize the es
parameter, and then save the result on the blockchain.
Here we fetch data of type T
using the key
. The T
data type requires implementation of the Decoder interface.
Example
From the example above we can see that the database::get
method fetches data of the type bytearray
from the chain, and then needs to be deserialized to obtain the result in the EnvelopeStruct
format.
Cross Contract Parameter Transfer
In the case of cross contract invocation, the parameters are transferred in the bytearray
format. Thus, it is necessary to serialize different data types to bytearray
format. An example for a cross contract invocation in the case of a WASM contract:
Last updated