Skip to content
This repository has been archived by the owner on Dec 12, 2024. It is now read-only.

Commit

Permalink
WIP: new page for Cells, Builders and Slices
Browse files Browse the repository at this point in the history
* New page for Cells, Builders and Slices
* All the cross-links have been updated to lead to the new page
* Added a couple of smaller link fixes here and there
  • Loading branch information
novusnota committed Jul 18, 2024
1 parent da8a197 commit c4dcb42
Show file tree
Hide file tree
Showing 21 changed files with 297 additions and 170 deletions.
1 change: 1 addition & 0 deletions pages/book/_meta.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export default {
},
types: 'Type system overview',
integers: 'Integers',
cells: 'Cells, Builders and Slices',
maps: 'Maps',
'structs-and-messages': 'Structs and Messages',
optionals: 'Optionals',
Expand Down
2 changes: 1 addition & 1 deletion pages/book/bounced.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ contract MyContract {
}
```

To process bounced messages manually, you can use a fallback definition that handles a raw [`Slice{:tact}`](/book/types#primitive-types) directly. Note, that such receiver will get **all** the bounced messages produced by your contract:
To process bounced messages manually, you can use a fallback definition that handles a raw [`Slice{:tact}`](/book/cells#slices) directly. Note, that such receiver will get **all** the bounced messages produced by your contract:

```tact /rawMsg: Slice/
contract MyContract {
Expand Down
103 changes: 103 additions & 0 deletions pages/book/cells.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Cells, Builders and Slices

import { Callout } from 'nextra/components'

{/*
TODO:
* Refine drafts (quickly!) and remove all TODOs from this page
* (Optional?) How to parse emitted messages (in TS and/or other languages with bindings)
*/}

[Cells](#cells), [Builders](#builders) and [Slices](#slices) are low-level [primitives](/book/types#primitive-types) of TON Blockchain. The virtual machine of TON Blockchain, [TVM][tvm], uses cells to represent all data structures in memory and persistent storage.

## Cells

{/*
TODO: (move from drafts)
* Don't describe everything, write from the Tact POV. Everything else can be linked to TON Docs.
*/}

## Builders

{/*
TODO: (move from drafts)
* Construction of Cells with Builders.
* Recommend using structs :)
"I strongly recommend you to use structs in Tact instead of manually composing and parsing cells"
*/}

## Slices

{/*
TODO: (move from drafts)
* Parsing of Cells with Slices.
* Recommend using structs :)
"I strongly recommend you to use structs in Tact instead of manually composing and parsing cells"
*/}

## Serialization

{/*
TODO: (move drafts over)
Similar to [`Int{:tact}`](/book/integers), some serialization options of `Cell{:tact}`, `Builder{:tact}` and `Slice{:tact}` types ..........
*/}

### `remaining` [#serialization-bytes64]

<Callout>

To be written as per [#26](https://github.com/tact-lang/tact-docs/issues/26).

</Callout>

### `bytes32` [#serialization-bytes64]

<Callout>

To be written as per [#94](https://github.com/tact-lang/tact-docs/issues/94).

</Callout>

### `bytes64` [#serialization-bytes64]

<Callout>

To be written as per [#94](https://github.com/tact-lang/tact-docs/issues/94).

</Callout>

<Callout>

Advanced information on [`Cell{:tact}`](#cells) serialization: [Canonical `Cell{:tact}` Serialization](https://docs.ton.org/develop/research-and-development/boc).

</Callout>

## Operations

### Manual construction and parsing [#operations-manual]

{<table>
<thead>
<tr>
<th>Construction</th>
<th>Construction</th>
</tr>
</thead>
<tbody>
</tbody>
</table>}

{/*
TODO: (move over from drafts)
* showcase the construction and parsing side by side, using the Builder and a Slice
Pick one (2nd?):
marshalling/demarshalling
composition(or construction)/parsing
store/load
*/}

### Using Structs for automatic construction and parsing [#operations-structs]

{/* TODO: add a simplified parsing version via .toCell() and .fromCell() references */}

[tvm]: https://docs.ton.org/learn/tvm-instructions/tvm-overview
2 changes: 1 addition & 1 deletion pages/book/contracts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ Constant initializations must be relatively simple and only rely on values known

You can read constants both in [receivers](#receiver-functions) and in [getters](#getter-functions).

Unlike [contract variables](#variables), **contract constants don't consume space in persistent state**. Their values are stored directly in the code [`Cell{:tact}`](/book/types#primitive-types) of the contract.
Unlike [contract variables](#variables), **contract constants don't consume space in persistent state**. Their values are stored directly in the code [`Cell{:tact}`](/book/cells#cells) of the contract.

```tact
// global constants are calculated in compile-time and cannot change
Expand Down
6 changes: 3 additions & 3 deletions pages/book/debug.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Here are a few questions to ask yourself to challenge your assumptions:

* Did you make a change to your code and assume it's unrelated to the issue you're facing? A common pitfall here is to modify the code and try to run the tests right away, without compiling the changes first.

* Did you expect variable or a [`Cell{:tact}`](/book/types#primitive-types) to contain a certain value (or a certain type of value) that is different from what was really there? Pay attention to your types and data layouts, especially their representation in [TL-B schemas](https://docs.ton.org/develop/data-formats/tl-b-language).
* Did you expect variable or a [`Cell{:tact}`](/book/cells#cells) to contain a certain value (or a certain type of value) that is different from what was really there? Pay attention to your types and data layouts, especially their representation in [TL-B schemas](https://docs.ton.org/develop/data-formats/tl-b-language).

* Do you know the intent of the code? It's often more difficult to debug someone else's code. If it's not your code, it's possible you might need to spend time learning exactly what the code does before you can debug it effectively.

Expand Down Expand Up @@ -273,15 +273,15 @@ To know the full list of such properties, look at auto-completion options provid

#### toEqualCell

The method `expect(…).toEqualCell(){:typescript}` checks equality of two [cells](/book/types#primitive-types):
The method `expect(…).toEqualCell(){:typescript}` checks equality of two [cells](/book/cells#cells):

```typescript {3}
expect(oneCell).toEqualCell(anotherCell);
```

#### toEqualSlice

The method `expect(…).toEqualSlice(){:typescript}` checks equality of two [slices](/book/types#primitive-types):
The method `expect(…).toEqualSlice(){:typescript}` checks equality of two [slices](/book/cells#slices):

```typescript {3}
expect(oneSlice).toEqualSlice(anotherSlice);
Expand Down
5 changes: 3 additions & 2 deletions pages/book/expressions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -247,9 +247,10 @@ Where `StateInit{:tact}` is a built-in [Struct][s], that consists of:

Field | Type | Description
:----- | :----------------- | :----------
`code` | [`Cell{:tact}`][p] | initial code of the [contract](/book/contracts) (the compiled bytecode)
`data` | [`Cell{:tact}`][p] | initial data of the [contract](/book/contracts) (arguments of `init(){:tact}` function of the contract)
`code` | [`Cell{:tact}`][cell] | initial code of the [contract](/book/contracts) (the compiled bytecode)
`data` | [`Cell{:tact}`][cell] | initial data of the [contract](/book/contracts) (arguments of `init(){:tact}` function of the contract)

[p]: /book/types#primitive-types
[cell]: /book/cells#cells
[s]: /book/structs-and-messages#structs
[m]: /book/structs-and-messages#messages
2 changes: 1 addition & 1 deletion pages/book/func.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Tact itself compiles to FunC and maps all its entities directly to various FunC

[Primitive types](/book/types#primitive-types) in Tact are directly mapped to FunC ones.

All rules about copying variables are the same. One of the big differences is that there are no visible mutation operators in Tact and most [`Slice{:tact}`](/book/types#primitive-types) operations mutate variables in place.
All rules about copying variables are the same. One of the big differences is that there are no visible mutation operators in Tact and most [`Slice{:tact}`](/book/cells#slices) operations mutate variables in place.

## Convert serialization

Expand Down
9 changes: 5 additions & 4 deletions pages/book/maps.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Allowed value types:

* [`Int{:tact}`][int]
* [`Bool{:tact}`](/book/types#booleans)
* [`Cell{:tact}`][p]
* [`Cell{:tact}`][cell]
* [`Address{:tact}`][p]
* [Struct](/book/structs-and-messages#structs)
* [Message](/book/structs-and-messages#messages)
Expand Down Expand Up @@ -152,7 +152,7 @@ if (fizz == null) {

### Convert to a `Cell`, `.asCell()` [#ascell]

Use `.asCell(){:tact}` [method](/book/functions#extension-function) on maps to convert all their values to a [`Cell{:tact}`][p] type. Be mindful, that [`Cell{:tact}`][p] type is able to store up to 1023 bits, so converting larger maps to the Cell will result in error.
Use `.asCell(){:tact}` [method](/book/functions#extension-function) on maps to convert all their values to a [`Cell{:tact}`][cell] type. Be mindful, that [`Cell{:tact}`][cell] type is able to store up to 1023 bits, so converting larger maps to the Cell will result in error.

As an example, this method is useful for sending small maps directly in the body of the reply:

Expand Down Expand Up @@ -290,7 +290,7 @@ struct SerializedMapInside {

While maps can be convenient to work with on a small scale, they cause a number of issues if the number of items is unbounded and map can significantly grow in size:

* As the upper bound of the smart contract state size is around $65\,000$ items of type [`Cell{:tact}`][p], it constrains the storage limit of maps to be about $30\,000$ key-value pairs for the whole contract.
* As the upper bound of the smart contract state size is around $65\,000$ items of type [`Cell{:tact}`][cell], it constrains the storage limit of maps to be about $30\,000$ key-value pairs for the whole contract.

* The more entries you have in a map, the bigger [compute fees](https://docs.ton.org/develop/howto/fees-low-level#computation-fees) you'll get. Thus, working with large maps makes compute fees tough to predict and manage.

Expand Down Expand Up @@ -326,5 +326,6 @@ If you still need a large map or an unbound (infinitely large) map, it's better
TODO: Add reference to sharding page as per: https://github.com/tact-lang/tact-docs/issues/155
*/}

[int]: /book/integers
[p]: /book/types#primitive-types
[int]: /book/integers
[cell]: /book/cells#cells
8 changes: 5 additions & 3 deletions pages/book/operators.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -374,15 +374,15 @@ Binary equality (_equal_) operator `=={:tact}` checks whether its two operands a

Binary inequality (_not equal_) operator `!={:tact}` checks whether its two operands are _not equal_, returning a result of type [`Bool{:tact}`][bool].

Both operators require operands to be of the same type and both don't perform implicit type conversions, except for the [`Cell{:tact}`][p] and [`Slice{:tact}`][p] types, which are implicitly compared by their hashes.
Both operators require operands to be of the same type and both don't perform implicit type conversions, except for the [`Cell{:tact}`][cell] and [`Slice{:tact}`][slice] types, which are implicitly compared by their hashes.

Both operators can be applied to the following list of types and values:

* [`Int{:tact}`][int]
* [`Bool{:tact}`][bool]
* [`Address{:tact}`][p]
* [`Cell{:tact}`][p], implicitly compares via `.hash(){:tact}`
* [`Slice{:tact}`][p], implicitly compares via `.hash(){:tact}`
* [`Cell{:tact}`][cell], implicitly compares via `.hash(){:tact}`
* [`Slice{:tact}`][slice], implicitly compares via `.hash(){:tact}`
* [`String{:tact}`][p]
* [`map<K, V>{:tact}`](/book/maps), but only if their key and value types are identical
* [Optionals and `null{:tact}` value](/book/optionals)
Expand Down Expand Up @@ -648,3 +648,5 @@ value |= 5; // also bitwise ORs 5 and assigns result back
[p]: /book/types#primitive-types
[bool]: /book/types#booleans
[int]: /book/integers
[cell]: /book/cells#cells
[slice]: /book/cells#slices
19 changes: 10 additions & 9 deletions pages/book/send.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@ TON blockchain is message-based — to communicate with other contracts and to d

Messages in Tact are commonly composed using a built-in [Struct](/book/structs-and-messages#structs) `SendParameters{:tact}`, which consists of:

Field | Type | Description
:------- | :-------------------- | :----------
`bounce` | [`Bool{:tact}`][p] | When set to `true` (default) message bounces back to the sender if the receiver contract doesn't exist or wasn't able to process the message.
`to` | [`Address{:tact}`][p] | Receiver internal [`Address{:tact}`][p] in TON blockchain.
`value` | [`Int{:tact}`][int] | The amount of [nanoToncoins][nano] you want to send with the message. This value is usually used to cover [forward fees][fwdfee], unless the optional flag [`SendPayGasSeparately{:tact}`](/book/message-mode#optional-flags) is used.
`mode` | [`Int{:tact}`][int] | An 8-bit value that configures how to send a message, defaults to $0$. See: [Message `mode`](/book/message-mode).
`body` | [`Cell?{:tact}`][p] | [Optional][opt] message body as a [`Cell{:tact}`][p]
`code` | [`Cell?{:tact}`][p] | [Optional][opt] initial code of the contract (the compiled bytecode)
`data` | [`Cell?{:tact}`][p] | [Optional][opt] initial data of the contract (arguments of [`init(){:tact}` function](/book/contracts#init-function) of the contract)
Field | Type | Description
:------- | :--------------------- | :----------
`bounce` | [`Bool{:tact}`][p] | When set to `true` (default) message bounces back to the sender if the receiver contract doesn't exist or wasn't able to process the message.
`to` | [`Address{:tact}`][p] | Receiver internal [`Address{:tact}`][p] in TON blockchain.
`value` | [`Int{:tact}`][int] | The amount of [nanoToncoins][nano] you want to send with the message. This value is usually used to cover [forward fees][fwdfee], unless the optional flag [`SendPayGasSeparately{:tact}`](/book/message-mode#optional-flags) is used.
`mode` | [`Int{:tact}`][int] | An 8-bit value that configures how to send a message, defaults to $0$. See: [Message `mode`](/book/message-mode).
`body` | [`Cell?{:tact}`][cell] | [Optional][opt] message body as a [`Cell{:tact}`][cell]
`code` | [`Cell?{:tact}`][cell] | [Optional][opt] initial code of the contract (the compiled bytecode)
`data` | [`Cell?{:tact}`][cell] | [Optional][opt] initial data of the contract (arguments of [`init(){:tact}` function](/book/contracts#init-function) of the contract)

Fields `code` and `data` are what's called an [init package](/book/expressions#initof), which is used in deployments of new contracts.

Expand Down Expand Up @@ -149,6 +149,7 @@ There, the second message won't actually be sent:

[p]: /book/types#primitive-types
[int]: /book/integers
[cell]: /book/cells#cells
[opt]: /book/optionals

[phases]: https://docs.ton.org/learn/tvm-instructions/tvm-overview#transactions-and-phases
Expand Down
12 changes: 7 additions & 5 deletions pages/book/structs-and-messages.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ fun example() {

### Convert to a `Cell`, `.toCell()` [#tocell]

It's possible to convert an arbitrary [Struct](#structs) or [Message](#messages) to the [`Cell{:tact}`][p] type by using the `.toCell(){:tact}` [extension function](/book/functions#extension-function):
It's possible to convert an arbitrary [Struct](#structs) or [Message](#messages) to the [`Cell{:tact}`][cell] type by using the `.toCell(){:tact}` [extension function](/book/functions#extension-function):

```tact
struct Big {
Expand Down Expand Up @@ -219,9 +219,9 @@ fun conversionFun() {

### Obtain from a `Cell` or `Slice`, `.fromCell()` and `.fromSlice()` [#fromcellslice]

Instead of manually parsing a [`Cell{:tact}`][p] or [`Slice{:tact}`][p] via a series of relevant `.loadSomething(){:tact}` function calls, one can use `.fromCell(){:tact}` and `.fromSlice(){:tact}` [extension functions](/book/functions#extension-function) for converting the provided [`Cell{:tact}`][p] or [`Slice{:tact}`][p] into the needed [Struct](#structs) or [Message](#messages).
Instead of manually parsing a [`Cell{:tact}`][cell] or [`Slice{:tact}`][slice] via a series of relevant `.loadSomething(){:tact}` function calls, one can use `.fromCell(){:tact}` and `.fromSlice(){:tact}` [extension functions](/book/functions#extension-function) for converting the provided [`Cell{:tact}`][cell] or [`Slice{:tact}`][slice] into the needed [Struct](#structs) or [Message](#messages).

Those extension functions only attempt to parse a [`Cell{:tact}`][p] or [`Slice{:tact}`][p] according to the structure of your [Struct](#structs) or [Message](#messages). In case layouts don't match, various exceptions may be thrown — make sure to wrap your code in [`try...catch{:tact}`](/book/statements#try-catch) blocks to prevent unexpected results.
Those extension functions only attempt to parse a [`Cell{:tact}`][cell] or [`Slice{:tact}`][slice] according to the structure of your [Struct](#structs) or [Message](#messages). In case layouts don't match, various exceptions may be thrown — make sure to wrap your code in [`try...catch{:tact}`](/book/statements#try-catch) blocks to prevent unexpected results.

```tact
struct Fizz { foo: Int }
Expand All @@ -248,7 +248,7 @@ fun constructThenParse() {

### Conversion laws

Whenever one converts between [`Cell{:tact}`][p]/[`Slice{:tact}`][p] and [Struct](#structs)/[Message](#messages) via `.toCell(){:tact}` and `.fromCell(){:tact}` functions, the following laws hold:
Whenever one converts between [`Cell{:tact}`][cell]/[`Slice{:tact}`][slice] and [Struct](#structs)/[Message](#messages) via `.toCell(){:tact}` and `.fromCell(){:tact}` functions, the following laws hold:

* For any instance of type [Struct](#structs)/[Message](#messages), calling `.toCell(){:tact}` on it, then applying `Struct.fromCell(){:tact}` (or `Message.fromCell(){:tact}`) to the result gives back the copy of the original instance:

Expand All @@ -270,7 +270,7 @@ fun lawOne() {
}
```

* For any [`Cell{:tact}`][p] with the same [TL-B](https://docs.ton.org/develop/data-formats/tl-b-language) layout as a given [Struct](#structs)/[Message](#messages), calling `Struct.fromCell(){:tact}` (or `Message.fromCell(){:tact}`) on it, and then converting the result to a [`Cell{:tact}`][p] via `.toCell(){:tact}` would give the copy of the original [`Cell{:tact}`][p]:
* For any [`Cell{:tact}`][cell] with the same [TL-B](https://docs.ton.org/develop/data-formats/tl-b-language) layout as a given [Struct](#structs)/[Message](#messages), calling `Struct.fromCell(){:tact}` (or `Message.fromCell(){:tact}`) on it, and then converting the result to a [`Cell{:tact}`][cell] via `.toCell(){:tact}` would give the copy of the original [`Cell{:tact}`][cell]:

```tact {9-10,15-16}
struct ArbitraryStruct { val: Int as uint32 }
Expand Down Expand Up @@ -298,3 +298,5 @@ fun lawTwo() {
[msg-fs]: /ref/core-cells#messagefromslice

[p]: /book/types#primitive-types
[cell]: /book/cells#cells
[slice]: /book/cells#slices
6 changes: 2 additions & 4 deletions pages/book/types.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,13 @@ Additionally, many of those types [can be made nullable](#optionals).

Tact supports a number of primitive data types that are tailored for smart contract use:

* [`Int{:tact}`][ints] — all numbers in Tact are $257$-bit signed integers, but [smaller representations](/book/integers#serialization) can be used to reduce storage costs.
* [`Int{:tact}`](/book/integers) — all numbers in Tact are $257$-bit signed integers, but [smaller representations](/book/integers#serialization) can be used to reduce storage costs.
* [`Bool{:tact}`](#booleans) — classical boolean with `true{:tact}` and `false{:tact}` values.
* `Address{:tact}` — standard [smart contract address](https://docs.ton.org/learn/overviews/addresses#address-of-smart-contract) in TON Blockchain.
* `Slice{:tact}`, `Cell{:tact}`, `Builder{:tact}` — low-level primitives of TON VM.
* [`Cell{:tact}`](/book/cells#cells), [`Builder{:tact}`](/book/cells#builders), [`Slice{:tact}`](/book/cells#slices) — low-level primitives of TON VM.
* `String{:tact}` — represents text strings in TON VM.
* `StringBuilder{:tact}` — helper type that allows you to concatenate strings in a gas-efficient way.

[ints]: /book/integers

### Booleans [#booleans]

The primitive type `Bool{:tact}` is the classical boolean type, which can hold only the two values: `true{:tact}` and `false{:tact}`. It's convenient for boolean and logical operations, as well as for storing flags.
Expand Down
Loading

0 comments on commit c4dcb42

Please sign in to comment.