Skip to content

Commit

Permalink
feat(docs): new cell-related functions plus minor corrections here an…
Browse files Browse the repository at this point in the history
…d there
  • Loading branch information
novusnota committed Dec 5, 2024
1 parent 2b72e66 commit 8453507
Show file tree
Hide file tree
Showing 4 changed files with 229 additions and 15 deletions.
2 changes: 1 addition & 1 deletion docs/src/content/docs/ref/core-advanced.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -479,7 +479,7 @@ nativeRandomize(lt); // equivalent to calling nativeRandomizeLt()
fun blockLt(): Int;
```

Returns the [`Int{:tact}`][int] value of the [logical time][lt] of the current block.
Returns the [`Int{:tact}`][int] value of the [starting logical time][lt] of the current block.

Usage example:

Expand Down
209 changes: 209 additions & 0 deletions docs/src/content/docs/ref/core-cells.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,64 @@ let c: Cell = emptyCell();
let fizz: Slice = c.beginParse();
```

## Cell.depth

<Badge text="Available since Tact 1.6" variant="tip" size="medium"/><p/>

```tact
extends fun depth(self: Cell): Int;
```

Extension function for the [`Cell{:tact}`][cell].

Computes and returns the [`Int{:tact}`][int] [depth][std-repr] of the [`Cell{:tact}`][cell]. Produces $0$ if the [`Cell{:tact}`][cell] has no references, otherwise $1$ plus the maximum of the depths of the referenced cells.

Usage example:

```tact
let c: Cell = beginCell().storeInt(42, 7).endCell();
let depth: Int = c.depth;
```

## Cell.computeDataSize

<Badge text="Available since Tact 1.6" variant="tip" size="medium"/><p/>

```tact
extends fun computeDataSize(self: Cell, maxCells: Int): DataSize;
```

Extension function for the [`Cell{:tact}`][cell].

Computes and returns the number of distinct cells, bits and refs in the [`Cell{:tact}`][tact] by using a [depth-first search (DFS)][dfs] algorithm, recursively traversing each referenced cell. This function is computationally expensive and can consume a lot of [gas][gas].

The results are packed into a `DataSize{:tact}` [Struct][struct] consisting of:

Field | Type | Description
:------ | :------------------ | :----------
`cells` | [`Int{:tact}`][int] | The total number of nested cells, including the starting one
`bits` | [`Int{:tact}`][int] | The total number of bits in all nested cells, including the starting one
`refs` | [`Int{:tact}`][int] | The total number of refs in all nested cells, including the starting one

If the specified `maxCells` value isn't enough to traverse all cells including the starting one, an exception with [exit code 8](/book/exit-codes#8) is thrown: `Cell overflow`.

Attempts to specify a negative value of `maxCells` throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.

Usage example:

```tact
let c: Cell = beginCell().storeInt(42, 7).storeRef(emptyCell()).endCell();
try {
let dataSize: DataSize = c.computeDataSize(2);
dataSize.cells; // 2
dataSize.bits; // 7
dataSize.refs; // 1
} catch (exitCode) {
// if maxCells was insufficient to traverse the cell
// and all of its references, the exitCode here would be 8
}
```

## Cell.hash

```tact
Expand Down Expand Up @@ -367,6 +425,25 @@ let b: Builder = beginCell();
let fizz: Int = b.bits(); // 0
```

## Builder.depth

<Badge text="Available since Tact 1.6" variant="tip" size="medium"/><p/>

```tact
extends fun depth(self: Builder): Int;
```

Extension function for the [`Builder{:tact}`][builder].

Computes and returns the [`Int{:tact}`][int] [depth][std-repr] of the [`Builder{:tact}`][builder]. Produces $0$ if the [`Builder{:tact}`][builder] has no references stored so far, otherwise $1$ plus the maximum of the depths of the referenced cells.

Usage example:

```tact
let b: Builder = beginCell().storeInt(42, 7);
let depth: Int = b.depth;
```

## Builder.asSlice

```tact
Expand Down Expand Up @@ -527,6 +604,12 @@ let s: Slice = beginCell().storeInt(42, 7).asSlice();
let fizz: Slice = s.preloadBits(7);
```

:::note

In order to reduce gas usage, prefer using this function over calling [`Slice.firstBits(){:tact}`](#slicefirstbits) since the latter is less optimized.

:::

## Slice.skipBits

```tact
Expand All @@ -549,6 +632,30 @@ s.skipBits(5); // all but first 5 bits
let fizz: Slice = s.loadBits(1); // load only 1 bit
```

## Slice.skipLastBits

<Badge text="Available since Tact 1.6" variant="tip" size="medium"/><p/>

```tact
extends fun skipLastBits(self: Slice, len: Int);
```

Extension function for the [`Slice{:tact}`][slice].

Preloads all but the last $0 ≤$ `len` $≤ 1023$ bits from the [`Slice{:tact}`][slice].

Attempts to specify an out-of-bounds `len` value throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.

Attempts to preload more data than [`Slice{:tact}`][slice] contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.

Usage example:

```tact
let s: Slice = beginCell().storeInt(42, 7).asSlice();
let allButLastFive: Slice = s.skipLastBits(5); // all but last 5 bits,
// i.e. only first 2
```

## Slice.loadBool

```tact
Expand Down Expand Up @@ -727,6 +834,106 @@ let s: Slice = beginCell().storeRef(emptyCell()).asSlice();
let fizz: Int = s.bits();
```

## Slice.firstBits

<Badge text="Available since Tact 1.6" variant="tip" size="medium"/><p/>

```tact
extends fun firstBits(self: Slice, len: Int): Slice;
```

Extension function for the [`Slice{:tact}`][slice].

Preloads the first $0 ≤$ `len` $≤ 1023$ bits from the [`Slice{:tact}`][slice].

Attempts to specify an out-of-bounds `len` value throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.

Attempts to preload more data than [`Slice{:tact}`][slice] contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.

Usage example:

```tact
let s: Slice = beginCell().storeInt(42, 7).asSlice();
let firstFive: Slice = s.firstBits(5); // first 5 bits
```

:::note

In order to reduce gas usage, prefer calling [`Slice.preloadBits(){:tact}`](#slicepreloadbits) over using this function since the former is more optimized.

:::

## Slice.lastBits

<Badge text="Available since Tact 1.6" variant="tip" size="medium"/><p/>

```tact
extends fun lastBits(self: Slice, len: Int): Slice;
```

Extension function for the [`Slice{:tact}`][slice].

Preloads the last $0 ≤$ `len` $≤ 1023$ bits from the [`Slice{:tact}`][slice].

Attempts to specify an out-of-bounds `len` value throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.

Attempts to preload more data than [`Slice{:tact}`][slice] contains throw an exception with [exit code 9](/book/exit-codes#9): `Cell underflow`.

Usage example:

```tact
let s: Slice = beginCell().storeInt(42, 7).asSlice();
let lastFive: Slice = s.lastBits(5); // last 5 bits
```

## Slice.depth

<Badge text="Available since Tact 1.6" variant="tip" size="medium"/><p/>

```tact
extends fun depth(self: Slice): Int;
```

Extension function for the [`Slice{:tact}`][slice].

Computes and returns the [`Int{:tact}`][int] [depth][std-repr] of the [`Slice{:tact}`][slice]. Produces $0$ if the [`Slice{:tact}`][slice] has no references, otherwise $1$ plus the maximum of the depths of the referenced cells.

Usage example:

```tact
let s: Slice = beginCell().storeInt(42, 7).asSlice();
let depth: Int = s.depth;
```

## Slice.computeDataSize

<Badge text="Available since Tact 1.6" variant="tip" size="medium"/><p/>

```tact
extends fun computeDataSize(self: Slice, maxCells: Int): DataSize;
```

Extension function for the [`Slice{:tact}`][slice]. Similar to [`Cell.computeDataSize(){:tact}`](#cellcomputedatasize), but doesn't take into account the cell that contains the [`Slice{:tact}`][slice] itself. However, accounts for its bits and refs.

If the specified `maxCells` value isn't enough to traverse all cells **not** including the starting one, an exception with [exit code 8](/book/exit-codes#8) is thrown: `Cell overflow`.

Attempts to specify a negative value of `maxCells` throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.

Usage example:

```tact
let s: Slice = beginCell().storeInt(42, 7).storeRef(emptyCell()).asSlice();
try {
let dataSize: DataSize = s.computeDataSize(1);
dataSize.cells; // 1
dataSize.bits; // 7
dataSize.refs; // 1
} catch (exitCode) {
// if maxCells was insufficient to traverse the cell
// and all of its references, the exitCode here would be 8
}
```

## Slice.empty

```tact
Expand Down Expand Up @@ -1129,3 +1336,5 @@ fun cautiousParse(payload: Slice): TripleAxe? {

[tlb]: https://docs.ton.org/develop/data-formats/tl-b-language
[sha-2]: https://en.wikipedia.org/wiki/SHA-2#Hash_standard
[dfs]: https://en.wikipedia.org/wiki/Depth-first_search
[gas]: https://docs.ton.org/v3/documentation/smart-contracts/transaction-fees/fees#gas
27 changes: 16 additions & 11 deletions docs/src/content/docs/ref/core-common.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ title: Common
description: "Commonly used global static functions from the Core library of Tact"
---

import { Badge } from '@astrojs/starlight/components';

List of the most commonly used built-in [global static functions](/book/functions#global-static-functions).

## Contextual
Expand Down Expand Up @@ -125,6 +127,10 @@ Creates a new [`Address{:tact}`][p] based on the [`chain` id](https://ton-blockc

This function tries to resolve constant values in [compile-time](/ref/core-comptime) whenever possible.

Attempts to specify an invalid `chain` ID (not $-1$ or $0$) throw an exception with [exit code 136](/book/exit-codes#136): `Invalid address`.

Attempts to specify an `chain` ID pointing to the masterchain ($-1$) without [masterchain support](/book/masterchain) enabled throw an exception with [exit code 137](/book/exit-codes#137): `Masterchain support is not enabled for this contract`.

Usage example:

```tact
Expand All @@ -136,12 +142,6 @@ let oldTonFoundationAddr: Address =
// chain id: 0 is a workchain, -1 is a masterchain
```

:::caution

This method throws an error with [exit code 136](/book/exit-codes#136) if `chain` is invalid or with [exit code 137](/book/exit-codes#137) if `chain` points to the masterchain ($-1$) without [masterchain support](/book/masterchain) enabled.

:::

:::note[Useful links:]

[`chain` (Workchain ID) in TON Docs](https://docs.ton.org/learn/overviews/addresses#workchain-id)\
Expand Down Expand Up @@ -172,23 +172,28 @@ fun contractAddressExt(chain: Int, code: Cell, data: Cell): Address;

Computes smart contract's [`Address{:tact}`][p] based on the `chain` id, contract's `code` and contract's initial state `data`. Use [`initOf{:tact}`](/book/expressions#initof) expression to obtain initial `code` and initial `data` of a given contract.

Attempts to specify an invalid `chain` ID (not $-1$ or $0$) throw an exception with [exit code 136](/book/exit-codes#136): `Invalid address`.

Attempts to specify an `chain` ID pointing to the masterchain ($-1$) without [masterchain support](/book/masterchain) enabled throw an exception with [exit code 137](/book/exit-codes#137): `Masterchain support is not enabled for this contract`.

Usage example:

```tact
let initPkg: StateInit = initOf SomeContract();
let hereBeDragons: Address = contractAddressExt(0, initPkg.code, initPkg.data);
```

:::caution
### addressNone

This method throws an error with [exit code 136](/book/exit-codes#136) if `chain` is invalid or with [exit code 137](/book/exit-codes#137) if `chain` points to the masterchain ($-1$) without [masterchain support](/book/masterchain) enabled.
<Badge text="Available since Tact 1.6" variant="tip" size="medium"/><p/>

:::
```tact
fun addressNone(): Address?;
```

:::note

For this function to work, the compiler option `debug` has to be set to `true{:tact}` for the current project in the [configuration file](/book/config).\
Read more about debugging on the dedicated page: [Debugging](/book/debug).
TODO: awaits resolution of [those comments](https://github.com/tact-lang/tact/pull/986#discussion_r1865450023).

:::

Expand Down
6 changes: 3 additions & 3 deletions docs/src/content/docs/ref/core-math.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ fun sqrt(num: Int): Int;

Computes the [square root](https://en.wikipedia.org/wiki/Square_root) of the [`Int{:tact}`][int] value `num`. Returns the result rounded to the nearest integer. If there are two equally close integers, rounding is done toward the even one.

Attempts to specify negative value of `num` throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Attempts to specify a negative value of `num` throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.

Usage examples:

Expand Down Expand Up @@ -160,7 +160,7 @@ Computes and returns the [rounded down][round-down] result of `(x * y) / z{:tact

If the value in calculation goes beyond the range from $-2^{256}$ to $2^{256} - 1$ inclusive, an exception with [exit code 4](/book/exit-codes#4) is thrown: `Integer overflow`.

Attempts to specify negative value of `z` throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.
Attempts to specify a negative value of `z` throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`.

Usage examples:

Expand Down Expand Up @@ -300,7 +300,7 @@ contract Example {

:::note

Note, that if you only need to obtain powers of $2$, use the [`pow2(){:tact}`](#pow2) function, as it's more gas-efficient.
If you only need to obtain powers of $2$, use the [`pow2(){:tact}`](#pow2) function, as it's more gas-efficient.

:::

Expand Down

0 comments on commit 8453507

Please sign in to comment.