Basic structure
The TON Virtual Machine (TVM) memory, persistent storage, and smart contract code consist of cells. In turn, each cell consists of- up to 1023 bits;
- up to 4 references to other cells.
Kinds of cells
There are two kinds of cells: ordinary and exotic. The former are the simplest and most commonly used flavor of cells, which can only contain data and references, while the latter are used for special purposes only. They sometimes appear in actual representations of blocks and other data structures on TON Blockchain. Their memory layouts and purposes differ significantly from ordinary cells. From the low-level perspective, ordinary and exotic cells can be distinguished by a special 1-bit flag stored outside the main 1,023 bits and read by TVM at runtime. Users cannot read this flag directly. TVM can support up to 256 different types of exotic cells that differ by a special 8-bit type identifier stored in the first byte of the cell data. TVM supports four types of exotic cells:- pruned branch (type identifier
0x01
); - library reference (type identifier
0x02
); - Merkle proof (type identifier
0x03
); - Merkle update (type identifier
0x04
).
Level of a cell
Every cell c has an attribute called its level, which takes integer values in the range0…3
.
A cell’s level affects the number of higher hashes it has, see the section on hashes for details.
The level of an ordinary cell is equal to the maximum of the levels of all its children :
For instance, each cell in a tree of cells that does not contain any exotic cell has level 0.
Exotic cells may have different rules for setting their level.
Standard cell representation and its hash
Before a cell can be transferred over the network or stored on disk, it must be serialized. A common way to do this is to use the so-called standard cell representation,CellRepr(c)
. The standard representation of a cell c
is a byte sequence that is constructed as follows:
- Two descriptor bytes and are serialized first. Byte equals
r+8s+32l
, where0 ≤ r ≤ 4
is the quantity of cell references contained in the cell,0 ≤ l ≤ 3
is the level of the cell, and0 ≤ s ≤ 1
is1
for exotic cells and0
for ordinary cells. Byte equals , where0 ≤ b ≤ 1023
is the quantity of data bits inc
. - Then the data bits are serialized as bytes. If
b
is not a multiple of eight, a binary1
and up to six binary0s
are appended to the data bits. After that, the data is split into 8-bit groups, and each group is interpreted as an unsigned big-endian integer 0 … 255 and stored into an byte. - Next, for every referenced cell,
2
bytes in big-endian format store the depth of the refs, i.e. the number of cells between the root of the
cell tree (the current cell) and the deepest reference, including it. For example, a cell containing only one reference and no further references would have a depth of1
, while the referenced cell would have a depth of0
. - Finally, for every referenced cell, the SHA-256 hash of its standard representation is stored, occupying
32
bytes per referenced cell, recursively repeating the said algorithm. Note that cyclic cell references are not allowed, so this algorithm always terminates. If there are no referenced cells, neither depths nor hashes are stored.
CellRepr(c)
are obtained. Thus, we got the serialization of c
.
However, the serialization of trees formed by cells is arranged differently, see bag of cells for details.
Cell manipulation
Cells are read-only and immutable, but there are two major sets of ordinary cell manipulation instructions in TVM:- Cell creation (or serialization) instructions, which are used to construct new cells from previously stored values and cells.
- Cell parsing (or deserialization) instructions, which are used to extract or load data previously stored into cells via serialization instructions.
Cell
type into either builder or slice types before such cells can be modified or inspected.
Libraries like @ton/core and @ton-community/assets-sdk provide efficient cell handling.
Below are examples of sequential cell creation, populating it with data, and then parsing.
Create a cell and store data
To build a cell, you use thebeginCell()
function. While the cell is open, you can store various data types with store...()
functions.
When you’re done, you close the cell with the endCell()
function.
storeRef()
function to create nested cells:
storeMaybe...()
helpers:
Load data from a cell
To read data from a cell, you first convert it into a slice using thebeginParse()
function.
Then, you can extract various data types with load...()
functions. You read data in the same order it was stored.
loadRef()
:
loadMaybe...()
functions. Returned values are nullable, so do not forget to check them for null.