diff --git a/pages/book/integers.mdx b/pages/book/integers.mdx index d14f68da..b37191a2 100644 --- a/pages/book/integers.mdx +++ b/pages/book/integers.mdx @@ -52,7 +52,7 @@ Therefore, the amount of $1.25$ Toncoin, which can be represented in Tact as [`t ## Serialization -When encoding `Int{:tact}` values to persistent state (fields of [contracts](/book/contracts) and [traits](/book/types#traits)), it's usually better to use smaller representations than $257$-bits to reduce [storage costs](https://docs.ton.org/develop/smart-contracts/fees#storage-fee). Usage of such representations is also called "serialization" due to them representing the native [TL-B](https://docs.ton.org/develop/data-formats/tl-b-languagehttps://docs.ton.org/develop/data-formats/tl-b-language) types which TON Blockchain operates on. +When encoding `Int{:tact}` values to persistent state (fields of [contracts](/book/contracts) and [traits](/book/types#traits)), it's usually better to use smaller representations than $257$-bits to reduce [storage costs](https://docs.ton.org/develop/smart-contracts/fees#storage-fee). Usage of such representations is also called "serialization" due to them representing the native [TL-B][tlb] types which TON Blockchain operates on. The persistent state size is specified in every declaration of a state variable after the `as{:tact}` keyword: @@ -88,25 +88,64 @@ Motivation is very simple: ### Serialization types -Name | Inclusive range | Space taken -:--------------- | :-------------------------: | :------------------------: -`uint8{:tact}` | $0$ to $2^{8} - 1$ | 8 bit = 1 byte -`uint16{:tact}` | $0$ to $2^{16} - 1$ | 16 bit = 2 bytes -`uint32{:tact}` | $0$ to $2^{32} - 1$ | 32 bit = 4 bytes -`uint64{:tact}` | $0$ to $2^{64} - 1$ | 64 bit = 8 bytes -`uint128{:tact}` | $0$ to $2^{128} - 1$ | 128 bit = 16 bytes -`uint256{:tact}` | $0$ to $2^{256} - 1$ | 256 bit = 32 bytes -`int8{:tact}` | $-2^{7}$ to $2^{7} - 1$ | 8 bit = 1 byte -`int16{:tact}` | $-2^{15}$ to $2^{15} - 1$ | 16 bit = 2 bytes -`int32{:tact}` | $-2^{31}$ to $2^{31} - 1$ | 32 bit = 4 bytes -`int64{:tact}` | $-2^{63}$ to $2^{63} - 1$ | 64 bit = 8 bytes -`int128{:tact}` | $-2^{127}$ to $2^{127} - 1$ | 128 bit = 16 bytes -`int256{:tact}` | $-2^{255}$ to $2^{255} - 1$ | 256 bit = 32 bytes -`int257{:tact}` | $-2^{256}$ to $2^{256} - 1$ | 257 bit = 32 bytes + 1 bit -`coins{:tact}` | $0$ to $2^{120} - 1$ | 120 bit = 15 bytes +Name | [TL-B][tlb] | Inclusive range | Space taken +:--------------: | :-------------------------: | :-------------------------: | :------------------------: +`uint8{:tact}` | [`uint8`][tlb-builtin] | $0$ to $2^{8} - 1$ | $8$ bits = $1$ byte +`uint16{:tact}` | [`uint16`][tlb-builtin] | $0$ to $2^{16} - 1$ | $16$ bits = $2$ bytes +`uint32{:tact}` | [`uint32`][tlb-builtin] | $0$ to $2^{32} - 1$ | $32$ bits = $4$ bytes +`uint64{:tact}` | [`uint64`][tlb-builtin] | $0$ to $2^{64} - 1$ | $64$ bits = $8$ bytes +`uint128{:tact}` | [`uint128`][tlb-builtin] | $0$ to $2^{128} - 1$ | $128$ bits = $16$ bytes +`uint256{:tact}` | [`uint256`][tlb-builtin] | $0$ to $2^{256} - 1$ | $256$ bits = $32$ bytes +`int8{:tact}` | [`int8`][tlb-builtin] | $-2^{7}$ to $2^{7} - 1$ | $8$ bits = $1$ byte +`int16{:tact}` | [`int16`][tlb-builtin] | $-2^{15}$ to $2^{15} - 1$ | $16$ bits = $2$ bytes +`int32{:tact}` | [`int32`][tlb-builtin] | $-2^{31}$ to $2^{31} - 1$ | $32$ bits = $4$ bytes +`int64{:tact}` | [`int64`][tlb-builtin] | $-2^{63}$ to $2^{63} - 1$ | $64$ bits = $8$ bytes +`int128{:tact}` | [`int128`][tlb-builtin] | $-2^{127}$ to $2^{127} - 1$ | $128$ bits = $16$ bytes +`int256{:tact}` | [`int256`][tlb-builtin] | $-2^{255}$ to $2^{255} - 1$ | $256$ bits = $32$ bytes +`int257{:tact}` | [`int257`][tlb-builtin] | $-2^{256}$ to $2^{256} - 1$ | $257$ bits = $32$ bytes + $1$ bit +`coins{:tact}` | [`VarUInteger 16`][varuint] | $0$ to $2^{120} - 1$ | between $4$ and $124$ bits, [see below](#serialization-coins) + +### Variable `coins` type [#serialization-coins] + +In Tact, `coins{:tact}` is an alias to [`VarUInteger 16`][varuint] in [TL-B][tlb] representation, i.e. it takes a variable bit length depending on the optimal number of bytes needed to store the given integer and is commonly used for storing [nanoToncoin](/book/integers#nanotoncoin) amounts. + +This serialization format consists of two [TL-B fields](https://docs.ton.org/develop/data-formats/tl-b-language#field-definitions): + +* `len`, a $4$-bit unsigned big-endian integer storing the byte length of the value provided +* `value`, a $8 * len$-bit unsigned big-endian representation of the value provided + +That is, integers serialized as `coins{:tact}` occupy between $4$ and $124$ bits ($4$ bits for `len` and $0$ to $15$ bytes for `value`) and have values in the inclusive range from $0$ to $2^{120} - 1$. + +Examples: + +```tact +struct Scrooge { + // len: 0000, 4 bits (always) + // value: none! + // in total: 4 bits + a: Int as coins = 0; // 0000 + + // len: 0001, 4 bits + // value: 00000001, 8 bits + // in total: 12 bits + b: Int as coins = 1; // 0001 00000001 + + // len: 0010, 4 bits + // value: 00000001 00000010, 16 bits + // in total: 20 bits + c: Int as coins = 258; // 0010 00000001 00000010 + + // len: 1111, 4 bits + // value: hundred twenty 1's in binary + // in total: 124 bits + d: Int as coins = pow(2, 120) - 1; // hundred twenty 1's in binary +} +``` + Read more on serialization here: [Compatibility with FunC](/book/func#convert-serialization) + ## Operations @@ -139,3 +178,7 @@ Here, `oneByte` is serialized as a [`uint8`](#serialization-types), which occupi Therefore, be **very** careful with numbers and always double-check calculations when using serialization. + +[tlb]: https://docs.ton.org/develop/data-formats/tl-b-languagehttps://docs.ton.org/develop/data-formats/tl-b-language +[tlb-builtin]: https://docs.ton.org/develop/data-formats/tl-b-language#built-in-types +[varuint]: https://docs.ton.org/develop/data-formats/msg-tlb#varuinteger-n diff --git a/pages/ref/core-cells.mdx b/pages/ref/core-cells.mdx index 1ad46d3c..0ebad2eb 100644 --- a/pages/ref/core-cells.mdx +++ b/pages/ref/core-cells.mdx @@ -125,7 +125,7 @@ extends fun storeCoins(self: Builder, value: Int): Builder; Extension function for the [`Builder{:tact}`][p]. -Stores (serializes) an unsigned [`Int{:tact}`][int] `value` in the range $0 .. 2^{120} − 1$ into the copy of the [`Builder{:tact}`][p]. The serialization of `value` consists of a 4-bit unsigned big-endian integer $l$, which is the smallest integer $l ≥ 0$, such that `value` $< 2^{8 * l}$, followed by an $8 * l$-bit unsigned big-endian representation of `value`. If `value` does not belong to the supported range, a range check exception is thrown. Returns that copy of the [`Builder{:tact}`][p]. +Stores (serializes) an unsigned [`Int{:tact}`][int] `value` in the range $0 .. 2^{120} − 1$ into the copy of the [`Builder{:tact}`][p]. The serialization of `value` consists of a $4$-bit unsigned big-endian integer $l$, which is the smallest integer $l ≥ 0$, such that `value` $< 2^{8 * l}$, followed by an $8 * l$-bit unsigned big-endian representation of `value`. If `value` does not belong to the supported range, a range check exception is thrown. Returns that copy of the [`Builder{:tact}`][p]. Attempts to store an out-of-bounds `value` throw an exception with [exit code 5](/book/exit-codes#5): `Integer out of expected range`. @@ -138,6 +138,13 @@ let b: Builder = beginCell(); let fizz: Builder = b.storeCoins(42); ``` + + + **Useful links:**\ + [Special `coins` serialization type](/book/integers#serialization-coins) + + + ## Builder.storeAddress ```tact @@ -470,7 +477,7 @@ extends mutates fun loadCoins(self: Slice): Int; Extension mutation function for the [`Slice{:tact}`][p]. -Loads and returns [serialized](#builderstorecoins) an unsigned [`Int{:tact}`][int] value in the range $0 .. 2^{120} - 1$ from the [`Slice{:tact}`][p]. This values usually represents the amount in [nanoToncoins](/book/integers#nanotoncoin). +Loads and returns [serialized](#builderstorecoins) an unsigned [`Int{:tact}`][int] value in the range $0 .. 2^{120} - 1$ from the [`Slice{:tact}`][p]. This value usually represents the amount in [nanoToncoins](/book/integers#nanotoncoin). Attempts to load such [`Int{:tact}`][int] when [`Slice{:tact}`][p] doesn't contain it throw an exception with [exit code 8](/book/exit-codes#8): `Cell overflow`. @@ -483,6 +490,13 @@ let s: Slice = beginCell().storeCoins(42).asSlice(); let fizz: Int = s.loadCoins(); ``` + + + **Useful links:**\ + [Special `coins` serialization type](/book/integers#serialization-coins) + + + ## Slice.loadAddress ```tact