diff --git a/docs/contribute/hacktoberfest.mdx b/docs/contribute/hacktoberfest.mdx new file mode 100644 index 0000000000..ff9fdbbcc3 --- /dev/null +++ b/docs/contribute/hacktoberfest.mdx @@ -0,0 +1,30 @@ +# Hack-TON-berfest + +Hacktoberfest is a month-long global celebration of open source software run by DigitalOcean in partnership with Intel, AppWrite, and DeepSource, with a strong focus on encouraging contributions to open source projects. + + +
+ tlb structure +
+ + +Here are main concepts of this event: + +* **Hacktoberfest is open to everyone**. +* Four quality pull requests must be submitted to public GitHub/GitLab repositories. +* You can sign up anytime between October 1 and October 31. + + +## What the hype? + +In the TON ecosystem we have own leaderboards and more participants we will have the more prizes pool will be! + +Prizes include: +* **Limited edition T-short** with TON branding +* **TON Hacktoberfest NFT** for every participant! +* **Prize in TON** for the most important contributions + +## FAQ + +Please, visit the main event page to see the FAQ answers: +* https://hacktoberfest.digitalocean.com/faq \ No newline at end of file diff --git a/static/img/docs/hacktoberfest.webp b/static/img/docs/hacktoberfest.webp new file mode 100644 index 0000000000..460d9026e3 Binary files /dev/null and b/static/img/docs/hacktoberfest.webp differ diff --git a/versioned_docs/version-1.0.0/contribute/README.md b/versioned_docs/version-1.0.0/contribute/README.md new file mode 100644 index 0000000000..4e14893523 --- /dev/null +++ b/versioned_docs/version-1.0.0/contribute/README.md @@ -0,0 +1,65 @@ +# How to Contribute + +## Identify an area to Contribute to + +There are several ways to identify an area where you can contribute to the Wiki: + +- The easiest is to reach out to one of the [Docs maintainers](/contribute/maintainers) + saying "I want to help contribute to the TON Docs". They’ll work with you to find + an area for you to contribute. +- If you have a specific contribution in mind but are unsure about it, confirm whether + the contribution is appropriate by contacting one of the [Docs maintainers](/contribute/maintainers) directly. +- See questions that often asked in TON Developers Chats. +- Feel free to read the issues in the GitHub repository. + +## TL;DR + +- If you need to add or change anything in TON Docs raise a PR + against the `main` branch. +- The documentation team will review the PR or reach out accordingly. +- Repository: https://github.com/SwiftAdviser/ton-docs + +## Development + +### Online one-click setup for contributing + +You can use Gitpod (a free, online, VS Code-like IDE) for contributing. With a single click, it will launch a workspace and automatically: + +* clone the docusaurus repo. +* install the dependencies. +* run `yarn start` +* So that you can start contributing straight away. + +[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/SwiftAdviser/ton-docs) + +:::tip + +If you are adding a new document, it is recommended to just have a basic summary/introduction and a link to your github or documentation for more details. + +::: + +### Code Conventions + +- **Most important**: Look around. Match the style you see used in the rest of the project. This includes formatting, naming files, naming things in code, naming things in documentation, etc. +- "Attractive" +- **For documentation**: Do not wrap lines at 80 characters - configure your editor to soft-wrap when editing documentation. + +Don't worry too much about styles in general—the maintainers will help you fix them as they review your code. + + + +### Pull Requests + +So you have decided to contribute code back to upstream by opening a pull request. You've invested a good chunk of time, and we appreciate it. We will do our best to work with you and get the PR looked at. + +Please make sure the following is done when submitting a pull request: + +1. **Keep your PR small**. Small pull requests (~300 lines of diff) are much easier to review and more likely to get merged. Make sure the PR does only one thing, otherwise please split it. +2. **Use descriptive titles**. It is recommended to follow commit message style. +3. **Test your changes**. Describe your test plan in your pull request description. + +All pull requests should be opened against the `main` branch. + +## What Happens Next? + +The TON Docs team will be monitoring for pull requests. Do help us by keeping pull requests consistent by following the guidelines above. \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/contribute/maintainers.md b/versioned_docs/version-1.0.0/contribute/maintainers.md new file mode 100644 index 0000000000..cfada8944f --- /dev/null +++ b/versioned_docs/version-1.0.0/contribute/maintainers.md @@ -0,0 +1,22 @@ +# Maintainers + + +## Active Team + +Current members of the TON Docs team are listed in alphabetical order below. + +### SwiftAdviser + +* Telegram: [@SwiftAdviser](https://t.me/SwiftAdviser) +* GitHub: [SwiftAdviser](https://github.com/SwiftAdviser) + + +## Acknowledgements + +TON Docs was originally created by [tolya-yanot](https://github.com/tolya-yanot) and [EmelyanenkoK](https://github.com/EmelyanenkoK). + +We’d like to recognize a few people who have made significant contributions to TON Docs in the past and have helped maintain and develop them: + +- [tolya-yanot](https://example.com) +- [EmelyanenkoK](https://example.com) +- [Tal Kol](https://example.com) \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/func/FAQ.md b/versioned_docs/version-1.0.0/develop/func/FAQ.md new file mode 100644 index 0000000000..3741e6483b --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/func/FAQ.md @@ -0,0 +1,2 @@ +# FAQ +Ask your questions in [github issues](https://github.com/ton-blockchain/docs) and they will appear here. diff --git a/versioned_docs/version-1.0.0/develop/func/builtins.md b/versioned_docs/version-1.0.0/develop/func/builtins.md new file mode 100644 index 0000000000..42f7f4c94e --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/func/builtins.md @@ -0,0 +1,22 @@ +# Built-ins +This section describes some language constructions which are less fundamental that ones described in previous sections. They could be defined in [stdlib.fc](/develop/func/stdlib.md), but it would leave less room for FunC optimizer. + +## Throwing exceptions +Exceptions can be thrown by conditional primitives `throw_if` and `throw_unless` and by unconditional `throw`. The first argument is the error code, the second is the condition (`throw` has only one argument). + +Currently FunC doesn't support catching exceptions, unless an exception handler is set with low-level TVM primitives. The primary purpose of described primitives is reverting transactions which don't satisfy some mandatory conditions (like `require` and `revert` in Solidity programming language). + +## Booleans +- `true` is alias for `-1` +- `false` is alias for `0` + +## Dump variable +Variable can be dumped to debug log by `~dump` function. + +## Integer operations +- `muldiv` is multiple-then-divide operation. Intermediate result is stored in 513-bit integer, so it won't overflow if the actual result fits into 257-bit integer. + +## Other primitives +- `null?` checks whether the argument is `null`. By the value `null` of TVM type `Null` FunC represents absence of a value of some atomic type, see [null values](/develop/func/types#null-values). +- `touch` and `~touch` move a variable to the top of the stack +- `at` gets the value of component of a tuple on specified position diff --git a/versioned_docs/version-1.0.0/develop/func/comments.md b/versioned_docs/version-1.0.0/develop/func/comments.md new file mode 100644 index 0000000000..c72e7ef6d5 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/func/comments.md @@ -0,0 +1,14 @@ +# Comments +FunC has single-line comments, which start with `;;` (double `;`). + +For example: +```cpp +int x = 1; ;; assign 1 to x +``` + +It also has multi-line comments, which start with `{-` and end with `-}`. Note that unlike in many other languages, FunC multi-line comments can be nested. For example: +```cpp +{- This is a multi-line comment + {- this is a comment in the comment -} +-} +``` diff --git a/versioned_docs/version-1.0.0/develop/func/compiler_directives.md b/versioned_docs/version-1.0.0/develop/func/compiler_directives.md new file mode 100644 index 0000000000..07a9301599 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/func/compiler_directives.md @@ -0,0 +1,46 @@ +# Compiler directives +Those are keywords that start with `#` and instruct compiler to do some actions, checks or adjust parameters. + +Those directives can be used only at the outermost level (not inside any function definition). + +## #include +The `#include` directive allows to include another FunC source code file that will be parsed at the place of include. + +Syntax is `#include "filename.fc";`. Files are automatically checked against re-inclusion and attempting to include +a file more than once would be silently ignored by default, with warning if verbosity level is no lower than 2. + +If an error happens during parsing of included file additionally a stack of inclusions is printed with locations +of each include in chain. + +## #pragma +The `#pragma` directive is the method for providing additional information to the compiler, beyond what is conveyed +in the language itself. + +### #pragma version +Version pragma is used to enforce specific version of FunC compiler when compiling the file. + +Version is specified in semver format, that is `a.b.c`, where `a` is major version, `b` is minor, and `c` is patch. + +There are several comparison operators available for the developer: +* `a.b.c` or `=a.b.c` - requires exactly the `a.b.c` version of the compiler, +* `>a.b.c` - requires compiler version to be higher than `a.b.c`, + * `>=a.b.c` - requires compiler version to be higher or equal to `a.b.c`, +* ``, `>=`, `<`, `<=`) short format assumes zeros in omitted parts, that is: +* `>a.b` is same as `>a.b.0` (and therefore does NOT match `a.b.0` version), +* `<=a` is same as `<=a.0.0` (and therefore does NOT match `a.0.1` version), +* `^a.b.0` is **NOT** the same as `^a.b`. + +For example, `^a.1.2` matches `a.1.3` but not `a.2.3` or `a.1.0`, however, `^a.1` matches them all. + +This directive may be used multiple times, the compiler version must satisfy all the provided conditions. + +### #pragma not-version +The syntax of this pragma is same as the version pragma, but it fails if the condition is satisfied. + +It can be used for blacklisting a specific version known to have problems, for example. \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/func/functions.md b/versioned_docs/version-1.0.0/develop/func/functions.md new file mode 100644 index 0000000000..74858fb5f8 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/func/functions.md @@ -0,0 +1,180 @@ +# Functions +FunC program is essentially a list of function declarations/definitions and global variable declarations. This section covers the first topic. + +Any function declaration or definition starts with a common pattern, and then one of the three things follows: +- single `;`, which means that the function is declared, but not defined yet. It may be defined later in the same file, or in some other file, which is passed before the current one to the FunC compiler. + + For example, + ```cpp + int add(int x, int y); + ``` + is a simple declaration of a function named `add` of type `(int, int) -> int`. +- assembler function body definition. It is the way to define functions by low-level TVM primitives for later use in FunC program. + For example, + ```cpp + int add(int x, int y) asm "ADD"; + ``` + is an assembler definition of the same function `add` of type `(int, int) -> int`, which will translate to the TVM opcode `ADD`. + +- ordinary block statement function body definition. It is the usual way to define functions. + For example, + ```cpp + int add(int x, int y) { + return x + y; + } + ``` + is an ordinary definition of the `add` function. + +## Function declaration +As said before, any function declaration or definition starts with a common pattern. The pattern is following: +```cpp +[] () +``` +where `[ ... ]` correspond to an optional entry. + +### Function name +Function name can be any [identifier](/develop/func/literals_identifiers#identifiers) and also it can start with `.` or `~` symbols. The meaning of those symbols is [explained](/develop/func/statements#methods-calls) in statements section. + +For example, `udict_add_builder?`, `dict_set` and `~dict_set` are valid and different function names (they are defined in [stdlib.fc](/develop/func/stdlib.md)). + +#### Special function names +FunC (actually Fift assembler) has several reserved function names with predefined [ids](/develop/func/functions#method_id). +- `main` and `recv_internal` have id = 0 +- `recv_external` has id = -1 +- `run_ticktock` has id = -2 + +Every program must have a function with id 0, that is `main` or `recv_internal` function. + +`recv_internal` is called when smart contract receives an inbound internal message, `recv_external` is for inbound external messages and `run_ticktock` is called in ticktock transactions of special smart contracts. + + +### Return type +Return type can be any atomic or composite type, as [types](/develop/func/types.md) section describes. For example, +```cpp +int foo(); +(int, int) foo'(); +[int, int] foo''(); +(int -> int) foo'''(); +() foo''''(); +``` +are valid functions declarations. +Type inference is also allowed. For example, +```cpp +_ pyth(int m, int n) { + return (m * m - n * n, 2 * m * n, m * m + n * n); +} +``` +is a valid definition of function `pyth` of type `(int, int) -> (int, int, int)`, which computes Pythagorean triples. + +### Function arguments +Function arguments are separated by commas. Valid declarations of an argument are following: +- Ordinary declaration: type + name. For example, `int x` is a declaration of argument of type `int` and name `x` in function declaration `() foo(int x);`. +- Unused argument declaration: only type. For example, + ```cpp + int first(int x, int) { + return x; + } + ``` + is a valid function definition of type `(int, int) -> int`. +- Argument with inferred type declaration: only name. + For example, + ```cpp + int inc(x) { + return x + 1; + } + ``` + is a valid function definition of type `int -> int`. The `int` type of `x` is inferred by type-checker. + +Note that although a function may look like a function of several arguments, it's actually a function of one [tensor-type](/develop/func/types#tensor-types) argument. To see the difference, please refer to [function application](/develop/func/statements#function-application). Nevertheless, the components of the argument tensor are conventionally called function arguments. + +### Specifiers +There are three types of specifiers: `impure`, `inline`/`inline_ref` and `method_id`. One, several or none of them can be put in function declaration, but currently they must be presented in the right order: for example, it is not allowed to put `impure` after `inline`. +#### Impure specifier +`impure` specifier means that the function can have some side effects which can't be ignored. For example, we should put `impure` specifier if the function can modify contract storage, send messages or throw an exception when some data is invalid and the function is intended to validate this data. + +If `impure` is not specified and the result of the function call is not used, then FunC compiler may and will delete this function call. + +For example, in [stdlib.fc](/develop/func/stdlib.md) function +```cpp +int random() impure asm "RANDU256"; +``` +is defined. `impure` is used because `RANDU256` changes the internal state of the random number generator. + +#### Inline specifier +If function has `inline` specifier, its code is actually substituted in every place where the function is called. Needless to say that recursive calls of inlined function are impossible. +#### Inline_ref specifier +Code of a function with `inline_ref` specifier is put into a separated cell and every time when the function is called a `CALLREF` command is executed by TVM. So it's similar to `inline`, but because a cell can be reused in several places without duplicating it, it is almost always more efficient in code size to use `inline_ref` specifier instead of `inline` unless the function is called exactly once. Recursive calls of `inline_ref`'ed functions are still impossible, because there is no cyclic references in TVM cells. +#### method_id +Every function in TVM program has an internal integer id by which it can be called. Ordinary functions are usually numbered by subsequent integers starting from 1, but get-methods of the contract are numbered by crc16 hashes of their name. `method_id()` specifier allows to set id of a function to specified value, and `method_id` uses the default value `(crc16() & 0xffff) | 0x10000`. If a function has `method_id` specifier, then it can be called in lite-client or ton-explorer as a get-method by its name. + +For example, +```cpp +(int, int) get_n_k() method_id { + (_, int n, int k, _, _, _, _) = unpack_state(); + return (n, k); +} +``` +is a get-method of multisig contract. + +### Polymorphism with forall +Before any function declaration or definition there can be `forall` type variables declarator. It has the following syntax: +```cpp +forall -> +``` +where type variable name can be any [identifier](/develop/func/literals_identifiers#identifiers). Usually they are named by capital letters though. + +For example, +```cpp +forall X, Y -> [Y, X] pair_swap([X, Y] pair) { + [X p1, Y p2] = pair; + return [p2, p1]; +} +``` +is a function that takes a tuple of length exactly 2, but with values of any (single stack entry) types in components, and swaps them with each other. + +`pair_swap([2, 3])` will produce `[3, 2]` and `pair_swap([1, [2, 3, 4]])` will produce `[[2, 3, 4], 1]`. + +In this example `X` and `Y` are [type variables](/develop/func/types#polymorphism-with-type-variables). When the function is called, type variables are substituted with actual types and the code of the function is executed. Note that although the function is polymorphic, the actual assembler code for it is the same for every type substitution. It is achieved essentially by polymorphism of stack manipulation primitives. Currently other forms of polymorphism (like ad-hoc polymorphism with type classes) are not supported. + +Also it is worth noticing that the type width of `X` and `Y` is supposed to be equal to 1, that is, the values of `X` or `Y` must occupy single stack entry. So you actually can't call the function `pair_swap` on a tuple of type `[(int, int), int]`, because type `(int, int)` has width 2, i.e. it occupies 2 stack entries. + +## Assembler function body definition +As mentioned above, function can be defined by assembler code. The syntax is an `asm` keyword followed by one or several assembler commands, represented as strings. +For example, one can define +```cpp +int inc_then_negate(int x) asm "INC" "NEGATE"; +``` +– function that increment an integer and then negates it. Calls of this function will be translated to 2 assembler commands `INC` and `NEGATE`. Alternative way to define the function is +```cpp +int inc_then_negate'(int x) asm "INC NEGATE"; +``` +`INC NEGATE` will be considered by FunC as one assembler command, but it is OK, because Fift assembler knows that it is 2 separate commands. + +:::info +The list of assembler commands can be found here: [TVM instructions](/learn/tvm-instructions/instructions). +::: + +### Rearranging stack entries +In some cases we want to pass arguments to assembler function is not exactly the same order as assembler command requires or/and take the result in different stack entries order than the command returns. We could manually rearrange the stack by adding corresponding stack primitives, but FunC can do it automatically. + +For example, suppose that assembler command `STUXQ` takes integer, builder and integer and returns builder along with integer flag, indicating success or failure of the operation. +We may define a function +```cpp +(builder, int) store_uint_quite(int x, builder b, int len) asm "STUXQ"; +``` +However, suppose we want to rearrange arguments. Then we can define +```cpp +(builder, int) store_uint_quite(builder b, int x, int len) asm(x b len) "STUXQ"; +``` +So you can indicate the required order of arguments after `asm` keyword. + +Also we can rearrange return values like this: +```cpp +(int, builder) store_uint_quite(int x, builder b, int len) asm( -> 1 0) "STUXQ"; +``` +The numbers correspond to indexes of returns values (0 is the deepest stack entry among returned values). + +Combining this techniques is also possible: +```cpp +(int, builder) store_uint_quite(builder b, int x, int len) asm(x b len -> 1 0) "STUXQ"; +``` diff --git a/versioned_docs/version-1.0.0/develop/func/global_variables.md b/versioned_docs/version-1.0.0/develop/func/global_variables.md new file mode 100644 index 0000000000..b781d8772d --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/func/global_variables.md @@ -0,0 +1,63 @@ +# Global variables +FunC program is essentially a list of function declarations/definitions and global variable declarations. This section covers the second topic. + +Global variable can be declared with `global` keyword followed by variable type and variable name. For example, +```cpp +global ((int, int) -> int) op; + +int check_assoc(int a, int b, int c) { + return op(op(a, b), c) == op(a, op(b, c)); +} + +int main() { + op = _+_; + return check_assoc(2, 3, 9); +} +``` +is a simple program that writes to a global functional variable `op` the addition operator `_+_` and checks the associativity of addition on three sample integers 2, 3 and 9. + +Internally global variables are stored in the c7 control register of TVM. + +Type of a global variable can be omitted. If so, it will be inferred by the usage of the variable. For example, we can rewrite the program as: +```cpp +global op; + +int check_assoc(int a, int b, int c) { + return op(op(a, b), c) == op(a, op(b, c)); +} + +int main() { + op = _+_; + return check_assoc(2, 3, 9); +} +``` + +It is possible to declare several variables after the same `global` keyword. The following codes are equivalent: +```cpp +global int A; +global cell B; +global C; +``` +```cpp +global int A, cell B, C; +``` + +It is not allowed to declare some local variable with the same name as an already declared global variable. For example, this code wouldn't compile: +```cpp +global cell C; + +int main() { + int C = 3; + return C; +} +``` +Note that this code is correct: +```cpp +global int C; + +int main() { + int C = 3; + return C; +} +``` +but here `int C = 3;` is equivalent to `C = 3;`, i.e. that is an assignment to global variable `C`, not a declaration of local variable `C` (you can find some explanation of this effect in [statements](/develop/func/statements#variable-declaration)). diff --git a/versioned_docs/version-1.0.0/develop/func/literals_identifiers.md b/versioned_docs/version-1.0.0/develop/func/literals_identifiers.md new file mode 100644 index 0000000000..d3667773c1 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/func/literals_identifiers.md @@ -0,0 +1,93 @@ +# Literals and Identifiers +## Number literals +FunC allows decimal and hexadecimal integer literals (leading zeros are allowed). + +For example, `0`, `123`, `-17`, `00987`, `0xef`, `0xEF`, `0x0`, `-0xfFAb`, `0x0001`, `-0`, `-0x0` are valid number literals. + +## String literals +Strings in FunC are quoted in double quotes `"` like `"this is a string"`. Special symbols like `\n` and multi-line strings are not supported. +Optionally string literals may specify type after them such as `"string"u`. + +The following strings types are supported: +* without type - used for asm function definitions and to define a slice const by ASCII string, +* `s` - defines a raw slice const by its contents (hex-encoded and optionally bit-padded), +* `a` - creates a slice const containing `MsgAddressInt` structure from specified address, +* `u` - creates an int const that corresponds to hex values of provided ASCII string, +* `h` - creates an int const that is first 32 bits of SHA256 hash of the string, +* `H` - creates an int const that is all 256 bits of SHA256 hash of the string, +* `c` - creates an int const that is crc32 value of the string. + +For example, following values result in the corresponding consts: +* `"string"` becomes `x{737472696e67}` slice const, +* `"abcdef"s` becomes `x{abcdef}` slice const, +* `"Ef8zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM0vF"a` becomes `x{9FE6666666666666666666666666666666666666666666666666666666666666667_}` slice const (`addr_std$10 anycast:none$0 workchain_id:int8=0xFF address:bits256=0x33...33`), +* `"NstK"u` becomes `0x4e73744b` int const, +* `"transfer(slice, int)"h` becomes `0x7a62e8a8` int const, +* `"transfer(slice, int)"H` becomes `0x7a62e8a8ebac41bd6de16c65e7be363bc2d2cbc6a0873778dead4795c13db979` int const, +* `"transfer(slice, int)"c` becomes `2235694568` int const. + +## Identifiers +FunC allows a really wide class of identifiers (functions and variables names). Namely, any (single-line) string which doesn't contain special symbols `;`, `,`, `(`, `)`, ` ` (space or tab), `~` and `.`, doesn't start as comment or string literal (with `"`), isn't a number literal, isn't an underscore `_` and isn't a keyword is a valid identifier (with the only exception that if it starts with `` ` ``, it must end with the same `` ` `` and can't contain any other `` ` `` except for this two). + +Also function names in function definitions may start with `.` or `~`. + +For example, those are valid identifier: +- `query`, `query'`, `query''` +- `elem0`, `elem1`, `elem2` +- `CHECK` +- `_internal_value` +- `message_found?` +- `get_pubkeys&signatures` +- `dict::udict_set_builder` +- `_+_` (the standard addition operator of type `(int, int) -> int` in prefix notation, although it is already defined) +- `fatal!` + +`'` at the end of the name of a variable is conventionally used when some modified version of the old value is introduced. For example, almost all modifying built-in primitives for hashmap manipulation (except ones with prefix `~`) take a hashmap and return a new version of the hashmap along with some other data, if necessary. It is convenient to name those values with the same name suffixed by `'`. + +Suffix `?` is usually used for boolean variables (TVM hasn't built-in type bool; bools are represented by integers: 0 is false and -1 is true) or for functions that returns some flag, usually indicating success of the operation (like `udict_get?` from [stdlib.fc](/develop/func/stdlib.md)). + +Those are not valid identifiers: +- `take(first)Entry` +- `"not_a_string` +- `msg.sender` +- `send_message,then_terminate` +- `_` + +Some more weird examples of valid identifiers: +- `123validname` +- `2+2=2*2` +- `-alsovalidname` +- `0xefefefhahaha` +- `{hehehe}` +- ``pa{--}in"`aaa`"`` + +Those also are not valid identifier: +- ``pa;;in"`aaa`"`` (because `;` is prohibited) +- `{-aaa-}` +- `aa(bb` +- `123` (it's a number) + +Also FunC has special type of identifiers, which quoted in back quotes `` ` ``. +In the quotes any symbols are allowed except for `\n` and the quotes themself. + +For example, `` `I'm a variable too` `` is a valid identifier, as well as `` `any symbols ; ~ () are allowed here...` `` + +## Constants +FunC allows to define compile-time constants that are substituted and precalculated during compilation. + +Constants are defined as `const optional-type identifier = value-or-expression;` + +`optional-type` can be used to force a specific type of constant and for better readability. + +As of now `int` and `slice` types are supported. + +`value-or-expression` can be a literal or a pre-computable expression of literals and constants. + +For example, constants can be defined as following: +* `const int101 = 101;` defines `int101` constant that is equivalent to numeric literal `101`, +* `const str1 = "const1", str2 = "aabbcc"s;` defines two constants that are equal to their corresponding strings, +* `const int int240 = ((int1 + int2) * 10) << 3;` defines `int240` constant that equals to the result of calculation, +* `const slice str2r = str2;` defines `str2r` constant that is equal to value of `str2` constant. + +Since numeric constants are substituted during compilation all optimization and pre-computations performed during +compilation are successfully performed (unlike old method defining constants via inline asm `PUSHINT`s). diff --git a/versioned_docs/version-1.0.0/develop/func/overview.md b/versioned_docs/version-1.0.0/develop/func/overview.md new file mode 100644 index 0000000000..fadd84bb8c --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/func/overview.md @@ -0,0 +1,39 @@ +# Overview + + +FunC is a domain-specific statically typed language. + +FunC programs are compiled into Fift assembler code, which generates corresponding bytecode for the TON Virtual Machine. + +Further this bytecode (actually a [tree of cells](/learn/overviews/Cells), like any other data in TON Blockchain) can be used for creating a smart contract in the blockchain or can be run on a local instance of TVM. + +You can find more information about FunC in [DOCUMENTATION](/develop/func/types) section. + +## Example + +Here is a simple data loaded written on FunC: + +```cpp +(slice, int) load_data() inline { + var ds = get_data().begin_parse(); + return ( + ds~load_msg_addr(), ;; owner_address + ds~load_uint(64) ;; counter + ); +} + +() save_data(slice owner_address, int counter) impure inline { + set_data(begin_cell() + .store_slice(owner_address) + .store_uint(counter, 64) + .end_cell()); +} +``` + +## Tutorials + +If you want to learn how to use FunC you can read the [SMART CONTRACTS](/develop/smart-contracts/) section. + +## Tools + +Find IDE plugins, SDK for FunC in the [Tools & SDK](/develop/tools) section. \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/func/statements.md b/versioned_docs/version-1.0.0/develop/func/statements.md new file mode 100644 index 0000000000..4ac8b68a9a --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/func/statements.md @@ -0,0 +1,310 @@ +# Statements +This sections briefly discusses FunC statements, constituting the code of ordinary functions bodies. + +## Expression statements +The most common type of statements is expression statement. It's an expression followed by `;`. Expressions description would be quite complicated, so only a sketch is presented here. + +### Variable declaration +It is not possible to declare a local variable without defining its initial value. + +Here are some examples of variables declarations: +```cpp +int x = 2; +var x = 2; +(int, int) p = (1, 2); +(int, var) p = (1, 2); +(int, int, int) (x, y, z) = (1, 2, 3); +(int x, int y, int z) = (1, 2, 3); +var (x, y, z) = (1, 2, 3); +(int x = 1, int y = 2, int z = 3); +[int, int, int] [x, y, z] = [1, 2, 3]; +[int x, int y, int z] = [1, 2, 3]; +var [x, y, z] = [1, 2, 3]; +``` + +Variable can be "redeclared" in the same scope. For example, this is a correct code: +```cpp +int x = 2; +int y = x + 1; +int x = 3; +``` +Actually the second occurrence of `int x` is not a declaration, but just a compile-time insurance that `x` has type `int`. So the third line is essentially equivalent to simple assignment `x = 3;`. + +And in nested scopes a variable can be truly redeclared just like in C language. For example, consider the code: +```cpp +int x = 0; +int i = 0; +while (i < 10) { + (int, int) x = (i, i + 1); + ;; here x is a variable of type (int, int) + i += 1; +} +;; here x is a (different) variable of type int +``` +But as mentioned in global variables [section](/develop/func/global_variables.md), global variable can't be redeclared. + +Note that variable declaration **is** an expression statement, so actually constructions like `int x = 2` are full-fledged expressions. For example, this is a correct code: +```cpp +int y = (int x = 3) + 1; +``` +It is a declaration of two variables `x` and `y`, equal to `3` and `4` correspondingly. +#### Underscore +Underscore `_` is used when a value is not needed. For example, suppose a function `foo` has type `int -> (int, int, int)`. We can get the first returned value and ignore the second and third like this: +```cpp +(int fst, _, _) = foo(42); +``` +### Function application +A call of a function looks like as such in a conventional language: arguments of the function call are listed after the function name, separated by commas. +```cpp +;; suppose foo has type (int, int, int) -> int +int x = foo(1, 2, 3); +``` + +But notice that `foo` is actually a function of **one** argument of type `(int, int, int)`. To see the difference, suppose `bar` is a function of type `int -> (int, int, int)`. Unlike in conventional languages, you can compose the functions like that: +```cpp +int x = foo(bar(42)); +``` +instead of equivalent, but more lengthy form: +```cpp +(int a, int b, int c) = bar(42); +int x = foo(a, b, c); +``` + +Also Haskell-style calls are possible, but not always (to be fixed later): +```cpp +;; suppose foo has type int -> int -> int -> int +;; i.e. it's carried +(int a, int b, int c) = (1, 2, 3); +int x = foo a b c; ;; ok +;; int y = foo 1 2 3; wouldn't compile +int y = foo (1) (2) (3); ;; ok +``` +### Lambda expressions +Lambda expressions are not supported yet. + +### Methods calls + +#### Non-modifying methods +If a function has at least one argument, it can be called as a non-modifying method. For example, `store_uint` has type `(builder, int, int) -> builder` (the second argument is value to store, and the third is the bit length). `begin_cell` is a function that creates a new builder. The following codes are equivalent: +```cpp +builder b = begin_cell(); +b = store_uint(b, 239, 8); +``` +```cpp +builder b = begin_cell(); +b = b.store_uint(239, 8); +``` +So the first argument of a function can be passed to it being located before the function name, if separated by `.`. The code can be further simplified: +```cpp +builder b = begin_cell().store_uint(239, 8); +``` +Multiple calls of methods are also possible: +```cpp +builder b = begin_cell().store_uint(239, 8) + .store_int(-1, 16) + .store_uint(0xff, 10); +``` +#### Modifying methods +If the first argument of a function has type `A` and return value of the function has the shape of `(A, B)` where `B` is some arbitrary type, then the function can be called as modifying method. Modifying methods calls may take some arguments and return some values, but they modify their first argument, that is, assign the first component of returned value to the variable from the first argument. For example, suppose `cs` is a cell slice and `load_uint` has type `(slice, int) -> (slice, int)`: it takes a cell slice and number of bits to load and returns the remainder of slice and the loaded value. The following codes are equivalent: +```cpp +(cs, int x) = load_uint(cs, 8); +``` +```cpp +(cs, int x) = cs.load_uint(8); +``` +```cpp +int x = cs~load_uint(8); +``` +In some cases we want to use a function as modifying method that doesn't return any value – only modifies the first argument. It can be done using unit type as following: suppose we want to define function `inc` of type `int -> int`, which increment an integer, and use it as modifying method. Then we should define `inc` as a function of type `int -> (int, ())`: +```cpp +(int, ()) inc(int x) { + return (x + 1, ()); +} +``` +When defined like that, it can be used as modifying method: +```cpp +x~inc(); +``` +will increment `x`. +#### `.` and `~` in function names +Suppose we want to use `inc` as non-modifying method too. We can write something like that: +```cpp +(int y, _) = inc(x); +``` +But it is possible to override the definition of `inc` as modifying method: +```cpp +int inc(int x) { + return x + 1; +} +(int, ()) ~inc(int x) { + return (x + 1, ()); +} +``` +and then call it like that: +```cpp +x~inc(); +int y = inc(x); +int z = x.inc(); +``` +The first call will modify x, the second and the third won't. + +In summary, when a function with name `foo` is called as non-modifying or modifying method (i.e. with `.foo` or `~foo` syntax), FunC compiler use the definition of `.foo` or `~foo` correspondingly if such definition is presented, and if not, it uses the definition of `foo`. + +### Operators +Note that currently all of unary and binary operators are integer operators. Logical operators are represented as bitwise integer operators (cf. [absene of boolean type](/develop/func/types#absence-of-boolean-type)). +#### Unary operators +There are two unary operators: +- `~` is bitwise not (priority 75). +- `-` is integer negation (priority 20). + +They should be separated from the argument. +- `- x` is ok. +- `-x` is not ok (it's a single identifier). + +#### Binary operators +With priority 30 (left-associative): +- `*` is integer multiplication +- `/` is integer division (floor) +- `~/` is integer division (round) +- `^/` is integer division (ceil) +- `%` is integer reduction by modulo (floor) +- `~%` is integer reduction by modulo (round) +- `^%` is integer reduction by modulo (ceil) +- `/%` returns the quotient and the remainder +- `&` is bitwise AND + +With priority 20 (left-associative): +- `+` is integer addition +- `-` is integer subtraction +- `|` is bitwise OR +- `^` is bitwise XOR + +With priority 17 (left-associative): +- `<<` is bitwise left shift +- `>>` is bitwise right shift +- `~>>` is bitwise right shift (round) +- `^>>` is bitwise right shift (ceil) + +With priority 15 (left-associative): +- `==` is integer equality check +- `!=` is integer inequality check +- `<` is integer comparison +- `<=` is integer comparison +- `>` is integer comparison +- `>=` is integer comparison +- `<=>` is integer comparison (returns -1, 0 or 1) + +They also should be separated from the argument: +- `x + y` is ok. +- `x+y` is not ok (it's a single identifier). + +#### Conditional operator +Has the usual syntax: +```cpp + ? : +``` +For example, +```cpp +x > 0 ? x * fac(x - 1) : 1; +``` +It has priority 13. + +#### Assignments +Priority 10. + +Simple assignment `=` and counterparts of binary operations: `+=`, `-=`, `*=`, `/=`, `~/=`, `^/=`, `%=`, `~%=`, `^%=`, `<<=`, `>>=`, `~>>=`, `^>>=`, `&=`, `|=`, `^=`. + +## Loops +FunC supports `repeat`, `while` and `do { ... } until` loops. `for` loop is not supported. +### Repeat loop +The syntax is a `repeat` keyword followed by an expression of type `int`. Repeats the code for specified number of times. Examples: +```cpp +int x = 1; +repeat(10) { + x *= 2; +} +;; x = 1024 +``` +```cpp +int x = 1, y = 10; +repeat(y + 6) { + x *= 2; +} +;; x = 65536 +``` +```cpp +int x = 1; +repeat(-1) { + x *= 2; +} +;; x = 1 +``` +If the number of times is less than `-2^31` or greater than `2^31 - 1`, range check exception is thrown. +### While loop +Has the usual syntax. Example: +```cpp +int x = 2; +while (x < 100) { + x = x * x; +} +;; x = 256 +``` +Note that the truth value of condition `x < 100` is of type `int` (cf. [absene of boolean type](/develop/func/types#absence-of-boolean-type)). + +### Until loop +Has the following syntax: +```cpp +int x = 0; +do { + x += 3; +} until (x % 17 == 0); +;; x = 51 +``` +## If statements +Examples: +```cpp +;; usual if +if (flag) { + do_something(); +} +``` +```cpp +;; equivalent to if (~ flag) +ifnot (flag) { + do_something(); +} +``` +```cpp +;; usual if-else +if (flag) { + do_something(); +} +else { + do_alternative(); +} +``` +```cpp +;; Some specific features +if (flag1) { + do_something1(); +} else { + do_alternative4(); +} +``` +The curly brackets are necessary. That code wouldn't be compiled: +```cpp +if (flag1) + do_something(); +``` + +## Block statements +Block statements are also allowed. They open a new nested scope: +```cpp +int x = 1; +builder b = begin_cell(); +{ + builder x = begin_cell().store_uint(0, 8); + b = x; +} +x += 1; +``` diff --git a/versioned_docs/version-1.0.0/develop/func/stdlib.md b/versioned_docs/version-1.0.0/develop/func/stdlib.md new file mode 100644 index 0000000000..ee79c4a2a9 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/func/stdlib.md @@ -0,0 +1,900 @@ +# FunC standard library + +:::info +This section discus the [stdlib.fc](https://github.com/ton-blockchain/ton/blob/master/crypto/smartcont/stdlib.fc) library with standard functions used in FunC. +::: + +Currently, the library is just a wrapper for most common assembler TVM commands, which aren't built-ins. Description of every TVM command used in the library can be found in [TVM documentation](https://ton-blockchain.github.io/tvm.pdf) (Appendix A). Some descriptions were borrowed into this document. + +Some functions are commented out in the file. It means that they have already become built-ins for optimization purposes. However, the type signature and semantics remain the same. + +Note that some less common commands are not presented in the stdlib. Someday they will also be added. + +## Tuple manipulation primitives +The names and the types are mostly self-explaining. See [polymorhism with forall](/develop/func/functions#polymorphism-with-forall) for more info on the polymorphic functions. + +Note that currently values of atomic type `tuple` can't be cast to composite tuple type (e.g. `[int, cell]`) and vise versa. + +### Lisp-style lists +Lists can be represented as nested 2-elements tuples. Empty list is conventionally represented as TVM `null` value (it can be obtained by calling `null()`). For example, tuple `(1, (2, (3, null)))` represents list `[1, 2, 3]`. Elements of a list can be of different types. +#### cons +```cpp +forall X -> tuple cons(X head, tuple tail) asm "CONS"; +``` +Adds an element to the beginning of lisp-style list. +#### uncons +```cpp +forall X -> (X, tuple) uncons(tuple list) asm "UNCONS"; +``` +Extracts the head and the tail of lisp-style list. +#### list_next +```cpp +forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS"; +``` +Extracts the tail and the head of lisp-style list. Can be used as [(non-)modifying method](/develop/func/statements#methods-calls). +```cpp +() foo(tuple xs) { + int x = xs.list_next(); ;; get the first element + int y = xs~list_next(); ;; pop the first element + int z = xs~list_next(); ;; pop the second element +} +``` +#### car +```cpp +forall X -> X car(tuple list) asm "CAR"; +``` +Returns the head of lisp-style list. +#### cdr +```cpp +tuple cdr(tuple list) asm "CDR"; +``` +Returns the tail of lisp-style list. +### Other tuple primitives +#### empty_tuple +```cpp +tuple empty_tuple() asm "NIL"; +``` +Creates 0-element tuple. +#### tpush +```cpp +forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; +forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; +``` +Appends a value `x` to a `Tuple t = (x1, ..., xn)`, but only if the resulting `Tuple t' = (x1, ..., xn, x)` is of length at most 255. Otherwise throws a type check exception. +#### single +```cpp +forall X -> [X] single(X x) asm "SINGLE"; +``` +Creates a singleton, i.e. a tuple of length one. +#### unsingle +```cpp +forall X -> X unsingle([X] t) asm "UNSINGLE"; +``` +Unpacks a singleton. +#### pair +```cpp +forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR"; +``` +Creates a pair. +#### unpair +```cpp +forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR"; +``` +Unpacks a pair. +#### triple +```cpp +forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE"; +``` +Creates a triple. + +#### untriple +```cpp +forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE"; +``` +Unpacks a triple. + +#### tuple4 +```cpp +forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE"; +``` +Creates 4-element tuple. + +#### untuple4 +```cpp +forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE"; +``` +Unpack 4-element tuple. + +#### first +```cpp +forall X -> X first(tuple t) asm "FIRST"; +``` +Returns the first element of a tuple. + +#### second +```cpp +forall X -> X second(tuple t) asm "SECOND"; +``` +Returns the second element of a tuple. + +#### third +```cpp +forall X -> X third(tuple t) asm "THIRD"; +``` +Returns the third element of a tuple. + +#### fourth +```cpp +forall X -> X fourth(tuple t) asm "3 INDEX"; +``` +Returns the fourth element of a tuple. + +#### pair_first +```cpp +forall X, Y -> X pair_first([X, Y] p) asm "FIRST"; +``` +Returns the first element of a pair. + +#### pair_second +```cpp +forall X, Y -> Y pair_second([X, Y] p) asm "SECOND"; +``` +Returns the second element of a pair. + +#### triple_first +```cpp +forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST"; +``` +Returns the first element of a triple. + +#### triple_second +```cpp +forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND"; +``` +Returns the second element of a triple. + +#### triple_third +```cpp +forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD"; +``` +Returns the third element of a triple. + +## Domain specific primitives +### Extracting info from c7 +Some useful information regarding smartcontract invocation can be found in [c7 special register](/learn/tvm-instructions/tvm_overview#control-registers). Those primitives serve for convenient data extraction. +#### now +```cpp +int now() asm "NOW"; +``` +Returns the current Unix time as an Integer +#### my_address +```cpp +slice my_address() asm "MYADDR"; +``` +Returns the internal address of the current smart contract as a Slice with a `MsgAddressInt`. If necessary, it can be parsed further using primitives such as `parse_std_addr`. +#### get_balance +```cpp +[int, cell] get_balance() asm "BALANCE"; +``` +Returns the remaining balance of the smart contract as a `tuple` consisting of an `int` (the remaining balance in nanotoncoins) and a `cell` (a dictionary with 32-bit keys representing the balance of “extra currencies”). Note that RAW primitives such as `send_raw_message` do not update this field. +#### cur_lt +```cpp +int cur_lt() asm "LTIME"; +``` +Returns the logical time of the current transaction. +#### block_lt +```cpp +int block_lt() asm "BLOCKLT"; +``` +Returns the starting logical time of the current +block. +#### config_param +```cpp +cell config_param(int x) asm "CONFIGOPTPARAM"; +``` +Returns the value of the global configuration parameter with integer index `i` as a `cell` or `null` value. +### Hashes +#### cell_hash +```cpp +int cell_hash(cell c) asm "HASHCU"; +``` +Computes the representation hash of a `cell c` and returns it as a 256-bit unsigned integer `x`. Useful for signing and checking signatures of arbitrary entities represented by a tree of cells. +#### slice_hash +```cpp +int slice_hash(slice s) asm "HASHSU"; +``` +Computes the hash of a `slice s` and returns it as a 256-bit unsigned integer `x`. The result is the same as if an ordinary cell containing only data and references from `s` had been created and its hash computed by `cell_hash`. +#### string_hash +```cpp +int string_hash(slice s) asm "SHA256U"; +``` +Computes sha256 of the data bits of `slice s`. If the bit length of `s` is not divisible by eight, throws a cell underflow exception. The hash value is returned as a 256-bit unsigned integer `x`. + +### Signature checks +#### check_signature +```cpp +int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; +``` +Checks the Ed25519-`signature` of a `hash` (a 256-bit unsigned integer, usually computed as the hash of some data) using `public_key` (also represented by a 256-bit unsigned integer). The signature must contain at least 512 data bits; only the first 512 bits are used. The result is −1 if the signature +is valid, 0 otherwise. Note that `CHKSIGNU` creates a 256-bit slice with the hash and calls `CHKSIGNS`. That is, if `hash` is computed as the hash of some data, these data are hashed _twice_, the second hashing occurring inside `CHKSIGNS`. +#### check_data_signature +```cpp +int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS"; +``` +Checks whether `signature` is a valid Ed25519-signature of the data portion of `slice data` using `public_key`, similarly to `check_signature`. If the bit length of `data` is not divisible by eight, throws a cell underflow exception. The verification of Ed25519 signatures is the standard one, with sha256 used to reduce `data` to the 256-bit number that is actually signed. + +### Computation of boc size +The primitives below may be useful for computing storage fees of user-provided data. +#### compute_data_size? +```cpp +(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; +``` +Returns `(x, y, z, -1)` or `(null, null, null, 0)`. Recursively computes the count of distinct cells `x`, data bits `y`, and cell references `z` in the DAG rooted at `cell c`, effectively returning the total storage used by this DAG taking into account the identification of equal cells. The values of `x`, `y`, and `z` are computed by a depth-first traversal of this DAG, with a hash table of visited cell hashes used to prevent visits of already-visited cells. The total count of visited cells `x` cannot exceed non-negative `max_cells`; otherwise the computation is aborted before visiting the `(max_cells + 1)`-st cell and a zero flag is returned to indicate failure. If `c` is `null`, returns `x = y = z = 0`. +#### slice_compute_data_size? +```cpp +(int, int, int, int) slice_compute_data_size?(slice s, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; +``` +Similar to `compute_data_size?`, but accepting a `slice s` instead of a `cell`. The returned value of `x` does not take into account the cell that contains the slice `s` itself; however, the data bits and the cell references of `s` are accounted for in `y` and `z`. +#### compute_data_size +```cpp +(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; +``` +A non-quiet version of `compute_data_size?` that throws a cell overflow exception (8) on failure. +#### slice_compute_data_size +```cpp +(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE"; +``` +A non-quiet version of `slice_compute_data_size?` that throws a cell overflow exception (8) on failure. +### Persistent storage save and load +#### get_data +```cpp +cell get_data() asm "c4 PUSH"; +``` +Returns the persistent contract storage cell. It can be parsed or modified with slice and builder primitives later. +#### set_data +```cpp +() set_data(cell c) impure asm "c4 POP"; +``` +Sets cell `c` as persistent contract data. You can update persistent contract storage with this primitive. +### Continuation primitives +#### get_c3 +```cpp +cont get_c3() impure asm "c3 PUSH"; +``` +Usually `c3` has a continuation initialized by the whole code of the contract. It is used for function calls. The primitive returns the current value of `c3`. +#### set_c3 +```cpp +() set_c3(cont c) impure asm "c3 POP"; +``` +Updates the current value of `c3`. Usually, it is used for updating smart contract code in run-time. Note that after execution of this primitive the current code (and the stack of recursive function calls) won't change, but any other function call will use a function from the new code. +#### bless +```cpp +cont bless(slice s) impure asm "BLESS"; +``` +Transforms a `slice s` into a simple ordinary continuation `c`, with `c.code = s` and an empty stack and savelist. + +### Gas related primitives +#### accept_message +```cpp +() accept_message() impure asm "ACCEPT"; +``` +Sets current gas limit `gl` to its maximal allowed value `gm`, and resets the gas credit `gc` to zero, decreasing the value of `gr` by `gc` in the process. In other words, the current smart contract agrees to buy some gas to finish the current transaction. This action is required to process external messages, which bring no value (hence no gas) with themselves. + +For more details check [accept_message effects](/develop/smart-contracts/guidelines/accept) +#### set_gas_limit +```cpp +() set_gas_limit(int limit) impure asm "SETGASLIMIT"; +``` +Sets current gas limit `gl` to the minimum of `limit` and `gm`, and resets the gas credit `gc` to zero. If the gas consumed so far (including the present instruction) exceeds the resulting value of `gl`, an (unhandled) out of gas exception is thrown before setting new gas limits. Notice that `set_gas_limit` with an argument `limit ≥ 2^63 − 1` is equivalent to `accept_message`. + +For more details check [accept_message effects](/develop/smart-contracts/guidelines/accept) +#### commit +```cpp +() commit() impure asm "COMMIT"; +``` +Commits the current state of registers `c4` (“persistent data”) and `c5` (“actions”) so that the current execution is considered “successful” with the saved values even if an exception is thrown later. +#### buy_gas +```cpp +() buy_gas(int gram) impure asm "BUYGAS"; +``` +Computes the amount of gas that can be bought for `gram` nanotoncoins, and sets `gl` accordingly in the same way as `set_gas_limit`. + +### Actions primitives +#### raw_reserve +```cpp +() raw_reserve(int amount, int mode) impure asm "RAWRESERVE"; +``` +Creates an output action which would reserve exactly `amount` nanotoncoins (if `mode = 0`), at most `amount` nanotoncoins (if `mode = 2`), or all but `amount` nanotoncoins (if `mode = 1` or `mode = 3`), from the remaining balance of the account. It is roughly equivalent to creating an outbound message carrying `amount` nanotoncoins (or `b − amount` nanotoncoins, where `b` is the remaining balance) to oneself, so that the subsequent output actions would not be able to spend more money than the remainder. Bit +2 in `mode` means that the external action does not fail if the specified amount cannot be reserved; instead, all remaining balance is reserved. Bit +8 in `mode` means `amount <- -amount` before performing any further actions. Bit +4 in `mode` means that `amount` is increased by the original balance of the current account (before the compute phase), including all extra currencies, before performing any other checks and actions. Currently, `amount` must be a non-negative integer, and `mode` must be in the range `0..15`. +#### raw_reserve_extra +```cpp +() raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX"; +``` +Similar to `raw_reserve`, but also accepts a dictionary `extra_amount` (represented by a `cell` or `null`) with extra currencies. In this way currencies other than TonCoin can be reserved. +#### send_raw_message +```cpp +() send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG"; +``` +Sends a raw message contained in `msg`, which should contain a correctly serialized object Message X, with the only exception that the source address is allowed to have dummy value `addr_none` (to be automatically replaced with the current smart contract address), and `ihr_fee`, `fwd_fee`, `created_lt` and `created_at` fields can have arbitrary values (to be rewritten with correct values during the action phase of the current transaction). Integer parameter `mode` contains the flags. Currently `mode = 0` is used for ordinary messages; +`mode = 128` is used for messages that are to carry all the remaining balance of the current smart contract (instead of the value originally indicated in the message); `mode = 64` is used for messages that carry all the remaining value of the inbound message in addition to the value initially indicated in the new message (if bit 0 is not set, the gas fees are deducted from this amount); `mode' = mode + 1` means that the sender wants to pay transfer fees separately; `mode' = mode + 2` means that any errors arising while processing this message during the action phase should be ignored. Finally, `mode' = mode + 32` means that the current account must be destroyed if its resulting balance is zero. This flag is usually employed together with +128. + +#### set_code +```cpp +() set_code(cell new_code) impure asm "SETCODE"; +``` +Creates an output action that would change this smart contract code to that given by cell `new_code`. Notice that this change will take effect only after the successful termination of the current run of the smart contract (cf. [set_c3](/develop/func/stdlib#set_c3)). + +### Random number generator primitives +The pseudo-random number generator uses the random seed, an unsigned 256-bit Integer, and (sometimes) other data kept in [c7](/learn/tvm-instructions/tvm_overview#control-registers). The initial value of the random seed before a smart contract is executed in TON Blockchain is a hash of the smart contract address and the global block random seed. If there are several runs of the same smart contract inside a block, then all of these runs will have the same random seed. This can be fixed, for example, by running `randomize_lt` before using the pseudo-random number generator for the first time. +#### random +```cpp +int random() impure asm "RANDU256"; +``` +Generates a new pseudo-random unsigned 256-bit integer `x`. The algorithm is as follows: if `r` is the old value of the random seed, considered as a 32-byte array (by constructing the big-endian representation of an unsigned 256-bit integer), then its `sha512(r)` is computed; the first 32 bytes of this hash are stored as the new value `r'` of the random seed, and the remaining 32 bytes are returned as the next random value `x`. +#### rand +```cpp +int rand(int range) impure asm "RAND"; +``` +Generates a new pseudo-random integer `z` in the range `0..range−1` (or `range..−1`, if `range < 0`). More precisely, an unsigned random value `x` is generated as in `random`; then `z := x * range / 2^256` is +computed. + +#### get_seed +```cpp +int get_seed() impure asm "RANDSEED"; +``` +Returns the current random seed as an unsigned 256-bit Integer. +#### set_seed +```cpp +int set_seed(int seed) impure asm "SETRAND"; +``` +Sets the random seed to unsigned 256-bit `seed`. + +#### randomize +```cpp +() randomize(int x) impure asm "ADDRAND"; +``` +Mixes unsigned 256-bit integer `x` into the random seed `r` by setting the random seed to sha256 of the concatenation of two 32-byte strings: the first with the big-endian representation of the old seed `r`, and the second with the big-endian representation of `x`. + +#### randomize_lt +```cpp +() randomize_lt() impure asm "LTIME" "ADDRAND"; +``` +Equivalent to `randomize(cur_lt());`. + +### Address manipulation primitives +The address manipulation primitives listed below serialize and deserialize values according to the following TL-B scheme: +```cpp +addr_none$00 = MsgAddressExt; + +addr_extern$01 len:(## 8) external_address:(bits len) + = MsgAddressExt; + +anycast_info$_ depth:(#<= 30) { depth >= 1 } + rewrite_pfx:(bits depth) = Anycast; + +addr_std$10 anycast:(Maybe Anycast) + workchain_id:int8 address:bits256 = MsgAddressInt; + +addr_var$11 anycast:(Maybe Anycast) addr_len:(## 9) + workchain_id:int32 address:(bits addr_len) = MsgAddressInt; +_ _:MsgAddressInt = MsgAddress; +_ _:MsgAddressExt = MsgAddress; + +int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool + src:MsgAddress dest:MsgAddressInt + value:CurrencyCollection ihr_fee:Grams fwd_fee:Grams + created_lt:uint64 created_at:uint32 = CommonMsgInfoRelaxed; + +ext_out_msg_info$11 src:MsgAddress dest:MsgAddressExt + created_lt:uint64 created_at:uint32 = CommonMsgInfoRelaxed; +``` +A deserialized `MsgAddress` is represented by a tuple `t` as follows: +* `addr_none` is represented by `t = (0)`, i.e., a tuple containing exactly +one integer equal to zero. +* `addr_extern` is represented by `t = (1, s)`, where slice `s` contains the +field `external_address`. In other words, `t` is a pair (a tuple consisting of two entries), containing an integer equal to one and slice `s`. +* `addr_std` is represented by `t = (2, u, x, s)`, where `u` is either a `null` (if `anycast` is absent) or a slice `s'` containing `rewrite_pfx` (if `anycast` is present). Next, integer `x` is the `workchain_id`, and slice `s` contains the address. +* `addr_var` is represented by `t = (3, u, x, s)`, where `u`, `x`, and `s` have the same meaning as for `addr_std`. + +#### load_msg_addr +```cpp +(slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR"; +``` +Loads from `slice s` the only prefix that is a valid `MsgAddress`, and returns both this prefix `s'` and the remainder `s''` of `s` as slices. +#### parse_addr +```cpp +tuple parse_addr(slice s) asm "PARSEMSGADDR"; +``` +Decomposes `slice s` containing a valid `MsgAddress` into a `tuple t` with separate fields of this `MsgAddress`. If `s` is not a valid `MsgAddress`, a cell deserialization exception is thrown. + +#### parse_std_addr +```cpp +(int, int) parse_std_addr(slice s) asm "REWRITESTDADDR"; +``` +Parses slice `s` containing a valid `MsgAddressInt` (usually a `msg_addr_std`), applies rewriting from the `anycast` (if present) to the same-length prefix of the address, and returns both the workchain and the 256-bit address as integers. If the address is not 256-bit, or if `s` is not a valid serialization of `MsgAddressInt`, throws a cell `deserialization` exception. +#### parse_var_addr +```cpp +(int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR"; +``` +A variant of `parse_std_addr` that returns the (rewritten) address as a slice `s`, even if it is not exactly 256 bit long (represented by a `msg_addr_var`). + +## Debug primitives +Currently only one function is available. +#### dump_stack +```cpp +() dump_stack() impure asm "DUMPSTK"; +``` +Dumps the stack (at most the top 255 values) and shows the total stack depth. + +## Slice primitives +It is said that a primitive *loads* some data, if it returns the data and the remainder of the slice (so it can also be used as [modifying method](/develop/func/statements#modifying-methods)). + +It is said that a primitive *preloads* some data, if it returns only the data (it can be used as [non-modifying method](/develop/func/statements#non-modifying-methods)). + +Unless otherwise stated, loading and preloading primitives read the data from a prefix of the slice. +#### begin_parse +```cpp +slice begin_parse(cell c) asm "CTOS"; +``` + +Converts a `cell` into a `slice`. Notice that `c` must be either an ordinary cell, or an exotic cell (see [TVM.pdf](https://ton-blockchain.github.io/tvm.pdf), 3.1.2) which is automatically loaded to yield an ordinary cell `c'`, converted into a `slice` afterwards. + +#### end_parse +```cpp +() end_parse(slice s) impure asm "ENDS"; +``` +Checks if `s` is empty. If not, throws an exception. +#### load_ref +```cpp +(slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; +``` +Loads the first reference from the slice. +#### preload_ref +```cpp +cell preload_ref(slice s) asm "PLDREF"; +``` +Preloads the first reference from the slice. +#### load_int +```cpp +;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; +``` +Loads a signed `len`-bit integer from a slice. +#### load_uint +```cpp +;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; +``` +Loads an unsigned `len`-bit integer from a slice. +#### preload_int +```cpp +;; int preload_int(slice s, int len) asm "PLDIX"; +``` +Preloads a signed `len`-bit integer from a slice. +#### preload_uint +```cpp +;; int preload_uint(slice s, int len) asm "PLDUX"; +``` +Preloads an unsigned `len`-bit integer from a slice. +#### load_bits +```cpp +;; (slice, slice) load_bits(slice s, int len) asm(s len -> 1 0) "LDSLICEX"; +``` +Loads the first `0 ≤ len ≤ 1023` bits from slice `s` into a separate slice `s''`. + +#### preload_bits +```cpp +;; slice preload_bits(slice s, int len) asm "PLDSLICEX"; +``` +Preloads the first `0 ≤ len ≤ 1023` bits from slice `s` into a separate slice `s''`. + +#### load_grams +```cpp +(slice, int) load_grams(slice s) asm( -> 1 0) "LDGRAMS"; +``` +Loads serialized amount of TonCoins (any unsigned integer up to `2^128 - 1`). + +#### skip_bits +```cpp +slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; +(slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; +``` +Returns all but the first `0 ≤ len ≤ 1023` bits of `s`. +#### first_bits +```cpp +slice first_bits(slice s, int len) asm "SDCUTFIRST"; +``` +Returns the first `0 ≤ len ≤ 1023` bits of `s`. +#### skip_last_bits +```cpp +slice skip_last_bits(slice s, int len) asm "SDSKIPLAST"; +(slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST"; +``` +Returns all but the last `0 ≤ len ≤ 1023` bits of `s`. +#### slice_last +```cpp +slice slice_last(slice s, int len) asm "SDCUTLAST"; +``` +Returns the last `0 ≤ len ≤ 1023` bits of `s`. +#### load_dict +```cpp +(slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT"; +``` +Loads a dictionary `D` from slice `s`. May be applied to dictionaries or to values of arbitrary `Maybe ^Y` types (returns `null` if `nothing` constructor is used). +#### preload_dict +```cpp +cell preload_dict(slice s) asm "PLDDICT"; +``` +Preloads a dictionary `D` from slice `s`. +#### skip_dict +```cpp +slice skip_dict(slice s) asm "SKIPDICT"; +``` +Loads a dictionary as `load_dict`, but returns only the remainder of the slice. +### Slice size primitives +#### slice_refs +```cpp +int slice_refs(slice s) asm "SREFS"; +``` +Returns the number of references in slice `s`. +#### slice_bits +```cpp +int slice_bits(slice s) asm "SBITS"; +``` +Returns the number of data bits in slice `s`. +#### slice_bits_refs +```cpp +(int, int) slice_bits_refs(slice s) asm "SBITREFS"; +``` +Returns both the number of data bits and the number of references in `s`. +#### slice_empty? +```cpp +int slice_empty?(slice s) asm "SEMPTY"; +``` +Checks whether a slice `s` is empty (i.e., contains no bits of data and no cell references). +#### slice_data_empty? +```cpp +int slice_data_empty?(slice s) asm "SDEMPTY"; +``` +Checks whether slice `s` has no bits of data. +#### slice_refs_empty? +```cpp +int slice_refs_empty?(slice s) asm "SREMPTY"; +``` +Checks whether slice `s` has no references. +#### slice_depth +```cpp +int slice_depth(slice s) asm "SDEPTH"; +``` +Returns the depth of slice `s`. If `s` has no references, then returns `0`; otherwise the returned value is one plus the maximum of depths of cells referred to from `s`. + +## Builder primitives +It is said that a primitive *stores* a value `x` into a builder `b` if it returns a modified version of the builder `b'` with the value `x` stored at the end of it. It can be used as [non-modifying method](/develop/func/statements#non-modifying-methods). + +All the primitives below first check whether there is enough space in the `builder`, and only then check the range of the value being serialized. +#### begin_cell +```cpp +builder begin_cell() asm "NEWC"; +``` +Creates a new empty `builder`. +#### end_cell +```cpp +cell end_cell(builder b) asm "ENDC"; +``` +Converts a `builder` into an ordinary `cell`. +#### store_ref +```cpp +builder store_ref(builder b, cell c) asm(c b) "STREF"; +``` +Stores a reference to cell `c` into builder `b`. +#### store_uint +```cpp +;; builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; +``` +Stores an unsigned `len`-bit integer `x` into `b` for `0 ≤ len ≤ 256`. +#### store_int +```cpp +;; builder store_int(builder b, int x, int len) asm(x b len) "STIX"; +``` +Stores a signed `len`-bit integer `x` into `b` for `0 ≤ len ≤ 257`. +#### store_slice +```cpp +builder store_slice(builder b, slice s) asm "STSLICER"; +``` +Stores slice `s` into builder `b`. +#### store_grams +```cpp +builder store_grams(builder b, int x) asm "STGRAMS"; +``` +Stores (serializes) an integer `x` in the range `0..2^128 − 1` into builder `b`. The serialization of `x` consists of a 4-bit unsigned big-endian integer `l`, which is the smallest integer `l ≥ 0`, such that `x < 2^8l`, followed by an `8l`-bit unsigned big-endian representation of `x`. If `x` does not belong to the supported range, a range check exception is thrown. + +It is the usual way to store amounts of TonCoins. + +#### store_dict +```cpp +builder store_dict(builder b, cell c) asm(c b) "STDICT"; +``` +Stores dictionary `D` represented by cell `c` or `null` into builder `b`. In other words, stores a `1`-bit and a reference to `c` if `c` is not `null` and `0`-bit otherwise. +#### store_maybe_ref +```cpp +builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; +``` +Equivalent to `store_dict`. + +### Builder size primitives +#### builder_refs +```cpp +int builder_refs(builder b) asm "BREFS"; +``` +Returns the number of cell references already stored in builder `b`. +#### builder_bits +```cpp +int builder_bits(builder b) asm "BBITS"; +``` +Returns the number of data bits already stored in builder `b`. +#### builder_depth +```cpp +int builder_depth(builder b) asm "BDEPTH"; +``` +Returns the depth of builder `b`. If no cell references are stored in `b`, then returns `0`; otherwise the returned value is one plus the maximum of depths of cells referred to from `b`. + +## Cell primitives +#### cell_depth +```cpp +int cell_depth(cell c) asm "CDEPTH"; +``` +Returns the depth of cell `c`. If `c` has no references, then return `0`; otherwise the returned value is one plus the maximum of depths of cells referred to from `c`. If `c` is a `null` instead of a cell, returns zero. +#### cell_null? +```cpp +int cell_null?(cell c) asm "ISNULL"; +``` +Checks whether `c` is a `null`. Usually a `null`-cell represents an empty dictionary. FunC also has polymorphic `null?` built-in, see [built-ins](/develop/func/builtins#other-primitives). + +## Dictionaries primitives +As said in [TVM.pdf](https://ton-blockchain.github.io/tvm.pdf): +> Dictionaries admit two different representations as TVM stack values: +> * A slice `s` with a serialization of a TL-B value of type `HashmapE(n, X)`. In other words, `s` consists either of one bit equal to zero (if the dictionary is empty), or of one bit equal to one and a reference to a cell containing the root of the binary tree, i.e., a serialized value of type `Hashmap(n, X)`. +> * A “Maybe cell” `c^?`, i.e., a value that is either a cell (containing a serialized value of type `Hashmap(n, X)` as before) or a `null` (corresponding to an empty dictionary, cf. [null values](/develop/func/types#null-values)). When a “Maybe cell” `c^?` is used to represent a dictionary, we usually denote it by `D`. +> +> Most of the dictionary primitives listed below accept and return dictionaries in the second form, which is more convenient for stack manipulation. However, serialized dictionaries inside larger TL-B objects use the first representation. + +In FunC dictionaries are also represented by the `cell` type with an implicit assumption that it may be a `null` value. There is no separate types for dictionaries with different key lengths or values types (after all, it's FunC, not FunC++). + +### Taxonomy note +A dictionary primitive may interpret the keys of the dictionary either as unsigned `l`-bit integers, as signed `l`-bit integers or as `l`-bit slices. The primitives listed below differ by the prefix before the word `dict` in their names. `i` stands for signed integer keys, `u` stands for unsigned integer keys and empty prefix stands for slice keys. + +For example, `udict_set` is a set-by-key function for dictionaries with unsigned integer keys, `idict_set` is the corresponding function for dictionaries with signed integer keys and `dict_set` is the function for dictionaries with slice keys. + +In the titles empty prefix is used. + +Also some of the primitives have their counterpart prefixed with `~`. It makes it possible to use them as [modifying methods](/develop/func/statements#modifying-methods). + +### Dictionary's values +A value in a dictionary may be stored either directly as subslice of an inner dictionary cell, or as a reference to a separate cell. In the first case it is not guaranteed that if the value fits into a cell, it fits to the dictionary (because a part of the inner cell may already be occupied by a part of the corresponding key). On the other hand, the second storing way is less gas-efficient. The second way is equivalent to storing in the first way a slice with empty data bits and exactly one reference to the value. + +#### dict_set +```cpp +cell udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; +cell idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; +cell dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; +(cell, ()) ~udict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUSET"; +(cell, ()) ~idict_set(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTISET"; +(cell, ()) ~dict_set(cell dict, int key_len, slice index, slice value) asm(value index dict key_len) "DICTSET"; +``` +Sets the value associated with `key_len`-bit key `index` in dictionary `dict` to `value` (a slice), and returns the resulting dictionary. +#### dict_set_ref +```cpp +cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; +cell udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; +(cell, ()) ~idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; +(cell, ()) ~udict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETREF"; +``` +Similar to `dict_set`, but with the value set to a reference to cell `value`. +#### dict_get? +```cpp +(slice, int) idict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGET" "NULLSWAPIFNOT"; +(slice, int) udict_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGET" "NULLSWAPIFNOT"; +``` +Looks up key `index` in dictionary `dict` with `ket_len`-bit keys. On success, returns the value found as a slice along with a `-1` flag indicating success. On failure, returns `(null, 0)`. +#### dict_get_ref? +```cpp +(cell, int) idict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETREF"; +(cell, int) udict_get_ref?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUGETREF"; +``` +Similar to `dict_get?`, but returns the first reference of the found value. +#### dict_get_ref +```cpp +cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF"; +``` +A variant of `dict_get_ref?` that returns `null` instead of the value if the key `index` is absent from dictionary `dict`. + +#### dict_set_get_ref +```cpp +(cell, cell) idict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETGETOPTREF"; +(cell, cell) udict_set_get_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTUSETGETOPTREF"; +``` +Sets the value associated with `index` to `value` (if `value` is `null`, then the key is deleted instead) and returns the old value (or `null`, if the value was absent). +#### dict_delete? +```cpp +(cell, int) idict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDEL"; +(cell, int) udict_delete?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDEL"; +``` +Deletes `key_len`-bit key `index` from dictionary `dict`. If the key is present, returns the modified dictionary `dict'` and the success flag `−1`. Otherwise, returns the original dictionary `dict` and `0`. +#### dict_delete_get? +```cpp +(cell, slice, int) idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, slice, int) udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~idict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTIDELGET" "NULLSWAPIFNOT"; +(cell, (slice, int)) ~udict_delete_get?(cell dict, int key_len, int index) asm(index dict key_len) "DICTUDELGET" "NULLSWAPIFNOT"; +``` +Deletes `ket_len`-bit key `index` from dictionary `dict`. If the key is present, returns the modified dictionary `dict'`, the original value `x` associated with the key k (represented by a Slice), and the success flag `−1`. Otherwise, returns `(dict, null, 0)`. +#### dict_add? +```cpp +(cell, int) udict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUADD"; +(cell, int) idict_add?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIADD"; +``` +An `add` counterpart of `dict_set`: sets the value associated with key `index` in dictionary `dict` to `value`, but only if it is not already present in `D`. Returns either modified version of the dictionary and `-1` flag or `(dict, 0)`. +#### dict_replace? +```cpp +(cell, int) udict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTUREPLACE"; +(cell, int) idict_replace?(cell dict, int key_len, int index, slice value) asm(value index dict key_len) "DICTIREPLACE"; +``` +A `replace` operation, which is similar to `dict_set`, but sets the value of key `index` in dictionary `dict` to `value` only if the key was already present in `dict`. Returns either modified version of the dictionary and `-1` flag or `(dict, 0)`. +### Builder counterparts +The following primitives accept the new value as a builder instead of a slice, which often is more convenient if the value needs to be serialized from several components computed in the stack. The net effect is roughly equivalent to converting b into a slice and executing the corresponding primitive listed above. +#### dict_set_builder +```cpp +cell udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; +cell idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; +cell dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; +(cell, ()) ~idict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTISETB"; +(cell, ()) ~udict_set_builder(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUSETB"; +(cell, ()) ~dict_set_builder(cell dict, int key_len, slice index, builder value) asm(value index dict key_len) "DICTSETB"; +``` +Similar to `dict_set` but accept a builder. +#### dict_add_builder? +```cpp +(cell, int) udict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUADDB"; +(cell, int) idict_add_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIADDB"; +``` +Similar to `dict_add?`, but accept a builder. +#### dict_replace_builder? +```cpp +(cell, int) udict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTUREPLACEB"; +(cell, int) idict_replace_builder?(cell dict, int key_len, int index, builder value) asm(value index dict key_len) "DICTIREPLACEB"; +``` +Similar to `dict_replace?`, but accept a builder. +#### dict_delete_get_min +```cpp +(cell, int, slice, int) udict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMIN" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMIN" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_min(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMIN" "NULLSWAPIFNOT2"; +``` +Computes the minimal key `k` in the dictionary `dict`, removes it and returns `(dict', x, k, -1)`, where `dict'` is the modified version of `dict` and `x` is the value associated with `k`. If the dict is empty, returns `(dict, null, null, 0)`. + +Note that the key returned by `idict_delete_get_min` may differ from the key returned by `dict_delete_get_min` and `udict_delete_get_min`. + +#### dict_delete_get_max +```cpp +(cell, int, slice, int) udict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, int, slice, int) idict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, slice, slice, int) dict_delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~udict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTUREMMAX" "NULLSWAPIFNOT2"; +(cell, (int, slice, int)) ~idict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTIREMMAX" "NULLSWAPIFNOT2"; +(cell, (slice, slice, int)) ~dict::delete_get_max(cell dict, int key_len) asm(-> 0 2 1 3) "DICTREMMAX" "NULLSWAPIFNOT2"; +``` +Computes the maximal key `k` in the dictionary `dict`, removes it and returns `(dict', x, k, -1)`, where `dict'` is the modified version of `dict` and `x` is the value associated with `k`. If the dict is empty, returns `(dict, null, null, 0)`. + +#### dict_get_min? +```cpp +(int, slice, int) udict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMIN" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_min?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMIN" "NULLSWAPIFNOT2"; +``` +Computes the minimal key `k` in dictionary `dict`, the associated value `x` and returns `(k, x, -1)`. If the dictionary is empty, returns `(null, null, 0)`. +#### dict_get_max? +```cpp +(int, slice, int) udict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAX" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_max?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAX" "NULLSWAPIFNOT2"; +``` +Computes the maximal key `k` in dictionary `dict`, the associated value `x` and returns `(k, x, -1)`. If the dictionary is empty, returns `(null, null, 0)`. +#### dict_get_min_ref? +```cpp +(int, cell, int) udict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMINREF" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_min_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMINREF" "NULLSWAPIFNOT2"; +``` +Similar to `dict_get_min?`, but returns the only reference in the value as a reference. +#### dict_get_max_ref? +```cpp +(int, cell, int) udict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTUMAXREF" "NULLSWAPIFNOT2"; +(int, cell, int) idict_get_max_ref?(cell dict, int key_len) asm (-> 1 0 2) "DICTIMAXREF" "NULLSWAPIFNOT2"; +``` +Similar to `dict_get_max?`, but returns the only reference in the value as a reference. +#### dict_get_next? +```cpp +(int, slice, int) udict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXT" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_next?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXT" "NULLSWAPIFNOT2"; +``` +Computes the minimal key `k` in dictionary `dict` that is greater than `pivot`, and returns `k`, associated value and a flag indicating success. If the dictionary is empty, returns `(null, null, 0)`. +#### dict_get_nexteq? +```cpp +(int, slice, int) udict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETNEXTEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_nexteq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETNEXTEQ" "NULLSWAPIFNOT2"; +``` +Similar to `dict_get_next?`, but computes the minimal key `k` that is greater than or equal to `pivot`. +#### dict_get_prev? +```cpp +(int, slice, int) udict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREV" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_prev?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREV" "NULLSWAPIFNOT2"; +``` +Similar to `dict_get_next?`, but computes the maximal key `k` smaller than `pivot`. +#### dict_get_preveq? +```cpp +(int, slice, int) udict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTUGETPREVEQ" "NULLSWAPIFNOT2"; +(int, slice, int) idict_get_preveq?(cell dict, int key_len, int pivot) asm(pivot dict key_len -> 1 0 2) "DICTIGETPREVEQ" "NULLSWAPIFNOT2"; +``` +Similar to `dict_get_prev?`, but computes the maximal key `k` smaller than or equal to `pivot`. +#### new_dict +```cpp +cell new_dict() asm "NEWDICT"; +``` +Creates an empty dictionary, which is actually a `null` value. Special case of `null()`. +#### dict_empty? +```cpp +int dict_empty?(cell c) asm "DICTEMPTY"; +``` +Checks whether a dictionary is empty. Equivalent to `cell_null?`. + +## Prefix dictionaries primitives +TVM also support dictionaries with non-fixed length keys which form a prefix code (i.e. there is no key that is a prefix of another key). Learn more about them in [TVM.pdf](https://ton-blockchain.github.io/tvm.pdf). + +#### pfxdict_get? +```cpp +(slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; +``` +Returns `(s', x, s'', -1)` or `(null, null, s, 0)`. +Looks up the unique prefix of slice `key` present in the prefix code dictionary `dict`. If found, the prefix of `s` is returned as `s'`, and the corresponding value (also a slice) as `x`. The remainder of `s` is returned as a slice `s''`. If no prefix of `s` is a key in prefix code dictionary `dict`, returns the unchanged `s` and a zero flag to indicate failure. +#### pfxdict_set? +```cpp +(cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET"; +``` +Similar to `dict_set`, but may fail if the key is a prefix of another key presented in the dictionary. Returns flag, indicating success. +#### pfxdict_delete? +```cpp +(cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL"; +``` +Similar to `dict_delete?`. + +## Special primitives +#### null +```cpp +forall X -> X null() asm "PUSHNULL"; +``` +By the TVM type `Null` FunC represents absence of a value of some atomic type. So `null` can actually have any atomic type. +#### ~impure_touch +```cpp +forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP"; +``` +Mark a variable as used, such that the code which produced it won't be deleted even it is not impure. (c.f. [impure specifier](/develop/func/functions#impure-specifier)) + + +## Other primitives +#### min +```cpp +int min(int x, int y) asm "MIN"; +``` +Computes the minimum of two integers `x` and `y`. +#### max +```cpp +int max(int x, int y) asm "MAX"; +``` +Computes the maximum of two integers `x` and `y`. +#### minmax +```cpp +(int, int) minmax(int x, int y) asm "MINMAX"; +``` +Sorts two integers. +#### abs +```cpp +int abs(int x) asm "ABS"; +``` +Computes the absolute value of an integer `x`. diff --git a/versioned_docs/version-1.0.0/develop/func/types.md b/versioned_docs/version-1.0.0/develop/func/types.md new file mode 100644 index 0000000000..b01f68198d --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/func/types.md @@ -0,0 +1,66 @@ +# Types +FunC has the following built-in types: + +## Atomic types +- `int` is the type of 257-bit signed integers. By default, overflow checks are enabled and lead to integer overflow exceptions. +- `cell` is the type of TVM cells. All persistent data in TON Blockchain is stored in trees of cells. Every cell has up to 1023 bits of arbitrary data in it and up to 4 references to other cells. Cells play a role of memory in stack-based TVM. +- `slice` is the type of cell slices. Cell can be transformed to a slice, and then the data bits and references to other cells from the cell can be obtained by loading them from the slice. +- `builder` is the type of cell builders. Data bits and references to other cells can be stored into a builder, and then the builder can be finalized to a new cell. +- `tuple` is the type of TVM tuples. Tuple is an ordered collection of up to 255 components, having arbitrary value types, possibly distinct. +- `cont` is the type of TVM continuations. Continuations are used for controlling the flow of TVM program execution. It is rather a low-level object from the perspective of FunC, although somewhat paradoxically quite general. + +Note that any of the types above occupy only a single entry in the TVM stack. + +### Absence of boolean type +In FunC booleans are represented as integers: `false` is represented as `0` and `true` is represented as `-1` (257 ones in binary notation). Logical operations are done as bitwise operations. When a condition is checked, every non-zero integer is considered as `true` value. + +### Null values +By the value `null` of TVM type `Null` FunC represents absence of a value of some atomic type. Some primitives from the standard library may be typed as ones returning an atomic type and actually return `null`s in some cases. Others may be typed as ones excepting a value of an atomic type, but work fine with `null` values too. Such behavior is explicitly stated in the primitive specification. By default `null` values are prohibited and lead to a run-time exception. + +In such a way, an atomic type `A` may be implicitly transformed into type `A^?` a.k.a. `Maybe A` (type-checker is agnostic to such a transformation). + +## Hole type +FunC has support for type inference. Types `_` and `var` represent type "holes", which can later be filled with some actual type during type checking. For example, `var x = 2;` is a definition of variable `x` equal to `2`. Type-checker can infer that `x` has type `int`, because `2` has type `int`, and left and right sides of an assignment must have equal types. + +## Composite types +Types can be composed in more complex ones. + +### Functional type +Types of the form `A -> B` represent functions with specified domain and codomain. For example, `int -> cell` is the type of functions of one integer argument, which return a TVM cell. + +Internally values of such types are represented as continuations. + +### Tensor types +Types of the form `(A, B, ...)` essentially represent ordered collections of values of types `A`, `B`, `...`, which all together occupy more than one TVM stack entry. + +For example, if a function `foo` has type `int -> (int, int)`, it means that the function takes one integer and returns pair of them. + +A call of this function may look like `(int a, int b) = foo(42);`. Internally the function consumes one stack entry and leaves two of them. + +Note that although in low-level perspective value `(2, (3, 9))` of type `(int, (int, int))` and value `(2, 3, 9)` of type `(int, int, int)` are represented in the same way as three stack entries `2`, `3` and `9`, for FunC type-checker they are values of **different** types: for example, code `(int a, int b, int c) = (2, (3, 9));` wouldn't be compiled. + +Special case of tensor type is the **unit type** `()`. It is usually used for representing the fact that a function doesn't return any value, or has no arguments. For example, a function `print_int` would have type `int -> ()` and the function `random` has type `() -> int`. It has unique inhabitant `()`, which occupy 0 stack entries. + +Type of form `(A)` is considered by type-checker as the same type as `A`. + +### Tuples types +Types of the form `[A, B, ...]` represent TVM tuples with concrete length and types of components, known in compile time. For example, `[int, cell]` is the type of TVM tuples, having length exactly 2, which first component is an integer, and the second is a cell. `[]` is the type of empty tuples (having the unique inhabitant – the empty tuple). Note that in contrast to unit type `()`, the value of `[]` occupy 1 stack entry. + +## Polymorphism with type variables +FunC has Miller-Rabin type system with support for polymorphic functions. For example, function +```cpp +forall X -> (X, X) duplicate(X value) { + return (value, value); +} +``` +is a polymorphic function which takes a (single stack entry) value and returns two copies of this value. `duplicate(6)` will produce values `6 6`, and `duplicate([])` will produce two copies `[] []` of empty tuple. + +In this example `X` is a type variable. + +See more info on this topic in the [functions](/develop/func/functions#polymorphism-with-forall) section. + +## User-defined types +Currently FunC has no support for defining types except for type constructions described above. + +## Type width +As you may have noticed, every value of a type occupies some number of stack entries. If it is the same number for all values of the type, this number is called **type width**. Polymorphic functions currently can be defined only for types with fixed and known in advance type width. diff --git a/versioned_docs/version-1.0.0/develop/getting-started.md b/versioned_docs/version-1.0.0/develop/getting-started.md new file mode 100644 index 0000000000..01dc817c82 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/getting-started.md @@ -0,0 +1,64 @@ +# Getting Started + +By community efforts there are already several tutorials available for new TON developers. Feel free to focus on the approach that suits the best for you. + +## Smart Contracts development + +:::tip starter tip +These materials are the best for newcomers to the TON development. +::: + +Right now there is 2 great approaches how to start developing TON smart contracts: +* [TON Hello World: Step-by-step guide for writing your first smart contract in FunC](https://society.ton.org/ton-hello-world-step-by-step-guide-for-writing-your-first-smart-contract-in-func) +* [TON Learn Guides: 10 zero-to-hero lessons](https://github.com/romanovichim/TonFunClessons_Eng) ([Ru version](https://github.com/romanovichim/TonFunClessons_ru)) + + +## Web and dApps development + +For web developers the best approach is to start from this article: +* [How TON wallets work and how to access them from JavaScript](https://society.ton.org/how-ton-wallets-work-and-how-to-access-them-from-javascript) + +### Learning by Examples + +In case you are web or bot developer, you could find useful these repositories: + +#### Examples + +* [TonCenter API Examples](https://github.com/toncenter/examples) (JavaScript, with comments) +* [Payment Channels Example](https://github.com/toncenter/payment-channels-example) (JavaScript, with comments) +* [TON Bridge front-end](https://github.com/ton-blockchain/bridge) (Vue.js, no comments) +* [Web Wallet source code](https://github.com/toncenter/ton-wallet) (JavaScript, no comments) + +#### NFT minters examples + +* [TON Diamonds NFT deployer](https://github.com/tondiamonds/ton-nft-deployer) (TypeScript, no comments) +* [NFT Minter Example](https://github.com/ton-foundation/token-contract/tree/main/nft/web-example) (JavaScript, with comments) +* [NFT Minter using React](https://github.com/tonbuilders/tonbuilders-minter) (React, no comments) + +#### Jetton Deployer + +Jettons are custom fungible tokens on TON blockchain. You can create your own token on TON blockchain using Jetton Deployer example below: + +* **[Jetton.Live](https://jetton.live/)** — open-source Jetton Deployer dApp +* [Jetton Deployer — Contracts](https://github.com/ton-defi-org/jetton-deployer-contracts) (FunC, TL-B) +* [Jetton Deployer — WebClient](https://github.com/ton-defi-org/jetton-deployer-webclient) (React, TypeScript) + +##### Tools to work with Jettons + +* [Scaleton](http://scaleton.io) — see your custom token balances. + +## Standard smart contracts + +:::caution advanced level +This information is **very low level** and could be hard to understand for newcomers. +So feel free to read about it later. +::: + +If you're already familiar with smart contracts, you could try to read the following examples: +- [Fungible (Jettons), Non-Fungible (NFT), Semi-Fungible Tokens Smart Contracts](https://github.com/ton-blockchain/token-contract/tree/main) +- [Standard Smart Contracts Examples](https://github.com/ton-blockchain/ton/tree/master/crypto/smartcont) +- [Wallet V4 Smart Contract Example](https://github.com/ton-blockchain/wallet-contract) + +:::info little tip +Feel free to focus on smart contracts written using _FunC_ (***.fc**) instead of low-level *Fift* (***.fif**) language. It would be easier experience. +::: \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/howto/README.md b/versioned_docs/version-1.0.0/develop/howto/README.md new file mode 100644 index 0000000000..9eb92649d9 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/howto/README.md @@ -0,0 +1,44 @@ +# HOWTO + +> This section describes instructions and manuals for interacting with the TON at a low level. + + +* **Getting Started** + + General information, compilation and installation instructions for the Lite Client. + +* **Step-by-Step** + + Step-by-step instructions for creating a new smart contract with the aid of the Lite Client. + +* **Full Node** + + Step-by-step instructions for setting up a Full Node in the TON Blockchain Network. + +* **Validator** + + Step-by-step instructions for upgrading a Full Node to a Validator. + +* **TON Sites** + + Step-by-step instructions to set up a proxy for accessing TON Sites or to creating new ones. + +* **TON DNS** + + Step-by-step instructions to register your own TON DNS domain, for example for your TON Site. + +* **Config Params** + + Step-by-step instructions to create configuration parameter proposals and vote for or against them. + +* **POW Givers** + + Step-by-step instructions to mine Proof-of-work giver smart contracts. + +* **Smart Contract Guidelines** + + Guidelines and best practices related to implementation of TON Blockchain smart contracts. + +* **Payment Processing** + + Overview and specific details which explain how to process (send and accept) digital assets on TON network. Useful for exchanges, exchangers, etc. diff --git a/versioned_docs/version-1.0.0/develop/howto/compile.md b/versioned_docs/version-1.0.0/develop/howto/compile.md new file mode 100644 index 0000000000..57b670d44b --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/howto/compile.md @@ -0,0 +1,87 @@ +# How to Compile + +## Common + +The software is likely to compile and work properly on most Linux systems. It should work on macOS and even Windows. + +1) Download the newest version of the TON blockchain sources, available at GitHub repository https://github.com/ton-blockchain/ton/ : + + ``` + git clone https://github.com/ton-blockchain/ton.git + git submodule update --init + ``` + +2) Install the newest versions of: + - `make` + - `cmake` version 3.0.2 or later + - `g++` or `clang` (or another C++14-compatible compiler as appropriate for your operating system). + - OpenSSL (including C header files) version 1.1.1 or later + +3) Suppose that you have fetched the source tree to directory `~/ton`, where `~` is your home directory, and that you have created an empty directory `~/liteclient-build`. Then run the following in a terminal on a Linux system: + + ``` + cd ~/liteclient-build + cmake ~/ton + ``` + +## Lite Client + +``` +cmake --build . --target lite-client +``` + +Download the newest configuration file from https://ton-blockchain.github.io/global.config.json for mainnet: + +``` +wget https://ton-blockchain.github.io/global.config.json +``` + +or from https://ton-blockchain.github.io/testnet-global.config.json for testnet: + +``` +wget https://ton-blockchain.github.io/testnet-global.config.json +``` + +Run the Lite Client with config: + +``` +./lite-client/lite-client -C global.config.json +``` + +If everything was installed successfully, the Lite Client will connect to a special server (a full node for the TON Blockchain Network) and will send some queries to the server. +If you indicate a writeable "database" directory as an extra argument to the client, it will download and save the block and the state corresponding to the newest masterchain block: + +``` +./lite-client/lite-client -C global.config.json -D ~/ton-db-dir +``` + +Basic help info can be obtained by typing `help` into the Lite Client. Type `quit` or press `Ctrl-C` to exit. + + +## Func + +To build FunC compiler from source code do [common part](/develop/howto/compile.md#Common) described above and then: + +``` +cmake --build . --target func +``` + +To compile FunC smart contract: + +``` +func -o output.fif -SPA source0.fc source1.fc ... +``` + +## Fift + +To build Fift compiler from source code do [common part](/develop/howto/compile.md#Common) described above and then: + +``` +cmake --build . --target fift +``` + +To run Fift script: + +``` +fift -s script.fif script_param0 script_param1 .. +``` diff --git a/versioned_docs/version-1.0.0/develop/howto/config-params.md b/versioned_docs/version-1.0.0/develop/howto/config-params.md new file mode 100644 index 0000000000..f57081c3d5 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/howto/config-params.md @@ -0,0 +1,295 @@ +The aim of this document is to provide basic explanation of configuration parameters of TON Blockchain, and to give step-by-step instructions for changing these parameters by a consensus of a majority of validators. We assume that the reader is already familiar with Fift and the Lite Client as explained in [LiteClient-HOWTO](https://toncoin.org/#/howto/step-by-step), and with [FullNode-HOWTO](https://toncoin.org/#/howto/full-node) and [Validator-HOWTO](https://toncoin.org/#/howto/validator) in the sections where validators' voting for the configuration proposals is described. + +#### 1. Configuration parameters +The **configuration parameters** are certain values that affect the behavior of validators and/or fundamental smart contracts of TON Blockchain. The current values of all configuration parameters are stored as a special part of the masterchain state, and are extracted from the current masterchain state when needed. Therefore, it makes sense to speak of the values of the configuration parameters with respect to a certain masterchain block. Each shardchain block contains a reference to the latest known masterchain block; the values from the corresponding masterchain state are assumed to be active for this shardchain block, and are used during its generation and validation. For masterchain blocks, the state of the previous masterchain block is used to extract the active configuration parameters. Therefore, even if one tries to change some configuration parameters inside a masterchain block, the changes will become active only for the next masterchain block. + +Each configuration parameter is identified by a signed 32-bit integer index, called **configuration parameter index** or simply **index**. The value of a configuration parameter always is a Cell. Some configuration parameters may be missing; then it is sometimes assumed that the value of this parameter is `Null`. There also is a list of **mandatory** configuration parameters that must be always present; this list is stored in configuration parameter `#10`. + +All configuration parameters are combined into a **configuration dictionary** - a Hashmap with signed 32-bit keys (configuration parameter indices) and values consisting of exactly one cell reference. In other words, a configuration dictionary is a value of TL-B type (`HashmapE 32 ^Cell`). In fact, the collection of all configuration parameters is stored in the masterchain state as a value of TL-B type `ConfigParams`: + + _ config_addr:bits256 config:^(Hashmap 32 ^Cell) = ConfigParams; + +We see that, apart from the configuration dictionary, `ConfigParams` contains `config_addr` -- 256-bit address of the configuration smart contract in the masterchain. More details on the configuration smart contract will be provided later. + +The configuration dictionary containing the active values of all configuration parameters is available via special TVM register `c7` to all smart contracts when their code is executed in a transaction. More precisely, when a smart contract is executed, `c7` is initialized by a Tuple, the only element of which is a Tuple with several "context" values useful for the execution of the smart contract, such as the current Unix time (as registered in the block header). The tenth entry of this Tuple (i.e., the one with zero-based index 9) contains a Cell representing the configuration dictionary. Therefore, it can be accesses by means of TVM instructions `PUSH c7; FIRST; INDEX 9`, or by equivalent instruction `CONFIGROOT`. In fact, special TVM instructions `CONFIGPARAM` and `CONFIGOPTPARAM` combine the previous actions with a dictionary lookup, returning any configuration parameter by its index. We refer to the TVM documentation for more details on these instructions. What is relevant here is that all configuration parameters are easily accessible from all smart contracts (masterchain or shardchain), and smart contracts may inspect them and use them to perform specific checks. For instance, a smart contract might extract workchain data storage prices from a configuration parameter to compute the price for storing a chunk of user-provided data. + +The values of configuration parameters are not arbitrary. In fact, if the configuration parameter index `i` is non-negative, then the value of this parameter must be a valid value of TL-B type (`ConfigParam i`). This restriction is enforced by the validators, which will not accept changes to configuration parameters with non-negative indices unless they are valid values of the corresponding TL-B type. + +Therefore, the structure of such parameters is determined in source file `crypto/block/block.tlb`, where (`ConfigParam i`) are defined for different values of `i`. For instance, + + _ config_addr:bits256 = ConfigParam 0; + _ elector_addr:bits256 = ConfigParam 1; + _ dns_root_addr:bits256 = ConfigParam 4; // root TON DNS resolver + + capabilities#c4 version:uint32 capabilities:uint64 = GlobalVersion; + _ GlobalVersion = ConfigParam 8; // all zero if absent + +We see that configuration parameter `#8` contains a Cell with no references and exactly 104 data bits. The first four bits must be `11000100`, then 32 bits with the currently enabled "global version" are stored, and 64-bit integer with flags corresponding to currently enabled capabilities follow. A more detailed description of all configuration parameters will be provided in an appendix to the TON Blockchain documentation; for now, one can inspect the TL-B scheme in `crypto/block/block.tlb` and check how different parameters are used in the validator sources. + +In contrast with configuration parameters with non-negative indices, configuration parameters with negative indices can contain arbitrary values. At least, no restrictions on their values are enforced by the validators. Therefore, they can be used to store important information (such as the Unix time when certain smart contracts must start operating) that is not crucial for the block generation, but is used by some of the fundamental smart contracts. + +#### 2. Changing configuration parameters + +We have already explained that the current values of configuration parameters are stored in a special portion of the masterchain state. How do they ever get changed? + +In fact, there is a special smart contract residing in the masterchain, called the **configuration smart contract**. Its address is determined by the `config_addr` field in `ConfigParams`, which we have described before. The first cell reference in its data must contain an up-to-date copy of all configuration parameters. When a new masterchain block is generated, the configuration smart contract is looked up by its address `config_addr`, and the new configuration dictionary is extracted from the first cell reference of its data. After some validity checks (such as verifying that any value with non-negative 32-bit index `i` is indeed a valid value of TL-B type (`ConfigParam i`)) the validator copies this new configuration dictionary into the portion of masterchain containing ConfigParams. This is performed after all transactions have been created, so only the final version of the new configuration dictionary stored in the configuration smart contract is inspected. If the validity checks fail, then the "true" configuration dictionary is left unchanged. In this way the configuration smart contract cannot install invalid values of configuration parameters. If the new configuration dictionary coincides with the current configuration dictionary, then no checks are performed and no changes made. + +In this way, all changes in configuration parameters are performed by the configuration smart contract, and it is its code that determines the rules for changing configuration parameters. Currently, the configuration smart contract supports two modes for changing configuration parameters: + +1) By means of an external message signed by a specific private key, corresponding to a public key stored in the data of the configuration smart contract. This is the method employed in the public testnet and probably in the smaller private test networks, controlled by one entity, because it enables the operator to easily change the values of any configuration parameters. Note that this public key may be changed by a special external message signed by an old key, and that if it is changed to zero, then this mechanism is disabled. Therefore, one might use it for fine-tuning immediately after the launch, and then disable for good. +2) By means of creating "configuration proposals" that are subsequently voted for or against by validators. Typically, a configuration proposal has to collect votes from more than 3/4 of all validators (by weight), and not only in one round, but in several rounds (i.e., several consecutive sets of validators have to confirm the proposed parameter change). This is the distributed governance mechanism to be used by TON Blockchain mainnet. + +We would like to describe the second way of changing configuration parameters in more detail. + +#### 3. Creating configuration proposals + +A new **configuration proposal** contains the following data: +- the index of the configuration parameter to be changed +- the new value of the configuration parameter (or Null, if it is to be deleted) +- the expiration Unix time of the proposal +- a flag indicating whether the proposal is **critical** or not +- an optional **old value hash** with the cell hash of the current value (the proposal can be activated only if the current value has indicated hash) + +Anybody with a wallet in the masterchain can create a new configuration proposal, provided he pays an adequate fee. However, only validators can vote for or against existing configuration proposals. + +Note that there are **critical** and **ordinary** configuration proposals. A critical configuration proposal can change any configuration parameter, including one of the so-called critical ones (the list of critical configuration parameters is stored in configuration parameter `#10`, which is itself critical). However, creating critical configuration proposals is more expensive, and they usually need to collect more validator votes in more rounds (the precise voting requirements for ordinary and critical configuration proposals are stored in critical configuration parameter `#11`). On the other hand, ordinary configuration proposals are cheaper, but they cannot change the critical configuration parameters. + +In order to create a new configuration proposal, one first has to generate a BoC (bag-of-cells) file containing the proposed new value. The exact way of doing this depends on the configuration parameter being changed. For instance, if we want to create parameter `-239` containing UTF-8 string "TEST" (i.e., `0x54455354`), we could create `config-param-239.boc` as follows: invoke Fift and then type + + 2 boc+>B "config-param-239.boc" B>file + bye + +As a result, 21-byte file `config-param-239.boc` will be created, containing the serialization of the required value. + +For more sophisticated cases, and especially for configuration parameters with non-negative indices this straightforward approach is not easily applicable. We recommend using `create-state` (available as `crypto/create-state` in the build directory) instead of `fift`, and copying and editing suitable portions from source files `crypto/smartcont/gen-zerostate.fif` and `crypto/smartcont/CreateState.fif`, which are usually employed to create the zero state (corresponding to the "genesis block" of other blockchain architectures) of the TON Blockchain. + +Consider, for instance, configuration parameter `#8`, which contains the currently-enabled global blockchain version and capabilities: + + capabilities#c4 version:uint32 capabilities:uint64 = GlobalVersion; + _ GlobalVersion = ConfigParam 8; + +We can inspect its current value by running the lite-client and typing `getconfig 8`: + +``` +> getconfig 8 +... +ConfigParam(8) = ( + (capabilities version:1 capabilities:6)) + +x{C4000000010000000000000006} +``` + +Now suppose that we want to enable the capability represented by bit `#3` (`+8`), which is `capReportVersion` (when enabled, this capability forces all collators to report their supported version and capabilities in the block headers of the blocks they generate). Therefore, we want to have `version=1` and `capabilities=14`. In this example, we still can guess the correct serialization and create the BoC file directly by typing in Fift + + x{C400000001000000000000000E} s>c 2 boc+>B "config-param8.boc" B>file + +(A 30-byte file `config-param8.boc` containing the desired value is created as a result.) + +However, in more complicated cases this might not be an option, so let's do this example differently. Namely, we can inspect source files `crypto/smartcont/gen-zerostate.fif` and `crypto/smartcont/CreateState.fif` for relevant portions: + + // version capabilities -- + { 8 config! } : config.version! + 1 constant capIhr + 2 constant capCreateStats + 4 constant capBounceMsgBody + 8 constant capReportVersion + 16 constant capSplitMergeTransactions + +and + + // version capabilities + 1 capCreateStats capBounceMsgBody or capReportVersion or config.version! + +We see that `config.version!` without the last `8 config!` essentially does what we need, so we can create a temporary Fift script, say, `create-param8.fif`: +``` +#!/usr/bin/fift -s +"TonUtil.fif" include + +1 constant capIhr +2 constant capCreateStats +4 constant capBounceMsgBody +8 constant capReportVersion +16 constant capSplitMergeTransactions +{ } : prepare-param8 + +// create new value for config param #8 +1 capCreateStats capBounceMsgBody or capReportVersion or prepare-param8 +// check the validity of this value +dup 8 is-valid-config? not abort"not a valid value for chosen configuration parameter" +// print +dup ."Serialized value = " B $1 tuck B>file +."(Saved into file " type .")" cr +``` + +Now if we run `fift -s create-param8.fif config-param8.boc`, or, even better, `crypto/create-state -s create-param8.fif config-param8.boc` (from the build directory), we see the following output: + + Serialized value = x{C400000001000000000000000E} + (Saved into file config-param8.boc) + +and we obtain 30-byte file `config-param8.boc` with the same content as before. + +Once we have a file with the desired value of the configuration parameter, we invoke script `create-config-proposal.fif` that can be found in directory `crypto/smartcont` of the source tree with suitable arguments. Again, we recommend using `create-state` (available as `crypto/create-state` from the build directory) instead of `fift`, because it is a special extended version of Fift that is able to do more blockchain-related validity checks: + +``` +$ crypto/create-state -s create-config-proposal.fif 8 config-param8.boc -x 1100000 + + +Loading new value of configuration parameter 8 from file config-param8.boc +x{C400000001000000000000000E} + +Non-critical configuration proposal will expire at 1586779536 (in 1100000 seconds) +Query id is 6810441749056454664 +resulting internal message body: x{6E5650525E838CB0000000085E9455904_} + x{F300000008A_} + x{C400000001000000000000000E} + +B5EE9C7241010301002C0001216E5650525E838CB0000000085E9455904001010BF300000008A002001AC400000001000000000000000ECD441C3C +(a total of 104 data bits, 0 cell references -> 59 BoC data bytes) +(Saved to file config-msg-body.boc) +``` + +We have obtained the body of an internal message to be sent to the configuration smart contract with a suitable amount of TON Coins from any (wallet) smart contract residing in the masterchain. The address of the configuration smart contract may be obtained by typing `getconfig 0` in the lite-client: +``` +> getconfig 0 +ConfigParam(0) = ( config_addr:x5555555555555555555555555555555555555555555555555555555555555555) +x{5555555555555555555555555555555555555555555555555555555555555555} +``` +We see that the address of the configuration smart contract is `-1:5555...5555`. By running suitable get-methods of this smart contract, we can find out the required payment for creating this configuration proposal: + +``` +> runmethod -1:5555555555555555555555555555555555555555555555555555555555555555 proposal_storage_price 0 1100000 104 0 + +arguments: [ 0 1100000 104 0 75077 ] +result: [ 2340800000 ] +remote result (not to be trusted): [ 2340800000 ] +``` + +The parameters to get-method `proposal_storage_price` are the critical flag (0 in this case), the time interval during which this proposal will be active (1.1 Megaseconds), the total amount of bits (104) and cell references (0) in the data. The latter two quantities can be seen in the output of `create-config-proposal.fif`. + +We see that one has to pay 2.3408 TON Coins to create this proposal. It is better to add at least 1.5 TON Coins to the message to pay for the processing fees, so we are going to send 4 TON Coins along with the request (all excess TON Coins will be returned back). Now we use `wallet.fif` (or the corresponding Fift script for the wallet we are using) to create a transfer from our wallet to the configuration smart contract carrying 4 TON Coins and the body from `config-msg-body.boc`. This usually looks like + +``` +$ fift -s wallet.fif my-wallet -1:5555555555555555555555555555555555555555555555555555555555555555 31 4. -B config-msg-body.boc + +Transferring GR$4. to account kf9VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVQft = -1:5555555555555555555555555555555555555555555555555555555555555555 seqno=0x1c bounce=-1 +Body of transfer message is x{6E5650525E835154000000085E9293944_} + x{F300000008A_} + x{C400000001000000000000000E} + +signing message: x{0000001C03} + x{627FAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA773594000000000000000000000000000006E5650525E835154000000085E9293944_} + x{F300000008A_} + x{C400000001000000000000000E} + +resulting external message: x{89FE000000000000000000000000000000000000000000000000000000000000000007F0BAA08B4161640FF1F5AA5A748E480AFD16871E0A089F0F017826CDC368C118653B6B0CEBF7D3FA610A798D66522AD0F756DAEECE37394617E876EFB64E9800000000E01C_} + x{627FAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA773594000000000000000000000000000006E5650525E835154000000085E9293944_} + x{F300000008A_} + x{C400000001000000000000000E} + +B5EE9C724101040100CB0001CF89FE000000000000000000000000000000000000000000000000000000000000000007F0BAA08B4161640FF1F5AA5A748E480AFD16871E0A089F0F017826CDC368C118653B6B0CEBF7D3FA610A798D66522AD0F756DAEECE37394617E876EFB64E9800000000E01C010189627FAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA773594000000000000000000000000000006E5650525E835154000000085E9293944002010BF300000008A003001AC400000001000000000000000EE1F80CD3 +(Saved to file wallet-query.boc) +``` + +Now we send the external message `wallet-query.boc` to the blockchain with the aid of the lite-client: + + > sendfile wallet-query.boc + .... + external message status is 1 + +After waiting for some time, we can inspect the incoming messages of our wallet to check for response messages from the configuration smart contract, or, if we feel lucky, simply inspect the list of all active configuration proposals by means of method `list_proposals` of the configuration smart contract: + +``` +> runmethod -1:5555555555555555555555555555555555555555555555555555555555555555 list_proposals +... +arguments: [ 107394 ] +result: [ ([64654898543692093106630260209820256598623953458404398631153796624848083036321 [1586779536 0 [8 C{FDCD887EAF7ACB51DA592348E322BBC0BD3F40F9A801CB6792EFF655A7F43BBC} -1] 112474791597373109254579258586921297140142226044620228506108869216416853782998 () 864691128455135209 3 0 0]]) ] +remote result (not to be trusted): [ ([64654898543692093106630260209820256598623953458404398631153796624848083036321 [1586779536 0 [8 C{FDCD887EAF7ACB51DA592348E322BBC0BD3F40F9A801CB6792EFF655A7F43BBC} -1] 112474791597373109254579258586921297140142226044620228506108869216416853782998 () 864691128455135209 3 0 0]]) ] +... caching cell FDCD887EAF7ACB51DA592348E322BBC0BD3F40F9A801CB6792EFF655A7F43BBC +``` + +We see that the list of all active configuration proposals consists of exactly one entry, represented by pair +``` +[6465...6321 [1586779536 0 [8 C{FDCD...} -1] 1124...2998 () 8646...209 3 0 0]] +``` +Here the first number `6465..6321` is the unique identifier of the configuration proposal, equal to its 256-bit hash. The second component of this pair is a Tuple describing the status of this configuration proposal. The first component of this Tuple is the expiration Unix time of the configuration proposal (`1586779546`). The second component (`0`) is the criticality flag. Next comes the configuration proposal proper, described by triple `[8 C{FDCD...} -1]`, where `8` is the index of the configuration parameter to be modified, `C{FDCD...}` is the cell with the new value (represented by the hash of this cell), and `-1` is the optional hash of the old value of this parameter (`-1` means that this hash has not been specified). Next we see a large number `1124...2998` representing the identifier of the current validator set, then an empty list `()` representing the set of all currently active validators that have voted for this proposal so far, then `weight_remaining` equal to `8646...209` - a number that is positive if the proposal has not yet collected enough validator votes in this round, and negative otherwise. Then we see three numbers `3 0 0`. These numbers are `rounds_remaining` (this proposal will survive at most three rounds, i.e., changes of the current validator set), `wins` (the count of rounds where the proposal collected votes of more than 3/4 of all validators by weight) and `losses` (the count of rounds where the proposal failed to collect 3/4 of all validator votes). + +We can inspect the proposed value for configuration parameter `#8` by asking the lite-client to expand cell `C{FDCD...}` using its hash `FDCD...` or a sufficiently long prefix of this hash to uniquely identify the cell in question: +``` +> dumpcell FDC +C{FDCD887EAF7ACB51DA592348E322BBC0BD3F40F9A801CB6792EFF655A7F43BBC} = + x{C400000001000000000000000E} +``` +We see that the value is `x{C400000001000000000000000E}`, which is indeed the value we have embedded into our configuration proposal. We can even ask the lite-client to display this Cell as a value of TL-B type (`ConfigParam 8`): +``` +> dumpcellas ConfigParam8 FDC +dumping cells as values of TLB type (ConfigParam 8) +C{FDCD887EAF7ACB51DA592348E322BBC0BD3F40F9A801CB6792EFF655A7F43BBC} = + x{C400000001000000000000000E} +( + (capabilities version:1 capabilities:14)) +``` +This is especially useful when we consider configuration proposals created by other people. + +Note that the configuration proposal is henceforth identified by its 256-bit hash -- the huge decimal number `6465...6321`. We can inspect the current status of a specific configuration proposal by running get-method `get_proposal` with the only argument equal to the identifier of the configuration proposal: +``` +> runmethod -1:5555555555555555555555555555555555555555555555555555555555555555 get_proposal 64654898543692093106630260209820256598623953458404398631153796624848083036321 +... +arguments: [ 64654898543692093106630260209820256598623953458404398631153796624848083036321 94347 ] +result: [ [1586779536 0 [8 C{FDCD887EAF7ACB51DA592348E322BBC0BD3F40F9A801CB6792EFF655A7F43BBC} -1] 112474791597373109254579258586921297140142226044620228506108869216416853782998 () 864691128455135209 3 0 0] ] +``` +We obtain essentially the same result as before, but for only one configuration proposal, and without the identifier of the configuration proposal at the beginning. + +#### 4. Voting for configuration proposals + +Once a configuration proposal is created, it is supposed to collect votes from more than 3/4 of all current validators (by weight, i.e., by stake) in the current and maybe in several subsequent rounds (elected validator sets). In this way the decision to change a configuration parameters must be approved by a significant majority not only of the current set of validators, but also of several subsequent sets of validators. + +Voting for a configuration proposal is possible only for current validators, listed (with their permanent public keys) in configuration parameter `#34`. The process is approximately the following: + +- The operator of a validator looks up `val-idx`, the (0-based) index of his validator in the current set of validators as stored in configuration parameter `#34`. +- The operator invokes special Fift script `config-proposal-vote-req.fif`, found in directory `crypto/smartcont` of the source tree, indicating `val-idx` and `config-proposal-id` as its arguments: +``` + $ fift -s config-proposal-vote-req.fif -i 0 64654898543692093106630260209820256598623953458404398631153796624848083036321 + Creating a request to vote for configuration proposal 0x8ef1603180dad5b599fa854806991a7aa9f280dbdb81d67ce1bedff9d66128a1 on behalf of validator with index 0 + 566F744500008EF1603180DAD5B599FA854806991A7AA9F280DBDB81D67CE1BEDFF9D66128A1 + Vm90RQAAjvFgMYDa1bWZ-oVIBpkaeqnygNvbgdZ84b7f-dZhKKE= + Saved to file validator-to-sign.req +``` +- After that, the vote request has to be signed by the current validator private key, using `sign 566F744...28A1` in `validator-engine-console` connected to the validator. This process is similar to that described in [Validator-HOWTO](https://toncoin.org/#/howto/validator) for participating in validator elections, but this time the currently active key has to be used. +- Next, another script `config-proposal-signed.fif` has to be invoked. It has similar arguments to `config-proposal-req.fif`, but it expects two extra arguments: the base64 representation of the public key used to sign the vote request, and the base64 representation of the signature itself. Again, this is quite similar to the process described in [Validator-HOWTO](https://toncoin.org/#/howto/validator). +- In this way file `vote-msg-body.boc` containing the body of an internal message carrying a signed vote for this configuration proposal is created. +- After that, `vote-msg-body.boc` has to be carried in an internal message from any smart contract residing in the masterchain (typically the controlling smart contract of the validator will be used) along with a small amount of TON Coins for processing (typically 1.5 TON Coins should suffice). This is again completely similar to the procedure employed during validator elections. This is typically achieved by means of running +``` +$ fift -s wallet.fif my_wallet_id -1:5555555555555555555555555555555555555555555555555555555555555555 1 1.5 -B vote-msg-body.boc +``` +(if a simple wallet is used to control the validator) and then sending the resulting file `wallet-query.boc` from the lite-client: + +``` +> sendfile wallet-query.boc +``` + +You can monitor answer messages from the configuration smart contract to the controlling smart contract to learn the status of your voting queries. Alternatively, you can inspect the status of the configuration proposal by means of get-method `show_proposal` of the configuration smart contract: +``` +> runmethod -1:5555555555555555555555555555555555555555555555555555555555555555 get_proposal 64654898543692093106630260209820256598623953458404398631153796624848083036321 +... +arguments: [ 64654898543692093106630260209820256598623953458404398631153796624848083036321 94347 ] +result: [ [1586779536 0 [8 C{FDCD887EAF7ACB51DA592348E322BBC0BD3F40F9A801CB6792EFF655A7F43BBC} -1] 112474791597373109254579258586921297140142226044620228506108869216416853782998 (0) 864691128455135209 3 0 0] ] +``` +This time the list of indices of validators that voted for this configuration proposal should be non-empty, and it should contain the index of your validator. In this example, this list is (`0`), meaning that only the validator with index `0` in configuration parameter `#34` has voted. If the list becomes large enough, the last-but-one integer (the first zero in `3 0 0`) in the proposal status will increase by one, indicating a new win by this proposal. If the number of wins becomes greater than or equal to the value indicated in configuration parameter `#11`, then the configuration proposal is automatically accepted and the proposed changes become effective immediately. On the other hand, when the validator set changes, then the list of validators that have already voted becomes empty, the value of `rounds_remaining` (three in `3 0 0`) is decreased by one, and if it becomes negative, the configuration proposal is destroyed. If it is not destroyed, and if it did not win in this round, then the number of losses (the second zero in `3 0 0`) is increased. If it becomes larger than a value specified in configuration parameter `#11`, then the configuration proposal is discarded. In this way all validators that have abstained from voting in a round have implicitly voted against. + +#### 5. An automated way for voting for configuration proposals + +Similarly to the automation provided by command `createelectionbid` of `validator-engine-console` for participating in validator elections, `validator-engine` and `validator-engine-console` offer an automated way of performing most of the steps explained in the previous section, producing a `vote-msg-body.boc` ready to be used with the controlling wallet. In order to use this method, you must install Fift scripts `config-proposal-vote-req.fif` and `config-proposal-vote-signed.fif` into the same directory that the validator-engine uses to look up `validator-elect-req.fif` and `validator-elect-signed.fif` as explained in Section 5 of [Validator-HOWTO](https://toncoin.org/#/howto/validator). After that, you simply run +``` + createproposalvote 64654898543692093106630260209820256598623953458404398631153796624848083036321 vote-msg-body.boc +``` +in validator-engine-console to create `vote-msg-body.boc` with the body of the internal message to be sent to the configuration smart contract. + +#### 6. Upgrading the code of configuration smart contract and the elector smart contract + +It may happen that the code of the configuration smart contract itself or the code of the elector smart contract has to be upgraded. To this end, the same mechanism as described above is used. The new code is to be stored into the only reference of a value cell, and this value cell has to be proposed as the new value of configuration parameter `-1000` (for upgrading the configuration smart contract) or `-1001` (for upgrading the elector smart contract). These parameters pretend to be critical, so a lot of validator votes are needed to change the configuration smart contract (this is akin to adopting a new constitution). We expect that such changes will involve first testing them in a test network, and discussing the proposed changes in public forums before each validator operator decides to vote for or against proposed changes. + +Alternatively, critical configuration parameters `0` (the address of the configuration smart contract) or `1` (the address of the elector smart contract) can be changed to other values, that must correspond to already existing and correctly initialized smart contracts. In particular, the new configuration smart contract must contain a valid configuration dictionary in the first reference of its persistent data. Since it is not so easy to correctly transfer changing data (such as the list of active configuration proposals, or the previous and current participant lists of validator elections) between different smart contracts, in most cases it is better to upgrade the code of existing smart contract rather than to change the configuration smart contract address. + +There are two auxiliary scripts used to create such configuration proposals to upgrade the code of the configuration or elector smart contract. Namely, `create-config-upgrade-proposal.fif` loads a Fift assembler source file (`auto/config-code.fif` by default, corresponding to the code automatically generated by FunC compiler from `crypto/smartcont/config-code.fc`) and creates the corresponding configuration proposal (for configuration parameter `-1000`). Similarly, `create-elector-upgrade-proposal.fif` loads a Fift assembler source file (`auto/elector-code.fif` by default) and uses it to create a configuration proposal for configuration parameter `-1001`. In this way creating configuration proposals to upgrade one of these two smart contracts should be very simple. However, one should also publish the modified FunC source of the smart contract, the exact version of the FunC compiler used to compile it, so that all validators (or rather their operators) would be able to reproduce the code in the configuration proposal (and compare the hashes), and study and discuss the source code and the changes in this code before deciding to vote for or against proposed changes. diff --git a/versioned_docs/version-1.0.0/develop/howto/full-node.md b/versioned_docs/version-1.0.0/develop/howto/full-node.md new file mode 100644 index 0000000000..1a01ecc0a1 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/howto/full-node.md @@ -0,0 +1,191 @@ +The aim of this document is to provide step-by-step instructions for setting up a full node for the TON Blockchain. We assume some familiarity with the TON Blockchain Lite Client, at least to the extent explained in the Getting Started. + +Note that you need a machine with a public IP address and a high-bandwidth network connection to run a TON Blockchain Full Node. Typically you'll need a sufficiently powerful server in a datacenter with good network connectivity, using at least a 1 Gbit/s connection to reliably accommodate peak loads (the average load is expected to be approximately 100 Mbit/s). We recommend a dual-processor server with at least eight cores in each processor, at least 256 MiB RAM, at least 8 TB of conventional HDD storage and at least 512 GB of faster SSD storage. It is a bad idea to run a Full Node on your home computer; instead, you could run a Full Node on a remote server, and use the TON Blockchain Lite Client to connect to it from home. + +## 0. Downloading and compiling + +The complete TON Blockchain Library and Validator software is downloaded and compiled similarly to the Lite Client. This process is outlined in the Getting Started page. The most important difference is that you have to download the complete sources from public GitHub repository https://github.com/ton-blockchain/ton (e.g., by running `git clone https://github.com/ton-blockchain/ton` and `git submodule update --init` afterward) instead of downloading the smaller Lite Client source archive. You should also build all goals defined in `CMakeLists.txt` (e.g. by running `cmake ` and `make` in your build directory), not only those specifically related to the Lite Client (which is also included in the larger distribution; you don't have to download and build it separately). We strongly recommend building a "release" or a "release with debug information" version of the TON Blockchain Library and especially of the Validator/Full Node bypassing `-DCMAKE_BUILD_TYPE=Release` or `-DCMAKE_BUILD_TYPE=RelWithDebInfo` as an extra argument to `cmake` during its first run (if you forgot to do this, you can later delete file `CMakeCache.txt` from your build directory and re-run `cmake` with the appropriate options). + +## 1. Full Node binaries + +After the sources have been compiled successfully, you should obtain executable files `validator-engine/validator-engine` and `validator-engine-console/validator-engine-console` in your build directory. These are the most important files you need to run a TON Blockchain Full Node (or even a Validator), and to control it. You might wish to install them into your `/usr/bin` or similar directory. You are also likely to need the `generate-random-id` utility during setup. + +## 2. Working directory of the Full Node + +The Full Node (also known as "validator-engine") stores its data in subdirectories of its working directory, e.g., `/var/ton-work/db`. It requires write access to this directory. If you want to use another directory as the working directory of the Full Node, you can use the command line option `--db `: + +``` +$ validator-engine --db ${DB_ROOT} +``` + +where `${DB_ROOT}` is `/var/ton-work/db` or any other directory where validator-engine has write permissions. + +## 3. Working directory layout + +An approximate layout of the working directory of the TON Blockchain Full Node software is as follows: + +* `${DB_ROOT}/config.json` -- Automatically generated configuration file. It is automatically regenerated by validator-engine on some occasions. When validator-engine is not running, you can edit this file in a text editor because it is a JSON file. +* `${DB_ROOT}/static` -- A directory with files that cannot be downloaded from the network, such as the "zerostate" (corresponding to the Genesis block of other blockchain architectures) of the masterchain and active workchains. Normally you don't have to initialize this directory unless you want to run your own instance of the TON Blockchain (for example, for testing or development purposes). Full nodes of existing instances of the TON Blockchain (such as the "testnet" and the "mainnet") will be able to download all required files from already running full nodes. +* `${DB_ROOT}/keyring` -- Stores public and private keys known to validator-engine. For example, if your full node runs as a validator for some of the TON Blockchain shardchains, the validator block signing key is kept here. You may wish to set more restrictive permissions for this directory, such as 0700 (in *nix systems), so that only the user under which validator-engine is running would have access to this directory. +* `${DB_ROOT}/error` -- A directory where validator-engine copies files related to severe error conditions (e.g., invalid block candidates) for further study. It is normally empty, and validator-engine never deletes files from this directory. +* `${DB_ROOT}/archive` -- A directory where old and rarely used blocks are kept until their storage period expires. You can mount a larger but slower disk partition at this directory, or make this directory a symlink to a directory in such a partition. We recommend locating the remainder of `${DB_ROOT}` in a fast storage device such as an SSD. +* `${DB_ROOT}/etc` -- (Non-automatic) configuration files may be kept here, or in any other directory read-accessible to validator-engine. +* Other subdirectories of `${DB_ROOT}` are used to keep ADNL cache data, recent blocks and states, and so on. They are not relevant to the purposes of this document. + +## 4. Global configuration of the TON Blockchain + +In order to set up your Full Node, you'll need a special JSON file called the "global configuration (file)". It is called this because it is the same for all full nodes, and even nodes participating in different instances of the TON Blockchain (e.g., "testnet" vs. "mainnet") share an almost identical global configuration. + +The "mainnet" global configuration can be downloaded at https://ton-blockchain.github.io/global.config.json as follows: + +``` +$ wget https://ton-blockchain.github.io/global.config.json +``` + +You may wish to put this file into `/var/ton-work/etc/ton-global.config.json` . + +We'll discuss the structure of this file later in more detail. For now, let us remark that the bulk of this file consists of a list of known TON DHT nodes required for the bootstrapping of the TON Network. A smaller section near the end of this file describes the particular instance of the TON Blockchain that we wish to connect to. + +All instances of the TON Blockchain use the same "global" TON Network (i.e., the TON Network is not fragmented into several instances for each blockchain instance). While the global network configuration is therefore independent of the particular TON Blockchain instance chosen, the Full Nodes belonging to different instances will later connect to different overlay subnetworks inside the TON Network. + +It is important to distinguish this "global configuration file", used for setting up a TON Blockchain Full Node, and the "local" or "automatic configuration file", automatically updated by validator-engine and usually stored in `${DB_ROOT}/config.json`. The global configuration is used to generate the initial automatic configuration file, which is thereafter updated by validator-engine itself (e.g., by adding new DHT nodes or storing hashes of newer masterchain blocks). + +## 5. Initializing the local configuration + +Once the global configuration file is downloaded, it can be used to create the initial local configuration in `${DB_ROOT}/config.json`. To do this, execute validator-engine once: + +``` +$ validator-engine -C /var/ton-work/etc/ton-global.config.json --db /var/ton-work/db/ --ip : -l /var/ton-work/log +``` + +Here `/var/ton-work/log` is the log directory of `validator-engine`, where it will create its log files. The argument to the `-C` command-line option is the global configuration file downloaded from https://ton-blockchain.github.io/ as explained above, and `/var/ton-work/db/` is the working directory `${DB_ROOT}`. Finally, `:` are the global IP address of this full node (you need to indicate a public IPv4 address here) and the UDP port used to run TON Network protocols such as ADNL and RLDP. Make sure that your firewall is configured to pass UDP packets with source or destination `:` at least for the `validator-engine` binary. + +When validator-engine is invoked as above, and `${DB_ROOT}/config.json` does not exist, it creates a new local configuration file `${DB_ROOT}/config.json` using the information from the global configuration file and from the command-line options such as `--ip`, and then exits. If `${DB_ROOT}/config.json` already exists, it is not rewritten; instead validator-engine starts up as a daemon using both the local and the global configuration. + +If you need to change the local configuration afterwards, you'll need to either delete this file and regenerate it from the global configuration (potentially forgetting other important information accumulated in the local configuration), or edit the local configuration in a text editor (when validator-engine is not running). + +## 6. Setting up remote control CLI + +You will almost surely want to enable validator-engine-console in the local configuration, to be able to control your Full Node (i.e., validator-engine daemon) when it is running. For this, you'll need to generate two keypairs, one for the server (validator-engine) and one for the client (validator-engine-console). In the examples below we assume that validator-engine-console runs on the same machine and connects to validator-engine through the loopback network interface. (This is not necessarily so; you can use validator-engine-console for remote control as well.) + +As a first step, use the `generate-random-id` executable to create two keypairs, one for the server (on the machine running `validator-engine`) and one for the client (on the machine running `validator-engine-console`): + +``` +$ ./generate-random-id -m keys -n server +6E9FD109F76E08B5710445C72D2C5FEDE04A96357DAA4EC0DDAEA025ED3AC3F7 bp/RCfduCLVxBEXHLSxf7eBKljV9qk7A3a6gJe06w/c= +``` + +This utility generates a new keypair and saves the private key into file `server` and the public key into `server.pub`. The hexadecimal (`6E9F...F7`) and the base64 (`bp/RC...6wc/=`) representations of the public key are displayed in the standard output, and are used henceforth to identify this key. + +We have to install the private key `server` into the keyring of the Full Node (validator-engine): + +``` +$ mv server /var/ton-work/db/keyring/6E9FD109F76E08B5710445C72D2C5FEDE04A96357DAA4EC0DDAEA025ED3AC3F7 +``` + +Notice that the file name to store this private key inside the keyring equals the hexadecimal identifier (which essentially is a hash of the public key) of this key. + +Next, we generate the client keypair: + +``` +$ ./generate-random-id -m keys -n client +8BBA4F8FCD7CC4EF573B9FF48DC63B212A8E9292B81FC0359B5DBB8719C44656 i7pPj818xO9XO5/0jcY7ISqOkpK4H8A1m127hxnERlY= +``` + +We obtain a client keypair, saved into files `client` and `client.pub`. This second operation should be run in the working directory of the client (validator-engine-console), possibly on another machine. + +Now we have to list the client's public key in the server's local configuration file `${DB_ROOT}/config.json`. To do this, open the local configuration file in a text editor (after terminating validator-engine if it was running) and find the empty `control` section: + +``` +"control": [ +] +``` + +Replace it with the following: + +``` +"control" : [ + { "id" : "bp/RCfduCLVxBEXHLSxf7eBKljV9qk7A3a6gJe06w/c=", + "port" : , + "allowed" : [ + { "id" : "i7pPj818xO9XO5/0jcY7ISqOkpK4H8A1m127hxnERlY=", + "permissions" : 15 + } + ] + } +], +``` + +`control.0.id` is set to the base64 identifier of the server's public key, and `control.0.allowed.0.id` is the base64 identifier of the client's public key. `` is the TCP port the server will listen to for console commands. + +## 7. Running the Full Node + +To run the full node, simply run the validator-engine binary in a console: + +``` +$ validator-engine --db ${DB_ROOT} -C /var/ton-work/etc/ton-global.config.json -l /var/ton-work/log +``` + +It will read the global configuration from `/var/ton-work/etc/ton-global.config.json`, the local configuration from `${DB_ROOT}/config.json`, and continue running silently. You should write suitable scripts for invoking validator-engine as a daemon (so that it does not terminate when the console is closed), but we'll skip these considerations for simplicity. (The command-line option `-d` of validator-engine should be sufficient for this on most *nix systems.) + +If the configuration is invalid, validator-engine will terminate immediately and, in most cases, output nothing. You'll have to study the log files under `/var/ton-work/log` to find out what went wrong. Otherwise, validator-engine will keep working silently. Again, you can understand what's going on by inspecting the log files, and by looking into subdirectories of the `${DB_ROOT}` directory. + +If everything works as expected, validator-engine will locate other full nodes participating in the same instance of the TON Blockchain, and download recent blocks of the masterchain and all shardchains. (You can actually control the number of recent blocks to be downloaded, or even download them all starting from the zerostate---but this topic is outside the scope of this document; try running validator-engine with command-line option `-h` to find out the list of all available options with brief explanations). + +## 8. Using the Console CLI + +If the validator-engine-console has been set up as explained in Section 6., you can use it to connect to the running validator-engine (i.e., your Full Node) and run simple status and key management queries: + +``` +$ ./validator-engine-console -k client -p server.pub -a : + +connecting to [:] +local key: 8BBA4F8FCD7CC4EF573B9FF48DC63B212A8E9292B81FC0359B5DBB8719C44656 +remote key: 6E9FD109F76E08B5710445C72D2C5FEDE04A96357DAA4EC0DDAEA025ED3AC3F7 +conn ready +> gettime +received validator time: time=1566568904 +``` + +The `gettime` command obtains the current Unix time at the validator. If everything has been configured properly, you'll see an output similar to the one above. Notice that you need both the client's private key (`client`) and the server's public key (`server.pub`) for the console to work. You might wish to move them (especially the client's private key) into a separate directory with suitable permissions. + +Other console commands are available in validator-engine-console. For instance, `help` displays a list of all console commands with short descriptions. In particular, they are used to set up the Full Node as a Validator for the TON Blockchain, as explained in the separate **Validator page**. + +## 9. Setting up the Full Node as a Lite Server + +You can set up your Full Node to function as a Lite Server, so that you can use the Lite Client to connect to it from the same or a remote host. For instance, sending the command `last` in a Lite Client connected to your Full Node will display the identifier of the most recent masterchain block known to your Full Node, so that you can inspect the progress of block downloading. You can also inspect the state of all smart contracts, send external messages (e.g., wallet queries), and so on as explained in the **Step-by-Step page**. + +In order to set up your Full Node as a Lite Server, you have to generate another keypair and install the private key into the server's keyring, similarly to what we did to enable the remote console: + +``` +$ utils/generate-random-id -m keys -n liteserver +BDFEA84525ADB3B16D0192488837C04883C10FF1F4031BB6DEECDD17544F5347 vf6oRSWts7FtAZJIiDfASIPBD/H0Axu23uzdF1RPU0c= + +mv liteserver ${DB_ROOT}/keyring/BDFEA84525ADB3B16D0192488837C04883C10FF1F4031BB6DEECDD17544F5347 +``` + +After that, stop validator-engine if it is running and open the local configuration file` ${TON_DB}/config.json` in a text editor. Find the empty section + +``` +"liteservers" : [ +] +``` + +and replace it with a record containing the TCP port for listening to inbound Lite Client connections and the lite server's public key: + +``` +"liteservers" : [ +{ +"id" : "vf6oRSWts7FtAZJIiDfASIPBD/H0Axu23uzdF1RPU0c=", +"port" : +} +], +``` + +Now start `validator-engine` again. If it does not terminate immediately, it is likely that you have re-configured it properly. Now you can use the lite-client binary (usually located as `lite-client/lite-client` with respect to the build directory) to connect to the Lite Server running as a part of your Full Node: + +``` +$ lite-client -a : -p liteserver.pub +``` + +Again, `help` lists all commands available in the Lite Client. The **Step-by-Step page** contains some examples of what can be done with the Lite Client. diff --git a/versioned_docs/version-1.0.0/develop/howto/getting-started.md b/versioned_docs/version-1.0.0/develop/howto/getting-started.md new file mode 100644 index 0000000000..5996025b16 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/howto/getting-started.md @@ -0,0 +1,60 @@ +Use this software at your own risk; consult the DISCLAIMER for more information. + +The software is licensed under GNU Lesser General Public License version 2 or later; consult LICENSE.LGPL and LGPL.v2 for more information. If you ever use any of these source files to develop your own versions of this or other software, you must attach a comment with the contents of LGPL.v2 to the beginning of each source file taken from this archive. + +The software is likely to compile and work properly on most Linux systems. It should work on macOS and even Windows. + +BASIC COMPILATION AND INSTALLATION INSTRUCTIONS + +1) Download the newest version of the TON blockchain sources, available at GitHub repository https://github.com/ton-blockchain/ton/ : + + ``` + git clone https://github.com/ton-blockchain/ton.git + git submodule update --init + ``` + +2) Install the newest versions of make, cmake (version 3.0.2 or later), OpenSSL (including C header files), and g++ or clang (or another C++14-compatible compiler as appropriate for your operating system). We strongly recommend installing OpenSSL version 1.1.1 or later for better performance, especially if you intend to run a Full Node or a Validator as well. + +3) Suppose that you have fetched the source tree to directory `~/ton`, where `~` is your home directory, and that you have created an empty directory `~/liteclient-build`. Then run the following in a terminal on a Linux system: + + ``` + cd ~/liteclient-build + cmake ~/ton + cmake --build . --target lite-client + ``` + + You might also build some extra utilities useful for smart-contract development: + + ``` + cmake --build . --target fift + cmake --build . --target func + ``` + +4) Download the newest configuration file from https://ton-blockchain.github.io/global.config.json for mainnet: + + ``` + wget https://ton-blockchain.github.io/global.config.json + ``` + + or from https://ton-blockchain.github.io/testnet-global.config.json for testnet + + ``` + wget https://ton-blockchain.github.io/testnet-global.config.json + ``` + +5) Run the Lite Client with config: + + ``` + ./lite-client/lite-client -C global.config.json + ``` + + If everything was installed successfully, the Lite Client will connect to a special server (a full node for the TON Blockchain Network) and will send some queries to the server. + If you indicate a writeable "database" directory as an extra argument to the client, it will download and save the block and the state corresponding to the newest masterchain block: + + ``` + ./lite-client/lite-client -C global.config.json -D ~/ton-db-dir + ``` + + Basic help info can be obtained by typing `help` into the Lite Client. Type `quit` or press Ctrl-C to exit. + +6) Now you can create new smart contracts, examine the state of existing smart contracts, send external messages to smart contracts and so on. You can also use Fift (if you have compiled it) to compile, execute, and debug your smart contracts locally. diff --git a/versioned_docs/version-1.0.0/develop/howto/mining.md b/versioned_docs/version-1.0.0/develop/howto/mining.md new file mode 100644 index 0000000000..9e66e160ad --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/howto/mining.md @@ -0,0 +1,144 @@ +## TON mining guide +### Table of contents +1. [Introduction](#introduction) +2. [Quick start](#quick-start) +3. [Basics](#basics) +4. [Advanced](#advanced) +5. [Miner hardware](#hardware) + * [General](#hardware) + * [Cloud instances](#hardware-cloud) + * [Income estimates](#hardware-estimates) +6. [FAQ](#faq) + * [General](#faq-general) + * [Hardware](#faq-hw) + * [Software](#faq-software) + +## Introduction +This document provides introduction into process of mining TON Coins using PoW givers. Please visit [ton.org/mining](https://ton.org/mining) for up to date status of TON mining. + +## Quick start +To start mining right away: + +1. Get a [computer suitable for mining](#hardware) +2. Install [Ubuntu](https://ubuntu.com) 20.04 desktop or server distribution +3. Install [mytonctrl](https://github.com/igroman787/mytonctrl#installation-ubuntu) in `lite` mode +4. Check your hardware and [expected mining income](#faq-emi) by running `emi` command within `mytonctrl` +5. If you do not yet have one: create `wallet address` using one of the [wallets](https://www.ton.org/wallets) +6. Define your `wallet address` as mining target by executing `set minerAddr "..."` in `mytonctrl` +7. Chose giver contract from the list available on [ton.org/mining](https://ton.org/mining) and set your miner to mine it by executing `set powAddr "..."` in `mytonctrl` +8. Start mining by executing `mon` in `mytonctrl` +9. Check CPU load on your machine, process called `pow-miner` should use most of your CPU +10. Wait to get lucky, output of step 4 should have told you approximately what are your chances to mine a block. + +## Basics +TON Coins are distributed by so-called `PoW Givers` which are smart contracts with certain amount of TONs assigned to them. Currently, there are 10 active PoW givers on TON network. Givers hand out coins in blocks of 100 TON each. In order to receive such block your computer needs to solve complex mathematical challenge issued by a giver and do that as fast as possible: you compete against other miners for the reward of 100 TON. If someone manages to solve the problem before you, all the work your machine has done is in vain and new round/race begins. + +It is important to understand that profits from mining do not "trickle in" as your machine does the works, they come in batches of 100 TON for every successful solution of giver challenge. This means that if your machine has a 10% chance to calculate block within 24h (see step 4 of [Quick start](#quickStart)) then you will probably need to wait for ~10 days before you will get a 100 TON reward. + +The process of mining is largely automated by `mytonctrl`, detailed information about the mining process can be found in [PoW givers](https://www.ton.org/#/howto/pow-givers) document. + +## Advanced +If you are serious about mining and wish to operate more than one machine/mining farm then you really need to learn TON and how mining works, please see [HOWTO](https://ton.org/#/howto/) section for in-depth information. Here is some general advise: + +* **DO** run your own node / liteServer on separate machine, this will ensure that your mining farm does not depend on external liteServers that can go down or not process your queries in timely fashion. +* **DO NOT** bombard public liteServers with `get_pow_params` queries, if you have custom scripts that poll givers status in high frequency you **must** use your own liteServer. Clients that violate this rule risk blacklisting of their IPs on public liteServers. +* **DO** try to understand how [mining process](https://www.ton.org/#/howto/pow-givers) works, most larger miners use their own scripts that offer many advantages over `mytonctrl` in environments with multiple mining machines. + +## Miner hardware +The total network hashrate of TON mining is very high, miners need high-performance machines if they wish to succeed. Mining on standard home computers and notebooks is futile and we advise against such attempts. + +#### CPU +Modern CPU that supports [Intel SHA Extension](https://en.wikipedia.org/wiki/Intel_SHA_extensions) is a **must**. Most miners use AMD EPYC or Threadripper based machines with at least 32 cores / 64 threads. + +#### GPU +Yes! You can mine TON using GPU, there is a version of pow-miner that is capable to use both Nvidia and AMD GPUs, you can find the code as well as instructions on how to use it in the [POW Miner GPU](https://github.com/tontechio/pow-miner-gpu/blob/main/crypto/util/pow-miner-howto.md) repository. + +For now one needs to be tech-savvy to use this but we are working on a more user-friendly solution. + +#### Memory +Almost entire mining process happens in L2 cache of the CPU. That means that memory speed and size play no role in mining performance. A dual AMD EPYC system with single DIMM on one memory channel will mine just as fast as one with 16 DIMMs occupying all channels. + +Please do note that this applies to plain mining process **only**, if your machine also runs full node or other processes then things change! But this is out of scope of this guide. + +#### Storage +Plain miner run in lite mode uses minimal space and does not store any data on storage. + +#### Network +Plain miner needs ability to open outgoing connections to internet. + +#### FPGA / ASIC +See [can I use FPGA / ASICs?](#faq-hw-asic) + +### Cloud machines +Many people mine using AWS or Google compute cloud machines. As outlined in the specs above what really matters is CPU, thus we advise AWS [c5a.24xlarge](https://aws.amazon.com/ec2/instance-types/c5/) or Google [n2d-highcpu-224](https://cloud.google.com/compute/vm-instance-pricing) instances. + +### Income estimates +The formula for income calculation is quite simple: `($total_bleed / $total_hashrate) * $your_hashrate`. This will give you **current** estimate. You can find out the variables on [ton.org/mining](https://ton.org/mining) or use estimated mining income calculator (`emi` command) in `mytonctrl`, here is sample output made on 7th of August 2021 using i5-11400F CPU: +``` +Mining income estimations +----------------------------------------------------------------- +Total network 24h earnings: 171635.79 TON +Average network 24h hashrate: 805276100000 HPS +Your machine hashrate: 68465900 HPS +Est. 24h chance to mine a block: 15% +Est. monthly income: 437.7 TON +``` + +**Important**: Please do note that the information provided is based on *network hashrate at the moment of execution* your actual income over time will depend on many factors such as changing network hashrate, chosen giver, and good portion of luck. + + +## FAQ +### General +#### Is TON PoS or PoW network? +TON Blockchain uses the Proof-of-Stake consensus and mining is not required to generate new blocks. +#### So how come there is Proof-of-Work in TON? +Well, the reason is that the initial issue of 5bn TON Coins was transferred to ad hoc Proof-of-Work Giver smart contracts. +Mining is used to obtain TON Coins from this smart contract. +#### How many coins are left for mining? +The most actual information is available on [ton.org/mining](https://ton.org/mining), see `bleed` graphs. PoW Giver contracts have their limits and will dry out once users mine all available TON Coins. +#### How many coins have been mined already? +As of August 2021, about 4.9BN TON Coins have been mined. +#### Who has mined those coins? +Coins have been mined to over 70'000 wallets, owners of those wallets are not known. +#### Is it difficult to start mining? +Not at all, all you need is [adequate hardware](#hardware) and to follow steps outlined in [quick start](#quickStart) section. +#### Is there another way to mine? +Yes, there is a 3rd party app [TON Miner Bot](https://t.me/TonMinerBot) +#### Where can I see mining statistics? +[ton.org/mining](https://ton.org/mining) +#### How many miners are out there? +We cannot say this, all we know is total hashrate of all miners on the network. There are however graphs on [ton.org/mining](https://ton.org/mining) that attempt to estimate quantity of machines of certan type needed to provide aproximate total hashrate. +#### Do i need TON coins to start mining? +No, you do not, anyone can start mining without owning a single TON Coin +#### I mine for hours, why my wallet total does not increase, not even by 1 TON? +TONs are mined in blocks of 100, you either guess a block and receive 100 TON or receive nothing. please see [basics](#basics) +#### I mine for days and I see no results, why? +Did you check your current [Income estimates](#hardware-estimates)? If field `Est. 24h chance to mine a block` is less than 100% then you need to be patient. Also please do note that a 50% chance to mine a block within 24h does not automatically mean that you will mine one within 2 days, 50% applies to each day individually. +#### Are there mining pools? +No, As of now there are no implementations of mining pools, everyone mines for himself. +#### Which giver should I mine? +It does not really matter which giver you choose, difficulty tends to fluctuate on each giver, so current easiest giver on [ton.org/mining](https://ton.org/mining) might become most complex within an hour, same applies in opposite direction. +### Hardware +#### Will faster machine always win? +No, all miners take different roads to find solution, the faster machine has higher probability of success but it is not guaranteed a victory! +#### How much income will my machine generate? +Please see [Income estimates](#hardware-estimates) +#### Can I use my BTC | ETH rig to mine TON? +No, TON uses single SHA256 hashing method which is different from BTC, ETH and others. ASICS or FPGAs build for mining other cryptos will not help. +#### What is better, single fast machine or several slow ones? +This is controversial, see: miner software launches threads for each core on the system and each core get's its own set of keys to process, so if you have one machine capable to run 64 threads and 4 x machines capable to run 16 threads each then they will be exactly as successful assuming that speed of each thread is the same. + +In real-world however CPUs with lower core count are usually clocked higher, so you will probably have better success with multiple machines. +#### If I run many machines, will they cooperate? +No, they will not. Each machine mines on its own but solution finding process is random, no machine, not even a single thread (see above) will take the same path, thus, their hashrates add up in your favor without direct cooperation. +#### Can I mine using ARM CPUs? +Depends on CPU, AWS Graviton2 instances are very capable miners indeed and are able to hold price/performance ratio alongside AMD EPYC based instances. +### Software +#### Can I mine using Windows / xBSD / some other OS? +Of course, [TON source code](https://github.com/ton-blockchain/ton) has been known to build on Windows, xBSD and other OSes. However, there is no comfortable automated installation as under Linux with `mytonctrl`, you will need to install the software by hand and create your own scripts. For FreeBSD there is a [port](https://github.com/sonofmom/freebsd_ton_port) source code that allows quick installation. +#### Will my mining become faster if I run mytonctrl in full node mode? +Calculation process by itself will not be faster but you will gain some stability and most importantly flexibility if you operate your own full node / liteServer. +#### What do I need to / how can I operate full node? +This is out of scope of this guide, please consult [Full node howto](https://ton.org/#/howto/full-node) and/or [mytonctrl instructions](https://github.com/igroman787/mytonctrl) +#### Can you help me to build software under my OS? +This is out of scope of this guide, please consult [Full node howto](https://ton.org/#/howto/full-node) as well as [Mytonctrl installation scripts](https://github.com/igroman787/mytonctrl/blob/master/scripts/toninstaller.sh#L44) for information about dependencies and process. diff --git a/versioned_docs/version-1.0.0/develop/howto/payment-processing.md b/versioned_docs/version-1.0.0/develop/howto/payment-processing.md new file mode 100644 index 0000000000..cfc91b0bb1 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/howto/payment-processing.md @@ -0,0 +1,91 @@ +# Asset processing on TON + +This document contains overview and specific details which explain how to process (send and accept) digital assets on TON network. + + +## Global overview +Embodying fully asynchronous approach TON blockchain involves a few concepts which are uncommon to traditional blockchains. In particular each interaction of any actor with blockchain consist of graph of asynchronously transferred messages between smart-contracts and/or external world. Common path of any interaction start from external message sent to `wallet` smart-contract which authenticate message sender using public-key cryptography, take duty of fee payment and sending inner blockchain messages. That way transactions on TON network is not synonym of interaction of user with blockchain, but merely node of the message graph: result of accepting and processing of message by smart-contract which may or may not lead to arising of new messages. Interaction may consist of arbitrary number of messages and transactions and span across prolonged period of time. Technically transactions with queues of messages are aggregated to blocks processed by validators. Asynchronous nature of **TON blockchain does not allow to predict hash and lt (logical time) of transaction** on the stage of sending message. Transactions accepted to block are final and will not be tampered. + +**Each inner blockchain message, that is message from one smart-contract to another, bear some amount of digital assets as well as arbitrary portion of data.** + +Smart-contract guidelines recommend to treat data payload starting with 32 binary zeroes as human-readable text message. Most software like wallets and libraries support this specification and allows to send text comment along with TON coins as well as display comments in other messages. + +Smart-contracts **pay fees for transactions** (usually from balance of incoming message) as well as **storage fee for contract's stored code and data**. Fees depend on workchain configs with maximal fees on `masterchain` and substantially lower fees on `basechain`. + + +## Digital assets on TON +TON has three types of digital assets. First is TON Coin, main token of the network. It is used for all basic operations on blockchain like paying gas fees or staking for validation. The second type is native tokens which are special kinds of assets which can be attached to any message in the network. This assets are currently not in use since functionality of issuing new native tokens is closed. Finally, the third type is contract assets: analogous to ERC20, assets which are managed by arbitrary contracts (there are a few proposed specifications) and thus can require custom rules for processing. + +### Simple TON coin transfer +To send TON coins user need to send request via external message, that is message from outer world to the blockchain, to special `wallet` smart-contract (see below). Upon receiving this request `wallet` will send inner message with desired amount of assets and optional data payload, for instance text comment. + +## Wallet smart-contract +Wallet smart-contracts are contracts on TON-network which serve task to allow actor outside blockchain to interact with blockchain entities. Generally it solves three challenges: +* authenticate owner: reject to process and pay fees for non-owners requests +* replay protection: prohibit repetitive execution of one request, for instance sending assets to some other smart-contract +* initiate arbitrary interaction with other smart-contracts + +Standart solution for the first challenge is public-key cryptography: `wallet` stores public key and check that incoming message with request is signed by corresponding private key which known to owner only. Solution to the third challenge is common as well, generally request contains a fully formed inner message which `wallet` sends to network. However, for replay protection there is a few different approaches. + +### Seqno-based wallets +Seqno-based wallets follow the most simple approach of sequencing message. Each message has special `seqno` integer which should coincide with counter stored in `wallet` smart-contract. `wallet` updates counter on each request thus ensuring that one request will not be processed twice. There are a few `wallet` versions that differs in publicly available methods, ability to limit request by expiration time and to have multiple wallets with the same public key. However inherent requirement of that approach is to send requests one by one, since any gap in `seqno` sequence will result in inability to process of all subsequent requests. + +### High-load wallets +This `wallet` type follows approach based on storing identificator of the non-expired processed requests in smart-contract storage. In this approach any request is checked of being duplicate of already processed request and, if replay is detected, dropped. Due to presence of expiration contract may not store all request forever, but remove those that can not be processed due to expiration limit. Requests to this `wallet` may be sent in parallel without interference with each other, however this approach requires more sophisticated monitoring of request processing. + +## Interaction with blockchain +Basic operations on TON blockchain can be carried out via tonlib. It is shared library which can be compiled along with TON node and expose API for interaction with blockchain via so called liteservers (servers for lite-clients). Tonlib follows trustless approach by checking proofs for all incoming data, thus there is no necessity in trusted data provider. Methods available to tonlib are listed [in TL scheme](https://github.com/ton-blockchain/ton/blob/master/tl/generate/scheme/tonlib_api.tl#L234). They can be used either as shared library, via wrappers like [pyTON](https://github.com/EmelyanenkoK/pyTON) or [tonlib-go](https://github.com/mercuryoio/tonlib-go/tree/master/v2) (technically those are wrappers for `tonlibjson`) or through `tonlib-cli`. + + +## Deploying wallet +To deploy wallet via Tonlib one need: +1. Generate private/public key pair via [createNewKey](https://github.com/ton-blockchain/ton/blob/master/tl/generate/scheme/tonlib_api.tl#L213) or it's wrapper functions (example in [tonlib-go](https://github.com/mercuryoio/tonlib-go/tree/master/v2#create-new-private-key)). Note that private key is generated locally and do not leave host machine. +2. Form [InitialAccountWallet](https://github.com/ton-blockchain/ton/blob/master/tl/generate/scheme/tonlib_api.tl#L60) structure corresponding to one of enabled `wallets`. Currently `wallet.v3`, `wallet.highload.v1`, `wallet.highload.v2` are available. +3. Calculate address of new `wallet` smart-contract via [getAccountAddress](https://github.com/ton-blockchain/ton/blob/master/tl/generate/scheme/tonlib_api.tl#L249) method. We recommend to use default revision `0` and also to deploy wallets in basechain `workchain=0` for lower processing and storage fees. +4. Send some TON Coins to calculated address. Note that you need to send them in `non-bounce` regime since this address has no code yet and thus cannot process incoming message. `non-bounce` flag indicate that even if processing will fail money should not be returned back with bounce message. We do not recommend to use `non-bounce` flag for other transactions, especially carrying large sums, since bounce mechanism provides some degree of protection against mistakes. +5. Form desired [action](https://github.com/ton-blockchain/ton/blob/master/tl/generate/scheme/tonlib_api.tl#L148), for instance `actionNoop` for deploy only. Than use [createQuery](https://github.com/ton-blockchain/ton/blob/master/tl/generate/scheme/tonlib_api.tl#L255) and [sendQuery](https://github.com/ton-blockchain/ton/blob/master/tl/generate/scheme/tonlib_api.tl#L260) to initiate interaction with blockchain. +6. Check contract in a few seconds by [getAccountState](https://github.com/ton-blockchain/ton/blob/master/tl/generate/scheme/tonlib_api.tl#L254) method. + +## Incoming message value +To calculate incoming value which message bring to the contract, one need to parse transaction which happens when message hits contract. Transaction can be obtained by [getTransactions](https://github.com/ton-blockchain/ton/blob/master/tl/generate/scheme/tonlib_api.tl#L236). For incoming wallet transaction, correct data consist of one incoming message and zero outcoming messages. Otherwise that either external message to wallet, that is owner spends TON Coins or wallet is not deployed and incoming transaction bounces back. +Anyway, in general case amount which message brings to the contract can be calculated as value of incoming message minus sum of value of outcoming messages minus fee: `value_{in_msg} - SUM(value_{out_msg}) - fee`. Technically, transaction representation contains three different fields with `fee` in name: `fee`, `storage_fee` and `other_fee`, that is total fee, part of the fee related to storage costs and part of the fee related to transaction processing. Only the first one should be used. + +## Checking contract's transactions +Transaction for contract can be obtained by [getTransactions](https://github.com/ton-blockchain/ton/blob/master/tl/generate/scheme/tonlib_api.tl#L236). This method allows to get 10 transactions from some `transactionId` and earlier. To process all incoming transactions the following steps should be done: +1. Latest `last_transaction_id` can be obtained via [getAccountState](https://github.com/ton-blockchain/ton/blob/master/tl/generate/scheme/tonlib_api.tl#L235) +2. List of 10 transactions should be loaded via `getTransactions` method. +3. Unseen transactions from this list should be processed. +4. Transactions where incoming message has source address are incoming payments; transactions where incoming message has no source address and also outcoming messages presented are outcoming payments. Those transactions should be processed accordingly. +5. If all of those 10 transactions are unseen, next 10 transaction should be loaded and steps 2,3,4,5 should be repeated. + + +## Accepting payments +There are a few approaches to accept payments that differs in method of distinguishing users. +### Invoice based approach +To accept payments basing on attached comments, service should +1. Deploy `wallet` contract +2. Generate unique `invoice` for each user. String representation of uuid32 will be enough. +3. Users should be instructed to send TON coins to service's `wallet` contract with attached `invoice` as comment. +4. Service should regularly poll getTransactions method for `wallet` contract. +5. For new transactions incoming message should be extracted, `comment` matched against database and value (see **Incoming message value** paragraph) deposited to user account. + +## Sending payments + +1. Service should deploy `wallet` and keep it funded to prevent contract destruction due to storage fees. Note storage fees are generally less than 1 TON Coin per year. +2. Service should get from user `destination_address` and optional `comment`. Note, for now we recommend either prohibit unfinished outgoing payments with the same (`destination_address`, `value`, `comment`) set or proper scheduling of those payments in that way that next payment is initiated only after previous one is confirmed. +3. Form [msg.dataText](https://github.com/ton-blockchain/ton/blob/master/tl/generate/scheme/tonlib_api.tl#L98) with `comment` as text. +4. Form [msg.message](https://github.com/ton-blockchain/ton/blob/master/tl/generate/scheme/tonlib_api.tl#L108) which contains `destination_address`, empty `public_key`, `amount` and `msg.dataText`. +5. Form [Action](https://github.com/ton-blockchain/ton/blob/master/tl/generate/scheme/tonlib_api.tl#L149) which contains set of outgoing messages. +6. Use create [createQuery](https://github.com/ton-blockchain/ton/blob/master/tl/generate/scheme/tonlib_api.tl#L255) and send [sendQuery](https://github.com/ton-blockchain/ton/blob/master/tl/generate/scheme/tonlib_api.tl#L260) query to send outgoing payment. +7. Service should regularly poll getTransactions method for `wallet` contract. Matching confirmed transactions with outgoing payments by (`destination_address`, `value`, `comment`) allows to mark payment as finished; detect and show user corresponding transaction hash and lt (logical time). +8. Requests to `v3` of `high-load` wallets have expiration time equal to 60 seconds by default. After that time unprocessed requests can be safely resent to the network (see steps 3-6). + +## Explorers + +Blockchain explorer - https://tonscan.org + +To generate link to transaction in explorer, service need to get lt (logic time), transaction hash and account address (account address for which lt and txhash was retrieved via getTransactions method). https://tonscan.org and https://explorer.toncoin.org/ may then show page for that tx in the following format: + +`https://tonscan.org/tx/{lt as int}:{txhash as base64url}:{account address}` + +`https://explorer.toncoin.org/transaction?account={account address}<={lt as int}&hash={txhash as base64url}` diff --git a/versioned_docs/version-1.0.0/develop/howto/pow-givers.md b/versioned_docs/version-1.0.0/develop/howto/pow-givers.md new file mode 100644 index 0000000000..8bdaa95857 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/howto/pow-givers.md @@ -0,0 +1,191 @@ +The aim of this text is to describe how to interact with Proof-of-Work Giver smart contracts to obtain TON Coins. We assume familiarity with the TON Blockchain LiteClient as explained in the `Getting Started`, and with the procedure required to compile the LiteClient and other software. For obtaining larger amount of TON Coins required for running a validator, we also assume acquaintance with the `Full Node` and `Validator` pages. You will also need a dedicated server powerful enough for running a Full Node in order to obtain the larger amount of TON Coins. Obtaining small amounts of TON Coins does not require a dedicated server and may be done in several minutes on a home computer. + +> Note that at the moment, due to a large number of miners, large resources are required for any mining + +## 1. Proof-of-Work Giver smart contracts + +In order to prevent a small number of malicious parties to collect all TON Coins, a special kind of "Proof-of-Work Giver" smart contract have been deployed in the masterchain of the network. The addresses of these smart contacts are: + +Small givers (deliver from 10 to 100 TON Coins every several minutes): + +* kf-kkdY_B7p-77TLn2hUhM6QidWrrsl8FYWCIvBMpZKprBtN +* kf8SYc83pm5JkGt0p3TQRkuiM58O9Cr3waUtR9OoFq716lN- +* kf-FV4QTxLl-7Ct3E6MqOtMt-RGXMxi27g4I645lw6MTWraV +* kf_NSzfDJI1A3rOM0GQm7xsoUXHTgmdhN5-OrGD8uwL2JMvQ +* kf8gf1PQy4u2kURl-Gz4LbS29eaN4sVdrVQkPO-JL80VhOe6 +* kf8kO6K6Qh6YM4ddjRYYlvVAK7IgyW8Zet-4ZvNrVsmQ4EOF +* kf-P_TOdwcCh0AXHhBpICDMxStxHenWdLCDLNH5QcNpwMHJ8 +* kf91o4NNTryJ-Cw3sDGt9OTiafmETdVFUMvylQdFPoOxIsLm +* kf9iWhwk9GwAXjtwKG-vN7rmXT3hLIT23RBY6KhVaynRrIK7 +* kf8JfFUEJhhpRW80_jqD7zzQteH6EBHOzxiOhygRhBdt4z2N + +Large givers (deliver 10000 TON Coins at least once a day): + +* kf8guqdIbY6kpMykR8WFeVGbZcP2iuBagXfnQuq0rGrxgE04 +* kf9CxReRyaGj0vpSH0gRZkOAitm_yDHvgiMGtmvG-ZTirrMC +* kf-WXA4CX4lqyVlN4qItlQSWPFIy00NvO2BAydgC4CTeIUme +* kf8yF4oXfIj7BZgkqXM6VsmDEgCqWVSKECO1pC0LXWl399Vx +* kf9nNY69S3_heBBSUtpHRhIzjjqY0ChugeqbWcQGtGj-gQxO +* kf_wUXx-l1Ehw0kfQRgFtWKO07B6WhSqcUQZNyh4Jmj8R4zL +* kf_6keW5RniwNQYeq3DNWGcohKOwI85p-V2MsPk4v23tyO3I +* kf_NSPpF4ZQ7mrPylwk-8XQQ1qFD5evLnx5_oZVNywzOjSfh +* kf-uNWj4JmTJefr7IfjBSYQhFbd3JqtQ6cxuNIsJqDQ8SiEA +* kf8mO4l6ZB_eaMn1OqjLRrrkiBcSt7kYTvJC_dzJLdpEDKxn + +> Note that by the current moment all large givers are depleted + +The first ten smart contracts enable a user willing to obtain a small amount of TON Coins to obtain some without spending too much computing power (typically, several minutes of work of a home computer should suffice). The remaining smart contracts are for obtaining larger amounts of TON Coins required for running a validator in the network; typically, a day of work of a dedicated server powerful enough to run a validator should suffice to obtain the necessary amount. + +> Note that at the moment, due to a large number of miners, large resources are required for mining small givers + +You should randomly choose one of these "proof-of-work giver" smart contracts (from one of these two lists depending on your purpose) and obtain TON Coins from this smart contract by a procedure similar to "mining". Essentially, you have to present an external message containing the proof of work and the address of your wallet to the chosen "proof-of-work giver" smart contract, and then the necessary amount will be sent to you. + +## 2. The "mining" process + +In order to create an external message containing the "proof of work", you should run a special "mining" utility, compiled from the TON sources located in the GitHub repository. The utility is located in file `./crypto/pow-miner` with respect to the build directory and can be compiled by typing `make pow-miner` in the build directory. + +However, before running `pow-miner`, you need to know the actual values of `seed` and `complexity` parameters of the chosen "proof-of-work giver" smart contract. This can be done by invoking get-method `get_pow_params` of this smart contract. For instance, if you use giver smart contract `kf-kkdY_B7p-77TLn2hUhM6QidWrrsl8FYWCIvBMpZKprBtN`, you can simply type + +``` +> runmethod kf-kkdY_B7p-77TLn2hUhM6QidWrrsl8FYWCIvBMpZKprBtN get_pow_params +``` + +in the LiteClient console and obtain an output like + +``` ... + arguments: [ 101616 ] + result: [ 229760179690128740373110445116482216837 53919893334301279589334030174039261347274288845081144962207220498432 100000000000 256 ] + remote result (not to be trusted): [ 229760179690128740373110445116482216837 53919893334301279589334030174039261347274288845081144962207220498432 100000000000 256 ] +``` + +The two first large numbers in the "result:" line are the `seed` and the `complexity` of this smart contract. In this example, the seed is `229760179690128740373110445116482216837` and the complexity is `53919893334301279589334030174039261347274288845081144962207220498432`. + +Next, you invoke the `pow-miner` utility as follows: + +``` +$ crypto/pow-miner -vv -w -t +``` + +Here: +* ``: is the number of CPU cores that you want to use for mining. +* ``: is the maximal amount of seconds that the miner would run before admitting failure. +* `` is the address of your wallet (possibly not initialized yet), either in the masterchain or in the workchain (note that you need a masterchain wallet to control a validator). +* `` and `` are the most recent values obtained by running get-method `get-pow-params`, +* `` is the address of the chosen proof-of-work giver smart contract. +* `` is the filename of the output file where the external message with the proof of work will be saved in the case of success. + +For example, if your wallet address is `kQBWkNKqzCAwA9vjMwRmg7aY75Rf8lByPA9zKXoqGkHi8SM7`, you might run + +``` +$ crypto/pow-miner -vv -w7 -t100 kQBWkNKqzCAwA9vjMwRmg7aY75Rf8lByPA9zKXoqGkHi8SM7 229760179690128740373110445116482216837 53919893334301279589334030174039261347274288845081144962207220498432 100000000000 kf-kkdY_B7p-77TLn2hUhM6QidWrrsl8FYWCIvBMpZKprBtN mined.boc +``` + +The program will run for some time (at most 100 seconds in this case) and either terminate successfully (with zero exit code) and save the required proof of work into file `mined.boc`, or terminate with a non-zero exit code if no proof of work was found. + +In the case of failure, you will see something like + +``` + [ expected required hashes for success: 2147483648 ] + [ hashes computed: 1192230912 ] +``` + +and the program will terminate with a non-zero exit code. Then you have to obtain the `seed` and `complexity` again (because they may have changed in the meantime as a result of processing requests from more successful miners) and re-run the `pow-miner` with the new parameters, repeating the process again and again until success. + +In the case of success, you will see something like + +``` + [ expected required hashes for success: 2147483648 ] + 4D696E65005EFE49705690D2AACC203003DBE333046683B698EF945FF250723C0F73297A2A1A41E2F1A1F533B3BC4F5664D6C743C1C5C74BB3342F3A7314364B3D0DA698E6C80C1EA4ACDA33755876665780BAE9BE8A4D6385A1F533B3BC4F5664D6C743C1C5C74BB3342F3A7314364B3D0DA698E6C80C1EA4 + Saving 176 bytes of serialized external message into file `mined.boc` + [ hashes computed: 1122036095 ] +``` + +Then you can use the LiteClient to send external message from file `mined.boc` to the proof-of-work giver smart contract (and you must do this as soon as possible): + +``` +> sendfile mined.boc +... external message status is 1 +``` + +You can wait for several seconds and check the state of your wallet: + +:::info +Please note here and further that the code, comments and/or documentation may contain parameters, methods and definitions “gram”, “nanogram”, etc. That is a legacy of the original TON code, developed by the Telegram. Gram cryptocurrency was never issued. The currency of TON is Toncoin and the currency of TON testnet is Test Toncoin. +::: +``` +> last +> getaccount kQBWkNKqzCAwA9vjMwRmg7aY75Rf8lByPA9zKXoqGkHi8SM7 +... +account state is (account + addr:(addr_std + anycast:nothing workchain_id:0 address:x5690D2AACC203003DBE333046683B698EF945FF250723C0F73297A2A1A41E2F1) + storage_stat:(storage_info + used:(storage_used + cells:(var_uint len:1 value:1) + bits:(var_uint len:1 value:111) + public_cells:(var_uint len:0 value:0)) last_paid:1593722498 + due_payment:nothing) + storage:(account_storage last_trans_lt:7720869000002 + balance:(currencies + grams:(nanograms + amount:(var_uint len:5 value:100000000000)) + other:(extra_currencies + dict:hme_empty)) + state:account_uninit)) +x{C005690D2AACC203003DBE333046683B698EF945FF250723C0F73297A2A1A41E2F12025BC2F7F2341000001C169E9DCD0945D21DBA0004_} +last transaction lt = 7720869000001 hash = 83C15CDED025970FEF7521206E82D2396B462AADB962C7E1F4283D88A0FAB7D4 +account balance is 100000000000ng +``` + +If nobody has sent a valid proof of work with this `seed` and `complexity` before you, the proof-of-work giver will accept your proof of work and this will be reflected in the balance of your wallet (10 or 20 seconds may elapse after sending the external message before this happens; be sure to make several attempts and type `last` each time before checking the balance of your wallet to refresh the LiteClient state). In the case of success, you will see that the balance has been increased (and even that your wallet has been created in uninitialized state if it did not exist before). In the case of failure, you will have to obtain the new `seed` and `complexity` and repeat the mining process from the very beginning. + +If you have been lucky and the balance of your wallet has been increased, you may want to initialize the wallet if it wasn't initialized before (more information on wallet creation can be found in `Step-by-Step`): + +``` +> sendfile new-wallet-query.boc +... external message status is 1 +> last +> getaccount kQBWkNKqzCAwA9vjMwRmg7aY75Rf8lByPA9zKXoqGkHi8SM7 +... +account state is (account + addr:(addr_std + anycast:nothing workchain_id:0 address:x5690D2AACC203003DBE333046683B698EF945FF250723C0F73297A2A1A41E2F1) + storage_stat:(storage_info + used:(storage_used + cells:(var_uint len:1 value:3) + bits:(var_uint len:2 value:1147) + public_cells:(var_uint len:0 value:0)) last_paid:1593722691 + due_payment:nothing) + storage:(account_storage last_trans_lt:7720945000002 + balance:(currencies + grams:(nanograms + amount:(var_uint len:5 value:99995640998)) + other:(extra_currencies + dict:hme_empty)) + state:(account_active + ( + split_depth:nothing + special:nothing + code:(just + value:(raw@^Cell + x{} + x{FF0020DD2082014C97BA218201339CBAB19C71B0ED44D0D31FD70BFFE304E0A4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED54} + )) + data:(just + value:(raw@^Cell + x{} + x{00000001CE6A50A6E9467C32671667F8C00C5086FC8D62E5645652BED7A80DF634487715} + )) + library:hme_empty)))) +x{C005690D2AACC203003DBE333046683B698EF945FF250723C0F73297A2A1A41E2F1206811EC2F7F23A1800001C16B0BC790945D20D1929934_} + x{FF0020DD2082014C97BA218201339CBAB19C71B0ED44D0D31FD70BFFE304E0A4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED54} + x{00000001CE6A50A6E9467C32671667F8C00C5086FC8D62E5645652BED7A80DF634487715} +last transaction lt = 7720945000001 hash = 73353151859661AB0202EA5D92FF409747F201D10F1E52BD0CBB93E1201676BF +account balance is 99995640998ng +``` + +Now you are a happy owner of 100 TON Coins. Congratulations! + +## 3. Automating the mining process in the case of failure + +If you fail to obtain your TON Coins for a long time, this may happen because too many other users are simultaneously "mining" from the same proof-of-work giver smart contract. Maybe you should choose another proof-of-work giver smart contract from one of the lists given above. Alternatively, you can write a simple script to automatically run `pow-miner` with the correct parameters again and again until success (detected by checking the exit code of `pow-miner`) and invoke the lite-client with parameter `-c 'sendfile mined.boc'` to send the external message immediately after it is found. \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/howto/step-by-step.md b/versioned_docs/version-1.0.0/develop/howto/step-by-step.md new file mode 100644 index 0000000000..fee421c541 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/howto/step-by-step.md @@ -0,0 +1,597 @@ +The aim of this document is to provide step-by-step instructions for compiling and creating a simple smart contract (a simple wallet) in the TON Blockchain Test Network using the TON Blockchain Lite Client and associated software. + +We assume here that the Lite Client is already properly downloaded, compiled and installed. + +> Note that this tutorial is for a testnet, so you must use the config https://ton-blockchain.github.io/testnet-global.config.json + +## 1. Smart-contract addresses + +Smart-contract addresses in the TON Network consist of two parts: + +(a) the workchain ID (a signed 32-bit integer) and + +(b) the address inside the workchain (64-512 bits depending on the workchain). + +Currently, only the masterchain (workchain_id=-1) and occasionally the basic workchain (workchain_id=0) are running in the TON Blockchain Network. Both of them have 256-bit addresses, so we henceforth assume that workchain_id is either 0 or -1 and that the address inside the workchain is exactly 256-bit. + +Under the conditions stated above, the smart-contract address can be represented in the following forms: + +A) "Raw": < decimal workchain_id>:<64 hexadecimal digits with address> + +B) "User-friendly", which is obtained by first generating: +- one tag byte (0x11 for "bounceable" addresses, 0x51 for "non-bounceable"; add +0x80 if the address should not be accepted by software running in the production network) +- one byte containing a signed 8-bit integer with the workchain_id (0x00 for the basic workchain, 0xff for the masterchain) +- 32 bytes containing 256 bits of the smart-contract address inside the workchain (big-endian) +- 2 bytes containing CRC16-CCITT of the previous 34 bytes + +In case B), the 36 bytes thus obtained are then encoded using base64 (i.e., with digits, upper- and lowercase Latin letters, '/' and '+') or base64url (with '_' and '-' instead of '/' and '+'), yielding 48 printable non-space characters. + +Example: + +The "test giver" (a special smart contract residing in the masterchain of the Test Network that gives up to 20 test coins to anybody who asks) has the address + +`-1:fcb91a3a3816d0f7b8c2c76108b8a9bc5a6b7a55bd79f8ab101c52db29232260` + +in the "raw" form (notice that uppercase Latin letters 'A'..'F' may be used instead of 'a'..'f') + +and + +`kf/8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15-KsQHFLbKSMiYIny` (base64) + +`kf_8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15-KsQHFLbKSMiYIny` (base64url) + +in the "user-friendly" form (to be displayed by user-friendly clients). Notice that both forms (base64 and base64url) are valid and must be accepted. + +Incidentally, other binary data related to the TON Blockchain have similar "armored" base64 representations, differing by their first bytes. For example, the ubiquitous 256-bit Ed25519 public keys are represented by first creating a 36-byte sequence as follows: +- one tag byte 0x3E, meaning that this is a public key +- one tag byte 0xE6, meaning that this is a Ed25519 public key +- 32 bytes containing the standard binary representation of the Ed25519 public key +- 2 bytes containing the big-endian representation of CRC16-CCITT of the previous 34 bytes. + +The resulting 36-byte sequence is converted into a 48-character base64 or base64url string in the standard fashion. For example, the Ed25519 public key `E39ECDA0A7B0C60A7107EC43967829DBE8BC356A49B9DFC6186B3EAC74B5477D` (usually represented by a sequence of 32 bytes `0xE3, 0x9E, ..., 0x7D`) has the following "armored" representation: + +`Pubjns2gp7DGCnEH7EOWeCnb6Lw1akm538YYaz6sdLVHfRB2` + +## Inspecting the state of a smart contract + +Inspecting the state of smart contracts with the aid of the TON Lite Client is easy. For the sample smart contract described above, you would run the Lite Client and enter the following commands: + +``` +> last +... +> getaccount -1:fcb91a3a3816d0f7b8c2c76108b8a9bc5a6b7a55bd79f8ab101c52db29232260 +or +> getaccount kf_8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15-KsQHFLbKSMiYIny +``` + +You will see something like this: + +:::info +Please note here and further that the code, comments and/or documentation may contain parameters, methods and definitions “gram”, “nanogram”, etc. That is a legacy of the original TON code, developed by the Telegram. Gram cryptocurrency was never issued. The currency of TON is Toncoin and the currency of TON testnet is Test Toncoin. +::: +``` +got account state for -1 : FCB91A3A3816D0F7B8C2C76108B8A9BC5A6B7A55BD79F8AB101C52DB29232260 with respect to blocks (-1,8000000000000000,2075):BFE876CE2085274FEDAF1BD80F3ACE50F42B5A027DF230AD66DCED1F09FB39A7:522C027A721FABCB32574E3A809ABFBEE6A71DE929C1FA2B1CD0DDECF3056505 +account state is (account + addr:(addr_std + anycast:nothing workchain_id:-1 address:xFCB91A3A3816D0F7B8C2C76108B8A9BC5A6B7A55BD79F8AB101C52DB29232260) + storage_stat:(storage_info + used:(storage_used + cells:(var_uint len:1 value:3) + bits:(var_uint len:2 value:707) + public_cells:(var_uint len:0 value:0)) last_paid:1568899526 + due_payment:nothing) + storage:(account_storage last_trans_lt:2310000003 + balance:(currencies + grams:(nanograms + amount:(var_uint len:6 value:9998859500889)) + other:(extra_currencies + dict:hme_empty)) + state:(account_active + ( + split_depth:nothing + special:nothing + code:(just + value:(raw@^Cell + x{} + x{FF0020DD2082014C97BA9730ED44D0D70B1FE0A4F260D31F01ED44D0D31FD166BAF2A1F8000120D74A8E11D307D459821804A817C80073FB0201FB00DED1A4C8CB1FC9ED54} + )) + data:(just + value:(raw@^Cell + x{} + x{00009A15} + )) + library:hme_empty)))) +x{CFFFCB91A3A3816D0F7B8C2C76108B8A9BC5A6B7A55BD79F8AB101C52DB2923226020680B0C2EC1C0E300000000226BF360D8246029DFF56534_} + x{FF0020DD2082014C97BA9730ED44D0D70B1FE0A4F260D31F01ED44D0D31FD166BAF2A1F8000120D74A8E11D307D459821804A817C80073FB0201FB00DED1A4C8CB1FC9ED54} + x{00000003} +last transaction lt = 2310000001 hash = 73F89C6F8910F598AD84504A777E5945C798AC8C847FF861C090109665EAC6BA +``` + +The first information line `got account state ... for ...` shows the account address and the masterchain block identifier with respect to which the account state has been dumped. Notice that even if the account state changes in a subsequent block, the `getaccount xxx` command will return the same result until the reference block is updated to a newer value by a `last` command. In this way one can study the state of all accounts and obtain consistent results. + +The `account state is (account ... ` line begins the pretty-printed deserialized view of the account state. It is a deserialization of TL-B data type Account, used to represent account states in the TON Blockchain as explained in the TON Blockchain documentation. (You can find the TL-B scheme used for deserialization in the source file `crypto/block/block.tlb`; notice that if the scheme is out of date, the deserialization may break down.) + +Finally, the last several lines beginning with `x{CFF...` (the "raw dump") contain the same information displayed as a tree of cells. In this case, we have one root cell containing the data bits `CFF...34_` (the underscore means that the last binary one and all subsequent binary zeroes are to be removed, so hexadecimal `4_` corresponds to binary `0`), and two cells that are its children (displayed with one-space indentation). + +We can see that `x{FF0020DD20...}` is the code of this smart contract. If we consult the Appendix A of the TON Virtual Machine documentation, we can even disassemble this code: `FF00` is `SETCP 0`, `20` is `DUP`, `DD` is `IFNOTRET`, `20` is `DUP`, and so on. (Incidentally, you can find the source code of this smart contract in the source file `crypto/block/new-testgiver.fif`) + +We can also see that `x{00009A15}` (the actual value you see may be different) is the persistent data of this smart contract. It is actually an unsigned 32-bit integer, used by the smart contract as the counter of operations performed so far. Notice that this value is big-endian (i.e., 3 is encoded as `x{00000003}`, not as `x{03000000}`), as are all integers inside the TON Blockchain. In this case the counter is equal to `0x9A15` = `39445`. + +The current balance of the smart contract is easily seen in the pretty-printed portion of the output. In this case, we see `... balance:(currencies:(grams:(nanograms:(... value:1000000000000000...))))`, which is the balance of the account in (test) nanotons (a million test TON Coins in this example; the actual number you see may be smaller). If you study the TL-B scheme provided in `crypto/block/scheme.tlb`, you will be able to find this number (10^15) in binary big-endian form in the raw dump portion as well (it is located near the end of the data bits of the root cell). + +## 3. Compiling a new smart contract + +Before uploading a new smart contract into the TON Blockchain, you need to determine its code and data and save them in serialized form into a file (called a "bag-of-cells" or BOC file, usually with a .boc suffix). Let us consider the case of a simple wallet smart contract, which stores a 32-bit operations counter and a 256-bit Ed25519 public key of its owner in its persistent data. + +Obviously, you'll need some tools for developing smart contracts - namely, a TON smart contract compiler. Basically, a TON smart contract compiler is a program that reads the source of a smart contract in a specialized high-level programming language and creates a .boc file from this source. + +One such tool is the Fift interpreter, which is included in this distribution and can help create simple smart contracts. Larger smart contracts should be developed using more sophisticated tools (such as the FunC compiler included in this distribution, that creates Fift assembler files from FunC source files; you can find some FunC smart-contract sources in the directory `crypto/smartcont`). However, Fift is sufficient for demonstration purposes. + +Consider the file `new-wallet.fif` (usually located as `crypto/smartcont/new-wallet.fif` with respect to the source directory) containing the source of a simple wallet smart contract: + +``` +#!/usr/bin/env fift -s +"TonUtil.fif" include +"Asm.fif" include + +{ ."usage: " @' $0 type ." []" cr + ."Creates a new wallet in specified workchain, with private key saved to or loaded from .pk" cr + ."('new-wallet.pk' by default)" cr 1 halt +} : usage +$# 1- -2 and ' usage if + +$1 parse-workchain-id =: wc // set workchain id from command line argument +def? $2 { @' $2 } { "new-wallet" } cond constant file-base + +."Creating new wallet in workchain " wc . cr + +// Create new simple wallet +<{ SETCP0 DUP IFNOTRET // return if recv_internal + DUP 85143 INT EQUAL IFJMP:<{ // "seqno" get-method + DROP c4 PUSHCTR CTOS 32 PLDU // cnt + }> + INC 32 THROWIF // fail unless recv_external + 512 INT LDSLICEX DUP 32 PLDU // sign cs cnt + c4 PUSHCTR CTOS 32 LDU 256 LDU ENDS // sign cs cnt cnt' pubk + s1 s2 XCPU // sign cs cnt pubk cnt' cnt + EQUAL 33 THROWIFNOT // ( seqno mismatch? ) + s2 PUSH HASHSU // sign cs cnt pubk hash + s0 s4 s4 XC2PU // pubk cs cnt hash sign pubk + CHKSIGNU // pubk cs cnt ? + 34 THROWIFNOT // signature mismatch + ACCEPT + SWAP 32 LDU NIP + DUP SREFS IF:<{ + // 3 INT 35 LSHIFT# 3 INT RAWRESERVE // reserve all but 103 coins from the balance + 8 LDU LDREF // pubk cnt mode msg cs + s0 s2 XCHG SENDRAWMSG // pubk cnt cs ; ( message sent ) + }> + ENDS + INC NEWC 32 STU 256 STU ENDC c4 POPCTR +}>c // >libref +// code + // data +null // no libraries +// Libs{ x{ABACABADABACABA} drop x{AAAA} s>c public_lib x{1234} x{5678} |_ s>c public_lib }Libs + // create StateInit +dup ."StateInit: " +dup ."signing message: " +dup ."External message for initialization is " B dup Bx. cr +file-base +"-query.boc" tuck B>file +."(Saved wallet creating query to file " type .")" cr +``` + +(The actual source file in your distribution may be slighly different.) Essentially, it is a complete Fift script for creating a new instance of this smart contract controlled by a newly-generated keypair. The script accepts command-line arguments, so you don't need to edit the source file each time you want to create a new wallet. + +Now, provided that you have compiled Fift binary (usually located as `crypto/fift` with respect to the build directory), you can run + +``` +$ crypto/fift -I/crypto/fift/lib -s /crypto/smartcont/new-wallet.fif 0 my_wallet_name +``` + +where 0 is the workchain to contain the new wallet (0 = basechain, -1 = masterchain), `my_wallet_name` is any identifier you wish to be associated with this wallet. The address of the new wallet will be saved into file `my_wallet_name.addr`, its newly-generated private key will be saved to `my_wallet_name.pk` (unless this file already exists; then the key will be loaded from this file instead), and the external message will be saved into `my_wallet_name-query.boc`. If you do not indicate the name of your wallet (`my_wallet_name` in the example above), the default name `new-wallet` is used. + +You may opt to set the `FIFTPATH` environment variable to `/crypto/fift/lib:/crypto/smartcont`, the directories containing `Fift.fif` and `Asm.fif` library files, and the sample smart-contract sources, respectively; then you can omit the `-I` argument to the Fift interpreter. If you install the Fift binary `crypto/fift` to a directory included in your `PATH` (e.g., `/usr/bin/fift`), you can simply invoke + +``` +$ fift -s new-wallet.fif 0 my_wallet_name +``` + +instead of indicating the complete search paths in the command line. + +If everything worked, you'll see something like the following + +``` +Creating new wallet in workchain 0 +Saved new private key to file my_wallet_name.pk +StateInit: x{34_} + x{FF0020DD2082014C97BA9730ED44D0D70B1FE0A4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED54} + x{00000000C59DC52962CC568AC5E72735EABB025C5BDF457D029AEEA6C2FFA5EB2A945446} + +new wallet address = 0:2ee9b4fd4f077c9b223280c35763df9edab0b41ac20d36f4009677df95c3afe2 +(Saving address to file my_wallet_name.addr) +Non-bounceable address (for init): 0QAu6bT9Twd8myIygMNXY9-e2rC0GsINNvQAlnfflcOv4uVb +Bounceable address (for later access): kQAu6bT9Twd8myIygMNXY9-e2rC0GsINNvQAlnfflcOv4rie +signing message: x{00000000} + +External message for initialization is x{88005DD369FA9E0EF93644650186AEC7BF3DB5616835841A6DE8012CEFBF2B875FC41190260D403E40B2EE8BEB2855D0F4447679D9B9519BE64BE421166ABA2C66BEAAAF4EBAF8E162886430243216DDA10FCE68C07B6D7DDAA3E372478D711E3E1041C00000001_} + x{FF0020DD2082014C97BA9730ED44D0D70B1FE0A4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED54} + x{00000000C59DC52962CC568AC5E72735EABB025C5BDF457D029AEEA6C2FFA5EB2A945446} + +B5EE9C724104030100000000E50002CF88005DD369FA9E0EF93644650186AEC7BF3DB5616835841A6DE8012CEFBF2B875FC41190260D403E40B2EE8BEB2855D0F4447679D9B9519BE64BE421166ABA2C66BEAAAF4EBAF8E162886430243216DDA10FCE68C07B6D7DDAA3E372478D711E3E1041C000000010010200A2FF0020DD2082014C97BA9730ED44D0D70B1FE0A4F260810200D71820D70B1FED44D0D31FD3FFD15112BAF2A122F901541044F910F2A2F80001D31F3120D74A96D307D402FB00DED1A4C8CB1FCBFFC9ED54004800000000C59DC52962CC568AC5E72735EABB025C5BDF457D029AEEA6C2FFA5EB2A945446BCF59C17 +(Saved wallet creating query to file my_wallet_name-query.boc) +``` + +In a nutshell, the Fift assembler (loaded by the `Asm.fif` include line) is used to compile the source code of the smart contract (contained in `<{ SETCP0 ... c4 POPCTR }>` lines) into its internal representation. The initial data of the smart contract is also created (by `` lines), containing a 32-bit sequence number (equal to zero) and a 256-bit public key from a newly-generated Ed25519 keypair. The corresponding private key is saved into the file `my_wallet_name.pk` unless it already exists (if you run this code twice in the same directory, the private key will be loaded from this file instead). + +The code and data for the new smart contract are combined into a `StateInit` structure (in the next lines), the address of the new smart contract (equal to the hash of this `StateInit` structure) is computed and output, and then an external message with a destination address equal to that of the new smart contract is created. This external message contains both the correct `StateInit` for the new smart contract and a non-trivial payload (signed by the correct private key). + +Finally, the external message is serialized into a bag of cells (represented by `B5EE...BE63`) and saved into the file `my_wallet_name-query.boc`. Essentially, this file is your compiled smart contract with all additional information necessary to upload it into the TON Blockchain. + +## 4. Transferring some funds to the new smart contract + +You might try to upload the new smart contract immediately by running the Lite Client and typing + +``` +> sendfile new-wallet-query.boc +``` + +or + +``` +> sendfile my_wallet_name-query.boc +``` + +if you chose to name your wallet `my_wallet_name`. + +Unfortunately, this won't work, because smart contracts must have a positive balance to be able to pay for storing and processing their data in the blockchain. So you have to transfer some funds to your new smart contract address first, displayed during its generation as `-1:60c0...c0d0` (in raw form) and `0f9..EKD` (in user-friendly form). + +In a real scenario, you would either transfer some TON Coins from your already existing wallet, ask a friend to do so, or buy some TON Coins at a cryptocurrency exchange, indicating `0f9...EKD` as the account to transfer the new TON Coins to. + +In the Test Network, you have another option: you can ask the "test giver" to give you some test TON Coins (up to 20). Let us explain how to do it. + +## 5. Using the test giver smart contract + +You need to know the address of the test giver smart contract. We'll assume that it is `-1:fcb91a3a3816d0f7b8c2c76108b8a9bc5a6b7a55bd79f8ab101c52db29232260`, or, equivalently, `kf_8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15-KsQHFLbKSMiYIny`, as indicated in one of the previous examples. You inspect the state of this smart contract in the Lite Client by typing + +``` +> last +> getaccount kf_8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15-KsQHFLbKSMiYIny +``` + +as explained above in Section 2. The only number you need from the output is the 32-bit sequence number stored in the smart contract data (it is `0x9A15` in the example above, but generally it will be different). A simpler way of obtaining the current value of this sequence number is by typing + +``` +> last +> runmethod kf_8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15-KsQHFLbKSMiYIny seqno +``` + +producing the correct value 39445 = 0x9A15: + +``` +got account state for -1 : FCB91A3A3816D0F7B8C2C76108B8A9BC5A6B7A55BD79F8AB101C52DB29232260 with respect to blocks (-1,8000000000000000,2240):18E6DA7707191E76C71EABBC5277650666B7E2CFA2AEF2CE607EAFE8657A3820:4EFA2540C5D1E4A1BA2B529EE0B65415DF46BFFBD27A8EB74C4C0E17770D03B1 +creating VM +starting VM to run method `seqno` (85143) of smart contract -1:FCB91A3A3816D0F7B8C2C76108B8A9BC5A6B7A55BD79F8AB101C52DB29232260 +... +arguments: [ 85143 ] +result: [ 39445 ] +``` + +Next, you create an external message to the test giver asking it to send another message to your (uninitialized) smart contract carrying a specified amount of test TON Coins. There is a special Fift script for generating this external message located at `crypto/smartcont/testgiver.fif`: + +``` +#!/usr/bin/env fift -s +"TonUtil.fif" include + +{ ."usage: " @' $0 type ." []" cr + ."Creates a request to TestGiver and saves it into .boc" cr + ."('testgiver-query.boc' by default)" cr 1 halt +} : usage + +$# 3 - -2 and ' usage if + +// "testgiver.addr" load-address +Masterchain 0xfcb91a3a3816d0f7b8c2c76108b8a9bc5a6b7a55bd79f8ab101c52db29232260 +2constant giver_addr + ."Test giver address = " giver_addr 2dup .addr cr 6 .Addr cr + +$1 true parse-load-address =: bounce 2=: dest_addr +$2 parse-int =: seqno +$3 $>GR =: amount +def? $4 { @' $4 } { "testgiver-query" } cond constant savefile + +."Requesting " amount .GR ."to account " +dest_addr 2dup bounce 7 + .Addr ." = " .addr +."seqno=0x" seqno x. ."bounce=" bounce . cr + +// create a message (NB: 01b00.., b = bounce) + + +dup ."enveloping message: " +dup ."resulting external message: " B dup Bx. cr +savefile +".boc" tuck B>file +."(Saved to file " type .")" cr +``` + +You can pass the required parameters as command-line arguments to this script + +``` +$ crypto/fift -I -s [] +``` + +For instance, + +``` +$ crypto/fift -I/crypto/fift/lib:/crypto/smartcont -s testgiver.fif 0QAu6bT9Twd8myIygMNXY9-e2rC0GsINNvQAlnfflcOv4uVb 0x9A15 6.666 wallet-query +``` + +or simply + +``` +$ fift -s testgiver.fif 0QAu6bT9Twd8myIygMNXY9-e2rC0GsINNvQAlnfflcOv4uVb 0x9A15 6.666 wallet-query +``` + +provided you have set up the environment variable `FIFTPATH` to `/crypto/fift/lib:/crypto/smartcont` and installed the fift binary as `/usr/bin/fift` (or anywhere else in your `PATH`). + +The newly-created message to the new smart contract must have its bounce bit clear, otherwise the transfer will be "bounced" to its sender. This is the reason we have passed the "non-bounceable" address `0QAu6bT9Twd8myIygMNXY9-e2rC0GsINNvQAlnfflcOv4uVb` of our new wallet smart contract. + +This Fift code creates an internal message from the test giver smart contract to the address of our new smart contract carrying 6.666 test TON Coins (you can enter any other amount here up to approximately 20 TON Coins). Then this message is enveloped into an external message addressed to the test giver; this external message must also contain the correct sequence number of the test giver. When the test giver receives such an external message, it checks whether the sequence number matches the one stored in its persistent data, and if it does, sends the embedded internal message with the required amount of test TON Coins to its destination (our smart contract in this case). + +The external message is serialized and saved into the file `wallet-query.boc`. Some output is generated in the process: + +``` +Test giver address = -1:fcb91a3a3816d0f7b8c2c76108b8a9bc5a6b7a55bd79f8ab101c52db29232260 +kf_8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15-KsQHFLbKSMiYIny +Requesting GR$6.666 to account 0QAu6bT9Twd8myIygMNXY9-e2rC0GsINNvQAlnfflcOv4uVb = 0:2ee9b4fd4f077c9b223280c35763df9edab0b41ac20d36f4009677df95c3afe2 seqno=0x9a15 bounce=0 +enveloping message: x{00009A1501} + x{42001774DA7EA783BE4D91194061ABB1EFCF6D585A0D61069B7A004B3BEFCAE1D7F1280C6A98B4000000000000000000000000000047494654} + +resulting external message: x{89FF02ACEEB6F264BCBAC5CE85B372D8616CA2B4B9A5E3EC98BB496327807E0E1C1A000004D0A80C_} + x{42001774DA7EA783BE4D91194061ABB1EFCF6D585A0D61069B7A004B3BEFCAE1D7F1280C6A98B4000000000000000000000000000047494654} + +B5EE9C7241040201000000006600014F89FF02ACEEB6F264BCBAC5CE85B372D8616CA2B4B9A5E3EC98BB496327807E0E1C1A000004D0A80C01007242001774DA7EA783BE4D91194061ABB1EFCF6D585A0D61069B7A004B3BEFCAE1D7F1280C6A98B4000000000000000000000000000047494654AFC17FA4 +(Saved to file wallet-query.boc) +``` + +## 6. Uploading the external message to the test giver smart contract + +Now we can invoke the Lite Client, check the state of the test giver (if the sequence number has changed, our external message will fail), and then type + +``` +> sendfile wallet-query.boc +``` + +We will see some output: + +``` +... external message status is 1 +``` + +which means that the external message has been delivered to the collator pool. Afterward one of the collators might choose to include this external message in a block, creating a transaction for the test giver smart contract to process this external message. We can check whether the state of the test giver has changed: + +``` +> last +> getaccount kf_8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15-KsQHFLbKSMiYIny +``` + +(If you forget to type `last`, you are likely to see the unchanged state of the test giver smart contract.) The resulting output would be: + +``` +got account state for -1 : FCB91A3A3816D0F7B8C2C76108B8A9BC5A6B7A55BD79F8AB101C52DB29232260 with respect to blocks (-1,8000000000000000,2240):18E6DA7707191E76C71EABBC5277650666B7E2CFA2AEF2CE607EAFE8657A3820:4EFA2540C5D1E4A1BA2B529EE0B65415DF46BFFBD27A8EB74C4C0E17770D03B1 +account state is (account + addr:(addr_std + anycast:nothing workchain_id:-1 address:xFCB91A3A3816D0F7B8C2C76108B8A9BC5A6B7A55BD79F8AB101C52DB29232260) + storage_stat:(storage_info + used:(storage_used + cells:(var_uint len:1 value:3) + bits:(var_uint len:2 value:707) + public_cells:(var_uint len:0 value:0)) last_paid:0 + due_payment:nothing) + storage:(account_storage last_trans_lt:10697000003 + balance:(currencies + grams:(nanograms + amount:(var_uint len:7 value:999993280210000)) + other:(extra_currencies + dict:hme_empty)) + state:(account_active + ( + split_depth:nothing + special:nothing + code:(just + value:(raw@^Cell + x{} + x{FF0020DDA4F260D31F01ED44D0D31FD166BAF2A1F80001D307D4D1821804A817C80073FB0201FB00A4C8CB1FC9ED54} + )) + data:(just + value:(raw@^Cell + x{} + x{00009A16} + )) + library:hme_empty)))) +x{CFF8156775B79325E5D62E742D9B96C30B6515A5CD2F1F64C5DA4B193C03F070E0D2068086C00000000000000009F65D110DC0E35F450FA914134_} + x{FF0020DDA4F260D31F01ED44D0D31FD166BAF2A1F80001D307D4D1821804A817C80073FB0201FB00A4C8CB1FC9ED54} + x{00000001} +``` + +You may notice that the sequence number stored in the persistent data has changed (in our example, to 0x9A16 = 39446), and the `last_trans_lt` field (the logical time of the last transaction of this account) has been increased. + +Now we can inspect the state of our new smart contract: + +``` +> getaccount 0QAu6bT9Twd8myIygMNXY9-e2rC0GsINNvQAlnfflcOv4uVb +or +> getaccount 0:2ee9b4fd4f077c9b223280c35763df9edab0b41ac20d36f4009677df95c3afe2 +``` + +Now we see + +``` +got account state for 0:2EE9B4FD4F077C9B223280C35763DF9EDAB0B41AC20D36F4009677DF95C3AFE2 with respect to blocks (-1,8000000000000000,16481):890F4D549428B2929F5D5E0C5719FBCDA60B308BA4B907797C9E846E644ADF26:22387176928F7BCEF654411CA820D858D57A10BBF1A0E153E1F77DE2EFB2A3FB and (-1,8000000000000000,16481):890F4D549428B2929F5D5E0C5719FBCDA60B308BA4B907797C9E846E644ADF26:22387176928F7BCEF654411CA820D858D57A10BBF1A0E153E1F77DE2EFB2A3FB +account state is (account + addr:(addr_std + anycast:nothing workchain_id:0 address:x2EE9B4FD4F077C9B223280C35763DF9EDAB0B41AC20D36F4009677DF95C3AFE2) + storage_stat:(storage_info + used:(storage_used + cells:(var_uint len:1 value:1) + bits:(var_uint len:1 value:111) + public_cells:(var_uint len:0 value:0)) last_paid:1553210152 + due_payment:nothing) + storage:(account_storage last_trans_lt:16413000004 + balance:(currencies + grams:(nanograms + amount:(var_uint len:5 value:6666000000)) + other:(extra_currencies + dict:hme_empty)) + state:account_uninit)) +x{CFF60C04141C6A7B96D68615E7A91D265AD0F3A9A922E9AE9C901D4FA83F5D3C0D02025BC2E4A0D9400000000F492A0511406354C5A004_} +``` + +Our new smart contract has some positive balance (of 6.666 test TON Coins), but has no code or data (reflected by `state:account_uninit`). + +## 7. Uploading the code and data of the new smart contract + +Now you can finally upload the external message with the `StateInit` of the new smart contract, containing its code and data: + +``` +> sendfile my_wallet_name-query.boc +... external message status is 1 +> last +... +> getaccount 0QAu6bT9Twd8myIygMNXY9-e2rC0GsINNvQAlnfflcOv4uVb +... +got account state for 0:2EE9B4FD4F077C9B223280C35763DF9EDAB0B41AC20D36F4009677DF95C3AFE2 with respect to blocks (-1,8000000000000000,16709):D223B25D8D68401B4AA19893C00221CF9AB6B4E5BFECC75FD6048C27E001E0E2:4C184191CE996CF6F91F59CAD9B99B2FD5F3AA6F55B0B6135069AB432264358E and (-1,8000000000000000,16709):D223B25D8D68401B4AA19893C00221CF9AB6B4E5BFECC75FD6048C27E001E0E2:4C184191CE996CF6F91F59CAD9B99B2FD5F3AA6F55B0B6135069AB432264358E +account state is (account + addr:(addr_std + anycast:nothing workchain_id:0 address:x2EE9B4FD4F077C9B223280C35763DF9EDAB0B41AC20D36F4009677DF95C3AFE2) + storage_stat:(storage_info + used:(storage_used + cells:(var_uint len:1 value:3) + bits:(var_uint len:2 value:963) + public_cells:(var_uint len:0 value:0)) last_paid:1553210725 + due_payment:nothing) + storage:(account_storage last_trans_lt:16625000002 + balance:(currencies + grams:(nanograms + amount:(var_uint len:5 value:5983177000)) + other:(extra_currencies + dict:hme_empty)) + state:(account_active + ( + split_depth:nothing + special:nothing + code:(just + value:(raw@^Cell + x{} + x{FF0020DDA4F260810200D71820D70B1FED44D0D7091FD709FFD15112BAF2A122F901541044F910F2A2F80001D7091F3120D74A97D70907D402FB00DED1A4C8CB1FCBFFC9ED54} + )) + data:(just + value:(raw@^Cell + x{} + x{00000001F61CF0BC8E891AD7636E0CD35229D579323AA2DA827EB85D8071407464DC2FA3} + )) + library:hme_empty)))) +x{CFF60C04141C6A7B96D68615E7A91D265AD0F3A9A922E9AE9C901D4FA83F5D3C0D020680F0C2E4A0EB280000000F7BB57909405928024A134_} + x{FF0020DDA4F260810200D71820D70B1FED44D0D7091FD709FFD15112BAF2A122F901541044F910F2A2F80001D7091F3120D74A97D70907D402FB00DED1A4C8CB1FCBFFC9ED54} + x{00000001F61CF0BC8E891AD7636E0CD35229D579323AA2DA827EB85D8071407464DC2FA3} +``` + +You will see that the smart contract has been initialized using code and data from the `StateInit` of the external message, and its balance has been slightly decreased because of the processing fees. Now it is up and running, and you can activate it by generating new external messages and uploading them to the TON Blockchain using the `sendfile` command of the Lite Client. + +## 8. Using the simple wallet smart contract + +Actually, the simple wallet smart contract used in this example can be used to transfer test TON Coins to any other accounts. It is in this respect similar to the test giver smart contract discussed above, with the difference that it processes only external messages signed by the correct private key (of its owner). In our case, it is the private key saved into the file `my_wallet_name.pk` during the compilation of the smart contract (see Section 3). + +An example of how you might use this smart contract is provided in sample file `crypto/smartcont/wallet.fif` : + +``` +#!/usr/bin/env fift -s +"TonUtil.fif" include + +{ ."usage: " @' $0 type ." [-B ] []" cr + ."Creates a request to simple wallet created by new-wallet.fif, with private key loaded from file .pk " + ."and address from .addr, and saves it into .boc ('wallet-query.boc' by default)" cr 1 halt +} : usage +$# dup 4 < swap 5 > or ' usage if +def? $6 { @' $5 "-B" $= { @' $6 =: body-boc-file [forget] $6 def? $7 { @' $7 =: $5 [forget] $7 } { [forget] $5 } cond + @' $# 2- =: $# } if } if + +true constant bounce + +$1 =: file-base +$2 bounce parse-load-address =: bounce 2=: dest_addr +$3 parse-int =: seqno +$4 $>GR =: amount +def? $5 { @' $5 } { "wallet-query" } cond constant savefile + +file-base +".addr" load-address +2dup 2constant wallet_addr +."Source wallet address = " 2dup .addr cr 6 .Addr cr +file-base +".pk" load-keypair nip constant wallet_pk + +def? body-boc-file { @' body-boc-file file>B B>boc } { } cond +constant body-cell + +."Transferring " amount .GR ."to account " +dest_addr 2dup bounce 7 + .Addr ." = " .addr +."seqno=0x" seqno x. ."bounce=" bounce . cr +."Body of transfer message is " body-cell + +dup ."signing message: " +dup ."resulting external message: " B dup Bx. cr +savefile +".boc" tuck B>file +."(Saved to file " type .")" cr +``` + +You can invoke this script as follows: + +``` +$ fift -I/crypto/fift/lib:/crypto/smartcont -s wallet.fif +``` + +or simply + +``` +$ fift -s wallet.fif +``` + +if you have correctly set up `PATH` and `FIFTPATH`. + +For example, + +``` +$ fift -s wallet.fif my_wallet_name kf8Ty2EqAKfAksff0upF1gOptUWRukyI9x5wfgCbh58Pss9j 1 .666 +``` + +Here `my_wallet_name` is the identifier of your wallet used before with `new-wallet.fif`; the address and the private key of your test wallet will be loaded from files `my_wallet_name.addr` and `my_wallet_name.pk` in the current directory. + +When you run this code (by invoking the Fift interpreter), you create an external message with a destination equal to the address of your wallet smart contract, containing a correct Ed25519 signature, a sequence number, and an enveloped internal message from your wallet smart contract to the smart contract indicated in `dest_addr`, with an arbitrary value attached and an arbitrary payload. When your smart contract receives and processes this external message, it first checks the signature and the sequence number. If they are correct, it accepts the external message, sends the embedded internal message from itself to the intended destination, and increases the sequence number in its persistent data (this is a simple measure to prevent replay attacks, in case this sample wallet smart contract code ends up used in a real wallet application). + +Of course, a true TON Blockchain wallet application would hide all the intermediate steps explained above. It would first communicate the address of the new smart contract to the user, asking them to transfer some funds to the indicated address (displayed in its non-bounceable user-friendly form) from another wallet or a cryptocurrency exchange, and then would provide a simple interface to display the current balance and to transfer funds to whatever other addresses the user wants. (The aim of this document is to explain how to create new non-trivial smart contracts and experiment with the TON Blockchain Test Network, rather than to explain how one could use the Lite Client instead of a more user-friendly wallet application.) + +One final remark: The above examples used smart contracts in the basic workchain (workchain 0). They would work in exactly the same way in the masterchain (workchain -1), if one passes workchain identifier -1 instead of 0 as the first argument to `new-wallet.fif`. The only difference is that the processing and storage fees in the basic workchain are 100-1000 times lower than in the masterchain. Some smart contracts (such as the validator election smart contract) accept transfers only from masterchain smart contracts, so you'll need a wallet in the masterchain if you wish to make stakes on behalf of your own validator and participate in the elections. diff --git a/versioned_docs/version-1.0.0/develop/howto/ton-sites.md b/versioned_docs/version-1.0.0/develop/howto/ton-sites.md new file mode 100644 index 0000000000..135845f3ee --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/howto/ton-sites.md @@ -0,0 +1,121 @@ +The aim of this document is to provide a gentle introduction into TON Sites, which are (TON) Web sites accessed through the TON Network. TON Sites may be used as a convenient entry point for other TON Services. In particular, HTML pages downloaded from TON Sites may contain links to `ton://...` URIs representing payments that can be performed by the user by clicking to the link, provided a TON Wallet is installed on the user's device. + +From the technical perspective, TON Sites are very much like the usual Web sites, but they are accessed through the TON Network (which is an overlay network inside the Internet) instead of the Internet. More specifically, they have an ADNL address (instead of a more customary IPv4 or IPv6 address), and they accept HTTP queries via RLDP protocol (which is a higher-level RPC protocol built upon ADNL, the main protocol of TON Network) instead of the usual TCP/IP. All encryption is handled by ADNL, so there is no need to use HTTPS (i.e., TLS). + +In order to access existing and create new TON Sites one needs special gateways between the "ordinary" internet and the TON Network. Essentially, TON Sites are accessed with the aid of a HTTP->RLDP proxy running locally on the client's machine, and they are created by means of a reverse RLDP->HTTP proxy running on a remote web server. + +## 1. Compiling RLDP-HTTP Proxy + +The RLDP-HTTP Proxy is a special utility specially designed for accessing and creating TON Sites. Its current (alpha) version is a part of the general TON Blockchain source tree, available at GitHub repository https://github.com/ton-blockchain/ton. In order to compile the RLDP-HTTP Proxy, follow the instructions outlined in **Getting Started** and **Validator**. The Proxy binary will be located as + +``` +rldp-http-proxy/rldp-http-proxy +``` + +in the build directory. Alternatively, you may want to build just the Proxy instead of building all TON Blockchain projects. This can be done by invoking + +``` +cmake --build . --target rldp-http-proxy +``` + +in the build directory. + +## 2. Running RLDP-HTTP Proxy to access TON Sites + +In order to access existing TON Sites, you need a running instance of RLDP-HTTP Proxy on your computer. It can be invoked as follows: + +``` +rldp-http-proxy/rldp-http-proxy -p 8080 -c 3333 -C global.config.json +``` + +or + +``` +rldp-http-proxy/rldp-http-proxy -p 8080 -a :3333 -C global.config.json +``` + +where `` is your public IPv4 address, provided you have one on your home computer. The TON Network global configuration file `global.config.json` can be downloaded at https://ton-blockchain.github.io/global.config.json : + +``` +wget https://ton-blockchain.github.io/global.config.json +``` + +In the above example, 8080 is the TCP port that will be listened to at localhost for incoming HTTP queries, and 3333 is the UDP port that will be used for all outbound and inbound RLDP and ADNL activity, i.e., for connecting to the TON Sites via the TON Network. + +If you have done everything correctly, the Proxy will not terminate, but it will continue running in the terminal. It can be used now for accessing TON Sites. When you don't need it anymore, you can terminate it by pressing `Ctrl-C`, or simply by closing the terminal window. + +## 3. Accessing TON Sites + +Now suppose that you have a running instance of the RLDP-HTTP Proxy running on your computer and listening on `localhost:8080` for inbound TCP connections, as explained above in Section 2. + +A simple test that everything is working properly may be performed using programs such as `curl` or `wget`. For example, + +``` +curl -x 127.0.0.1:8080 http://test.ton +``` + +attempts to download the main page of (TON) Site `test.ton` using the proxy at `127.0.0.1:8080`. If the proxy is up and running, you'll see something like + +``` + +

TON Blockchain Test Network — files and resources

+

News

+
    +... + +``` + +because TON Site `test.ton` is currently set up to be a mirror of Web Site https://test.ton.org. + +You can also access TON Sites by means of their ADNL addresses by using fake domain `.adnl`: + +``` +curl -x 127.0.0.1:8080 http://untzo7eat2h77xzfugxrfgfy3zbl5txomvetzke6fwr45lehvdkxauy.adnl/ +``` + +currently fetches the same TON Web page. + +Alternatively, you can set up `localhost:8080` as a HTTP proxy in your browser. For example, if you use Firefox, visit [Setup] -> General -> Network Settings -> Settings -> Configure Proxy Access -> Manual Proxy configuration, and type "127.0.0.1" into the field "HTTP Proxy", and "8080" into the field "Port". If you don't have Firefox yet, visit https://www.getfirefox.com first. + +Once you have set up `localhost:8080` as the HTTP proxy to be used in your browser, you can simply type the required URI, such as `http://test.ton` or `http://untzo7eat2h77xzfugxrfgfy3zbl5txomvetzke6fwr45lehvdkxauy.adnl/`, in the navigation bar of your browser, and interact with the TON Site in the same way as with the usual Web Sites. + +## 4. Creating TON Sites + +Most people will need just to access existing TON Sites, not to create new ones. However, if you want to create one, you'll need to run RLDP-HTTP Proxy on your server, along with the usual web server software such as Apache or Nginx. + +We suppose that you know already how to set up an ordinary website, and that you have already configured one on your server, accepting incoming HTTP connections on TCP port `:80`, and defining the required TON Network domain name, say, `example.ton`, as the main domain name or an alias for your web site in the configuration of your web server. + +After that, you first need to generate a persistent ADNL address for your server: + +``` +mkdir keyring + +util/generate-random-id -m adnlid +``` + +You see something like + +``` +45061C1D4EC44A937D0318589E13C73D151D1CEF5D3C0E53AFBCF56A6C2FE2BD vcqmha5j3ceve35ammfrhqty46rkhi455otydstv66pk2tmf7rl25f3 +``` + +This is your newly-generated persistent ADNL address, in hexadecimal and user-friendly form. The corresponding private key is saved into file `45061...2DB` in the current directory. Move it into the keyring directory: + +``` +mv 45061C1* keyring/ +``` + +After that, you execute + +``` +rldp-http-proxy -a :3333 -L '*' -C global.config.json -A +``` + +(with `` equal to `vcqm...35f3` in this example) in the background (you can try this in a terminal at first, but if you want your TON Site to run permanently, you'll have to use options `-d` and `-l ` as well). + +If all works properly, the RLDP-HTTP proxy will accept incoming HTTP queries from the TON Network via RLDP/ADNL running on UDP port 3333 (of course, you can use any other UDP port if you want to) of IPv4 address `` (in particular, if you are using a firewall, don't forget to allow `rldp-http-proxy` to receive and send UDP packets from this port), and it will forward these HTTP queries addressed to all hosts (if you want to forward only specific hosts, change `-L '*'` to `-L `) to TCP port `80` at `127.0.0.1`, i.e., to your ordinary Web server. + +You can visit TON Site `http://.adnl` (`http://vcqmha5j3ceve35ammfrhqty46rkhi455otydstv66pk2tmf7rl25f3.adnl` in this example) from a browser running on a client machine as explained in Sections 2 and 3 and check whether your TON Site is actually available to the public. + +If you want to, you can register a TON DNS domain, such as 'example.ton', and create a record for this domain pointing to the persistent ADNL address of your TON Site. Then the RLDP-HTTP proxies running in client mode would resolve http://example.ton as pointing to your ADNL address and will access your TON Site. The process of registration of TON DNS domains is described in a separate document. + diff --git a/versioned_docs/version-1.0.0/develop/howto/validator.md b/versioned_docs/version-1.0.0/develop/howto/validator.md new file mode 100644 index 0000000000..1165c43f8b --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/howto/validator.md @@ -0,0 +1,262 @@ +The aim of this document is to provide step-by-step instructions for setting up a full node for the TON Blockchain as a validator. We assume that a TON Blockchain Full Node is already up and running as explained in [FullNode-HOWTO](https://toncoin.org/#/howto/full-node). We also assume some familiarity with the TON Blockchain Lite Client. + +Note that a validator must be run on a dedicated high-performance server with high network bandwidth installed in a reliable data center, and that you'll need a large amount of TON Coins (test TON Coins, if you want to run a validator in the "testnet") as stakes for your validator. If your validator works incorrectly or is not available for prolonged periods of time, you may lose part or all of your stake, so it makes sense to use high-performance, reliable servers. We recommend a dual-processor server with at least eight cores in each processor, at least 256 MiB RAM, at least 8 TB of conventional HDD storage and at least 512 GB of faster SSD storage, with 1 Gbit/s network (and Internet) connectivity to reliably accommodate peak loads. + +## 0. Downloading and compiling + +The basic instructions are the same as for a TON Blockchain Full Node, as explained in [FullNode-HOWTO](https://toncoin.org/#/howto/full-node). In fact, any Full Node will automatically work as a validator if it discovers that the public key corresponding to its private key appears as a member of the current validator set for the currently selected TON Blockchain instance. In particular, the Full Node and the Validator use the same binary file `validator-engine`, and are controlled by means of the same `validator-engine-console`. + +## 1. Controlling smart contract of a validator + +In order to run a Validator, you'll need a Full Node that is already up and running (and completely synchronized with the current blockchain state), and a wallet in the masterchain holding a large amount of TON Coins (or test TON Coins, if you want to run a validator in the "testnet" TON Blockchain instance). Typically you'll need at least 100,001 TON Coins in the production network, and at least 10,001 test TON Coins in the test network. The actual value (in nanotons) can be found as the value of `min_stake` in configuration parameter `#17` (available by typing `getconfig 17` into the Lite Client), plus one TON Coin. + +Each validator is identified by its (Ed25519) public key. During the validator elections, the validator (or rather its public key) is also associated with a smart contract residing in the masterchain. For simplicity, we say that the validator is "controlled" by this smart contract (e.g., a wallet smart contract). Stakes are accepted on behalf of this validator only if they arrive from its associated smart contract, and only that associated smart contract is entitled to collect the validator's stake after it is unfrozen, along with the validator's share of bonuses (e.g., block mining fees, transaction and message forwarding fees collected from the users of the TON Blockchain by the validator pool). Typically the bonuses are distributed proportionally to the (effective) stakes of the validators. On the other hand, validators with higher stakes are assigned a larger amount of work to perform (i.e., they have to create and validate blocks for more shardchains), so it is important not to stake an amount that will yield more validation work than your node is capable of handling. + +Notice that each validator (identified by its public key) can be associated with at most one controlling smart contract (residing in the masterchain), but the same controlling smart contract may be associated with several validators. In this way you can run several validators (on different physical servers) and make stakes for them from the same smart contract. If one of these validators stops functioning and you lose its stake, the other validators should continue operating and will keep their stakes and potentially receive bonuses. + +## 2. Creating the controlling smart contract + +If you don't have a controlling smart contract, you can simply create a wallet in the masterchain. A simple wallet can be created with the aid of the script `new-wallet.fif`, located in the subdirectory `crypto/smartcont` of the source tree. In what follows, we assume that you have configured the environment variable `FIFTPATH` to include `/crypto/fift/lib:/crypto/smartcont`, and that your `PATH` includes a directory with the Fift binary (located as `/crypto/fift`). Then you can simply run + +```sh +$ fift -s new-wallet.fif -1 my_wallet_id +``` + +where `my_wallet_id` is any identifier you want to assign to your new wallet, and `-1` is the workchain identifier for the masterchain. If you have not set up `FIFTPATH` and `PATH`, then you'll have to run a longer version of this command in your build directory as follows: + +```sh +$ crypto/fift -I /crypto/fift/lib:/crypto/smartcont -s new-wallet.fif -1 my_wallet_id +``` + +Once you run this script, the address of the new smart contract is displayed: + +``` +... +new wallet address = -1:af17db43f40b6aa24e7203a9f8c8652310c88c125062d1129fe883eaa1bd6763 +(Saving address to file my_wallet_id.addr) +Non-bounceable address (for init): 0f-vF9tD9Atqok5yA6n4yGUjEMiMElBi0RKf6IPqob1nYzqK +Bounceable address (for later access): kf-vF9tD9Atqok5yA6n4yGUjEMiMElBi0RKf6IPqob1nY2dP +... +(Saved wallet creating query to file my_wallet_id-query.boc) +``` + +Now `my_wallet_id.pk` is a new file containing the private key for controlling this wallet (you must keep it secret), and `my_wallet_id.addr` is a (not so secret) file containing the address of this wallet. Once this is done, you have to transfer some (test) TON Coins to the non-bounceable address of your wallet, and run `sendfile my_wallet_id-query.boc` in the Lite Client to finish creating the new wallet. This process is explained in more detail in the [Step-by-Step](https://toncoin.org/#/howto/step-by-step). + +If you are running a validator in the "mainnet", it is a good idea to use more sophisticated wallet smart contracts (e.g., a multi-signature wallet). For the "testnet", the simple wallet should be enough. + +## 3. Elector smart contract + +The elector smart contract is a special smart contract residing in the masterchain. Its full address is `-1:xxx..xxx`, where `-1` is the workchain identifier (`-1` corresponds to the masterchain), and `xxx..xxx` is the hexadecimal representation of its 256-bit address inside the masterchain. In order to find out this address, you have to read the configuration parameter `#1` from a recent state of the blockchain. This is easily done by means of the command `getconfig 1` in the Lite Client: + +``` +> getconfig 1 +ConfigParam(1) = ( elector_addr:xA4C2C7C05B093D470DE2316DBA089FA0DD775FD9B1EBFC9DC9D04B498D3A2DDA) +x{A4C2C7C05B093D470DE2316DBA089FA0DD775FD9B1EBFC9DC9D04B498D3A2DDA} +``` + +In this case, the complete elector address is `-1:A4C2C7C05B093D470DE2316DBA089FA0DD775FD9B1EBFC9DC9D04B498D3A2DDA`. + +We assume familiarity with the Lite Client and that you know how to run it and how to obtain a global configuration file for it. Notice that the above command can be run in batch mode by using the `-c` command-line option of the Lite Client: + +```sh +$ lite-client -C -c 'getconfig 1' +... +ConfigParam(1) = ( elector_addr:xA4C2C7C05B093D470DE2316DBA089FA0DD775FD9B1EBFC9DC9D04B498D3A2DDA) +x{A4C2C7C05B093D470DE2316DBA089FA0DD775FD9B1EBFC9DC9D04B498D3A2DDA} +... +``` + +The elector smart contract has several uses. Most importantly, you can participate in validator elections or collect unfrozen stakes and bonuses by sending messages from the controlling smart contract of your validator to the elector smart contract. You can also learn about current validator elections and their participants by invoking the so-called `get-methods` of the elector smart contract. + +Namely, running + +```sh +> runmethod -1:A4C2C7C05B093D470DE2316DBA089FA0DD775FD9B1EBFC9DC9D04B498D3A2DDA active_election_id +... +arguments: [ 86535 ] +result: [ 1567633899 ] +``` + +(or `lite-client -C -c "runmethod -1: active_election_id"` in batch mode) will return the identifier of the currently active elections (a non-zero integer, typically the Unix time of the start of the service term of the validator group being elected), or `0`, if no elections are currently active. In this example, the identifier of the active elections is `1567633899`. + +You can also recover the list of all active participants (pairs of 256-bit validator public keys and their corresponding stakes expressed in nanotons) by running the method `participant_list` instead of `active_election_id`. + +## 4. Creating a validator public key and ADNL address + +In order to participate in validator elections, you need to know the elections identifier (obtained by running get-method `active_elections_id` of the elector smart contract), and also the public key of your validator. The public key is created by running validator-engine-console (as explained in [FullNode-HOWTO](https://toncoin.org/#/howto/full-node)) and running the following commands: + +``` +$ validator-engine-console ... +... +conn ready +> newkey +created new key BCA335626726CF2E522D287B27E4FAFFF82D1D98615957DB8E224CB397B2EB67 +> exportpub BCA335626726CF2E522D287B27E4FAFFF82D1D98615957DB8E224CB397B2EB67 +got public key: xrQTSIQEsqZkWnoADMiBnyBFRUUweXTvzRQFqb5nHd5xmeE6 +> addpermkey BCA335626726CF2E522D287B27E4FAFFF82D1D98615957DB8E224CB397B2EB67 1567633899 1567733900 +success +``` + +Now the full node (validator-engine) has generated a new keypair, exported the base64 representation of the public key (`xrQT...E6`), and registered it as a persistent key for signing blocks starting from Unix time `1567633899` (equal to the election identifier) until `1567733900` (equal to the previous number plus the term duration of the validator set to be elected, available in configuration parameter `#15`, which can be learned by typing `getconfig 15` in the Lite Client, plus a safety margin in case elections actually happen later than intended). + +You also need to define a temporary key to be used by the validator to participate in the network consensus protocol. The simplest way (sufficient for testing purposes) is to set this key equal to the persistent (block signing) key: + +``` +> addtempkey BCA335626726CF2E522D287B27E4FAFFF82D1D98615957DB8E224CB397B2EB67 BCA335626726CF2E522D287B27E4FAFFF82D1D98615957DB8E224CB397B2EB67 1567733900 +success +``` + +It is also a good idea to create a dedicated ADNL address to be used exclusively for validator purposes: + +``` +> newkey +created new key C5C2B94529405FB07D1DDFB4C42BFB07727E7BA07006B2DB569FBF23060B9E5C +> addadnl C5C2B94529405FB07D1DDFB4C42BFB07727E7BA07006B2DB569FBF23060B9E5C 0 +success +> addvalidatoraddr BCA335626726CF2E522D287B27E4FAFFF82D1D98615957DB8E224CB397B2EB67 C5C2B94529405FB07D1DDFB4C42BFB07727E7BA07006B2DB569FBF23060B9E5C 1567733900 +success +``` + +Now `C5C2B94529405FB07D1DDFB4C42BFB07727E7BA07006B2DB569FBF23060B9E5C` is a new ADNL address, which will be used by the Full Node for running as a validator with the public key `BCA...B67`, with expiration time set to `1567733900`. + +## 5. Creating an election participation request + +The special script `validator-elect-req.fif` (located in `/crypto/smartcont`) is used to create a message that has to be signed by the validator in order to participate in the elections. It is run as follows: + +``` +$ fift -s validator-elect-req.fif [] +``` + +For example, + +``` +$ fift -s validator-elect-req.fif kf-vF9tD9Atqok5yA6n4yGUjEMiMElBi0RKf6IPqob1nY2dP 1567633899 2.7 C5C2B94529405FB07D1DDFB4C42BFB07727E7BA07006B2DB569FBF23060B9E5C +``` + +or, if you have created the controlling wallet by means of `new-wallet.fif`, you can use `@my_wallet_id.addr` instead of copying the wallet address `kf-vF...dP`: + +``` +$ fift -s validator-elect-req.fif @my_wallet_id.addr 1567633899 2.7 C5C2B94529405FB07D1DDFB4C42BFB07727E7BA07006B2DB569FBF23060B9E5C + +Creating a request to participate in validator elections at time 1567633899 from smart contract Uf+vF9tD9Atqok5yA6n4yGUjEMiMElBi0RKf6IPqob1nY4EA = -1:af17db43f40b6aa24e7203a9f8c8652310c88c125062d1129fe883eaa1bd6763 with maximal stake factor with respect to the minimal stake 176947/65536 and validator ADNL address c5c2b94529405fb07d1ddfb4c42bfb07727e7ba07006b2db569fbf23060b9e5c +654C50745D7031EB0002B333AF17DB43F40B6AA24E7203A9F8C8652310C88C125062D1129FE883EAA1BD6763C5C2B94529405FB07D1DDFB4C42BFB07727E7BA07006B2DB569FBF23060B9E5C +ZUxQdF1wMesAArMzrxfbQ_QLaqJOcgOp-MhlIxDIjBJQYtESn-iD6qG9Z2PFwrlFKUBfsH0d37TEK_sHcn57oHAGsttWn78jBgueXA== +``` + +Here ` = 2.7` is the maximum ratio allowed between your stake and the minimal validator stake in the elected validator group. In this way you can be sure that your stake will be no more than 2.7 times the smallest stake, so the workload of your validator is at most 2.7 times the lowest one. If your stake is too large compared to the stakes of other validators, then it will be clipped to this value (2.7 times the smallest stake), and the remainder will be returned to you (i.e., to the controlling smart contract of your validator) immediately after elections. + +Now you obtain a binary string in hexadecimal (`654C...9E5C`) and base64 form to be signed by the validator. This can be done in `validator-engine-console`: + +``` +> sign BCA335626726CF2E522D287B27E4FAFFF82D1D98615957DB8E224CB397B2EB67 654C50745D7031EB0002B333AF17DB43F40B6AA24E7203A9F8C8652310C88C125062D1129FE883EAA1BD6763C5C2B94529405FB07D1DDFB4C42BFB07727E7BA07006B2DB569FBF23060B9E5C +got signature ovf9cmr2J/speJEtMU+tZm6zH/GBEyZCPpaukqL3mmNH9Wipyoys63VFh0yR386bARHKMPpfKAYBYslOjdSjCQ +``` + +Here `BCA...B67` is the identifier of the signing key of our validator, and `654...E5C` is the message generated by `validator-elect-req.fif`. The signature is `ovf9...jCQ` (this is the base64 representation of 64-byte Ed25519 signature). + +Now you have to run another script `validator-elect-signed.fif`, which also requires the public key and the signature of the validator: + +``` +$ fift -s validator-elect-signed.fif @my_wallet_id.addr 1567633899 2.7 C5C2B94529405FB07D1DDFB4C42BFB07727E7BA07006B2DB569FBF23060B9E5C xrQTSIQEsqZkWnoADMiBnyBFRUUweXTvzRQFqb5nHd5xmeE6 ovf9cmr2J/speJEtMU+tZm6zH/GBEyZCPpaukqL3mmNH9Wipyoys63VFh0yR386bARHKMPpfKAYBYslOjdSjCQ== +Creating a request to participate in validator elections at time 1567633899 from smart contract Uf+vF9tD9Atqok5yA6n4yGUjEMiMElBi0RKf6IPqob1nY4EA = -1:af17db43f40b6aa24e7203a9f8c8652310c88c125062d1129fe883eaa1bd6763 with maximal stake factor with respect to the minimal stake 176947/65536 and validator ADNL address c5c2b94529405fb07d1ddfb4c42bfb07727e7ba07006b2db569fbf23060b9e5c +String to sign is: 654C50745D7031EB0002B333AF17DB43F40B6AA24E7203A9F8C8652310C88C125062D1129FE883EAA1BD6763C5C2B94529405FB07D1DDFB4C42BFB07727E7BA07006B2DB569FBF23060B9E5C +Provided a valid Ed25519 signature A2F7FD726AF627FB2978912D314FAD666EB31FF1811326423E96AE92A2F79A6347F568A9CA8CACEB7545874C91DFCE9B0111CA30FA5F28060162C94E8DD4A309 with validator public key 8404B2A6645A7A000CC8819F20454545307974EFCD1405A9BE671DDE7199E13A +query_id set to 1567632790 + +Message body is x{4E73744B000000005D702D968404B2A6645A7A000CC8819F20454545307974EFCD1405A9BE671DDE7199E13A5D7031EB0002B333C5C2B94529405FB07D1DDFB4C42BFB07727E7BA07006B2DB569FBF23060B9E5C} + x{A2F7FD726AF627FB2978912D314FAD666EB31FF1811326423E96AE92A2F79A6347F568A9CA8CACEB7545874C91DFCE9B0111CA30FA5F28060162C94E8DD4A309} + +Saved to file validator-query.boc +``` + +Alternatively, if you are running `validator-engine-console` on the same machine as your wallet, you can skip the above steps and instead use the `createelectionbid` command in the Validator Console to directly create a file (e.g., `validator-query.boc`) with the message body containing your signed elections participation request. For this command to work, you have to run `validator-engine` with the `-f ` command-line option, where `` is a directory containing copies of all required Fift source files (such as `Fift.fif`, `TonUtil.fif`, `validator-elect-req.fif`, and `validator-elect-signed.fif`), even though these files normally reside in different source directories (`/crypto/fift/lib and /crypto/smartcont`). + +Now you have a message body containing your elections participation request. You must send it from the controlling smart contract, carrying the stake as its value (plus one extra TON Coin for sending confirmation). If you use the simple wallet smart contract, this can be done by using the `-B` command-line argument to `wallet.fif`: + +``` +$ fift -s wallet.fif my_wallet_id -1:A4C2C7C05B093D470DE2316DBA089FA0DD775FD9B1EBFC9DC9D04B498D3A2DDA 1 100001. -B validator-query.boc +Source wallet address = -1:af17db43f40b6aa24e7203a9f8c8652310c88c125062d1129fe883eaa1bd6763 +kf-vF9tD9Atqok5yA6n4yGUjEMiMElBi0RKf6IPqob1nY2dP +Loading private key from file my_wallet_id.pk +Transferring GR$100001. to account kf-kwsfAWwk9Rw3iMW26CJ-g3Xdf2bHr_J3J0EtJjTot2lHQ = -1:a4c2c7c05b093d470de2316dba089fa0dd775fd9b1ebfc9dc9d04b498d3a2dda seqno=0x1 bounce=-1 +Body of transfer message is x{4E73744B000000005D702D968404B2A6645A7A000CC8819F20454545307974EFCD1405A9BE671DDE7199E13A5D7031EB0002B333C5C2B94529405FB07D1DDFB4C42BFB07727E7BA07006B2DB569FBF23060B9E5C} + x{A2F7FD726AF627FB2978912D314FAD666EB31FF1811326423E96AE92A2F79A6347F568A9CA8CACEB7545874C91DFCE9B0111CA30FA5F28060162C94E8DD4A309} + +signing message: x{0000000101} + x{627FD26163E02D849EA386F118B6DD044FD06EBBAFECD8F5FE4EE4E825A4C69D16ED32D79A60A8500000000000000000000000000001} + x{4E73744B000000005D702D968404B2A6645A7A000CC8819F20454545307974EFCD1405A9BE671DDE7199E13A5D7031EB0002B333C5C2B94529405FB07D1DDFB4C42BFB07727E7BA07006B2DB569FBF23060B9E5C} + x{A2F7FD726AF627FB2978912D314FAD666EB31FF1811326423E96AE92A2F79A6347F568A9CA8CACEB7545874C91DFCE9B0111CA30FA5F28060162C94E8DD4A309} + +resulting external message: x{89FF5E2FB687E816D5449CE40753F190CA4621911824A0C5A2253FD107D5437ACEC6049CF8B8EA035B0446E232DB8C1DFEA97738076162B2E053513310D2A3A66A2A6C16294189F8D60A9E33D1E74518721B126A47DA3A813812959BD0BD607923B010000000080C_} + x{627FD26163E02D849EA386F118B6DD044FD06EBBAFECD8F5FE4EE4E825A4C69D16ED32D79A60A8500000000000000000000000000001} + x{4E73744B000000005D702D968404B2A6645A7A000CC8819F20454545307974EFCD1405A9BE671DDE7199E13A5D7031EB0002B333C5C2B94529405FB07D1DDFB4C42BFB07727E7BA07006B2DB569FBF23060B9E5C} + x{A2F7FD726AF627FB2978912D314FAD666EB31FF1811326423E96AE92A2F79A6347F568A9CA8CACEB7545874C91DFCE9B0111CA30FA5F28060162C94E8DD4A309} + +B5EE9C7241040401000000013D0001CF89FF5E2FB687E816D5449CE40753F190CA4621911824A0C5A2253FD107D5437ACEC6049CF8B8EA035B0446E232DB8C1DFEA97738076162B2E053513310D2A3A66A2A6C16294189F8D60A9E33D1E74518721B126A47DA3A813812959BD0BD607923B010000000080C01016C627FD26163E02D849EA386F118B6DD044FD06EBBAFECD8F5FE4EE4E825A4C69D16ED32D79A60A85000000000000000000000000000010201A84E73744B000000005D702D968404B2A6645A7A000CC8819F20454545307974EFCD1405A9BE671DDE7199E13A5D7031EB0002B333C5C2B94529405FB07D1DDFB4C42BFB07727E7BA07006B2DB569FBF23060B9E5C030080A2F7FD726AF627FB2978912D314FAD666EB31FF1811326423E96AE92A2F79A6347F568A9CA8CACEB7545874C91DFCE9B0111CA30FA5F28060162C94E8DD4A309062A7721 +(Saved to file wallet-query.boc) +``` + +Now you just have to send `wallet-query.boc` from the Lite Client (not the Validator Console): + +``` +> sendfile wallet-query.boc +``` + +or you can use the Lite Client in batch mode: + +``` +$ lite-client -C -c "sendfile wallet-query.boc" +``` + +This is an external message signed by your private key (which controls your wallet); it instructs your wallet smart contract to send an internal message to the elector smart contract with the prescribed payload (containing the validator bid and signed by its key) and transfer the specified amount of TON Coins. When the elector smart contract receives this internal message, it registers your bid (with the stake equal to the specified amount of TON Coins minus one), and sends you (i.e., the wallet smart contract) a confirmation (carrying 1 TON Coin minus message forwarding fees back) or a rejection message with an error code (carrying back almost all of the original stake amount minus processing fees). + +You can check whether your stake has been accepted by running get-method `participant_list` of the elector smart contract. + +## 6. Recovering stakes and bonuses + +If your stake is only partially accepted (because of ``) during the elections, or after your stake is unfrozen (this happens some time after the expiration of the term of the validator group to which your validator has been elected), you may want to collect back all or part of your stake, along with whatever share of bonuses is due to your validator. The elector smart contract does not send the stake and bonuses to you (i.e., the controlling smart contract) in a message. Instead, it credits the amount to be returned to you inside a special table, which can be inspected with the aid of get-method `compute_returned_stake` (which expects the address of the controlling smart contract as an argument): + +``` +$ lite-client -C -rc 'runmethod -1:A4C2C7C05B093D470DE2316DBA089FA0DD775FD9B1EBFC9DC9D04B498D3A2DDA compute_returned_stake 0xaf17db43f40b6aa24e7203a9f8c8652310c88c125062d1129fe883eaa1bd6763' +arguments: [ 79196899299028790296381692623119733846152089453039582491866112477478757689187 130944 ] +result: [ 0 ] +``` + +If the result is zero, nothing is due to you. Otherwise, you'll see part or all of your stake, perhaps with some bonuses. In that case, you can create a stake recovery request by using `recover-stake.fif`: + +``` +$ fift -s recover-stake.fif +query_id for stake recovery message is set to 1567634299 + +Message body is x{47657424000000005D70337B} + +Saved to file recover-query.boc +``` + +Again, you have to send `recover-query.boc` as the payload of a message from the controlling smart contract (i.e., your wallet) to the elector smart contract: + +``` +$ fift -s wallet.fif my_wallet_id -B recover-query.boc +``` + +For example, + +``` +$ fift -s wallet.fif my_wallet_id -1:A4C2C7C05B093D470DE2316DBA089FA0DD775FD9B1EBFC9DC9D04B498D3A2DDA 2 1. -B recover-query.boc +... +(Saved to file wallet-query.boc) +``` + +Notice that this message carries a small value (one TON Coin) just to pay the message forwarding and processing fees. If you indicate a value equal to zero, the message will not be processed by the election smart contract (a message with exactly zero value is almost useless in the TON Blockchain context). + +Once `wallet-query.boc` is ready, you can send it from the Lite Client: + +``` +$ liteclient -C -c 'sendfile wallet-query.boc' +``` + +If you have done everything correctly (in particular indicated the correct seqno of your wallet instead of `2` in the example above), you'll obtain a message from the elector smart contract containing the change from the small value you sent with your request (1 TON Coin in this example) plus the recovered portion of your stake and bonuses. + +## 7. Participating in the next elections + +Notice that even before the term of the validator group containing your elected validator finishes, new elections for the next validator group will be announced. You'll probably want to participate in them as well. For this, you can use the same validator, but you must generate a new validator key and new ADNL address. You'll also have to make a new stake before your previous stake is returned (because your previous stake will be unfrozen and returned only sometime after the next validator group becomes active), so if you want to participate in concurrent elections, it likely does not make sense to stake more than half of your TON Coins. diff --git a/versioned_docs/version-1.0.0/develop/howto/wallets.md b/versioned_docs/version-1.0.0/develop/howto/wallets.md new file mode 100644 index 0000000000..9c5f14ee68 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/howto/wallets.md @@ -0,0 +1,32 @@ +You can download standard wallets from https://ton.org/wallets. + +These are convenient, tested and secure wallets. + +## Troubleshooting + +### Basic + +* Make sure your wallet is downloaded from https://ton.org/wallets. + +* Make sure you have your recovery words backed up. If not, click on "Back up wallet" and make a backup. + +* Make sure that config URL is https://ton.org/global-config-wallet.json and blockchain ID is **mainnet** in Settings of your wallet. + +* If your settings are different, enter the correct values. + +* If you cannot enter **mainnet** into blockchain ID - update your wallet from https://ton.org/wallets. + +### Everything above has been done, but the wallet does not connect + +* Just reopen the wallet app. When the application starts, it will choose another lite server. + +### A long time ago I had a wallet, I have recovery words, but the wallet does not connect + +* Oh, you're a TON veteran. Some lite servers may not have such a long history, so you'd better use the archive node when you first log in. + +* Make sure your wallet is downloaded from https://ton.org/wallets. + +* In wallet Settings in config URL enter https://ton.org/global-config-archive.json and **mainnet** in blockchain ID. Apply settings. + +* After the wallet is successfully synchronized - put in settings in config URL https://ton.org/global-config-wallet.json again. + diff --git a/versioned_docs/version-1.0.0/develop/installation.md b/versioned_docs/version-1.0.0/develop/installation.md new file mode 100644 index 0000000000..c65c00b2eb --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/installation.md @@ -0,0 +1,134 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# Installation + +## Prerequisites + +For local development of TON smart contracts you always need to prepare binaries of `func`, `fift` and `lite-client` on your machine. + +You can download and setup them below. + +## Precompiled binaries + +### 1. Download + +Download the binaries from the table below - make sure to select the correct version according to the operating system you're using and install the additional dependencies: + +| OS | fift | func | lite-client | Additional dependencies | +|------------------------|------|------------------------------------------------------------------------------------------------|-------------|-------| +| MacOS M1 | [download](https://github.com/ton-defi-org/ton-binaries/releases/download/macos-m1/fift) | [download](https://github.com/ton-defi-org/ton-binaries/releases/download/macos-m1/func) | [download](https://github.com/ton-defi-org/ton-binaries/releases/download/macos-m1/lite-client) | `brew install openssl` | +| MacOS Intel | [download](https://github.com/ton-defi-org/ton-binaries/releases/download/macos-intel/fift) | [download](https://github.com/ton-defi-org/ton-binaries/releases/download/macos-intel/func) | [download](https://github.com/ton-defi-org/ton-binaries/releases/download/macos-intel/lite-client) | `brew install openssl`
    `brew reinstall readline` | +| Windows 64 | [download](https://github.com/ton-defi-org/ton-binaries/releases/download/windows-64/fift.exe) | [download](https://github.com/ton-defi-org/ton-binaries/releases/download/windows-64/func.exe) | [download](https://github.com/ton-defi-org/ton-binaries/releases/download/windows-64/lite-client.exe) | Install [OpenSSL 1.1.1](https://slproweb.com/download/Win64OpenSSL_Light-1_1_1q.msi) | +| Ubuntu 18 | [download](https://github.com/ton-defi-org/ton-binaries/releases/download/ubuntu-18/fift) | [download](https://github.com/ton-defi-org/ton-binaries/releases/download/ubuntu-18/func) | [download](https://github.com/ton-defi-org/ton-binaries/releases/download/ubuntu-18/lite-client) | `sudo apt install libssl-dev` | +| Ubuntu 16 | [download](https://github.com/ton-defi-org/ton-binaries/releases/download/ubuntu-16/fift) | [download](https://github.com/ton-defi-org/ton-binaries/releases/download/ubuntu-16/func) | [download](https://github.com/ton-defi-org/ton-binaries/releases/download/ubuntu-16/lite-client) | `sudo apt install libssl-dev` | +| Debian 10 | [download](https://github.com/ton-defi-org/ton-binaries/releases/download/debian-10/fift) | [download](https://github.com/ton-defi-org/ton-binaries/releases/download/debian-10/func) | [lite-client](https://github.com/ton-defi-org/ton-binaries/releases/download/debian-10/lite-client) | `sudo apt install libssl-dev` | + +### 2. Setup your binaries + +export const Highlight = ({children, color}) => ( + +{children} + +); + + + + + 1. After download, you need to `create` a new folder, for example **`C:/Users/%USERNAME%/ton/bin`** and move the installed files there. + + 2. To open the Windows environment variables press the Win + R keys on the keyboard, type `sysdm.cpl` and press Enter. + + 3. On the "_Advanced_" tab, click the "Environment Variables..." button. + + 4. In the _"User variables"_ section, select the "_Path_" variable and click "Edit" (this is usually required). + + 5. To add a new value `(path)` to the system variable in the next window, click the button "New". + In the new field, you need to specify the path to the folder where the previously installed files are stored: + + ``` + C:\Users\%USERNAME%\ton\bin\ + ``` + + 6. To check that everything was installed correctly, run in terminal (_cmd.exe_): + + ```bash + fift -V -and func -V -and lite-client -V + ``` + + 7. If you plan to use fift you need `FIFTPATH` environment variable with necessary imports: + + 1. Download [fiftlib.zip](https://github.com/ton-defi-org/ton-binaries/releases/download/fiftlib/fiftlib.zip) + 2. Open the zip in some directory on your machine (like **`C:/Users/%USERNAME%/ton/lib/fiftlib`**) + 3. Create new (click button "New") environment variable `FIFTPATH` in "_User variables_" section. + 4. In the "_Variable value_" field, specify the path to the files: **`/%USERNAME%/ton/lib/fiftlib`** and click OK. Done. + + +:::caution important +Instead of the `%USERNAME%` keyword, you must insert your own `username`. +::: + + + + + 1. After download, make sure the downloaded binaries are executable by changing their permissions: + ```bash + chmod +x func + chmod +x fift + chmod +x lite-client + ``` + + 2. It's also useful to place these binaries in your path (or copy them to `/usr/local/bin`) to make sure you can access them from anywhere. + ```bash + cp ./func /usr/local/bin/func + cp ./fift /usr/local/bin/fift + cp ./lite-client /usr/local/bin/lite-client + ``` + + 3. To check that everything was installed correctly, run in terminal + ```bash + fift -V && func -V && lite-client -V + ``` + + 4. If you plan to `use fift`, also download [fiftlib.zip](https://github.com/ton-defi-org/ton-binaries/releases/download/fiftlib/fiftlib.zip), open the zip in some directory on your machine (like `/usr/local/lib/fiftlib`) and set the environment variable `FIFTPATH` to point to this directory. + + ``` + unzip fiftlib.zip + mkdir -p /usr/local/lib/fiftlib + cp fiftlib/* /usr/local/lib/fiftlib + ``` + +:::info Hey, you're almost finished :) +Remember to set the **environment variable** `FIFTPATH` to point to this directory. +::: + + + + + + + +## Build from source + +If you don't want to rely on pre-compiled binaries and prefer to compile the binaries by yourself, you can follow the [official instructions](https://ton.org/#/compile). The gist instructions provided below: + +### Linux (Ubuntu / Debian) + +```bash +sudo apt update +sudo apt install git make cmake g++ libssl-dev zlib1g-dev wget +cd ~ && git clone https://github.com/ton-blockchain/ton.git +cd ~/ton && git submodule update --init +mkdir ~/ton/build && cd ~/ton/build && cmake .. -DCMAKE_BUILD_TYPE=Release && make -j 4 +``` +## Other sources for binaries + +The core team provides automatic builds for several operating systems as [GitHub Actions](https://github.com/ton-blockchain/ton/actions). + +Click on the link above, choose the workflow on the left relevant to your operating system, click on a recent green passing build and under "Artifacts" download `ton-binaries`. diff --git a/versioned_docs/version-1.0.0/develop/payment-processing/common.md b/versioned_docs/version-1.0.0/develop/payment-processing/common.md new file mode 100644 index 0000000000..a0a7bbbceb --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/payment-processing/common.md @@ -0,0 +1,5 @@ +# Create a key pair and a wallet + +```js reference +https://github.com/toncenter/examples/blob/main/common.js +``` \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/payment-processing/deposits-multi-wallet.md b/versioned_docs/version-1.0.0/develop/payment-processing/deposits-multi-wallet.md new file mode 100644 index 0000000000..e12c855228 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/payment-processing/deposits-multi-wallet.md @@ -0,0 +1,5 @@ +# Accepting deposits to multiple wallets + +```js reference +https://github.com/toncenter/examples/blob/main/deposits-multi-wallet.js +``` \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/payment-processing/deposits-single-wallet.md b/versioned_docs/version-1.0.0/develop/payment-processing/deposits-single-wallet.md new file mode 100644 index 0000000000..fec797e6c6 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/payment-processing/deposits-single-wallet.md @@ -0,0 +1,5 @@ +# Accepting deposits to a single wallet + +```js reference +https://github.com/toncenter/examples/blob/main/deposits-single-wallet.js +``` \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/payment-processing/withdrawals.md b/versioned_docs/version-1.0.0/develop/payment-processing/withdrawals.md new file mode 100644 index 0000000000..84d12054a4 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/payment-processing/withdrawals.md @@ -0,0 +1,5 @@ +# Withdrawal processing + +```js reference +https://github.com/toncenter/examples/blob/main/withdrawals.js +``` \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/smart-contracts/README.md b/versioned_docs/version-1.0.0/develop/smart-contracts/README.md new file mode 100644 index 0000000000..3f18e64f8c --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/smart-contracts/README.md @@ -0,0 +1,84 @@ +# Introduction + + +Right now there is 2 great approaches how to start developing TON smart contracts: +* [TON Hello World: Step by step guide for writing your first smart contract in FunC](https://society.ton.org/ton-hello-world-step-by-step-guide-for-writing-your-first-smart-contract-in-func) +* [TON Learn Guides: 10 zero-to-hero lessons](https://github.com/romanovichim/TonFunClessons_Eng) ([Ru version](https://github.com/romanovichim/TonFunClessons_ru)) + +## Environment + +### Online + +You can try to deploy TON smart contracts online using [Glitch Workspace](https://glitch.com/edit/#!/remix/clone-from-repo?&REPO_URL=https%3A%2F%2Fgithub.com%2Fton-defi-org%2Ftonstarter-contracts.git). + +Glitch runs the [tonstarter-contracts](https://github.com/ton-defi-org/tonstarter-contracts) environment directly in the browser, so it is almost identical to the local setup but doesn't require installing anything on your machine. + +[![Remix on Glitch](https://cdn.glitch.com/2703baf2-b643-4da7-ab91-7ee2a2d00b5b%2Fremix-button-v2.svg)](https://glitch.com/edit/#!/remix/clone-from-repo?&REPO_URL=https%3A%2F%2Fgithub.com%2Fton-defi-org%2Ftonstarter-contracts.git) + +:::info +Online IDE is perfect for hackathons, contests, or just to try TON development. +::: + +### Local + +A local environment allows you to develop contracts _faster_, with more comfort, and use bonuses like [IDE plugins](/develop/tools/ide-plugins) with syntax highlight for smart contracts development. + +Continue in the [INSTALLATION](/develop/installation) guide. + +## Development Toolkit + +Start developing, testing and debugging smart contracts easily with these resources: + +* [tonstarter-contracts](https://github.com/ton-defi-org/tonstarter-contracts) - All-in-one templates to build, deploy and test FunC contracts +* [toncli](https://github.com/disintar/toncli) — Comfy CLI to build, deploy and test FunC contracts. +* [MyLocalTON](/participate/nodes/local-ton.md) - Run your private TON blockchain +* [ton-contract-executor](https://github.com/Naltox/ton-contract-executor) - Library for running contracts locally + + +## TON Virtual Machine + +TON smart contracts are executed on their own TON Virtual Machine (TVM). +TVM is built on the stack principle, which makes it efficient and easy to implement. + +You can read more about how TVM works in [TVM bird's-eye overview](/learn/tvm-instructions/tvm_overview). + +## FunC language + +High-level language FunC is used to program smart contracts on TON. + +Feel free to read more about FunC in [DOCUMENTATION](/develop/func/overview.md) section. + +## Smart Contract Guidelines + +TON allows you to do anything, but on production smart contracts must be followed _smart contract guidelines_ if you want to discover the full power of the TON blockchain: + +* [Smart Contract Guidelines](/develop/smart-contracts/guidelines) + +## Fift language + +:::caution advanced level +This information is **very low level** and could be hard to understand for newcomers. +So feel free to read about it later. +::: + +Messages to smart contracts are binary data. To construct such messages, you can use one of the SDKs **or** the special programming language Fift. + +Since Fift is close to TVM opcodes, it also helps to know the limits of your brain. + +- [Fift documentation](https://ton-blockchain.github.io/fiftbase.pdf) +- [Fift scripts for standard smart contracts](https://github.com/ton-blockchain/ton/tree/master/crypto/smartcont) + + +## FAQ + +- **Is TVM compatible with EVM?** + + TVM cannot be compatible with the Ethereum Virtual Machine (EVM) because the TON has a different modern architecture (TON asynchronous, Ethereum synchronous). + + [Read more](https://telegra.ph/Its-time-to-try-something-new-Asynchronous-smart-contracts-03-25). + +- **Is it possible to write on Solidity for TON?** + + No, you can't write on Solidity for TON. + + But if you add asynchronous messages to Solidity syntax and the ability to interact with data at a low level, then you get FunC. FunC has a familiar syntax similar to most modern programming languages and is designed specifically for TON. diff --git a/versioned_docs/version-1.0.0/develop/smart-contracts/fees.md b/versioned_docs/version-1.0.0/develop/smart-contracts/fees.md new file mode 100644 index 0000000000..afa31013dc --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/smart-contracts/fees.md @@ -0,0 +1,132 @@ +# Transaction Fees + +This document provides general idea of transaction fees in TON and particularly computation fees for funC code. There is also the [detailed specification in TVM whitepaper](https://ton-blockchain.github.io/tvm.pdf). + +# Transactions and phases + +As was described in [TVM overview](/learn/tvm-instructions/tvm_overview) transaction execution consist of a few phases. During those phases corresponding fees may be deducted. + +Generally: +```cpp +transaction_fee = storage_fees + + in_fwd_fees + + computation_fees + + action_fees + + out_fwd_fees +``` +where: + * `storage_fees` - fees corresponding to occupation of some space in chain state by contract + * `in_fwd_fees` - fees for importing to blockchain incoming message (it is only relevant for messages which were not previously onchain, that is `external` messages. For ordinary messages from contract to contract this fee is not applicable). + * `computation_fees` - fees corresponding to execution of TVM instructions + * `action_fees` - fees related to processing of action list (sending messages, setting libraries etc) + * `out_fwd_fees` - fees related to importing to blockchain of outcoming message + +## Computation fees + +### Gas +All computation costs are nominated in gas units. Price of gas units is determined by this chain config (Config 20 for masterchain and Config 21 for basechain) and may be changed only by consensus of validator. Note, unlike in other systems, user can not set his own gas price and there is no fee market. + +Current settings in basechain are as follows: 1 gas unit costs 1000 of nanoTONs. + +## TVM instructions cost +On the lowest-level (TVM instruction execution) the gas price for most primitives +equals the _basic gas price_, computed as `P_b := 10 + b + 5r`, +where `b` is the instruction length in bits and `r` is the +number of cell references included in the instruction. + +Apart from that basic fees, the following fees appear: + * Price of "parsing" cells (i.e., transforming cells into slices). Equal to 100 gas units for cells which is loading for the first time and 25 for subsequent loads during the same tx. + * Price of cells "creation" (i.e. transforming builders to cells). Equal to 500 gas units. + * Price of throwing exception - 50 gas units + * Price of tuple operations - 1 gas unit for every tuple element + * Price for implicit jumps - 10 gas units. It is price paid when all instructions in current continuation-cell are executed however there are references in that continuation cell and execution flow jumps to the first reference. + * Price for implicit back jumps - 5 gas units. It is price paid when all instructions in current continuation are executed and execution flow jumps back to the continuation from which just finished continuation was called. + * Price for moving stack elements between continuations. 1 gas unit per element, however first 32 elements moving is free. + +## FunC constructions gas fees + +Almost all functions used in funC are defined in [stdlib.func](https://github.com/ton-blockchain/ton/blob/master/crypto/smartcont/stdlib.fc) which maps funC functions to Fift assembler instructions. In turn Fift assembler instructions are mapped to bit-sequence instructions in [asm.fif](https://github.com/ton-blockchain/ton/blob/master/crypto/fift/lib/Asm.fif). So if you want to understand how much exactly instruction call will cost you, you need to find `asm` representation in `stdlib.func`, then find bit-sequence in `asm.fif` and calculate instruction length in bits. + +However, generally fees related to bit-lengths are minor in comparisson with fees related to cell parsing and creation, as well as jumps and just number of executed instructions. + +So, if you try to optimize your code start with architecture optimization, the decreasing number of cell parsing/creation operations, then with decreasing number of jumps. + +### Operations with cells +Just example of how proper cell work may substantially decrease gas costs. + +Lets imagine that you want to write some encoded payload to the outgoing message. Straightforward implementation will be as follows: +```cpp +slice payload_encoding(int a, int b, int c) { + return + begin_cell().store_uint(a,8) + .store_uint(b,8) + .store_uint(c,8) + end_cell().begin_parse(); +} + +() send_message(slice destination) impure { + slice payload = payload_encoding(1, 7, 12); + var msg = begin_cell() + .store_uint(0x18, 6) + .store_slice(destination) + .store_coins(0) + .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1) ;; some flags related to message header + .store_uint(0x33bbff77, 32) ;; op-code (see smart-contract guidelines) + .store_uint(cur_lt(), 64) ;; query_id (see smart-contract guidelines) + .store_slice(payload) + .end_cell(); + send_raw_message(msg, 64); +} +``` + +What is the problem with this code? `payload_encoding` to generate slice bit-string first create cell via `end_cell()` (+500 gas units) and then additionally parse it `begin_parse()` (+100 gas units). The same code can be written without those unnecessary operations by changing some used types: + +```cpp +;; we add asm for function which stores one builder to the another, which is absent from stdlib +builder store_builder(builder to, builder what) asm(what to) "STB"; + +builder payload_encoding(int a, int b, int c) { + return + begin_cell().store_uint(a,8) + .store_uint(b,8) + .store_uint(c,8); +} + +() send_message(slice destination) impure { + builder payload = payload_encoding(1, 7, 12); + var msg = begin_cell() + .store_uint(0x18, 6) + .store_slice(destination) + .store_coins(0) + .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1) ;; some flags related to message header + .store_uint(0x33bbff77, 32) ;; op-code (see smart-contract guidelines) + .store_uint(cur_lt(), 64) ;; query_id (see smart-contract guidelines) + .store_builder(payload) + .end_cell(); + send_raw_message(msg, 64); +} +``` +By passing bit-string in the another form (builder instead of slice) we substantially decrease computation cost by very slight change in code. + +### Inline and inline_refs +By default, when you have funC function, it gets it's own `id`, stored in separate leaf of id->function dictionary and when you call it somewhere in program, searching of function in dictionary and subsequent jump occur. Such behavior is justified if your function is used from many places in the code and thus jumps allows to decrease size of the code (by storing function body one time). However if function is only used one or two times it is often much cheaper to declare this function as `inline` or `inline_ref`. `inline` modificator place body of the function right into the code of the parent function, while `inline_ref` place function code into the reference (still jump to the reference is much cheaper than searching and jumping to dictionary entry). + +### Dictionaries +Dictionaries in the TON are introduced as trees (DAGs to be precise) of cells. That means that if you search, read or write to dictionary, you need to parse all cells of according branch of the tree. That means that + * a) dicts operations are not fixed in gas costs (since size and number of nodes in the branch depends on given dictionary and given key) + * b) it is expedient to optimize dict usage by using special instructions like `replace` instead of `delete` and `add` + * c) developer should be aware of iteration operations (like next and prev) as well `min_key`/`max_key` operations to avoid unneccessary iteration through whole dict + +### Stack operations +Note that funC manipulate stack entries under the hood. That means that code +```cpp +(int a, int b, int c) = some_f(); +return (c, b, a); +``` +will be translated to a few instructions which change the order of elements on the stack. + +When number of stack entries are substantial (10+) and their are actively used in different order stack operations fees may become non-negligible. + + + + diff --git a/versioned_docs/version-1.0.0/develop/smart-contracts/getting-started.md b/versioned_docs/version-1.0.0/develop/smart-contracts/getting-started.md new file mode 100644 index 0000000000..083bfb030f --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/smart-contracts/getting-started.md @@ -0,0 +1,74 @@ +# Getting Started + + +It's a list of links to articles and tools which can help you to start developing smart-contracts for [TON](https://ton.org) blockchain + +## What is smart-contract? +Self executing program hosted at blockchain. For example in the TON blockchain every wallet is smart-contract. + +Smart-contract have state and persistent storage, which can contain any sort of variables. + +Smart-contract can store data, move funds to other smart-contracts, compute something. + +## How to start using or developing smart-contracts? + +To begin with, you must pay attention to two existing programming languages related to developing smart contracts in TON: [FunC](https://ton.org/#/func) and [Fift](https://ton-blockchain.github.io/fiftbase.pdf). FunC is used to write the logic of contracts, it is compiled to fift-asm code, which can then be translated to bytecode for TVM. The functionality of Fift is very wide. To begin with, fift-asm is an [Asm.fif](https://github.com/newton-blockchain/ton/blob/master/crypto/fift/lib/Asm.fif) program that allows you to translate asm-like(fift-asm) code into byte code for TVM. We also use Fift to automatically test and write queries to smart contracts. + +You can get the binaries of the FunC compiler and the Fift interpreter by building code from [newton-blockchain/ton](https://github.com/newton-blockchain/ton) repo. + +You can use [toncli](https://github.com/disintar/toncli) to easily and conveniently develop smart contracts using FunC and Fift, especially useful if you are a beginner. The [tonweb](https://github.com/toncenter/tonweb) library is available for writing web interfaces. The official [documentation](https://ton.org/#/docs) can also help you a lot. + +## Chats with other developers +* 🇺🇸 [TonDev Chat](https://t.me/tondev_eng) - TON Developers chat +* 🇺🇸 [TON Society Chat](https://t.me/tonsociety_chat) - Global Hub for TON Builders +* 🇺🇸 [Tonic Discord](https://discord.gg/tWxm8nrKt8) — Discord community for TON developers +* 🇺🇸 [Smart-Contracts Dev Chat](https://t.me/tonsc_chat) — chat focused on smart-contracts development. +* 🇷🇺 [TonDevRu Chat](https://t.me/tondev) - TON Developers chat + +## About fift and func which are used to develop smart contracts: +1. [Fift official docs](https://ton-blockchain.github.io/fiftbase.pdf) +2. [FunC official docs](https://ton.org/#/func) +3. [Fift instructions in C++](https://github.com/newton-blockchain/ton/blob/9875f02ef4ceba5b065d5e63c920f91aec73224e/crypto/fift/words.cpp#L2723-L3110) + +## About TL-B + +TL-B (Type Language - Binary) serves to describe the type system, constructors, and existing functions. For example we can use TL-B schemes to build binary structures associated with the TON blockchain. Special TL-B parsers can read schemes to deserialize binary data into different objects. (definition from the [documentation](https://github.com/tonuniverse/TL-B-docs)) + +1. [Documentation with examples](https://github.com/tonuniverse/TL-B-docs) +2. [Some about TL-B are described in tvm.pdf](https://newton-blockchain.github.io/tvm.pdf) + +### Smart contracts examples: +1. [Official smart contracts (wallets, givers, etc.)](https://github.com/newton-blockchain/ton/tree/master/crypto/smartcont) +2. https://github.com/ton-blockchain/wallet-contract +3. Telegram contests, a lot of different smart contracts + 1. https://contest.com/blockchain + 2. https://contest.com/blockchain-2 & https://contest.com/blockchain-2-bonus +4. [Gambling smart contract](https://github.com/deNULL/ton-gamble) +5. [Auction smart contract](https://github.com/deNULL/ton-auction) +6. [Smart contract with text sending](https://github.com/akifoq/ton-samples/blob/master/text/main.fc) +7. [Example of simple token contract](https://github.com/akifoq/TonToken) +8. [Official draft fungible, non-fungible token contracts](https://github.com/ton-blockchain/token-contract) + * [NFT standart discussion](https://github.com/ton-blockchain/TIPs/issues/62) +9. [Wallet v4 contract (Supports external plugins installation)](https://github.com/ton-blockchain/wallet-contract) + * [Subscribtion plugin](https://github.com/ton-blockchain/wallet-contract/blob/main/func/simple-subscription-plugin.fc) +10. [TRC-20 (like ERC-20) token contract](https://github.com/cod1ng-studio/TRC20) +11. [Examples of using fift runvm to run transactions](https://github.com/disintar/toncli/tree/master/src/toncli/projects/external_code) +12. [Slotmachine game smart contract](https://gregory-wimbelson.gitbook.io/ton-cookbook/) + +### Articles about smartcontracts: +1. Official guidelines - https://ton.org/#/howto/smart-contract-guidelines +2. Develop, deploy and use lottery smart contract - https://habr.com/ru/post/494528/ +3. Extend wallet smart contract and deploy it - https://telegra.ph/Hello-World-TON-smart-contract-for-15-minutes-11-20 + +### Deploy smart contract: +1. [Smart contract deployer](https://deployer.tonsc.org/) by t.me/ProjectManageRR +2. [TON CLI](https://github.com/disintar/toncli) by t.me/disintar +3. [Documented generate.fif](https://gist.github.com/tvorogme/fdb174ac0740b6a52d1dbdf85f4ddc63) by t.me/disintar +4. [Lite-client installation guide](https://ton.org/#/howto/getting-started). Via lite-client you can send .boc file to deploy smart contract to blockchain +5. [Compilation and deploy of the gambling smart contract](https://gregory-wimbelson.gitbook.io/ton-cookbook/compilation-and-deploy-of-the-ton-smart-contract) + +### IDE plugins and syntax highlighting +1. [Intellij Platform plugin](https://github.com/andreypfau/intellij-ton) +2. [neovim FunC syntax highlighting](https://github.com/PythoNyashka/neovim-ton-dev) +3. Visual Studio Code [fift syntax highlighting](https://marketplace.visualstudio.com/items?itemName=dotcypress.language-fift) + and [FunC syntax highlighting](https://marketplace.visualstudio.com/items?itemName=raiym.FunC) diff --git a/versioned_docs/version-1.0.0/develop/smart-contracts/governance.md b/versioned_docs/version-1.0.0/develop/smart-contracts/governance.md new file mode 100644 index 0000000000..d56ee07eba --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/smart-contracts/governance.md @@ -0,0 +1,66 @@ +# Governance contracts + +In TON, consensus parameters of node operation related to TVM, catchain, fees and chain topology — as well as how those parameters are stored and updated — are controlled by a set of special smart contracts (in contrast to old-fashioned and inflexible ways of hardcoding of those parameters adopted by blockchains of previous generations). That way, TON implements comprehensive and transparent on-chain governance. The set of special contracts itself is governed by parameters and currently includes Elector, Config and DNS contract and, in the future, will be extended by extra-currency Minter and others. + +## Elector + +The Elector smart contract controls the way how rounds of validation change each other, who gets the duty to validate the blockchain, and how rewards for validation would be distributed. If you are looking for a practical way to becoming a validator and interacting with Elector, check [validator instrucitons](https://ton.org/validator). + +Elector stores data of Toncoin that is not withdrawn in `credits` hashmap, new applications in `elect` hashmap, and information about previous elections in _past\_elections_ hashmap (the latter is stored inside _complaints_ about validator misbehaving and _frozen_ - stakes of validator for already finished rounds, which are withheld for `stake_held_for`(ConfigParam 15)).The Elector contract has 3 purposes: + - Process applications for the election of validators + - Conduct elections + - Process validator misbehaving reports + - Distribute validation reward. + +### Processing applications +To create an application, a future validator needs to form a special message that contains the corresponding parameters (ADNL address, public key, `max_factor`, etc.), attach it to some sum of TON (called a stake), and send it to the Elector. In turn, the Elector checks those parameterss and either registers an application or immediately returns the stake back to the sender. Note that applications are only accepted from addresses on the masterchain. + +### Conducting elections +The Elector is a special smart contract that have the option to be forcedly invoked at the beginning and the end of each block (so-called Tick and Tock transactions). The Elector, indeed, is invoked on each block and checks whether it is the time to conduct a new election. + +The general concept of the election process is to consider all applications, in particular, their TON amount and `max_factor` (the maximal ratio of validation work this applicant is agreed to do in comparison to the weakest validator), and set weights to each validator proportional to the TON amount but in such a way that all `max_factor` conditions are met. + +Technically, it is implemented the following way: + +1. The Elector takes all applications with a stake amount above the current network minimum `min_stake` (ConfigParam 17). +2. It sorts them by stake in descending order. +3. If there are more participants than the maximum number of validators (`max_validators` ConfigParam 16), discard the tail of the list. +4. Cycle `i` from `1` to `N` (remaining number of participants) + - Take the first `i` element from the list (sorted in descending order) + - Assume that _i_-th candidate will be the last accepted (and thus has the lowest weight) and calculate an effective stake (`true_stake` in code) with respect to `max_factor`. In other words, the effective stake of a _j_-th (`j ( + +{children} + +); + + +The simplest way to protect smart contracts from replay attacks related to external messages is to store a 32-bit counter `cur-seqno` in the persistent data of the smart contract, and to expect a `req-seqno` value in (the signed part of) any inbound external messages. Then an external message is ACCEPTed only if both the signature is valid and `req-seqno` equals `cur-seqno`. After successful processing, the `cur-seqno` value in the persistent data is increased by one, so the same external message will never be accepted again. + +And One could also include an `expire-at` field in the external message, and accept an external message only if the current Unix time is less than the value of this field. This approach can be used in conjunction with `seqno`; alternatively, the receiving smart contract could store the set of (the hashes of) all recent (not expired) accepted external messages in its persistent data, and reject a new external message if it is a duplicate of one of the stored messages. Some garbage collecting of expired messages in this set should also be performed to avoid bloating the persistent data. + +:::note +In general, an external message begins with a 256-bit signature (if needed), a 32-bit `req-seqno` (if needed), a 32-bit `expire-at` (if needed), and possibly a 32-bit `op` and other required parameters depending on `op`. The layout of external messages does not need to be as standardized as that of the internal messages because external messages are not used for interaction between different smart contracts (written by different developers and managed by different owners). +::: \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/smart-contracts/guidelines/get-methods.md b/versioned_docs/version-1.0.0/develop/smart-contracts/guidelines/get-methods.md new file mode 100644 index 0000000000..824ac6c403 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/smart-contracts/guidelines/get-methods.md @@ -0,0 +1,14 @@ +# Get Methods + +Some smart contracts are expected to implement certain well-defined get-methods. + +[//]: # (![image](/img/docs/Screenshot_4.png)) + +For instance, any subdomain resolver smart contract for TON DNS is expected to implement the get-method `dnsresolve`. Custom smart contracts may define their specific get-methods. + +:::danger +Our only general recommendation at this point is to implement the get-method `seqno` (without parameters) that returns the current `seqno` of a smart contract that uses sequence numbers to prevent replay attacks related to inbound external methods, whenever such a method makes sense. +::: + + + diff --git a/versioned_docs/version-1.0.0/develop/smart-contracts/guidelines/internal-messages.md b/versioned_docs/version-1.0.0/develop/smart-contracts/guidelines/internal-messages.md new file mode 100644 index 0000000000..0fa466e0b5 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/smart-contracts/guidelines/internal-messages.md @@ -0,0 +1,42 @@ +# Internal messages + +Smart contracts interact with each other by sending the so-called **internal messages**. When an internal message reaches its intended destination, an ordinary transaction is created on behalf of the destination account, and the internal message is processed as specified by the code and the persistent data of this account (smart contract). + +:::info +In particular, the processing transaction can create one or several outbound internal messages, some of which could be addressed to the source address of the internal message being processed. This can be used to create simple "client-server applications", when a query is encapsulated in an internal message and sent to another smart contract, which processes the query and sends back a response, again as an internal message. +::: + +This approach leads to the necessity of distinguishing whether an internal message is intended as a "query" or as a "response", or doesn't require any additional processing (like a "simple money transfer"). Furthermore, when a response is received, there must be a means to understand to which query it corresponds. + +In order to achieve this goal, the following recommended internal message layout can be used (notice that the TON Blockchain does not enforce any restrictions on the message body, so these are indeed just recommendations): + +1. The body of the message can be embedded into the message itself, or be stored in a separate cell referred to from the message, as indicated by the TL-B scheme fragment: + +```cpp +message$_ {X:Type} ... body:(Either X ^X) = Message X; +``` + +The receiving smart contract should accept at least internal messages with embedded message bodies (whenever they fit into the cell containing the message). If it accepts message bodies in separate cells (using the `right` constructor of `(Either X ^X)`), the processing of the inbound message should not depend on the specific embedding option chosen for the message body. On the other hand, it is perfectly valid not to support message bodies in separate cells at all for simpler queries and responses. + +2. The message body typically begins with the following fields: + + * A 32-bit (big-endian) unsigned integer `op`, identifying the `operation` to be performed, or the `method` of the smart contract to be invoked. + * A 64-bit (big-endian) unsigned integer `query_id`, used in all query-response internal messages to indicate that a response is related to a query (the `query_id` of a response must be equal to the `query_id` of the corresponding query). If `op` is not a query-response method (e.g., it invokes a method that is not expected to send an answer), then `query_id` may be omitted. + * The remainder of the message body is specific for each supported value of `op`. + +3. If `op` is zero, then the message is a "simple transfer message with comment". The comment is contained in the remainder of the message body (without any `query_id` field, i.e., starting from the fifth byte). If it does not begin with the byte `0xff`, the comment is a text one; it can be displayed "as is" to the end user of a wallet (after filtering invalid and control characters and checking that it is a valid UTF-8 string). + + For instance, users may indicate the purpose of a simple transfer from their wallet to the wallet of another user in this text field. On the other hand, if the comment begins with the byte `0xff`, the remainder is a "binary comment", which should not be displayed to the end user as text (only as hex dump if necessary). The intended use of "binary comments" is, e.g., to contain a purchase identifier for payments in a store, to be automatically generated and processed by the store's software. + + Most smart contracts should not perform non-trivial actions or reject the inbound message on receiving a "simple transfer message". In this way, once `op` is found to be zero, the smart contract function for processing inbound internal messages (usually called `recv_internal()`) should immediately terminate with a zero exit code indicating success (e.g., by throwing exception `0`, if no custom exception handler has been installed by the smart contract). This will lead to the receiving account being credited with the value transferred by the message without any further effect. + +4. A "simple transfer message without comment" has an empty body (without even an `op` field). The above considerations apply to such messages as well. Note that such messages should have their bodies embedded into the message cell. + +5. We expect "query" messages to have an `op` with the high-order bit clear, i.e., in the range `1 .. 2^31-1`, and "response" messages to have an `op` with the high-order bit set, i.e., in the range `2^31 .. 2^32-1`. If a method is neither a query nor a response (so that the corresponding message body does not contain a `query_id` field), it should use an `op` in the "query" range `1 .. 2^31 - 1`. + +6. There are some "standard" response messages with the `op` equal to `0xffffffff` and `0xfffffffe`. In general, the values of `op` from `0xfffffff0` to `0xffffffff` are reserved for such standard responses. + + * `op` = `0xffffffff` means "operation not supported". It is followed by the 64-bit `query_id` extracted from the original query, and the 32-bit `op` of the original query. All but the simplest smart contracts should return this error when they receive a query with an unknown `op` in the range `1 .. 2^31-1`. + * `op` = `0xfffffffe` means "operation not allowed". It is followed by the 64-bit `query_id` of the original query, followed by the 32-bit `op` extracted from the original query. + + Notice that unknown "responses" (with an `op` in the range `2^31 .. 2^32-1`) should be ignored (in particular, no response with an `op` equal to `0xffffffff` should be generated in response to them), just as unexpected bounced messages (with "bounced" flag set). \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/smart-contracts/guidelines/non-bouncable-messages.md b/versioned_docs/version-1.0.0/develop/smart-contracts/guidelines/non-bouncable-messages.md new file mode 100644 index 0000000000..d84a253f58 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/smart-contracts/guidelines/non-bouncable-messages.md @@ -0,0 +1,25 @@ +# Non-bounceable messages + +export const Highlight = ({children, color}) => ( + +{children} + +); + +Almost all internal messages sent between smart contracts should be bounceable, i.e., should have their `"bounce"` bit set. Then, if the destination smart contract does not exist, or if it throws an unhandled exception while processing this message, the message will be `"bounced"` back carrying the remainder of the original value (minus all message transfer and gas fees). The bounced message will have the same body, but with the `"bounce"` flag cleared and the `"bounced"` flag set. Therefore, all smart contracts should check the `"bounced"` flag of all inbound messages and either silently accept them (by immediately terminating with a zero exit code) or perform some special processing to detect which outbound query has failed. + +:::info +The query contained in the body of a bounced message should never be executed. +::: + +On some occasions, `non-bounceable internal messages` must be used. For instance, new accounts cannot be created without at least one non-bounceable internal message sent to them. Unless this message contains a `StateInit` with the code and data of the new smart contract, it does not make sense to have a non-empty body in a non-bounceable internal message. + +:::tip +It is a good idea `not to allow` the end user (e.g., of a wallet) to send unbounceable messages carrying large value (e.g., more than five TON Coins), or at least to warn them if they try this. It is a `better idea` to send a small amount first, then initialize the new smart contract, and then send a larger amount. +::: \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/smart-contracts/guidelines/processing.md b/versioned_docs/version-1.0.0/develop/smart-contracts/guidelines/processing.md new file mode 100644 index 0000000000..a598a2a1a2 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/smart-contracts/guidelines/processing.md @@ -0,0 +1,13 @@ +# Paying for processing queries and sending responses + +In general, if a smart contract wants to send a query to another smart contract, it should pay for sending the internal message to the destination smart contract (message forwarding fees), for processing this message at the destination (gas fees), and for sending back the answer if required (message forwarding fees). + +:::note +In most cases, the sender will attach a small amount of TON Coins (e.g., one TON Coin) to the internal message (sufficient to pay for the processing of this message), and set its "bounce" flag (i.e., send a bounceable internal message); the receiver will return the unused portion of the received value with the answer (deducting message forwarding fees from it). This is normally accomplished by invoking `SENDRAWMSG` with `mode = 64` (cf. Appendix A of TON VM documentation). +::: + +If the receiver is unable to parse the received message and terminates with a non-zero exit code (for example, because of an unhandled cell deserialization exception), the message will be automatically "bounced" back to its sender, with the `"bounce"` flag cleared and the `"bounced"` flag set. The body of the bounced message will be the same as that of the original message; therefore, it is important to check the "bounced" flag of incoming internal messages before parsing the `op` field in the smart contract and processing the corresponding query (otherwise there is a risk that the query contained in a bounced message will be processed by its original sender as a new separate query). If the `"bounced"` flag is set, special code could find out which query has failed (e.g., by deserializing `op` and `query_id` from the bounced message) and take appropriate action. A simpler smart contract might simply ignore all bounced messages (terminate with zero exit code if `"bounced"` flag is set). + +On the other hand, the receiver might parse the incoming query successfully and find out that the requested method `op` is not supported, or that another error condition is met. Then a response with `op` equal to `0xffffffff` or another appropriate value should be sent back, using `SENDRAWMSG` with `mode = 64` as mentioned above. + +In some situations, the sender wants both to transfer some value to the sender and to receive either a confirmation or an error message. For instance, the validator elections smart contract receives an election participation request along with the stake as the attached value. In such cases, it makes sense to attach, say, one extra TON Coin to the intended value. If there is an error (e.g., the stake may not be accepted for any reason), the full received amount (minus the processing fees) should be returned to the sender along with an error message (e.g., by using `SENDRAWMSG` with `mode = 64` as explained before). In the case of success, the confirmation message is created and exactly one TON Coin is sent back (with the message transferring fees deducted from this value; this is `mode = 1` of `SENDRAWMSG`). diff --git a/versioned_docs/version-1.0.0/develop/smart-contracts/guidelines/tips.md b/versioned_docs/version-1.0.0/develop/smart-contracts/guidelines/tips.md new file mode 100644 index 0000000000..13a63b38fd --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/smart-contracts/guidelines/tips.md @@ -0,0 +1,45 @@ +# Tips & Tricks + +## About bounce TONs back + +If you have the `throw_if` function (with code != 0) in recv_internal triggered and the bounce flag set([tblkch.pdf 4.2.5](https://newton-blockchain.github.io/tblkch.pdf)), all coins will be sent back + +Read more in the [original discussion](https://t.me/tondev/44958). + + +## About charging gas fees + +This information is based on this [discussion](https://github.com/DKeysil/awesome-ton-smart-contracts/issues/1) + +`accept_message` simply sets the gas limit to the maximal possible value (the gas that can be bought by both original contract balance and message value, or, more commonly, the maximal gas amount allowed to use in single transaction) and also sets gas credit to zero. + +In the case of external messages you need to accept the message in order to make transaction appear in the block (or, more precisely speaking, you need to somehow set gas credit to zero). You can accept message at any time during the TVM execution, even after calling `send_raw_message` primitive. The only way the fees may be charged from the account is to put a transaction into the blockchain, so it's the reason why "transactions" with no `accept_message` are "free". + +In the case of internal messages the initial gas limit is set equal to the amount of gas that can be bought by message value. `accept_message` raises that limit. Even without `accept_message` you can spend more coins than the message value by sending some other messages which carry value. + +Using `set_gas_limit` in internal messages does not limit the possibility of spending more TON than came with the message when sending other messages that carry value. You can use `raw_reserve` in addition to gas limit to limit spendable amount of coins. + +FunC docs: +- [`accept_message`](/develop/func/stdlib#accept_message) +- [`set_gas_limit`](/develop/func/stdlib#set_gas_limit) +- [`raw_reserve`](/develop/func/stdlib#raw_reserve) + + +Read more in the [original discussion](https://t.me/tondev/45882). + + +## Spend less gas in huge smart contracts + +`touch()` is tip to the compiler how best to organize the stack. The command puts a variable at top of the stack ([func docs](/develop/func/stdlib#impure_touch)) + +### Example + +In this code: + +```js reference +https://github.com/ton-blockchain/wallet-contract/blob/main/func/wallet-v4-code.fc#L71-L92 +``` + +`cs~touch();` will place `cs` on top of the stack and then the interaction with the variable will be cheaper. + +Read more in the [original discussion](https://t.me/tondev/45956). \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/smart-contracts/messages.md b/versioned_docs/version-1.0.0/develop/smart-contracts/messages.md new file mode 100644 index 0000000000..4ff882790e --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/smart-contracts/messages.md @@ -0,0 +1,153 @@ +# Sending messages + +Composition, parsing and sending messages lie on the intersection of [TL-B schemas](/learn/overviews/TL-B), [transaction phases and TVM](/learn/tvm-instructions/tvm_overview.md). + +Indeed, funC expose [send_raw_message](/develop/func/stdlib#send_raw_message) function which expects serialized message as argument. + +Since TON is a comprehensive system with wide functionality, messages which need to be able to support all of this functionality may look quite complicated. Still, most of that functionality is not used in common scenarios and message serialization in most cases may be reduced to +```cpp + var msg = begin_cell() + .store_uint(0x18, 6) + .store_slice(addr) + .store_coins(amount) + .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1) + .store_slice(message_body) + .end_cell(); +``` + +Therefore, the developer should not be afraid, and if something in this document seems incomprehensible on first reading, it's okay. Just grasp the general idea. + +Let's dive in! + +## Types of messages +There are three types of messages: + * external - messages which are sent from outside of blockchain to some smart-contract inside. Such messages should be explicitly accepted by smart-contract during so called `credit_gas`. If message is not accepted, node should not accept it into block or relay it to other nodes. + * internal - messages which are sent from one blockchain entity to another. Such messages (in contrast to external) may carry some TONs and pay for themselves. Thus smart-contract which receive such message may not accept it: in this case gas will be deducted from message value. + * logs - messages which are sent from blockchain entity to outer world. Generally speaking there is no mechanism of sending such messages out of blockchain: indeed, while all nodes in the network have consensus on whether message was created or not, there are no rules on how process them. Logs may be directly sent to `/dev/null`, logged to disk, saved to indexed database or even sent by non-blockchain means (email/telegram/sms), all of this is in the sole discretion of the given node. + +## Message layout + +We will start with internal messages layout + +TL-B scheme which describes message which can be sent by smart-contract is as follows: +```cpp +message$_ {X:Type} info:CommonMsgInfoRelaxed + init:(Maybe (Either StateInit ^StateInit)) + body:(Either X ^X) = MessageRelaxed X; +``` + +Lets put it into words. Serialization of any message consist of three fields: info (header of some sort, which describe source, destination and other metadata), init (field which is only required for initialisation of messages) and body (message payload). + +`Maybe` and `Either` and other type expressions mean as following: +* when we have field `info:CommonMsgInfoRelaxed` it means that serialization of `CommonMsgInfoRelaxed` is injected directly to the serialization cell +* when we have field `body:(Either X ^X)` it means that when we (de)serialize some type `X` we first put one `either` bit which is `0` if `X` is serialized to the same cell or `1` if it is serialized to the separate cell. +* when we have field `init:(Maybe (Either StateInit ^StateInit))` it means that we first put `0` or `1` depending on whether this field empty or not; and if it is not empty we serialize `Either StateInit ^StateInit` (again put one `either` bit which is `0` if `StateInit` is serialized to the same cell or `1` if it is serialized to the separate cell). + +`CommonMsgInfoRelaxed` layout is as follows: + +```cpp +int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool + src:MsgAddress dest:MsgAddressInt + value:CurrencyCollection ihr_fee:Grams fwd_fee:Grams + created_lt:uint64 created_at:uint32 = CommonMsgInfoRelaxed; + +ext_out_msg_info$11 src:MsgAddress dest:MsgAddressExt + created_lt:uint64 created_at:uint32 = CommonMsgInfoRelaxed; +``` + +Let's focus on `int_msg_info` for now. +It starts with 1bit prefix `0`, then there are three 1-bit flags, namely whether Instant Hypercube Routing disabled (currently always true), whether message should be bounced if there are errors during it's processing, whether message itself is result of bounce. Then source and destination address is serialized, then value of the message and four integers related to message forwarding fees and time. + +If message is sent from the smart-contract, some of those fields will be rewritten to correct values. In particular, validator will rewrite `bounced`, `src`, `ihr_fee`, `fwd_fee`, `created_lt` and `created_at`. That means two things: first, another smart-contract during handling message may trust those fields (sender may not forge source address, `bounced` flag, etc); and second, that during serialization we may put to those fields any valid values (anyway those values will be overwritten). + + +Straight-forward serialization of the message would be as follows: +```cpp + var msg = begin_cell() + .store_uint(0, 1) ;; tag + .store_uint(1, 1) ;; ihr_disabled + .store_uint(1, 1) ;; allow bounces + .store_uint(0, 1) ;; not bounced itself + .store_slice(source) + .store_slice(destination) + ;; serialize CurrencyCollection (see below) + .store_coins(amount) + .store_dict(extra_currencies) + .store_coins(0) ;; ihr_fee + .store_coins(fwd_value) ;; fwd_fee + .store_uint(cur_lt(), 64) ;; lt of transaction + .store_uint(now(), 32) ;; unixtime of transaction + .store_uint(0, 1) ;; no init-field flag (Maybe) + .store_uint(0, 1) ;; inplace message body flag (Either) + .store_slice(msg_body) + .end_cell(); +``` + +However, instead of step by step serialization of all fields, usually developers use short-cuts. Thus lets consider how message can be sent from the smart-contract on example from [elector-code](https://github.com/ton-blockchain/ton/blob/master/crypto/smartcont/elector-code.fc#L153) +```cpp +() send_message_back(addr, ans_tag, query_id, body, grams, mode) impure inline_ref { + ;; int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool src:MsgAddress -> 011000 + var msg = begin_cell() + .store_uint(0x18, 6) + .store_slice(addr) + .store_coins(grams) + .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1) + .store_uint(ans_tag, 32) + .store_uint(query_id, 64); + if (body >= 0) { + msg~store_uint(body, 32); + } + send_raw_message(msg.end_cell(), mode); +} +``` + +First it put `0x18` value into 6 bits, that is put `0b011000`. What is it? + +* First bit is `0` - 1bit prefix which indicates that it is `int_msg_info`. + +* Then there are 3 bits `1`, `1` and `0`, meaning Instant Hypercube Routing is disabled, message can be bounced and that message is not result of bouncing itself. +* Then there should be sender address, however since it anyway will be rewritten with the same effect any valid address may be stored there. The shortest valid address serialization is serialization of `addr_none` and it serializes as two-bit string `00`. + +Thus `.store_uint(0x18, 6)` is the optimized way of serializing tag and first 4 fields. + +Next line serializes destination address. + +Then we should serialize value. Generally message value is a `CurrencyCollection` object with the following scheme: +```cpp +nanograms$_ amount:(VarUInteger 16) = Grams; + +extra_currencies$_ dict:(HashmapE 32 (VarUInteger 32)) + = ExtraCurrencyCollection; + +currencies$_ grams:Grams other:ExtraCurrencyCollection + = CurrencyCollection; +``` + +This scheme means that in addtion to TON value, message may carry the dictionary of additional _extra-currencies_. However currently we may neglect it and just assume that message value is serialized as "number of nanotons as variable integer" and "`0` - empty dictionary bit". + +Indeed, in elector code above we serialize coins amount via `.store_coins(grams)` but then just put string of zeroes with length equal to `1 + 4 + 4 + 64 + 32 + 1 + 1`. What is it? +* First bit stands for empty extra-currencies dictionary. +* Then we have two 4bit long fields. They encode 0 as `VarUInteger 16`. Indeed since `ihr_fee` and `fwd_fee` will be overwritten we may as well put there zeroes. +* Then we put zero to `created_lt` and `created_at` fields. Those fields will be overwritten as well, however in contrast to fees, these fields have fixed length and thus are encoded as 64 and 32 bit long strings. +* _(at that moment we alredy serialized message header and pass to init/body)_ +* next zero-bit means that there is no `init` field +* and last zero-bit means that msg_body will be serialized in-place +* after that message body (with arbitrary layout) is encoded. + +That way instead of individual serialization of 14 parameters, we execute 4 serialization primitives. + +## Full scheme +Full scheme of messages layout as well as layout of all constituting fields (as well as scheme of ALL objects in TON) is presented in [block.tlb](https://github.com/ton-blockchain/ton/blob/master/crypto/block/block.tlb). + +## Message size + +:::info cell size +Note that any [Cell](/learn/overviews/Cells) may contain up to `1023` bits. If you need to store more data you should split it into chunks and store in reference cells. +::: + +If, for instance, your message body size is 900 bits long you can not to store it in the same cell with the message header. +Indeed, in addition to message header fields, total size of the cell will be more than 1023 bits and during serialization there will be `cell overflow` exception. In this case, instead of `0` that stands for "inplace message body flag (Either)" there should be `1` and message body should be stored in reference cell. + +Those things should be handled carefully due to the fact that some fields have variable size. + +For instance `MsgAddress` may be represented by 4 constructors `addr_none`, `addr_std`, `addr_extern`, `addr_var` with length from 2 bits ( for `addr_none`) to 586 bits (for `addr_var` in the largest form). The same stands for nanoTON amounts which is serialized as `VarUInteger 16`, that means 4 bits indicating the byte-length of the integer and then indicated earlier bytes for integer itself: that way 0 nanoTONs will be serialized as `0b0000` (4 bits which encode zero-length byte string and then zero bytes), while 100.000.000 TON (or 100000000000000000 nanoTONs) will be serialized as `0b10000000000101100011010001010111100001011101100010100000000000000000` (`0b1000` stands for 8 bytes and then 8 bytes themselves). diff --git a/versioned_docs/version-1.0.0/develop/smart-contracts/sdk/toncli.md b/versioned_docs/version-1.0.0/develop/smart-contracts/sdk/toncli.md new file mode 100644 index 0000000000..432d617fea --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/smart-contracts/sdk/toncli.md @@ -0,0 +1,34 @@ +# Using toncli + +_toncli — The Open Network cross-platform smart contract command line interface._ + +Easy to deploy and interact with TON smart contracts. + +Good solution for **Python** stack developers. + +* [GitHub repository](https://github.com/disintar/toncli) + +## Quick Start + +Here are tutorials written using toncli library: +* [Quick Start Guide](https://github.com/disintar/toncli/blob/master/docs/quick_start_guide.md) — simple steps how-to deploy example smart contract to TON. +* [TON Learn Guides: 10 zero-to-hero lessons](https://github.com/romanovichim/TonFunClessons_Eng) ([Ru version](https://github.com/romanovichim/TonFunClessons_ru)) + +## Installation + +Here is an [INSTALLATION](https://github.com/disintar/toncli/blob/master/INSTALLATION.md) tutorial in main repository. + +## Useful articles + +Other useful articles about using toncli in development: + +1. [All commands of cli](https://github.com/disintar/toncli/blob/master/docs/advanced/commands.md) +2. [Run get methods](https://github.com/disintar/toncli/blob/master/docs/advanced/get_methods.md) +3. [Multiple contracts](https://github.com/disintar/toncli/blob/master/docs/advanced/multiple_contracts.md) +4. [Send boc with fift](https://github.com/disintar/toncli/blob/master/docs/advanced/send_boc_with_fift.md) +5. [Project structure](https://github.com/disintar/toncli/blob/master/docs/advanced/project_structure.md) +6. [Interesting features](https://github.com/disintar/toncli/blob/master/docs/advanced/intresting_features.md) +7. [Send internal fift messages](https://github.com/disintar/toncli/blob/master/docs/advanced/send_fift_internal.md) +8. [How FunC test works?](https://github.com/disintar/toncli/blob/master/docs/advanced/func_tests_new.md) +9. [How to debug transactions with toncli?](https://github.com/disintar/toncli/blob/master/docs/advanced/transaction_debug.md) +10. [Dockerfile for FunC testing GitHub repository](https://github.com/Trinketer22/func_docker) \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/smart-contracts/sdk/tonstarter.md b/versioned_docs/version-1.0.0/develop/smart-contracts/sdk/tonstarter.md new file mode 100644 index 0000000000..5a2bfb0147 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/smart-contracts/sdk/tonstarter.md @@ -0,0 +1,49 @@ +# Using tonstarter-contracts + +## Overview + +A _tonstarter-contracts_ based on TypeScript, TON Contract Executor and mochajs. + +Good solution for **JavaScript** stack developers. + +* [GitHub repository](https://github.com/ton-defi-org/tonstarter-contracts) +* [Online IDE using Glitch](https://github.com/ton-defi-org/tonstarter-contracts) + +## Quick Start + +To start developing on your local machine just clone repository: + +```bash +git clone https://github.com/ton-defi-org/tonstarter-contracts +cd tonstarter-contracts +``` +or use pre-defined Online IDE provided before. + +After that feel free to go: +* [TON Hello World: Step by step guide for writing your first smart contract in FunC](https://society.ton.org/ton-hello-world-step-by-step-guide-for-writing-your-first-smart-contract-in-func) +* ... or continue to [Testing & Debugging](/develop/smart-contracts/testing/tonstarter) section to test example smart contract. + + +## What does SDK contain? + +Directory structure looks like: + +* `contracts/*.fc` - Smart contracts for TON blockchain written in [FunC](https://ton.org/docs/#/func) language +* `test/*.spec.ts` - Test suite for the contracts in TypeScript ([MochaJS](https://mochajs.org/) test runner) +* `build/_build.ts` - Build script to compile the FunC code to [Fift](https://ton-blockchain.github.io/docs/fiftbase.pdf) and [TVM](https://ton-blockchain.github.io/docs/tvm.pdf) opcodes +* `build/_deploy.ts` - Deploy script to deploy the compiled code to TON +* `build/_setup.ts` - Setup script to install build dependencies + +:::info +An optimal setup to develop fully tested contracts in the most seamless way possible. +::: + +## Principles + +* **Cross-platform support** - works on Mac M1, Mac Intel, Windows or Linux. +* **Strong belief in tests** - contracts often manage money - they must be developed under high scrutiny. +* **Clear and documented code** to help users audit the contracts sources and understand what they do. +* **Reliance on modern TypeScript** to develop clean and typed scripts and tests in a modern framework. +* **Reliance on TypeScript for deployment** instead of working with `fift` CLI tools - it's simply easier. +* **Tests are executed in JavaScript** with TVM in web-assembly - a great balance of speed and convenience. +* Following of the TON contract [best practices](/develop/smart-contracts/guidelines) appearing in the official docs. diff --git a/versioned_docs/version-1.0.0/develop/smart-contracts/testing/toncli.md b/versioned_docs/version-1.0.0/develop/smart-contracts/testing/toncli.md new file mode 100644 index 0000000000..6216b405cc --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/smart-contracts/testing/toncli.md @@ -0,0 +1,26 @@ +# Using toncli + +:::tip starter tip +If you didn't use toncli before, try [QUICK START GUIDE](https://github.com/disintar/toncli/blob/master/docs/quick_start_guide.md). +::: + +## Testing using toncli + +toncli uses FunC to test smart contracts. + +Right now the best tutorial describing testing using toncli is: +* [How FunC test works?](https://github.com/disintar/toncli/blob/master/docs/advanced/func_tests_new.md) +* [How to debug transactions with toncli?](https://github.com/disintar/toncli/blob/master/docs/advanced/transaction_debug.md) + +## Examples + +Here are repository with examples of FunC files used for test in one of the TON Contests: +* [ton-blockchain/func-contest2-solutions](https://github.com/ton-blockchain/func-contest2-solutions) + +## Testing using Docker + +Docker image should come in handy to run [toncli](https://github.com/disintar/toncli) with the [new tests support](https://github.com/disintar/toncli/blob/master/docs/advanced/func_tests_new.md). Setting it all up manually could be cumbersome otherwise. + +Built on Ubuntu 20.04 so should be WSL docker compatible. + +* [Dockerfile for FunC testing GitHub repository](https://github.com/Trinketer22/func_docker) \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/smart-contracts/testing/tonstarter.md b/versioned_docs/version-1.0.0/develop/smart-contracts/testing/tonstarter.md new file mode 100644 index 0000000000..c87c488dfa --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/smart-contracts/testing/tonstarter.md @@ -0,0 +1,86 @@ +# Using tonstarter-contracts + +A tonstarter-contracts project rely on _TON Contract Executor_ library. Tests are running inside Node.js by running TVM in web-assembly using _ton-contract-executor_. + +:::caution draft +This is a concept article. We're still looking for someone experienced to write it. +::: + +## Testing using TON Contract Executor + +This library allows you to run Ton Virtual Machine locally and execute contract. That allows you to write & debug & fully test your contracts before launching them to the network. + +TON Contract executor allows you to: + +* execute smart contracts from FunC source code +* execute smart contracts from existing data & code Cells +* get TVM executing logs +* debug your contracts via debug primitives +* it handles internal state changes of contract data +* allows calling of so-called GET methods of smart contracts +* allows sending & debugging internal messages +* allows sending & debugging external messages +* allows debugging of messages sent by smart contract +* handle changes in smart contract code +* allows manipulations with C7 register of smart contract (including time, random seed, network config, etc.) +* allows you to make some gas optimizations + +:::info +Basically you can **develop**, **debug**, and **fully cover your contract with unit-tests** fully locally without deploying it to the network. +::: + +#### Links + +* [GitHub repository](https://github.com/Naltox/ton-contract-executor) +* [npm.js](https://www.npmjs.com/package/ton-contract-executor) + +## Example + +:::tip +You can see examples even using [Online IDE](https://glitch.com/edit/#!/remix/clone-from-repo?&REPO_URL=https%3A%2F%2Fgithub.com%2Fton-defi-org%2Ftonstarter-contracts.git) with a pre-defined repository. +::: + +Feel free to check repository code to find how _counter smart contract_ testing works: +* [main.fc](https://github.com/ton-defi-org/tonstarter-contracts/blob/main/contracts/main.fc) — original smart contract code example. +* [counter.spec.ts](https://github.com/ton-defi-org/tonstarter-contracts/blob/main/test/counter.spec.ts) — test that cover counter methods. + +### Simple counter + +To start and experiment just copy repository from GitHub: +```bash +git clone https://github.com/ton-defi-org/tonstarter-contracts +cd tonstarter-contracts +``` + +#### Build project + +Let us build a simple counter smart contract from boilerplate project: + +```bash +npm run build +``` + +#### Local tests + +After that to see how tests work just write in tonstarter-contracts and read the console: + +```bash +npm run test +``` + +You'll see in console result of basic tests checks. + +#### Deploying contract + +In case you want test smart contract in mainnet or testnet use commands and read console: + +```bash +npm run deploy # mainnet +npm run deploy:testnet # testnet +``` + +:::tip +Read console carefully, it has useful information about wallet, contract, faucet etc. +::: + +Right now you have a battle-tested counter smart contract in TON blockchain! Yahoo! \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/tools/README.md b/versioned_docs/version-1.0.0/develop/tools/README.md new file mode 100644 index 0000000000..f059c0ffed --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/tools/README.md @@ -0,0 +1,57 @@ +# Overview + +## Prerequisites + +Here you can links to the most important resources for you to get started with TON: + +- [Wallets](https://ton.org/wallets) — a list of popular wallets for TON. +- [Explorers](https://ton.app/explorers) — to read transactions in the blockchain. +- [IDE plugins](/develop/tools/ide-plugins) — for comfort development. +- [Testnet](/develop/tools/testnet/) — testnet and how to use it. + +### SDK + +Here is a list of modern SDKs that continuously supported and improved: + +* [tonweb](https://github.com/toncenter/tonweb) — JavaScript API for TON blockchain. +* [ton-js](https://github.com/tonwhales/ton) — Cross-platform client for TON blockchain. +* [tonutils-go](https://github.com/xssnick/tonutils-go) — Go utils for TON blockchain. +* [ton-kotlin](https://github.com/andreypfau/ton-kotlin) — Kotlin SDK for TON blockchain. +* [psylopunk/pytonlib](https://github.com/psylopunk/pytonlib) — Python SDK. +* [toncenter/pytonlib](https://github.com/toncenter/pytonlib) — Python SDK. + +### Authentication + +In case you want to add login to your website using wallet exists these approaches: + +* [TON Connect](https://github.com/tonkeeper/ton-connect/blob/main/TonConnectSpecification.md) by Tonkeeper +* [Tonhub Extensions](https://developers.tonhub.com/docs/apps) by Tonhub + + +### TonLib + +TonLib was a one of the first libraries for working with TON blockchain. + + +* [C++ TonLib](https://github.com/ton-blockchain/ton/tree/master/example/cpp) +* [Python TonLib wrapper](https://github.com/toncenter/pytonlib) +* [Golang TonLib wrapper](https://github.com/ton-blockchain/tonlib-go) +* [Java TonLib wrapper (JNI)](https://github.com/ton-blockchain/tonlib-java) + +#### Usage examples + +* [Desktop standard wallet (C++ and Qt)](https://github.com/newton-blockchain/wallet-desktop) +* [Android standard wallet (Java)](https://github.com/trm-dev/wallet-android) +* [iOS standard wallet (Swift)](https://github.com/trm-dev/wallet-ios) +* [TonLib CLI (C++)](https://github.com/ton-blockchain/ton/blob/master/tonlib/tonlib/tonlib-cli.cpp) + + + +## APIs + +* [TonCenter](https://toncenter.com/) — Fast and reliable HTTP API for The Open Network +* [TonApi.io](https://tonapi.io/) — API that allows to work with indexed blockchain information. + +### End-points + +* [GetBlock Nodes](https://getblock.io/nodes/ton/) — connect and test your dApp to TON using GetBlocks Nodes. diff --git a/versioned_docs/version-1.0.0/develop/tools/apis/README.md b/versioned_docs/version-1.0.0/develop/tools/apis/README.md new file mode 100644 index 0000000000..27ee890d8d --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/tools/apis/README.md @@ -0,0 +1,67 @@ +# APIs + + +At the moment, two API options are available to interact with TON: + +## 1. HTTP API + +Standard HTTP JSON RPC similar to many blockchains. + +Clients connect to the [ton-http-api](https://github.com/toncenter/ton-http-api) server that proxies requests to the lite server (node) using TonLib. + +You can connect to public [toncenter.com](https://toncenter.com) or run your own http-api instance. + +👍 - Habitual. Suitable for a quick start. +👎 - Like in most blockchains, you cannot fully trust server responses, because its responses do not contain proofs. + +### API reference + +[https://toncenter.com/api/v2/](https://toncenter.com/api/v2/) + +#### SDK + +- [JavaScript TonWeb](https://github.com/toncenter/tonweb) + +#### Usage examples: + +- [Standard web wallet](https://github.com/toncenter/ton-wallet) (Plain JS) +- [Bridge frontend](https://github.com/ton-blockchain/bridge) (Vue.js) + +## 2. TON API + + Clients connect directly to lite servers (nodes) using a binary protocol. + + The client downloads keyblocks, the current state of the account and their **Merkle proofs**, which guarantees validity of the received data. + + Read operations (like get-method calls) are made by launching a local TVM with a downloaded and verified state. + + There is no need to download the full state of blockchain, the client only downloads what is needed for the operation. Calling local TVM is also lightweight. + + You can connect to public lite servers from the global config ([mainnet](https://ton.org/global-config.json) or [testnet](https://ton-blockchain.github.io/testnet-global.config.json)) or run your own lite server. + + Since it checks Merkle proofs, you can even use untrusted lite servers. + + Read more about Merkle proofs at [TON Whitepaper](https://ton-blockchain.github.io/ton.pdf) 2.3.10, 2.3.11. + +👍 - Ultra secure API with Merkle proofs. +👎 - Need more time to figure it out. Not compatible with web frontends (non-HTTP protocol). + +### API reference + + Requests and responses to the server are described by a TL schema that allows you to generate a typed interface for a specific programming language. + + [TonLib TL Schema](https://github.com/ton-blockchain/ton/blob/master/tl/generate/scheme/tonlib_api.tl) + +#### SDK: + + - [C++ TonLib](https://github.com/ton-blockchain/ton/tree/master/example/cpp) + - [Python TonLib wrapper](https://github.com/toncenter/pytonlib) + - [Golang TonLib wrapper](https://github.com/ton-blockchain/tonlib-go) + - [Java TonLib wrapper (JNI)](https://github.com/ton-blockchain/tonlib-java) + +#### Usage example: + + - [Desktop standard wallet](https://github.com/newton-blockchain/wallet-desktop) (C++ and Qt) + - [Android standard wallet](https://github.com/trm-dev/wallet-android) (Java) + - [iOS standard wallet](https://github.com/trm-dev/wallet-ios) (Swift) + - [TonLib CLI](https://github.com/ton-blockchain/ton/blob/master/tonlib/tonlib/tonlib-cli.cpp) (C++) diff --git a/versioned_docs/version-1.0.0/develop/tools/ide-plugins.md b/versioned_docs/version-1.0.0/develop/tools/ide-plugins.md new file mode 100644 index 0000000000..af4ac2a5e1 --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/tools/ide-plugins.md @@ -0,0 +1,27 @@ +# IDE plugins + +## VS Code plugin + +Visual Studio Code is a free and popular IDE for developers. + +- [Marketplace link](https://marketplace.visualstudio.com/items?itemName=tonwhales.func-vscode) +- [GitHub repository](https://github.com/ton-foundation/vscode-func) + +## IntelliJ IDEs Plugin + +:::info +Could be used for any of JetBrains products. +::: + +You can install plugin by these ways: +- Find plugin directly in IDE plugins section with "**TON Development**" keywords +- [Marketplace link](https://plugins.jetbrains.com/plugin/18541-ton-development) +- [GitHub repository](https://github.com/ton-blockchain/intellij-ton) + +## FunC Sublime Text plugin + +- [GitHub repository](https://github.com/savva425/func_plugin_sublimetext3) + +## neovim plugin + +- [GitHub repository](https://github.com/cryshado/neovim-ton-dev) \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/tools/testnet/README.md b/versioned_docs/version-1.0.0/develop/tools/testnet/README.md new file mode 100644 index 0000000000..b2d3199ddd --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/tools/testnet/README.md @@ -0,0 +1,25 @@ +# Testnet + +Use TON test network for development and testing purpose. + +:::info +Coins in test network have no value, the test network can be reset. +::: + +* Testnet global config: https://ton-blockchain.github.io/testnet-global.config.json +* You can get free test coins in https://t.me/testgiver_ton_bot + +## Services + +For convenience, almost the entire infrastructure of the mainnet (wallets, API, bridges, etc.) has been recreated in the test network. + +* Explorer: https://testnet.tonscan.org +* Web Wallet: https://wallet.ton.org?testnet=true +* Browser Extension: use [mainnet browser extension](https://chrome.google.com/webstore/detail/ton-wallet/nphplpgoakhhjchkkhmiggakijnkhfnd) and [do this](https://github.com/toncenter/ton-wallet#switch-between-mainnettestnet-in-extension). +* Testnet HTTP API: https://testnet.toncenter.com +* Testnet bridge: https://ton.org/bridge?testnet=true + +## Some third parties + +* To switch to testnet in [Tonkeeper](https://tonkeeper.com/) tap the version in settings 5 times. +* Testnet CryptoBot: https://t.me/CryptoTestnetBot \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/develop/web3/dns.md b/versioned_docs/version-1.0.0/develop/web3/dns.md new file mode 100644 index 0000000000..5df5cde17e --- /dev/null +++ b/versioned_docs/version-1.0.0/develop/web3/dns.md @@ -0,0 +1,45 @@ +# TON DNS + +TON DNS is a service for translating human-readable domain names (such as `test.ton` or `mysite.temp.ton`) into TON smart contract addresses, ADNL addresses employed by services running in the TON Network (such as TON Sites), and so on. + +## Standard + +[TON DNS Standard](https://github.com/ton-blockchain/TIPs/issues/81) describes the format of domain names, the process of resolving a domain, the interface of DNS smart contracts and the format of DNS records. + +## SDK + +Working with TON DNS is implemented in JavaScript SDK [TonWeb](https://github.com/toncenter/tonweb) and [TonLib](https://ton.org/#/apis/?id=_2-ton-api). + +```js +const address: Address = await tonweb.dns.getWalletAddress('test.ton'); + +// or + +const address: Address = await tonweb.dns.resolve('test.ton', TonWeb.dns.DNS_CATEGORY_WALLET); +``` + +Also `lite-client` and `tonlib-cli` is supported DNS queries. + +## First-level domain + +Currently, only domains ending in `.ton` are recognized as valid TON DNS domains. + +Root DNS smart contract source code - https://github.com/ton-blockchain/dns-contract/blob/main/func/root-dns.fc. + +This could change in the future. Adding a new first-level domain will require new root smart contract and general vote to change the [network config #4](https://ton.org/#/smart-contracts/governance?id=config). + +## *.ton domains + +*.ton domains implemented in the form of NFT. Since they implement the NFT standard, they are compatible with regular NFT services (e.g. NFT marketplaces) and wallets that can display NFT. + +*.ton domains source code - https://github.com/ton-blockchain/dns-contract. + +.ton domains resolver implements NFT collection interface and .ton domain implements NFT item interface. + +Primary sale of *.ton domains is available at a decentralized open auction https://dns.ton.org. Source code - https://github.com/ton-blockchain/dns. + +## Subdomains + +The domain owner can make subdomains by setting the address of the smart contract responsible for resolving subdomains in the DNS record `sha256("dns_next_resolver")`. + +It can be any smart contract that implements the DNS standard. diff --git a/versioned_docs/version-1.0.0/learn/docs.md b/versioned_docs/version-1.0.0/learn/docs.md new file mode 100644 index 0000000000..02a1c0f5e2 --- /dev/null +++ b/versioned_docs/version-1.0.0/learn/docs.md @@ -0,0 +1,23 @@ +# Whitepapers + +This section presents the original documentation written by Dr. Nikolai Durov, which describes in full all the parts of the TON. + +:::info +Please note here and further that the code, comments and/or documentation may contain parameters, methods and definitions “gram”, “nanogram”, etc. That is a legacy of the original TON code, developed by the Telegram. Gram cryptocurrency was never issued. The currency of TON is Toncoin and the currency of TON testnet is Test Toncoin. +::: + +* [TON](https://ton-blockchain.github.io/ton.pdf) + + TON Whitepaper – a general description of TON Network and TON Blockchain. + +* [TON Virtual Machine](https://ton-blockchain.github.io/tvm.pdf) + + TON Virtual Machine description. + +* [TON Blockchain](https://ton-blockchain.github.io/tblkch.pdf) + + TON Blockchain description (may include outdated information). + +* [Catchain Consensus Protocol](https://ton-blockchain.github.io/catchain.pdf) + + Description of Byzantine Fault Tolerant (BFT) Consensus protocol employed by TON Blockchain while creating new blocks. diff --git a/versioned_docs/version-1.0.0/learn/introduction.md b/versioned_docs/version-1.0.0/learn/introduction.md new file mode 100644 index 0000000000..02d60241b3 --- /dev/null +++ b/versioned_docs/version-1.0.0/learn/introduction.md @@ -0,0 +1,31 @@ +# Introduction + + +:::info new to blockchain? +If you're completely new to blockchain technology and want to understand the ideas and why it's so important — it's easier to start with these materials: + +* [How a Blockchain Can Help You on a Deserted Island](https://talkol.medium.com/why-decentralized-consensus-blockchain-is-good-for-business-5ff263468210) +* [How to Run a Blockchain on a Deserted Island with Pen and Paper](https://talkol.medium.com/how-to-run-a-blockchain-on-a-deserted-island-with-pen-and-paper-899949ec555b) +* [\[YouTube\] Crypto Networks and Why They Matter](https://youtu.be/2wxtiNgXBaU) +::: + + +## What is TON? + +The _The Open Network (TON)_ is a fast, secure and scalable blockchain and +network project, focused on handling _millions of transactions per second_ if +necessary, and both user-friendly and service provider-friendly platform. + +One might think about TON as a huge distributed supercomputer, +or rather a huge "_superserver_", intended to host and provide a variety of +services. + +Next concept to read: [Blockchain of Blockchains](/learn/overviews/TON_blockchain_overview). + +## Ethereum to TON + + +Especially for Ethereum developers, our community made a small introduction article that could help you understand more about TON: + +* [SIX unique aspects of TON Blockchain that will surprise Solidity developers](https://society.ton.org/six-unique-aspects-of-ton-blockchain-that-will-surprise-solidity-developers) +* [It’s time to try something new: Asynchronous smart contracts](https://telegra.ph/Its-time-to-try-something-new-Asynchronous-smart-contracts-03-25) \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/learn/old/catchain.pdf b/versioned_docs/version-1.0.0/learn/old/catchain.pdf new file mode 100644 index 0000000000..2ad154c096 Binary files /dev/null and b/versioned_docs/version-1.0.0/learn/old/catchain.pdf differ diff --git a/versioned_docs/version-1.0.0/learn/old/fiftbase.pdf b/versioned_docs/version-1.0.0/learn/old/fiftbase.pdf new file mode 100644 index 0000000000..1108ade38a Binary files /dev/null and b/versioned_docs/version-1.0.0/learn/old/fiftbase.pdf differ diff --git a/versioned_docs/version-1.0.0/learn/old/tblkch.pdf b/versioned_docs/version-1.0.0/learn/old/tblkch.pdf new file mode 100644 index 0000000000..2e7748cef0 Binary files /dev/null and b/versioned_docs/version-1.0.0/learn/old/tblkch.pdf differ diff --git a/versioned_docs/version-1.0.0/learn/old/ton.pdf b/versioned_docs/version-1.0.0/learn/old/ton.pdf new file mode 100644 index 0000000000..b329407834 Binary files /dev/null and b/versioned_docs/version-1.0.0/learn/old/ton.pdf differ diff --git a/versioned_docs/version-1.0.0/learn/old/tvm.pdf b/versioned_docs/version-1.0.0/learn/old/tvm.pdf new file mode 100644 index 0000000000..6609f7f57a Binary files /dev/null and b/versioned_docs/version-1.0.0/learn/old/tvm.pdf differ diff --git a/versioned_docs/version-1.0.0/learn/overviews/ADNL.md b/versioned_docs/version-1.0.0/learn/overviews/ADNL.md new file mode 100644 index 0000000000..e0706f4954 --- /dev/null +++ b/versioned_docs/version-1.0.0/learn/overviews/ADNL.md @@ -0,0 +1,94 @@ +# ADNL Protocol + +Abstract Datagram Network Layer (ADNL) is the core protocol of TON, which helps network peers to communicate with each other. + +## Peer identity +Each peer must have at least one identity, but it's not restricted to use multiple. Each identity is a keypair, which is used to perform Diffie-Hellman between peers. Abstract network address is derived from public key in such way: `address = SHA-256(type_id || public_key)`. Note that type_id must be serialized as little-endian uint32. + +## Public-key cryptosystems list +| type_id | cryptosystem | +|------------|---------------------| +| 0x4813b4c6 | ed255191 | + +_1. To perform x25519, keypair must be generated in x25519 format. However, public key is transmitted over the network in ed25519 format, so you have to convert public key from x25519 to ed25519, example of such conversion can be found [here](https://github.com/tonstack/adnl-rs/blob/master/src/integrations/dalek.rs#L10) for Rust and [here](https://github.com/andreypfau/curve25519-kotlin/blob/f008dbc2c0ebc3ed6ca5d3251ffb7cf48edc91e2/src/commonMain/kotlin/curve25519/MontgomeryPoint.kt#L39) for Kotlin._ + +## Client-server protocol (ADNL over TCP) +Client connects to server using TCP and sends ADNL handshake packet, which contains server abstract address, client public key, and encrypted AES-CTR session parameters, which is determined by the client. + +### Handshake +First, client must perform key agreement protocol (for example, x25519) using their private key and server public key, taking into account the `type_id` of server key. In the result, client have `secret`, which is used to encrypt session keys in the next steps. + +Then, client have to generate AES-CTR session parameters, 16-byte nonce and 32-byte key, both for TX (client->server) and RX (server->client) directions and serialize it into 160-byte buffer as follows: + +| Parameter | Size | +|--------------|----------| +| rx_key | 32 bytes | +| tx_key | 32 bytes | +| rx_nonce | 16 bytes | +| tx_nonce | 16 bytes | +| padding | 64 bytes | + +The purpose of padding is unknown, it is not used by server implementations. It is recommended to fill whole 160-byte buffer with random bytes, otherwise an attacker may perform active MitM attack using compromised AES-CTR session parameters. + +The next step is to encrypt session parameters using `secret` computed by key agreement protocol above. To do that, an instance of AES-256 in mode CTR with 128-bit big endian counter must be initialized using pair of (key, nonce) which is computed in such way (`aes_params` is a 160-byte buffer which was built above): +```cpp +hash = SHA-256(aes_params) +key = secret[0..16] || hash[16..32] +nonce = hash[0..4] || secret[20..32] +``` +After encryption of `aes_params` which is noted as `E(aes_params)`, instance of AES should be disposed, as it is not needed anymore. + +Now we are ready to serialize all that information to the 256-bytes handshake packet and send it to server: + +| Parameter | Size | Notes | +|---------------------|-----------|------------------------------------------------------------| +| receiver_address | 32 bytes | Server peer identity as described in corresponding section | +| sender_public | 32 bytes | Client public key | +| SHA-256(aes_params) | 32 bytes | Integrity proof of session parameters | +| E(aes_params) | 160 bytes | Encrypted session parameters | + +Server must decrypt session parameters using a secret, derived from the key agreement protocol in the same way as client. Then server must perform following checks to ensure security properties of the protocol: +1. Server must have corresponding private key for `receiver_address`, otherwise there is no way to perform the key agreement protocol. +2. `SHA-256(aes_params) == SHA-256(D(E(aes_params)))`, otherwise the key agreement protocol has failed and `secret` is not equal on both sides. + +If any of this checks has failed, server must immediately drop the connection without any response to the client. If all checks pass, server must issue an empty datagram (see Datagram section) to client to prove that it owns the private key for the specified `receiver_address`. + + +### Datagram + +Both client and server must initialize two AES-CTR instances each, for TX and RX directions. AES-256 must be used in mode CTR with 128-bit big endian counter. Each AES instance is initialized using pair of (key, nonce) belonging to it, which can be taken from `aes_params` in handshake. + +To send a datagram, peer (client or server) must build the following structure, encrypt it, and send to the other peer: + +| Parameter | Size | Notes | +|-----------|----------------------|------------------------------------------------------------| +| length | 4 bytes (LE) | Length of the whole datagram, excluding `length` field | +| nonce | 32 bytes | Random value | +| buffer | `length - 64` bytes | Actual data to be sent to the other side | +| hash | 32 bytes | `SHA-256(nonce \|\| buffer)` to ensure integrity | + +The whole structure must be encrypted by the corresponding AES instance (TX for client -> server, RX for server -> client). + +The receiving peer must fetch the first 4 bytes, decrypt it into `length` field and read exactly `length` bytes to get the full datagram. The receiving peer may start to decrypt and process `buffer` earlier, but it must take into account that it may be corrupted, intentionally or occasionally. Datagram `hash` must be checked to ensure integrity of the `buffer`. In case of failure, no new datagrams can be issued and the connection must be dropped. + +The first datagram in session always goes from server to client after handshake packet was successfully accepted by server, and it's actual buffer is empty. Client should decrypt it and disconnect from server in case of failure, because it means that the server not follows the protocol properly and actual session keys differs on server and client side. + +### Security considerations +#### Handshake padding +It is unknown why initial TON team decided to include this field into handshake. `aes_params` integrity is protected by SHA-256 hash and confidentiality is protected by the key derived from `secret` parameter. Probably, it was designed to migrate from AES-CTR at some moment. To do this, specification may be extended to include special magic value in `aes_params`, which will signalize that the peer is ready to use the updated primitives. The response to such handshake may be decrypted twice, with new and old schemes, to clarify which scheme other peer is actually using. + +#### Session parameters encryption key derivation process +If encryption key derives only from `secret` parameter, it become static, because the secret is static. To derive new encryption key for each session, developers also took `SHA-256(aes_params)`, which is random if `aes_params` is random. However, the actual key derivation algorithm with concatenation of different subarrays is considered harmful. + +#### Datagram nonce +It is not obvious why `nonce` field in datagram is present, because even without it any two ciphertexts will differ, because of session-bounded keys for AES and encryption in CTR mode. However, the following attack can be performed in case of absent or predictable nonce. CTR encryption mode turns block ciphers such as AES into stream ciphers, so it is possible to perform bit-flipping attack. If attacker knows the plaintext which belongs to encrypted datagram, they can obtain pure keystream and than XOR it with their own plaintext, efficiently replace the message which was sent by peer. The buffer integrity is protected by SHA-256 hash, but an attacker can replace it too, because knowledge of full plaintext means knowledge of its hash. To prevent such attack, nonce field is present, so attacker can't replace SHA-256 without the knowledge of nonce. + +## P2P protocol (ADNL over UDP) +TBD + +## References +- [The Open Network, p. 80](https://ton-blockchain.github.io/ton.pdf) +- [ADNL implementation in TON](https://github.com/ton-blockchain/ton/tree/master/adnl) + +_Thanks to the [hacker-volodya](https://github.com/hacker-volodya) for contributing to the community!_ +_Here a [link to the original article](https://github.com/tonstack/ton-docs/tree/main/ADNL) on GitHub._ \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/learn/overviews/Cells.md b/versioned_docs/version-1.0.0/learn/overviews/Cells.md new file mode 100644 index 0000000000..6621b5ff49 --- /dev/null +++ b/versioned_docs/version-1.0.0/learn/overviews/Cells.md @@ -0,0 +1,48 @@ +# Cells + +Everything in TON is stored in cells. Cell is a data structure containing: + +- up to **1023 bits** of data (not bytes!) +- up to **4 references** to other cells + +Bits and references are not intermixed (stored separately). Circular references are forbidden: for any cell none of its descendant cell can have this cell as reference. + +Thus, all cells constitute a directed acyclic graph (DAG). A good picture of it: + +![Directed Acylic Graph](/img/docs/dag.png) + +## Cell types + +Currently, there are 5 types of cells: _ordinary_ and 4 _exotic_. +Exotic types are the following: +* Pruned branch cell +* Library reference cell +* Merkle proof cell +* Merkle update cell + +:::tip +More on exotic cells: [**TVM Whitepaper, section 3**](https://ton.org/tvm.pdf). +::: + +## Cell flavors + +Cell is an opaque object optimized for compact storage. + +In particular, it deduplicates data: if there are several eqivalent sub-cells referenced in different branches, their content is only stored once. However, opaqueness means that a cell can not be modified or read directly. Thus, there are 2 additional flavors of the cells: +* _Builder_ for partially constructed cells, for which fast operations for appending bitstrings, integers, other cells, and references to other cells can be defined. +* _Slice_ for 'dissected' cells representing either the remainder of a partially parsed cell, or a value (subcell) residing inside such a cell and extracted from it by a parsing instruction. + +Another special cell flavor is used in TVM: + +* _Continuation_ for cells containing op-codes (instructions) for Ton Virtual Machine, see [TVM Bird's-eye overview](/learn/tvm-instructions/tvm_overview). + +## Serialization of data to cells + +Any object in TON (message, message queue, block, whole blockchain state, contract code and data) serializes to a cell. + +The process of serialization is described by TL-B scheme: a formal description of how this object can be serialized to Builder or how to parse object of given type from the Slice. +TL-B for cells is the same as TL or ProtoBuf for byte-streams. + +:::tip TL-B +Navigate to the [TL-B](/learn/overviews/TL-B) section for more info. +::: \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/learn/overviews/TL-B.md b/versioned_docs/version-1.0.0/learn/overviews/TL-B.md new file mode 100644 index 0000000000..b8651e52e8 --- /dev/null +++ b/versioned_docs/version-1.0.0/learn/overviews/TL-B.md @@ -0,0 +1,145 @@ +# TL-B Overview + +:::caution advanced level +This information is **very low level** and could be hard to understand for newcomers. +So feel free to read about it later. +::: + +TL-B stands for "Typed Language - Binary". It is used to describe scheme of (de)serialization of objects to [Cells](/learn/overviews/Cells.md). There are detailed and complete TL-B schemes for all objects in TON: https://github.com/ton-blockchain/ton/blob/master/crypto/block/block.tlb. + +## Scheme + +Each TL-B scheme consists of declarations. Each declaration describes _constructor_ for some _type_. For instance _type_ Bool may have two _constructors_ for `true` and `false` values. + +Typical TL-B declarations are shown below: +```cpp +bool_false$0 = Bool; +bool_true$1 = Bool; + +unary_zero$0 = Unary ~0; +unary_succ$1 {n:#} x:(Unary ~n) = Unary ~(n + 1); + +acc_trans#5 account_addr:bits256 + transactions:(HashmapAug 64 ^Transaction CurrencyCollection) + state_update:^(HASH_UPDATE Account) + = AccountBlock; +``` + + +Each TL-B declaration consist of: +* Constructor: _constructor name_ immediately followed by an optional _constructor tag_ +* list of explicit and implicit field definitions are separated by whitespaces (`" "`, `"\n"`, etc) +* sign `=` +* (optionally parametrized) _Type name_ + +Example: two constructors (with different binary prefixes) for `Bool` type. +```cpp +bool_false$0 = Bool; +bool_true$1 = Bool; +``` + +### Constructor +Constructor is declared via a `constructor_name[separator,tag]`. + +A `constructor_name` consists of `[A-z0-9_]` symbols. snake_case names are conventionally used. + +A constructor name can be followed by a `separator`. Absence of `separator` means that `tag` will be calculated automatically as 32bit `crc32`-sum of constructor declarations. If `separator` is present, it can take two values `#` and `$`. The former means that a `tag` will be given in a hexadecimal form, the latter means a binary `tag`. +After both separators, an undercore symbol `_` may come standing for an empty tag. + + +There is also a special constructor_name `_` (called anonymous constructor) that means that there is only one unnamed constructor with empty tag for a given type. + +The table below displays possible tag definitions. + +| Constructor | tag | +| ----------- | ----------- | +| `_` | empty tag for anonymous constructor | +| `some` | automatically calculated 32-bit tag | +| `some#bba` | 12-bit tag equal to `0b101110111010` | +| `some$01011` | 5-bit tag equal to `0b01011` | +| `some#_` | empty tag | +| `some$_` | empty tag | + +Note that pregenerated tages are not usually used; explicitly declared are preferred. +### Field definitions +#### Explicit +Each field definition has the _ident : type-expr_, where _ident_ is an identifier with the name of the field (replaced by an underscore `_` for anonymous fields), and _type-expr_ is the field type. The type provided here is a type expression, which may include simple types or parametrized types with suitable parameters. Variables — i.e., the (identifiers of the) previously defined fields of types `#` (natural numbers) or `Type` (type of types) — may be used as parameters for the parametrized types. + +There is a few predefined _types_: +* `#` - means unsigned 32-bit number +* `## N` - the same as `uintN` - means unsigned N-bit number +* `#<= N` - means a number between `0` and `N` (including both). Such number is stored in `ceil(log2(N+1))` bits. +* `N * Bit` - means N-bit slice +* `^Cell` - means arbitrary cell in reference +* `^[ field_definitions ]` - means that field definitions are stored in referenced cell +* `Type` - stands for arbitrary type (but only presents in implicit definitions). + +_type-expr_ usually consist of (optionally parametrized) _Type_ only like: `last_trans_lt:uint64` or `_:StateInit`. However it is possilbe that _type-expr_ also contains conditions. In that case _type-expr_ consist of _ident_, `:`, _condition_, `?`, _type_. If condition (which can refer to previously defined fields) renders to `false` corresponding field is not presented. For instance `prev:n?^(ProofChain n)` means that `prev` field is only presented for objects when `n>0`. + +#### Implicit +Some fields may be implicit. Their definitions are surrounded by curly braces, which indicate that the field is not actually present in the serialization, but that its value must be deduced from other data (usually the parameters of the type being serialized). +For instance +```cpp +nothing$0 {X:Type} = Maybe X; +just$1 {X:Type} value:X = Maybe X; +``` + +means the following: some other constructor may define field `var:(Maybe #)`. In that case, variable will be serialized either as `1` bit and serialization of `#` (uint32) if `var` is presents, or as `0` bit if `var` absents. That way `Maybe` is declared as C++-like _template_ type for arbitrary type X. However if `Maybe` would be declared as `nothing$0 {X:#} = Maybe X;`, that will mean that `Maybe` is declared for arbitrary number (not totally arbitrary type X). + +### Type definition +Type name consist of `[A-z0-9_]` symbols. By convention it is CamelCase name. + +It can be parametrized by one or more parameters. + +Some occurrences of “variables” are prefixed by a tilde(`~`). That means that prior to deserialization the exact value of that variable is not known, but instead will be computed during deserialization. + +Lets consider +```cpp +unary_zero$0 = Unary ~0; +unary_succ$1 {n:#} x:(Unary ~n) = Unary ~(n + 1); +``` + +and the case when we want to deserialize `Unary ~N` object from the slice containing `0b1111111100101` bit string. When we say that we want to deserialize `Unary ~N` that means that we do not know yet whether we deserialize `Unary 0`, `Unary 7` or `Unary 1020`. Instead we start with `0b1111111100101` and compare it with constructor prefixes `0b0` for `unary_zero` and `0b1` for `unary_succ`. We see that we have `unary_succ`, but again the value of `N` can not be deducted, instead we should obtain it from deserialization of variable `x`. This variable has type `Unary ~(N-1)` and value of `N-1` can be deducted from deserialization of the rest bits in slice. +We get the rest bits of the slice and try to deserialize `Unary ~(N-1)` and again see `unary_succ` tag. That way we recursively dive into `Unary` until we get to the `Unary ~(N-8)`. At that level we see that rest of the slice starts from `unary_zero` tag and thus constitute `Unary 0` object. Popping back up we can get that initially we had `Unary 8` object. +So after deserialization of `Unary ~N` from Slice(`0b1111111100101`) we get `Unary 8` object and the rest Slice(`0b0101`) from which subsequent variables of the constructor can be deserialized. + +### Constraints +Some implicit fields may contain constraints, for instance `{n <= m}`. It means that previously defined variables n and m should satisfy corresponding the inequality. This inequality is inherent property of the constructor. It should be checked during serialization, besides objects with variables which not satisfy constraints are invalid. + +Example of constructors with constraints: +```cpp +hml_short$0 {m:#} {n:#} len:(Unary ~n) {n <= m} s:(n * Bit) = HmLabel ~n m; +hml_long$10 {m:#} n:(#<= m) s:(n * Bit) = HmLabel ~n m; +hml_same$11 {m:#} v:Bit n:(#<= m) = HmLabel ~n m; +``` + +## Comments +TL-B schemas support C-like comments: +```cpp +/* +This is a +multiline +comment +*/ + +// This is one line comment +``` + + +## (De)serialization +Given the TL-B scheme any object can be serialized to builder and deserialized from slice. +In particular, when we deserialize object we need to start with determination of corresponding constructor by tag and then deserialize variables one by one from left to right (recursively jumping to serialization of variable which are TL-B objects themselves). +During serialization we going the other way, by finding and writing to the builder `tag` which corresponds to given object of the type and then continue from left to write with each variable. + +For parsers, It is recommended to read scheme once and generate serializator and deserializator for each type, instead of referring to the scheme on the fly. + +## BNF Grammar + +**Backus–Naur form** can be found in [TlbParser.bnf](https://github.com/andreypfau/intellij-ton/blob/main/src/main/grammars/TlbParser.bnf), thanks to [@andreypfau](https://github.com/andreypfau). + +TL-B is also supported by [intellij-ton plugin](https://github.com/andreypfau/intellij-ton). + +Docs on TL-B can be found in [TVM whitepaper](https://ton.org/tvm.pdf) and in concise (collected in one place) form [here](https://github.com/tonstack/TL-B-docs). +## Generator of serializators and deserializators +Example of generator, used by TON node itself can be found in [Ton node sources](https://github.com/ton-blockchain/ton/blob/master/crypto/tl/tlbc.cpp). + diff --git a/versioned_docs/version-1.0.0/learn/overviews/TL-B_language.mdx b/versioned_docs/version-1.0.0/learn/overviews/TL-B_language.mdx new file mode 100644 index 0000000000..6c61f87e76 --- /dev/null +++ b/versioned_docs/version-1.0.0/learn/overviews/TL-B_language.mdx @@ -0,0 +1,213 @@ +# TL-B Language + +:::caution advanced level +This information is **very low level** and could be hard to understand for newcomers. +So feel free to read about it later. +::: + +TL-B (Type Language - Binary) serves to describe the type system, constructors, and existing functions. For example we can use TL-B schemes to build binary structures associated with the TON blockchain. Special TL-B parsers can read schemes to deserialize binary data into different objects. + +## Overview + +We refer to any set of TL-B constructs as TL-B documents. A TL-B document usually consists of declarations of types (i.e. their constructors) and functional combinators. The declaration of each combinator ends with a semicolon(`;`). + +Here is an example of a possible TL-B document. +tlb structure + +## Constructors + +Constructors are used to specify the type of combinator, including the state at serialization. For example constructors can also be used when you want to specify an `op` in query to a smart contract in the TON. + +```cpp +// .... +hm_edge#_ {n:#} {X:Type} {l:#} {m:#} label:(HmLabel ~l n) +{n = (~m) + l} node:(HashmapNode m X) = Hashmap n X; + +hmn_leaf#_ {X:Type} value:X = HashmapNode 0 X; +// .... +``` + +The left-hand side of each equation describes a way to define, or even to serialize, a value of the type indicated in the right-hand side. Such a description begins with the name of a constructor, such as `hm_edge` or `hml_long`, immediately followed by an optional constructor tag, such as `#_` or `$10`, which describes the bitstring used to encode (serialize) the constructor in question. + +learn by examples! + +| constructor | serialization | +|-----------------------|-------------------------------------------| +| `some#0x3f5476ca` | 32-bit uint serialize from hex value | +| `some$0101` | serialize `0101` raw bits | +| `some` | serialize `crc32(equation) \| 0x80000000` | +| `some#_` or `some$_` | serialize nothing | +| `some#` or `some$` | TL-B parsers will get it wrong | + + +Tags may be given in either binary (after a dollar sign) or hexadecimal notation (after a hash sign). If a tag is not explicitly provided, TL-B parser must computes a default 32-bit constructor tag by hashing with crc32 algorithm the text of the “equation” with `| 0x80000000` defining this constructor in a certain fashion. Therefore, empty tags must be explicitly provided by `#_` or `$_`. + +All constructor names must be distinct, and constructor tags for the same type must constitute a prefix code (otherwise the deserialization would not be unique); i.e. no tag can be a prefix of any other. + +This is an example from the [TonToken](https://github.com/akifoq/TonToken/blob/master/func/token/scheme.tlb) repository that shows +us how to implement an internal message TL-B scheme: + +```cpp +extra#_ amount:Grams = Extra; + +addr_std$10 anycast:(## 1) {anycast = 0} + workchain_id:int8 address:bits256 = MsgAddrSmpl; + +transfer#4034a3c0 query_id:uint64 + reciever:MsgAddrSmpl amount:Extra body:Any = Request; +``` + +In this example `transfer#4034a3c0` will be serialized as a 32 bit unsigned integer from hex value after hash sign(`#`). This meets the standard declaration of an `op` in the [Smart contract guidelines](https://ton.org/#/howto/smart-contract-guidelines). + +To meet the standard described in paragraph 5 of the [Smart contract guidelines](https://ton.org/#/howto/smart-contract-guidelines), it is not enough for us to calculate the crc32. You can follow the following examples to define an `op` in requests or responses from smart contracts in a TL-B scheme: + +```python +import binascii + + +def main(): + req_text = "some_request" + req = format(binascii.crc32(bytes(req_text, "utf-8")) & 0x7fffffff, 'x') + print(f"{req_text}#{req} = Request;") # some_request#733d0d35 = Request; + + rsp_text = "some_response" + rsp = format(binascii.crc32(bytes(rsp_text, "utf-8")) | 0x80000000, 'x') + print(f"{rsp_text}#{rsp} = Response;") # some_response#88b0eb8f = Response; + + +if __name__ == "__main__": + main() +``` + + +## Field definitions + +The constructor and its optional tag are followed by field definitions. Each field definition is of the form `ident:type-expr`, where ident is an identifier with the name of the field16 (replaced by an underscore for anonymous fields), and type-expr is the field’s type. The type provided here is a type expression, which may include simple types or parametrized types with suitable parameters. Variables — i.e., the (identifiers of the) previously defined fields of types `#` (natural numbers) or `Type` (type of types) — may be used as parameters for the parametrized types. The serialization process recursively serializes each field according to its type, and the serialization of a value ultimately consists of the concatenation of bitstrings representing the constructor (i.e., the constructor tag) and the field values. + +Some fields may be implicit. Their definitions are surrounded by curly +braces(`{`, `}`), which indicate that the field is not actually present in the serialization, but that its value must be deduced from other data (usually the parameters of the type being serialized). Example: + +```cpp +nothing$0 {X:Type} = Maybe X; +just$1 {X:Type} value:X = Maybe X; +``` + +Finally, some equalities/inequalities may be included in curly brackets as well. These are certain “equations”, which must be satisfied by the “variables” included in them. If one of the variables is prefixed by a tilde, its value will be uniquely determined by the values of all other variables participating in the equation (which must be known at this point) when the definition is processed from the left to the right. For example: + +```cpp +addr_std$10 anycast:(## 1) {anycast = 0} + workchain_id:int8 address:bits256 = MsgAddrSmpl; +``` + +Some occurrences of “variables” (i.e., already-defined fields) are prefixed by a tilde(`~`). This indicates that the variable’s occurrence is used in the opposite way of the default behavior: in the left-hand side of the equation, it means that the variable will be deduced (computed) based on this occurrence, instead of substituting its previously computed value; in the right-hand side, conversely, it means that the variable will not be deduced from the type being serialized, but rather that it will be computed during the deserialization process. In other words, a tilde transforms an “input argument” into an “output argument”, and vice versa. + +For example, we can use this to write TL-B scheme for simple transaction in the TON with comment(which must be serialized as a sequence of cells): + +```cpp +empty#_ b:bits = Snake ~0; +cons#_ {n:#} b:bits next:^(Snake ~n) = Snake ~(n + 1); + +op:#0 comment:Snake = Request; +``` + +A caret (`ˆ`) preceding a type `X` means that instead of serializing a value of type `X` as a bitstring inside the current cell, we place this value into a separate cell, and add a reference to it into the current cell. Therefore `ˆX` means “the type of references to cells containing values of type `X`”. + +Parametrized type `#<= p` with `p : #` (this notation means `“p of type #”`, i.e., a natural number) denotes the subtype of the natural numbers type `#`, consisting of integers `0 ... p;` it is serialized into `[log2(p + 1)]` bits as an unsigned big-endian integer. Type `#` by itself is serialized as an unsigned 32-bit integer. Parametrized type `## b` with `b : #<=31` is equivalent to `#<= 2^b − 1` (i.e., it is an unsigned b-bit integer). For example: + +```cpp +action_send_msg#0ec3c86d mode:(## 8) + out_msg:^(MessageRelaxed Any) = OutAction; +``` + +In this scheme `mode:(## 8)` will be serialized as 8-bit unsigned integer. + +## Conditional (optional) fields + +The serialization of the conditional fields is determined from the other, already specified fields. + +For example(from [`block.tlb`](https://github.com/newton-blockchain/ton/blob/ae5c0720143e231c32c3d2034cfe4e533a16d969/crypto/block/block.tlb#L418)): + +```cpp +block_info#9bc7a987 version:uint32 + not_master:(## 1) + after_merge:(## 1) before_split:(## 1) + after_split:(## 1) + want_split:Bool want_merge:Bool + key_block:Bool vert_seqno_incr:(## 1) + flags:(## 8) { flags <= 1 } + seq_no:# vert_seq_no:# { vert_seq_no >= vert_seqno_incr } + { prev_seq_no:# } { ~prev_seq_no + 1 = seq_no } + shard:ShardIdent gen_utime:uint32 + start_lt:uint64 end_lt:uint64 + gen_validator_list_hash_short:uint32 + gen_catchain_seqno:uint32 + min_ref_mc_seqno:uint32 + prev_key_block_seqno:uint32 + gen_software:flags . 0?GlobalVersion + master_ref:not_master?^BlkMasterInfo + prev_ref:^(BlkPrevInfo after_merge) + prev_vert_ref:vert_seqno_incr?^(BlkPrevInfo 0) + = BlockInfo; +``` + +In this example, the cell reference `^BlkMasterInfo` will be serialized only if `not_master` > 0. And the `GlobalVersion` will be serialized only if `flags == 0`. + +## Namespaces + +Available in the TL version from Telegram, but as it turned out, not used in TL-B + +## Comments + +Comments are the same as in C++ +```cpp +/* +This is +a comment +*/ + +// This is one line comment +``` + +## Library usage + +You can use TL-B libraries to extend your documents and to avoid writing repetitive schemes. We have prepared a set of ready-made libraries that you can use. They are mostly based on block.tlb, but we have also added some combinators of our own. + +- `tonstdlib.tlb` +- `tonextlib.tlb` +- `hashmap.tlb` + +In TL-B libraries there is no concept of cyclic import. Just indicate the dependency on some other document (library) at the top of the document with the keyword `dependson`. For example: + +file `mydoc.tlb`: +```cpp +// +// dependson "libraries/tonstdlib.tlb" +// + +op:uint32 data:Any = MsgBody; +something$0101 data:(Maybe ^MsgBody) = SomethingImportant; +``` + +In dependencies, you are required to specify the correct relative path. The example above is located in such a tree: + +``` +. +├── mydoc.tlb +├── libraries +│ ├── ... +│ └── tonstdlib.tlb +└── ... +``` + +## IDE Support + +The [intellij-ton](https://github.com/andreypfau/intellij-ton) plugin supports Fift, FunC and also TL-B. +The TL-B grammar is described in the [TlbParser.bnf](https://github.com/andreypfau/intellij-ton/blob/main/src/main/grammars/TlbParser.bnf) file. + +## Useful sources + +- [Telegram Open Network Virtual Machine](https://ton.org/tvm.pdf) +- [A description of an older version of TL](https://core.telegram.org/mtproto/TL) +- [block.tlb](https://github.com/newton-blockchain/ton/blob/master/crypto/block/block.tlb) + +_Thanks to the [Vudi](https://github.com/Vudi) and [cryshado](https://github.com/cryshado) for contributing to the community!_ \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/learn/overviews/TON_blockchain_overview.md b/versioned_docs/version-1.0.0/learn/overviews/TON_blockchain_overview.md new file mode 100644 index 0000000000..6a95029cd2 --- /dev/null +++ b/versioned_docs/version-1.0.0/learn/overviews/TON_blockchain_overview.md @@ -0,0 +1,52 @@ +# Blockchain of Blockchains + + +:::tip +Terms '**smart contract**', '**account**' and '**actor**' are used interchangeably in this document to define a blockchain entity. +::: + +## Single actor + +Let's consider one smart contract. + +In TON it is a _thing_, with properties like `address`, `code`, `data`, `balance` and others. In other words, it is an object which has some _storage_ and _behavior_. +That behavior has the following pattern: +* something happens (the most common situation is that a contract gets a message) +* contract handles that event according to its own properties by executing its `code` in TON Virtual Machine. +* contract modifies its own properties (`code`, `data` and others) +* contract optionally generates outgoing messages +* contract goes to the standby mode till the next event + +A combination of these steps is called **transaction**. It is important that events are handled one by one, thus _transactions_ are strictly ordered and cannot interrupt each other. + +This behavior pattern is well known and called Actor. + +Sequence of _transactions_ `Tx1 -> Tx2 -> Tx3 -> ....` may be called **chain**. And in the considered case it is called **AccountChain** to emphasize that it is _the chain_ of a single account transactions. + +Now, since nodes that process transactions need from time to time to coordinate the state of the smart contract (to reach a _consensus_ about the state) those _transactions_ are batched. +`[Tx1 -> Tx2] -> [Tx3 -> Tx4 -> Tx5] -> [] -> [Tx6]` +Batching does not intervene in sequencing, each transaction still has only one prev tx and at most one next tx, but now this sequence is cut into the **blocks**. + +It is also expedient to include queues of incoming and outgoing messages to _blocks_. In that case, _block_ will contain a full set of information that determine and describe what happened to the smart contract during that block. + +## Shards +Now let's consider many accounts. We can get a few _AccountChains_ and store them together, such set of _AccountChains_ is called **ShardChain**. In the same way, we can cut **ShardChain** into the **ShardBlocks**, which are an aggregation of individual _AccountBlocks_. + + +Note that since _ShardChain_ consists of easily distinguished _AccountChains_ we can easily split them. That way if we have 1 _ShardChain_ which describes events that happen with 1 million accounts and there are too many transactions per second for being processed and stored by one node, we just divide (or **split**) that chain into two smaller _ShardChains_ with each chain accounting for half million of accounts and each chain processed on a separate subset of nodes. + +Analogously, if some shards became too unoccupied they can be **merged** into one bigger shard. + +There are obviously two limiting cases: when the shard contains only one account (and thus can not be split further) and when the shard contains all accounts. + +Accounts can interact with each other by sending messages. There is a special mechanism of routing which move messages from outgoing queues to corresponding incoming queues and ensures that 1) all messages will be delivered 2) messages will be delivered consequently (the message sent earlier will reach the destination earlier). + +_Side note:_ to make splitting and merging deterministic, aggregation of accountchains into shards is based on bit-representation of account addresses. That way all accounts in shardchain will have exactly the same binary prefix (for instance all addresses will start with `0b00101`). + +## Blockchain +Aggregation of all shards which contain all accounts behaving by one set of rules is called a **Blockchain**. + +In TON there can be many sets of rules and thus many blockchains which operate simultaneously and can interact with each other by sending messages crosschain the same way how accounts of one chain interact with each other. + +### Masterchain +There is a necessity for the synchronization of message routing and transaction execution. In other words, nodes in the network need a way to fix some 'point' in a multichain state and reach a consensus about that state. In TON for that purpose a special chain **MasterChain** is used. Blocks of _masterchain_ contain additional information (latest block hashes) about all other chains in the system, thus any observer unambiguously determines the state of all multichain systems at some masterchain block. diff --git a/versioned_docs/version-1.0.0/learn/tvm-instructions/generate_md.py b/versioned_docs/version-1.0.0/learn/tvm-instructions/generate_md.py new file mode 100644 index 0000000000..84fa7fc0cc --- /dev/null +++ b/versioned_docs/version-1.0.0/learn/tvm-instructions/generate_md.py @@ -0,0 +1,93 @@ +import argparse +import csv +import re +import sys + +parser = argparse.ArgumentParser(description="Generate TVM instruction reference document") +parser.add_argument("instructions_csv", type=str, help="csv file with the instructions") +parser.add_argument("doc_template", type=str, help="template for the document") +parser.add_argument("out_file", type=str, help="output file") +args = parser.parse_args() + +TABLE_HEADER = \ + "| xxxxxxx
    Opcode " +\ + "| xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax " +\ + "| xxxxxxxxxxxxxxxxx
    Stack " +\ + "| xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description " +\ + "| xxxx
    Gas |\n" +\ + "|:-|:-|:-|:-|:-|" + +categories = dict() +cmd_to_name = dict() + +with open(args.instructions_csv, "r") as f: + reader = csv.DictReader(f) + for row in reader: + cat = row["doc_category"] + if cat not in categories: + categories[cat] = [] + categories[cat].append(row) + if row["name"] != "": + for s in row["doc_fift"].split("\n"): + s = s.strip() + if s != "": + s = s.split()[-1] + if s not in cmd_to_name: + cmd_to_name[s] = row["name"] + +def name_to_id(s): + return "instr-" + s.lower().replace("_", "-").replace("#", "SHARP") + +def make_link(text, cmd): + if cmd not in cmd_to_name: + return text + name = cmd_to_name[cmd] + return "[%s](#%s)" % (text, name_to_id(name)) + +def gen_links(text): + return re.sub("`([^ `][^`]* )?([A-Z0-9#-]+)`", lambda m: make_link(m.group(0), m.group(2)), text) + +def make_table(cat): + if cat not in categories: + print("No such category", cat, file=sys.stderr) + return "" + table = [TABLE_HEADER] + for row in categories[cat]: + opcode = row["doc_opcode"] + fift = row["doc_fift"] + stack = row["doc_stack"] + desc = row["doc_description"] + gas = row["doc_gas"] + + if opcode != "": + opcode = "**`%s`**" % opcode + + if fift != "": + fift = "
    ".join("`%s`" % s.strip() for s in fift.split("\n")) + + if stack != "": + stack = "_`%s`_" % stack + stack = stack.replace("|", "\\|") + stack = stack.strip() + + desc = desc.replace("|", "\\|") + desc = desc.replace("\n", "
    ") + + if gas != "": + gas = gas.replace("|", "\\|") + gas = "`" + gas + "`" + + desc = gen_links(desc) + desc = "
    " % name_to_id(row["name"]) + desc + + table.append("| %s | %s | %s | %s | %s |" % (opcode, fift, stack, desc, gas)) + + return "\n".join(table) + +templ = open(args.doc_template, "r").read() + +templ = gen_links(templ) + +doc = re.sub("{{ *Table: *([a-zA-Z0-9_-]+) *}}", lambda m: make_table(m.group(1)), templ) +with open(args.out_file, "w") as f: + print(doc, file=f) diff --git a/versioned_docs/version-1.0.0/learn/tvm-instructions/instructions.csv b/versioned_docs/version-1.0.0/learn/tvm-instructions/instructions.csv new file mode 100644 index 0000000000..63f06f94a3 --- /dev/null +++ b/versioned_docs/version-1.0.0/learn/tvm-instructions/instructions.csv @@ -0,0 +1,951 @@ +name,alias_of,tlb,doc_category,doc_opcode,doc_fift,doc_stack,doc_gas,doc_description +NOP,,#00,stack_basic,00,NOP,-,18,Does nothing. +SWAP,XCHG_0I,#01,stack_basic,01,SWAP,x y - y x,18,Same as `s1 XCHG0`. +XCHG_0I,,#0 i:(## 4) {1 <= i},stack_basic,0i,s[i] XCHG0,,18,"Interchanges `s0` with `s[i]`, `1 <= i <= 15`." +XCHG_IJ,,#10 i:(## 4) j:(## 4) {1 <= i} {i + 1 <= j},stack_basic,10ij,s[i] s[j] XCHG,,26,"Interchanges `s[i]` with `s[j]`, `1 <= i < j <= 15`." +XCHG_0I_LONG,,#11 ii:uint8,stack_basic,11ii,s0 [ii] s() XCHG,,26,"Interchanges `s0` with `s[ii]`, `0 <= ii <= 255`." +XCHG_1I,,#1 i:(## 4) {2 <= i},stack_basic,1i,s1 s[i] XCHG,,18,"Interchanges `s1` with `s[i]`, `2 <= i <= 15`." +PUSH,,#2 i:uint4,stack_basic,2i,s[i] PUSH,,18,Pushes a copy of the old `s[i]` into the stack. +DUP,PUSH,#20,stack_basic,20,DUP,x - x x,18,Same as `s0 PUSH`. +OVER,PUSH,#21,stack_basic,21,OVER,x y - x y x,18,Same as `s1 PUSH`. +POP,,#3 i:uint4,stack_basic,3i,s[i] POP,,18,Pops the old `s0` value into the old `s[i]`. +DROP,POP,#30,stack_basic,30,DROP,x -,18,"Same as `s0 POP`, discards the top-of-stack value." +NIP,POP,#31,stack_basic,31,NIP,x y - y,18,Same as `s1 POP`. +XCHG3,,#4 i:uint4 j:uint4 k:uint4,stack_complex,4ijk,s[i] s[j] s[k] XCHG3,,26,Equivalent to `s2 s[i] XCHG` `s1 s[j] XCHG` `s[k] XCHG0`. +XCHG2,,#50 i:uint4 j:uint4,stack_complex,50ij,s[i] s[j] XCHG2,,26,Equivalent to `s1 s[i] XCHG` `s[j] XCHG0`. +XCPU,,#51 i:uint4 j:uint4,stack_complex,51ij,s[i] s[j] XCPU,,26,Equivalent to `s[i] XCHG0` `s[j] PUSH`. +PUXC,,#52 i:uint4 j:uint4,stack_complex,52ij,s[i] s[j-1] PUXC,,26,Equivalent to `s[i] PUSH` `SWAP` `s[j] XCHG0`. +PUSH2,,#53 i:uint4 j:uint4,stack_complex,53ij,s[i] s[j] PUSH2,,26,Equivalent to `s[i] PUSH` `s[j+1] PUSH`. +XCHG3_ALT,,#540 i:uint4 j:uint4 k:uint4,stack_complex,540ijk,s[i] s[j] s[k] XCHG3_l,,34,Long form of `XCHG3`. +XC2PU,,#541 i:uint4 j:uint4 k:uint4,stack_complex,541ijk,s[i] s[j] s[k] XC2PU,,34,Equivalent to `s[i] s[j] XCHG2` `s[k] PUSH`. +XCPUXC,,#542 i:uint4 j:uint4 k:uint4,stack_complex,542ijk,s[i] s[j] s[k-1] XCPUXC,,34,Equivalent to `s1 s[i] XCHG` `s[j] s[k-1] PUXC`. +XCPU2,,#543 i:uint4 j:uint4 k:uint4,stack_complex,543ijk,s[i] s[j] s[k] XCPU2,,34,Equivalent to `s[i] XCHG0` `s[j] s[k] PUSH2`. +PUXC2,,#544 i:uint4 j:uint4 k:uint4,stack_complex,544ijk,s[i] s[j-1] s[k-1] PUXC2,,34,Equivalent to `s[i] PUSH` `s2 XCHG0` `s[j] s[k] XCHG2`. +PUXCPU,,#545 i:uint4 j:uint4 k:uint4,stack_complex,545ijk,s[i] s[j-1] s[k-1] PUXCPU,,34,Equivalent to `s[i] s[j-1] PUXC` `s[k] PUSH`. +PU2XC,,#546 i:uint4 j:uint4 k:uint4,stack_complex,546ijk,s[i] s[j-1] s[k-2] PU2XC,,34,Equivalent to `s[i] PUSH` `SWAP` `s[j] s[k-1] PUXC`. +PUSH3,,#547 i:uint4 j:uint4 k:uint4,stack_complex,547ijk,s[i] s[j] s[k] PUSH3,,34,Equivalent to `s[i] PUSH` `s[j+1] s[k+1] PUSH2`. +BLKSWAP,,#55 i:uint4 j:uint4,stack_complex,55ij,[i+1] [j+1] BLKSWAP,,26,"Permutes two blocks `s[j+i+1] … s[j+1]` and `s[j] … s0`. +`0 <= i,j <= 15` +Equivalent to `[i+1] [j+1] REVERSE` `[j+1] 0 REVERSE` `[i+j+2] 0 REVERSE`." +ROT2,BLKSWAP,#5513,stack_complex,5513,"ROT2 +2ROT",a b c d e f - c d e f a b,26,Rotates the three topmost pairs of stack entries. +ROLL,BLKSWAP,#550 i:uint4,stack_complex,550i,[i+1] ROLL,,26,"Rotates the top `i+1` stack entries. +Equivalent to `1 [i+1] BLKSWAP`." +ROLLREV,BLKSWAP,#55 i:uint4 zero:(## 4) {zero = 0},stack_complex,55i0,"[i+1] -ROLL +[i+1] ROLLREV",,26,"Rotates the top `i+1` stack entries in the other direction. +Equivalent to `[i+1] 1 BLKSWAP`." +PUSH_LONG,,#56 ii:uint8,stack_complex,56ii,[ii] s() PUSH,,26,"Pushes a copy of the old `s[ii]` into the stack. +`0 <= ii <= 255`" +POP_LONG,,#57 ii:uint8,stack_complex,57ii,[ii] s() POP,,26,"Pops the old `s0` value into the old `s[ii]`. +`0 <= ii <= 255`" +ROT,,#58,stack_complex,58,ROT,a b c - b c a,18,Equivalent to `1 2 BLKSWAP` or to `s2 s1 XCHG2`. +ROTREV,,#59,stack_complex,59,"ROTREV +-ROT",a b c - c a b,18,Equivalent to `2 1 BLKSWAP` or to `s2 s2 XCHG2`. +SWAP2,,#5A,stack_complex,5A,"SWAP2 +2SWAP",a b c d - c d a b,18,Equivalent to `2 2 BLKSWAP` or to `s3 s2 XCHG2`. +DROP2,,#5B,stack_complex,5B,"DROP2 +2DROP",a b - ,18,Equivalent to `DROP` `DROP`. +DUP2,,#5C,stack_complex,5C,"DUP2 +2DUP",a b - a b a b,18,Equivalent to `s1 s0 PUSH2`. +OVER2,,#5D,stack_complex,5D,"OVER2 +2OVER",a b c d - a b c d a b,18,Equivalent to `s3 s2 PUSH2`. +REVERSE,,#5E i:uint4 j:uint4,stack_complex,5Eij,[i+2] [j] REVERSE,,26,Reverses the order of `s[j+i+1] … s[j]`. +BLKDROP,,#5F0 i:uint4,stack_complex,5F0i,[i] BLKDROP,,26,Equivalent to `DROP` performed `i` times. +BLKPUSH,,#5F i:(## 4) j:uint4 {1 <= i},stack_complex,5Fij,[i] [j] BLKPUSH,,26,"Equivalent to `PUSH s(j)` performed `i` times. +`1 <= i <= 15`, `0 <= j <= 15`." +PICK,,#60,stack_complex,60,"PICK +PUSHX",,18,"Pops integer `i` from the stack, then performs `s[i] PUSH`." +ROLLX,,#61,stack_complex,61,ROLLX,,18,"Pops integer `i` from the stack, then performs `1 [i] BLKSWAP`." +-ROLLX,,#62,stack_complex,62,"-ROLLX +ROLLREVX",,18,"Pops integer `i` from the stack, then performs `[i] 1 BLKSWAP`." +BLKSWX,,#63,stack_complex,63,BLKSWX,,18,"Pops integers `i`,`j` from the stack, then performs `[i] [j] BLKSWAP`." +REVX,,#64,stack_complex,64,REVX,,18,"Pops integers `i`,`j` from the stack, then performs `[i] [j] REVERSE`." +DROPX,,#65,stack_complex,65,DROPX,,18,"Pops integer `i` from the stack, then performs `[i] BLKDROP`." +TUCK,,#66,stack_complex,66,TUCK,a b - b a b,18,Equivalent to `SWAP` `OVER` or to `s1 s1 XCPU`. +XCHGX,,#67,stack_complex,67,XCHGX,,18,"Pops integer `i` from the stack, then performs `s[i] XCHG`." +DEPTH,,#68,stack_complex,68,DEPTH,- depth,18,Pushes the current depth of the stack. +CHKDEPTH,,#69,stack_complex,69,CHKDEPTH,i -,18/58,"Pops integer `i` from the stack, then checks whether there are at least `i` elements, generating a stack underflow exception otherwise." +ONLYTOPX,,#6A,stack_complex,6A,ONLYTOPX,,18,"Pops integer `i` from the stack, then removes all but the top `i` elements." +ONLYX,,#6B,stack_complex,6B,ONLYX,,18,"Pops integer `i` from the stack, then leaves only the bottom `i` elements. Approximately equivalent to `DEPTH` `SWAP` `SUB` `DROPX`." +BLKDROP2,,#6C i:(## 4) j:uint4 {1 <= i},stack_complex,6Cij,[i] [j] BLKDROP2,,26,"Drops `i` stack elements under the top `j` elements. +`1 <= i <= 15`, `0 <= j <= 15` +Equivalent to `[i+j] 0 REVERSE` `[i] BLKDROP` `[j] 0 REVERSE`." +NULL,,#6D,tuple,6D,"NULL +PUSHNULL", - null,18,Pushes the only value of type _Null_. +ISNULL,,#6E,tuple,6E,ISNULL,x - ?,18,"Checks whether `x` is a _Null_, and returns `-1` or `0` accordingly." +TUPLE,,#6F0 n:uint4,tuple,6F0n,[n] TUPLE,x_1 ... x_n - t,26+n,"Creates a new _Tuple_ `t=(x_1, … ,x_n)` containing `n` values `x_1`,..., `x_n`. +`0 <= n <= 15`" +NIL,TUPLE,#6F00,tuple,6F00,NIL,- t,26,Pushes the only _Tuple_ `t=()` of length zero. +SINGLE,TUPLE,#6F01,tuple,6F01,SINGLE,x - t,27,"Creates a singleton `t:=(x)`, i.e., a _Tuple_ of length one." +PAIR,TUPLE,#6F02,tuple,6F02,"PAIR +CONS",x y - t,28,"Creates pair `t:=(x,y)`." +TRIPLE,TUPLE,#6F03,tuple,6F03,TRIPLE,x y z - t,29,"Creates triple `t:=(x,y,z)`." +INDEX,,#6F1 k:uint4,tuple,6F1k,[k] INDEX,t - x,26,"Returns the `k`-th element of a _Tuple_ `t`. +`0 <= k <= 15`." +FIRST,INDEX,#6F10,tuple,6F10,"FIRST +CAR",t - x,26,Returns the first element of a _Tuple_. +SECOND,INDEX,#6F11,tuple,6F11,"SECOND +CDR",t - y,26,Returns the second element of a _Tuple_. +THIRD,INDEX,#6F12,tuple,6F12,THIRD,t - z,26,Returns the third element of a _Tuple_. +UNTUPLE,,#6F2 n:uint4,tuple,6F2n,[n] UNTUPLE,t - x_1 ... x_n,26+n,"Unpacks a _Tuple_ `t=(x_1,...,x_n)` of length equal to `0 <= n <= 15`. +If `t` is not a _Tuple_, or if `|t| != n`, a type check exception is thrown." +UNSINGLE,UNTUPLE,#6F21,tuple,6F21,UNSINGLE,t - x,27,Unpacks a singleton `t=(x)`. +UNPAIR,UNTUPLE,#6F22,tuple,6F22,"UNPAIR +UNCONS",t - x y,28,"Unpacks a pair `t=(x,y)`." +UNTRIPLE,UNTUPLE,#6F23,tuple,6F23,UNTRIPLE,t - x y z,29,"Unpacks a triple `t=(x,y,z)`." +UNPACKFIRST,,#6F3 k:uint4,tuple,6F3k,[k] UNPACKFIRST,t - x_1 ... x_k,26+k,"Unpacks first `0 <= k <= 15` elements of a _Tuple_ `t`. +If `|t|= |t|`, throws a range check exception." +SETFIRST,SETINDEX,#6F50,tuple,6F50,SETFIRST,t x - t',26+|t|,Sets the first component of _Tuple_ `t` to `x` and returns the resulting _Tuple_ `t'`. +SETSECOND,SETINDEX,#6F51,tuple,6F51,SETSECOND,t x - t',26+|t|,Sets the second component of _Tuple_ `t` to `x` and returns the resulting _Tuple_ `t'`. +SETTHIRD,SETINDEX,#6F52,tuple,6F52,SETTHIRD,t x - t',26+|t|,Sets the third component of _Tuple_ `t` to `x` and returns the resulting _Tuple_ `t'`. +INDEXQ,,#6F6 k:uint4,tuple,6F6k,[k] INDEXQ,t - x,26,"Returns the `k`-th element of a _Tuple_ `t`, where `0 <= k <= 15`. In other words, returns `x_{k+1}` if `t=(x_1,...,x_n)`. If `k>=n`, or if `t` is _Null_, returns a _Null_ instead of `x`." +FIRSTQ,INDEXQ,#6F60,tuple,6F60,"FIRSTQ +CARQ",t - x,26,Returns the first element of a _Tuple_. +SECONDQ,INDEXQ,#6F61,tuple,6F61,"SECONDQ +CDRQ",t - y,26,Returns the second element of a _Tuple_. +THIRDQ,INDEXQ,#6F62,tuple,6F62,THIRDQ,t - z,26,Returns the third element of a _Tuple_. +SETINDEXQ,,#6F7 k:uint4,tuple,6F7k,[k] SETINDEXQ,t x - t',26+|t’|,"Sets the `k`-th component of _Tuple_ `t` to `x`, where `0 <= k < 16`, and returns the resulting _Tuple_ `t'`. +If `|t| <= k`, first extends the original _Tuple_ to length `n’=k+1` by setting all new components to _Null_. If the original value of `t` is _Null_, treats it as an empty _Tuple_. If `t` is not _Null_ or _Tuple_, throws an exception. If `x` is _Null_ and either `|t| <= k` or `t` is _Null_, then always returns `t'=t` (and does not consume tuple creation gas)." +SETFIRSTQ,SETINDEXQ,#6F70,tuple,6F70,SETFIRSTQ,t x - t',26+|t’|,Sets the first component of _Tuple_ `t` to `x` and returns the resulting _Tuple_ `t'`. +SETSECONDQ,SETINDEXQ,#6F71,tuple,6F71,SETSECONDQ,t x - t',26+|t’|,Sets the second component of _Tuple_ `t` to `x` and returns the resulting _Tuple_ `t'`. +SETTHIRDQ,SETINDEXQ,#6F72,tuple,6F72,SETTHIRDQ,t x - t',26+|t’|,Sets the third component of _Tuple_ `t` to `x` and returns the resulting _Tuple_ `t'`. +TUPLEVAR,,#6F80,tuple,6F80,TUPLEVAR,x_1 ... x_n n - t,26+n,"Creates a new _Tuple_ `t` of length `n` similarly to `TUPLE`, but with `0 <= n <= 255` taken from the stack." +INDEXVAR,,#6F81,tuple,6F81,INDEXVAR,t k - x,26,"Similar to `k INDEX`, but with `0 <= k <= 254` taken from the stack." +UNTUPLEVAR,,#6F82,tuple,6F82,UNTUPLEVAR,t n - x_1 ... x_n,26+n,"Similar to `n UNTUPLE`, but with `0 <= n <= 255` taken from the stack." +UNPACKFIRSTVAR,,#6F83,tuple,6F83,UNPACKFIRSTVAR,t n - x_1 ... x_n,26+n,"Similar to `n UNPACKFIRST`, but with `0 <= n <= 255` taken from the stack." +EXPLODEVAR,,#6F84,tuple,6F84,EXPLODEVAR,t n - x_1 ... x_m m,26+m,"Similar to `n EXPLODE`, but with `0 <= n <= 255` taken from the stack." +SETINDEXVAR,,#6F85,tuple,6F85,SETINDEXVAR,t x k - t',26+|t’|,"Similar to `k SETINDEX`, but with `0 <= k <= 254` taken from the stack." +INDEXVARQ,,#6F86,tuple,6F86,INDEXVARQ,t k - x,26,"Similar to `n INDEXQ`, but with `0 <= k <= 254` taken from the stack." +SETINDEXVARQ,,#6F87,tuple,6F87,SETINDEXVARQ,t x k - t',26+|t’|,"Similar to `k SETINDEXQ`, but with `0 <= k <= 254` taken from the stack." +TLEN,,#6F88,tuple,6F88,TLEN,t - n,26,Returns the length of a _Tuple_. +QTLEN,,#6F89,tuple,6F89,QTLEN,t - n or -1,26,"Similar to `TLEN`, but returns `-1` if `t` is not a _Tuple_." +ISTUPLE,,#6F8A,tuple,6F8A,ISTUPLE,t - ?,26,Returns `-1` or `0` depending on whether `t` is a _Tuple_. +LAST,,#6F8B,tuple,6F8B,LAST,t - x,26,Returns the last element of a non-empty _Tuple_ `t`. +TPUSH,,#6F8C,tuple,6F8C,"TPUSH +COMMA",t x - t',26+|t’|,"Appends a value `x` to a _Tuple_ `t=(x_1,...,x_n)`, but only if the resulting _Tuple_ `t'=(x_1,...,x_n,x)` is of length at most 255. Otherwise throws a type check exception." +TPOP,,#6F8D,tuple,6F8D,TPOP,t - t' x,26+|t’|,"Detaches the last element `x=x_n` from a non-empty _Tuple_ `t=(x_1,...,x_n)`, and returns both the resulting _Tuple_ `t'=(x_1,...,x_{n-1})` and the original last element `x`." +NULLSWAPIF,,#6FA0,tuple,6FA0,NULLSWAPIF,x - x or null x,26,"Pushes a _Null_ under the topmost _Integer_ `x`, but only if `x!=0`." +NULLSWAPIFNOT,,#6FA1,tuple,6FA1,NULLSWAPIFNOT,x - x or null x,26,"Pushes a _Null_ under the topmost _Integer_ `x`, but only if `x=0`. May be used for stack alignment after quiet primitives such as `PLDUXQ`." +NULLROTRIF,,#6FA2,tuple,6FA2,NULLROTRIF,x y - x y or null x y,26,"Pushes a _Null_ under the second stack entry from the top, but only if the topmost _Integer_ `y` is non-zero." +NULLROTRIFNOT,,#6FA3,tuple,6FA3,NULLROTRIFNOT,x y - x y or null x y,26,"Pushes a _Null_ under the second stack entry from the top, but only if the topmost _Integer_ `y` is zero. May be used for stack alignment after quiet primitives such as `LDUXQ`." +NULLSWAPIF2,,#6FA4,tuple,6FA4,NULLSWAPIF2,x - x or null null x,26,"Pushes two nulls under the topmost _Integer_ `x`, but only if `x!=0`. +Equivalent to `NULLSWAPIF` `NULLSWAPIF`." +NULLSWAPIFNOT2,,#6FA5,tuple,6FA5,NULLSWAPIFNOT2,x - x or null null x,26,"Pushes two nulls under the topmost _Integer_ `x`, but only if `x=0`. +Equivalent to `NULLSWAPIFNOT` `NULLSWAPIFNOT`." +NULLROTRIF2,,#6FA6,tuple,6FA6,NULLROTRIF2,x y - x y or null null x y,26,"Pushes two nulls under the second stack entry from the top, but only if the topmost _Integer_ `y` is non-zero. +Equivalent to `NULLROTRIF` `NULLROTRIF`." +NULLROTRIFNOT2,,#6FA7,tuple,6FA7,NULLROTRIFNOT2,x y - x y or null null x y,26,"Pushes two nulls under the second stack entry from the top, but only if the topmost _Integer_ `y` is zero. +Equivalent to `NULLROTRIFNOT` `NULLROTRIFNOT`." +INDEX2,,#6FB i:uint2 j:uint2,tuple,6FBij,[i] [j] INDEX2,t - x,26,"Recovers `x=(t_{i+1})_{j+1}` for `0 <= i,j <= 3`. +Equivalent to `[i] INDEX` `[j] INDEX`." +CADR,INDEX2,#6FB4,tuple,6FB4,CADR,t - x,26,Recovers `x=(t_2)_1`. +CDDR,INDEX2,#6FB5,tuple,6FB5,CDDR,t - x,26,Recovers `x=(t_2)_2`. +INDEX3,,#6FE_ i:uint2 j:uint2 k:uint2,tuple,6FE_ijk,[i] [j] [k] INDEX3,t - x,26,"Recovers `x=t_{i+1}_{j+1}_{k+1}`. +`0 <= i,j,k <= 3` +Equivalent to `[i] [j] INDEX2` `[k] INDEX`." +CADDR,INDEX3,#6FD4,tuple,6FD4,CADDR,t - x,26,Recovers `x=t_2_2_1`. +CDDDR,INDEX3,#6FD5,tuple,6FD5,CDDDR,t - x,26,Recovers `x=t_2_2_2`. +PUSHINT_4,,#7 i:uint4,const_int,7i,"[x] PUSHINT +[x] INT",- x,18,"Pushes integer `x` into the stack. `-5 <= x <= 10`. +Here `i` equals four lower-order bits of `x` (`i=x mod 16`)." +ZERO,PUSHINT_4,#70,const_int,70,"ZERO +FALSE",- 0,18, +ONE,PUSHINT_4,#71,const_int,71,ONE,- 1,18, +TWO,PUSHINT_4,#72,const_int,72,TWO,- 2,18, +TEN,PUSHINT_4,#7A,const_int,7A,TEN,- 10,18, +TRUE,PUSHINT_4,#7F,const_int,7F,TRUE,- -1,18, +PUSHINT_8,,#80 xx:int8,const_int,80xx,"[xx] PUSHINT +[xx] INT",- xx,26,Pushes integer `xx`. `-128 <= xx <= 127`. +PUSHINT_16,,#81 xxxx:int16,const_int,81xxxx,"[xxxx] PUSHINT +[xxxx] INT",- xxxx,34,Pushes integer `xxxx`. `-2^15 <= xx < 2^15`. +PUSHINT_LONG,,#82 l:(## 5) xxx:(int (8 * l + 19)),const_int,82lxxx,"[xxx] PUSHINT +[xxx] INT",- xxx,23,"Pushes integer `xxx`. +_Details:_ 5-bit `0 <= l <= 30` determines the length `n=8l+19` of signed big-endian integer `xxx`. +The total length of this instruction is `l+4` bytes or `n+13=8l+32` bits." +PUSHPOW2,,#83 xx:uint8,const_int,83xx,[xx+1] PUSHPOW2,- 2^(xx+1),26,"(Quietly) pushes `2^(xx+1)` for `0 <= xx <= 255`. +`2^256` is a `NaN`." +PUSHNAN,PUSHPOW2,#83FF,const_int,83FF,PUSHNAN,- NaN,26,Pushes a `NaN`. +PUSHPOW2DEC,,#84 xx:uint8,const_int,84xx,[xx+1] PUSHPOW2DEC,- 2^(xx+1)-1,26,Pushes `2^(xx+1)-1` for `0 <= xx <= 255`. +PUSHNEGPOW2,,#85 xx:uint8,const_int,85xx,[xx+1] PUSHNEGPOW2,- -2^(xx+1),26,Pushes `-2^(xx+1)` for `0 <= xx <= 255`. +PUSHREF,,#88 c:^Cell,const_data,88,[ref] PUSHREF,- c,18,"Pushes the reference `ref` into the stack. +_Details:_ Pushes the first reference of `cc.code` into the stack as a _Cell_ (and removes this reference from the current continuation)." +PUSHREFSLICE,,#89 c:^Cell,const_data,89,[ref] PUSHREFSLICE,- s,118/43,"Similar to `PUSHREF`, but converts the cell into a _Slice_." +PUSHREFCONT,,#8A c:^Cell,const_data,8A,[ref] PUSHREFCONT,- cont,118/43,"Similar to `PUSHREFSLICE`, but makes a simple ordinary _Continuation_ out of the cell." +PUSHSLICE,,#8B x:(## 4) sss:((8 * x + 4) * Bit),const_data,8Bxsss,"[slice] PUSHSLICE +[slice] SLICE",- s,22,"Pushes the slice `slice` into the stack. +_Details:_ Pushes the (prefix) subslice of `cc.code` consisting of its first `8x+4` bits and no references (i.e., essentially a bitstring), where `0 <= x <= 15`. +A completion tag is assumed, meaning that all trailing zeroes and the last binary one (if present) are removed from this bitstring. +If the original bitstring consists only of zeroes, an empty slice will be pushed." +PUSHSLICE_REFS,,#8C r:(## 2) xx:(## 5) c:((r + 1) * ^Cell) ssss:((8 * xx + 1) * Bit),const_data,8Crxxssss,"[slice] PUSHSLICE +[slice] SLICE",- s,25,"Pushes the slice `slice` into the stack. +_Details:_ Pushes the (prefix) subslice of `cc.code` consisting of its first `1 <= r+1 <= 4` references and up to first `8xx+1` bits of data, with `0 <= xx <= 31`. +A completion tag is also assumed." +PUSHSLICE_LONG,,#8D r:(#<= 4) xx:(## 7) c:(r * ^Cell) ssss:((8 * xx + 6) * Bit),const_data,8Drxxsssss,"[slice] PUSHSLICE +[slice] SLICE",- s,28,"Pushes the slice `slice` into the stack. +_Details:_ Pushes the subslice of `cc.code` consisting of `0 <= r <= 4` references and up to `8xx+6` bits of data, with `0 <= xx <= 127`. +A completion tag is assumed." +,,,const_data,,"x{} PUSHSLICE +x{ABCD1234} PUSHSLICE +b{01101} PUSHSLICE",- s,,"Examples of `PUSHSLICE`. +`x{}` is an empty slice. `x{...}` is a hexadecimal literal. `b{...}` is a binary literal. +More on slice literals [here](https://github.com/Piterden/TON-docs/blob/master/Fift.%20A%20Brief%20Introduction.md#user-content-51-slice-literals). +Note that the assembler can replace `PUSHSLICE` with `PUSHREFSLICE` in certain situations (e.g. if there’s not enough space in the current continuation)." +,,,const_data,," PUSHREF + PUSHREFSLICE",- c/s,,"Examples of `PUSHREF` and `PUSHREFSLICE`. +More on building cells in fift [here](https://github.com/Piterden/TON-docs/blob/master/Fift.%20A%20Brief%20Introduction.md#user-content-52-builder-primitives)." +PUSHCONT,,#8F_ r:(## 2) xx:(## 7) c:(r * ^Cell) ssss:((8 * xx) * Bit),const_data,8F_rxxcccc,"[builder] PUSHCONT +[builder] CONT",- c,26,"Pushes a continuation made from `builder`. +_Details:_ Pushes the simple ordinary continuation `cccc` made from the first `0 <= r <= 3` references and the first `0 <= xx <= 127` bytes of `cc.code`." +PUSHCONT_SHORT,,#9 x:(## 4) ssss:((8 * x) * Bit),const_data,9xccc,"[builder] PUSHCONT +[builder] CONT",- c,18,"Pushes a continuation made from `builder`. +_Details:_ Pushes an `x`-byte continuation for `0 <= x <= 15`." +,,,const_data,,"<{ code }> PUSHCONT +<{ code }> CONT +CONT:<{ code }>",- c,,"Pushes a continuation with code `code`. +Note that the assembler can replace `PUSHCONT` with `PUSHREFCONT` in certain situations (e.g. if there’s not enough space in the current continuation)." +ADD,,#A0,arithm_basic,A0,ADD,x y - x+y,18, +SUB,,#A1,arithm_basic,A1,SUB,x y - x-y,18, +SUBR,,#A2,arithm_basic,A2,SUBR,x y - y-x,18,Equivalent to `SWAP` `SUB`. +NEGATE,,#A3,arithm_basic,A3,NEGATE,x - -x,18,"Equivalent to `-1 MULCONST` or to `ZERO SUBR`. +Notice that it triggers an integer overflow exception if `x=-2^256`." +INC,,#A4,arithm_basic,A4,INC,x - x+1,18,Equivalent to `1 ADDCONST`. +DEC,,#A5,arithm_basic,A5,DEC,x - x-1,18,Equivalent to `-1 ADDCONST`. +ADDCONST,,#A6 cc:int8,arithm_basic,A6cc,"[cc] ADDCONST +[cc] ADDINT +[-cc] SUBCONST +[-cc] SUBINT",x - x+cc,26,`-128 <= cc <= 127`. +MULCONST,,#A7 cc:int8,arithm_basic,A7cc,"[cc] MULCONST +[cc] MULINT",x - x*cc,26,`-128 <= cc <= 127`. +MUL,,#A8,arithm_basic,A8,MUL,x y - x*y,18, +DIV_BASE,,#A9 m:uint1 s:uint2 cdft:(Either [ d:uint2 f:uint2 ] [ d:uint2 f:uint2 tt:uint8 ]),arithm_div,A9mscdf,,,26,"This is the general encoding of division, with an optional pre-multiplication and an optional replacement of the division or multiplication by a shift. Variable fields are as follows: +`0 <= m <= 1` - Indicates whether there is pre-multiplication (`MULDIV` and its variants), possibly replaced by a left shift. +`0 <= s <= 2` - Indicates whether either the multiplication or the division have been replaced by shifts: `s=0` - no replacement, `s=1` - division replaced by a right shift, `s=2` - multiplication replaced by a left shift (possible only for `m=1`). +`0 <= c <= 1` - Indicates whether there is a constant one-byte argument `tt` for the shift operator (if `s!=0`). For `s=0`, `c=0`. If `c=1`, then `0 <= tt <= 255`, and the shift is performed by `tt+1` bits. If `s!=0` and `c=0`, then the shift amount is provided to the instruction as a top-of-stack _Integer_ in range `0...256`. +`1 <= d <= 3` - Indicates which results of division are required: `1` - only the quotient, `2` - only the remainder, `3` - both. +`0 <= f <= 2` - Rounding mode: `0` - floor, `1` - nearest integer, `2` - ceiling. +All instructions below are variants of this." +DIV,DIV_BASE,#A904,arithm_div,A904,DIV,x y - q,26,"`q=floor(x/y)`, `r=x-y*q`" +DIVR,DIV_BASE,#A905,arithm_div,A905,DIVR,x y - q’,26,"`q’=round(x/y)`, `r’=x-y*q’`" +DIVC,DIV_BASE,#A906,arithm_div,A906,DIVC,x y - q'',26,"`q’’=ceil(x/y)`, `r’’=x-y*q’’`" +MOD,DIV_BASE,#A908,arithm_div,A908,MOD,x y - r,26, +DIVMOD,DIV_BASE,#A90C,arithm_div,A90C,DIVMOD,x y - q r,26, +DIVMODR,DIV_BASE,#A90D,arithm_div,A90D,DIVMODR,x y - q' r',26, +DIVMODC,DIV_BASE,#A90E,arithm_div,A90E,DIVMODC,x y - q'' r'',26, +RSHIFTR_VAR,DIV_BASE,#A925,arithm_div,A925,RSHIFTR,x y - round(x/2^y),26, +RSHIFTC_VAR,DIV_BASE,#A926,arithm_div,A926,RSHIFTC,x y - ceil(x/2^y),34, +RSHIFTR,DIV_BASE,#A935 tt:uint8,arithm_div,A935tt,[tt+1] RSHIFTR#,x y - round(x/2^(tt+1)),34, +RSHIFTC,DIV_BASE,#A936 tt:uint8,arithm_div,A936tt,[tt+1] RSHIFTC#,x y - ceil(x/2^(tt+1)),34, +MODPOW2,DIV_BASE,#A938 tt:uint8,arithm_div,A938tt,[tt+1] MODPOW2#,x - x mod 2^(tt+1),26, +MULDIV,DIV_BASE,#A984,arithm_div,A98,MULDIV,x y z - q,26,`q=floor(x*y/z)` +MULDIVR,DIV_BASE,#A985,arithm_div,A985,MULDIVR,x y z - q',26,`q'=round(x*y/z)` +MULDIVMOD,DIV_BASE,#A98C,arithm_div,A98C,MULDIVMOD,x y z - q r,26,"`q=floor(x*y/z)`, `r=x*y-z*q`" +MULRSHIFT_VAR,DIV_BASE,#A9A4,arithm_div,A9A4,MULRSHIFT,x y z - floor(x*y/2^z),26,`0 <= z <= 256` +MULRSHIFTR_VAR,DIV_BASE,#A9A5,arithm_div,A9A5,MULRSHIFTR,x y z - round(x*y/2^z),26,`0 <= z <= 256` +MULRSHIFTC_VAR,DIV_BASE,#A9A6,arithm_div,A9A6,MULRSHIFTC,x y z - ceil(x*y/2^z),34,`0 <= z <= 256` +MULRSHIFT,DIV_BASE,#A9B4 tt:uint8,arithm_div,A9B4tt,[tt+1] MULRSHIFT#,x y - floor(x*y/2^(tt+1)),34, +MULRSHIFTR,DIV_BASE,#A9B5 tt:uint8,arithm_div,A9B5tt,[tt+1] MULRSHIFTR#,x y - round(x*y/2^(tt+1)),34, +MULRSHIFTC,DIV_BASE,#A9B6 tt:uint8,arithm_div,A9B6tt,[tt+1] MULRSHIFTC#,x y - ceil(x*y/2^(tt+1)),26, +LSHIFTDIV_VAR,DIV_BASE,#A9C4,arithm_div,A9C4,LSHIFTDIV,x y z - floor(2^z*x/y),26,`0 <= z <= 256` +LSHIFTDIVR_VAR,DIV_BASE,#A9C5,arithm_div,A9C5,LSHIFTDIVR,x y z - round(2^z*x/y),26,`0 <= z <= 256` +LSHIFTDIVC_VAR,DIV_BASE,#A9C6,arithm_div,A9C6,LSHIFTDIVC,x y z - ceil(2^z*x/y),34,`0 <= z <= 256` +LSHIFTDIV,DIV_BASE,#A9D4 tt:uint8,arithm_div,A9D4tt,[tt+1] LSHIFT#DIV,x y - floor(2^(tt+1)*x/y),34, +LSHIFTDIVR,DIV_BASE,#A9D5 tt:uint8,arithm_div,A9D5tt,[tt+1] LSHIFT#DIVR,x y - round(2^(tt+1)*x/y),34, +LSHIFTDIVC,DIV_BASE,#A9D6 tt:uint8,arithm_div,A9D6tt,[tt+1] LSHIFT#DIVC,x y - ceil(2^(tt+1)*x/y),26, +LSHIFT,,#AA cc:uint8,arithm_logical,AAcc,[cc+1] LSHIFT#,x - x*2^(cc+1),26,`0 <= cc <= 255` +RSHIFT,,#AB cc:uint8,arithm_logical,ABcc,[cc+1] RSHIFT#,x - floor(x/2^(cc+1)),18,`0 <= cc <= 255` +LSHIFT_VAR,,#AC,arithm_logical,AC,LSHIFT,x y - x*2^y,18,`0 <= y <= 1023` +RSHIFT_VAR,,#AD,arithm_logical,AD,RSHIFT,x y - floor(x/2^y),18,`0 <= y <= 1023` +POW2,,#AE,arithm_logical,AE,POW2,y - 2^y,18,"`0 <= y <= 1023` +Equivalent to `ONE` `SWAP` `LSHIFT`." +AND,,#B0,arithm_logical,B0,AND,x y - x&y,18,"Bitwise and of two signed integers `x` and `y`, sign-extended to infinity." +OR,,#B1,arithm_logical,B1,OR,x y - x|y,18,Bitwise or of two integers. +XOR,,#B2,arithm_logical,B2,XOR,x y - x xor y,18,Bitwise xor of two integers. +NOT,,#B3,arithm_logical,B3,NOT,x - ~x,26,Bitwise not of an integer. +FITS,,#B4 cc:uint8,arithm_logical,B4cc,[cc+1] FITS,x - x,26/76,"Checks whether `x` is a `cc+1`-bit signed integer for `0 <= cc <= 255` (i.e., whether `-2^cc <= x < 2^cc`). +If not, either triggers an integer overflow exception, or replaces `x` with a `NaN` (quiet version)." +CHKBOOL,FITS,#B400,arithm_logical,B400,CHKBOOL,x - x,26/76,"Checks whether `x` is a “boolean value'' (i.e., either 0 or -1)." +UFITS,,#B5 cc:uint8,arithm_logical,B5cc,[cc+1] UFITS,x - x,26/76,"Checks whether `x` is a `cc+1`-bit unsigned integer for `0 <= cc <= 255` (i.e., whether `0 <= x < 2^(cc+1)`)." +CHKBIT,UFITS,#B500,arithm_logical,B500,CHKBIT,x - x,26/76,"Checks whether `x` is a binary digit (i.e., zero or one)." +FITSX,,#B600,arithm_logical,B600,FITSX,x c - x,26/76,Checks whether `x` is a `c`-bit signed integer for `0 <= c <= 1023`. +UFITSX,,#B601,arithm_logical,B601,UFITSX,x c - x,26/76,Checks whether `x` is a `c`-bit unsigned integer for `0 <= c <= 1023`. +BITSIZE,,#B602,arithm_logical,B602,BITSIZE,x - c,26,Computes smallest `c >= 0` such that `x` fits into a `c`-bit signed integer (`-2^(c-1) <= c < 2^(c-1)`). +UBITSIZE,,#B603,arithm_logical,B603,UBITSIZE,x - c,26,"Computes smallest `c >= 0` such that `x` fits into a `c`-bit unsigned integer (`0 <= x < 2^c`), or throws a range check exception." +MIN,,#B608,arithm_logical,B608,MIN,x y - x or y,26,Computes the minimum of two integers `x` and `y`. +MAX,,#B609,arithm_logical,B609,MAX,x y - x or y,26,Computes the maximum of two integers `x` and `y`. +MINMAX,,#B60A,arithm_logical,B60A,"MINMAX +INTSORT2",x y - x y or y x,26,Sorts two integers. Quiet version of this operation returns two `NaN`s if any of the arguments are `NaN`s. +ABS,,#B60B,arithm_logical,B60B,ABS,x - |x|,26,Computes the absolute value of an integer `x`. +QADD,,#B7A0,arithm_quiet,B7A0,QADD,x y - x+y,26, +QSUB,,#B7A1,arithm_quiet,B7A1,QSUB,x y - x-y,26, +QSUBR,,#B7A2,arithm_quiet,B7A2,QSUBR,x y - y-x,26, +QNEGATE,,#B7A3,arithm_quiet,B7A3,QNEGATE,x - -x,26, +QINC,,#B7A4,arithm_quiet,B7A4,QINC,x - x+1,26, +QDEC,,#B7A5,arithm_quiet,B7A5,QDEC,x - x-1,26, +QMUL,,#B7A8,arithm_quiet,B7A8,QMUL,x y - x*y,26, +QDIV,,#B7A904,arithm_quiet,B7A904,QDIV,x y - q,34,Division returns `NaN` if `y=0`. +QDIVR,,#B7A905,arithm_quiet,B7A905,QDIVR,x y - q’,34, +QDIVC,,#B7A906,arithm_quiet,B7A906,QDIVC,x y - q'',34, +QMOD,,#B7A908,arithm_quiet,B7A908,QMOD,x y - r,34, +QDIVMOD,,#B7A90C,arithm_quiet,B7A90C,QDIVMOD,x y - q r,34, +QDIVMODR,,#B7A90D,arithm_quiet,B7A90D,QDIVMODR,x y - q' r',34, +QDIVMODC,,#B7A90E,arithm_quiet,B7A90E,QDIVMODC,x y - q'' r'',34, +QMULDIVR,,#B7A985,arithm_quiet,B7A985,QMULDIVR,x y z - q',34, +QMULDIVMOD,,#B7A98C,arithm_quiet,B7A98C,QMULDIVMOD,x y z - q r,34, +QLSHIFT,,#B7AC,arithm_quiet,B7AC,QLSHIFT,x y - x*2^y,26, +QRSHIFT,,#B7AD,arithm_quiet,B7AD,QRSHIFT,x y - floor(x/2^y),26, +QPOW2,,#B7AE,arithm_quiet,B7AE,QPOW2,y - 2^y,26, +QAND,,#B7B0,arithm_quiet,B7B0,QAND,x y - x&y,26, +QOR,,#B7B1,arithm_quiet,B7B1,QOR,x y - x|y,26, +QXOR,,#B7B2,arithm_quiet,B7B2,QXOR,x y - x xor y,26, +QNOT,,#B7B3,arithm_quiet,B7B3,QNOT,x - ~x,26, +QFITS,,#B7B4 cc:uint8,arithm_quiet,B7B4cc,[cc+1] QFITS,x - x,34,"Replaces `x` with a `NaN` if x is not a `cc+1`-bit signed integer, leaves it intact otherwise." +QUFITS,,#B7B5 cc:uint8,arithm_quiet,B7B5cc,[cc+1] QUFITS,x - x,34,"Replaces `x` with a `NaN` if x is not a `cc+1`-bit unsigned integer, leaves it intact otherwise." +QFITSX,,#B7B600,arithm_quiet,B7B600,QFITSX,x c - x,34,"Replaces `x` with a `NaN` if x is not a c-bit signed integer, leaves it intact otherwise." +QUFITSX,,#B7B601,arithm_quiet,B7B601,QUFITSX,x c - x,34,"Replaces `x` with a `NaN` if x is not a c-bit unsigned integer, leaves it intact otherwise." +SGN,,#B8,compare_int,B8,SGN,x - sgn(x),18,"Computes the sign of an integer `x`: +`-1` if `x<0`, `0` if `x=0`, `1` if `x>0`." +LESS,,#B9,compare_int,B9,LESS,x y - xy,18, +NEQ,,#BD,compare_int,BD,NEQ,x y - x!=y,18,Equivalent to `EQUAL` `NOT`. +GEQ,,#BE,compare_int,BE,GEQ,x y - x>=y,18,Equivalent to `LESS` `NOT`. +CMP,,#BF,compare_int,BF,CMP,x y - sgn(x-y),18,"Computes the sign of `x-y`: +`-1` if `xy`. +No integer overflow can occur here unless `x` or `y` is a `NaN`." +EQINT,,#C0 yy:int8,compare_int,C0yy,[yy] EQINT,x - x=yy,26,"Returns `-1` if `x=yy`, `0` otherwise. +`-2^7 <= yy < 2^7`." +ISZERO,EQINT,#C000,compare_int,C000,ISZERO,x - x=0,26,Checks whether an integer is zero. Corresponds to Forth's `0=`. +LESSINT,,#C1 yy:int8,compare_int,C1yy,"[yy] LESSINT +[yy-1] LEQINT",x - xyy,26,"Returns `-1` if `x>yy`, `0` otherwise. +`-2^7 <= yy < 2^7`." +ISPOS,GTINT,#C200,compare_int,C200,ISPOS,x - x>0,26,Checks whether an integer is positive. Corresponds to Forth's `0>`. +ISNNEG,GTINT,#C2FF,compare_int,C2FF,ISNNEG,x - x >=0,26,Checks whether an integer is non-negative. +NEQINT,,#C3 yy:int8,compare_int,C3yy,[yy] NEQINT,x - x!=yy,26,"Returns `-1` if `x!=yy`, `0` otherwise. +`-2^7 <= yy < 2^7`." +ISNAN,,#C4,compare_int,C4,ISNAN,x - x=NaN,18,Checks whether `x` is a `NaN`. +CHKNAN,,#C5,compare_int,C5,CHKNAN,x - x,18/68,Throws an arithmetic overflow exception if `x` is a `NaN`. +SEMPTY,,#C700,compare_other,C700,SEMPTY,s - ?,26,"Checks whether a _Slice_ `s` is empty (i.e., contains no bits of data and no cell references)." +SDEMPTY,,#C701,compare_other,C701,SDEMPTY,s - ?,26,Checks whether _Slice_ `s` has no bits of data. +SREMPTY,,#C702,compare_other,C702,SREMPTY,s - ?,26,Checks whether _Slice_ `s` has no references. +SDFIRST,,#C703,compare_other,C703,SDFIRST,s - ?,26,Checks whether the first bit of _Slice_ `s` is a one. +SDLEXCMP,,#C704,compare_other,C704,SDLEXCMP,s s' - x,26,"Compares the data of `s` lexicographically with the data of `s'`, returning `-1`, 0, or 1 depending on the result." +SDEQ,,#C705,compare_other,C705,SDEQ,s s' - ?,26,"Checks whether the data parts of `s` and `s'` coincide, equivalent to `SDLEXCMP` `ISZERO`." +SDPFX,,#C708,compare_other,C708,SDPFX,s s' - ?,26,Checks whether `s` is a prefix of `s'`. +SDPFXREV,,#C709,compare_other,C709,SDPFXREV,s s' - ?,26,"Checks whether `s'` is a prefix of `s`, equivalent to `SWAP` `SDPFX`." +SDPPFX,,#C70A,compare_other,C70A,SDPPFX,s s' - ?,26,"Checks whether `s` is a proper prefix of `s'` (i.e., a prefix distinct from `s'`)." +SDPPFXREV,,#C70B,compare_other,C70B,SDPPFXREV,s s' - ?,26,Checks whether `s'` is a proper prefix of `s`. +SDSFX,,#C70C,compare_other,C70C,SDSFX,s s' - ?,26,Checks whether `s` is a suffix of `s'`. +SDSFXREV,,#C70D,compare_other,C70D,SDSFXREV,s s' - ?,26,Checks whether `s'` is a suffix of `s`. +SDPSFX,,#C70E,compare_other,C70E,SDPSFX,s s' - ?,26,Checks whether `s` is a proper suffix of `s'`. +SDPSFXREV,,#C70F,compare_other,C70F,SDPSFXREV,s s' - ?,26,Checks whether `s'` is a proper suffix of `s`. +SDCNTLEAD0,,#C710,compare_other,C710,SDCNTLEAD0,s - n,26,Returns the number of leading zeroes in `s`. +SDCNTLEAD1,,#C711,compare_other,C711,SDCNTLEAD1,s - n,26,Returns the number of leading ones in `s`. +SDCNTTRAIL0,,#C712,compare_other,C712,SDCNTTRAIL0,s - n,26,Returns the number of trailing zeroes in `s`. +SDCNTTRAIL1,,#C713,compare_other,C713,SDCNTTRAIL1,s - n,26,Returns the number of trailing ones in `s`. +NEWC,,#C8,cell_build,C8,NEWC,- b,18,Creates a new empty _Builder_. +ENDC,,#C9,cell_build,C9,ENDC,b - c,518,Converts a _Builder_ into an ordinary _Cell_. +STI,,#CA cc:uint8,cell_build,CAcc,[cc+1] STI,x b - b',26,"Stores a signed `cc+1`-bit integer `x` into _Builder_ `b` for `0 <= cc <= 255`, throws a range check exception if `x` does not fit into `cc+1` bits." +STU,,#CB cc:uint8,cell_build,CBcc,[cc+1] STU,x b - b',26,Stores an unsigned `cc+1`-bit integer `x` into _Builder_ `b`. In all other respects it is similar to `STI`. +STREF,,#CC,cell_build,CC,STREF,c b - b',18,Stores a reference to _Cell_ `c` into _Builder_ `b`. +STBREFR,,#CD,cell_build,CD,"STBREFR +ENDCST",b b'' - b,518,Equivalent to `ENDC` `SWAP` `STREF`. +STSLICE,,#CE,cell_build,CE,STSLICE,s b - b',18,Stores _Slice_ `s` into _Builder_ `b`. +STIX,,#CF00,cell_build,CF00,STIX,x b l - b',26,Stores a signed `l`-bit integer `x` into `b` for `0 <= l <= 257`. +STUX,,#CF01,cell_build,CF01,STUX,x b l - b',26,Stores an unsigned `l`-bit integer `x` into `b` for `0 <= l <= 256`. +STIXR,,#CF02,cell_build,CF02,STIXR,b x l - b',26,"Similar to `STIX`, but with arguments in a different order." +STUXR,,#CF03,cell_build,CF03,STUXR,b x l - b',26,"Similar to `STUX`, but with arguments in a different order." +STIXQ,,#CF04,cell_build,CF04,STIXQ,x b l - x b f or b' 0,26,"A quiet version of `STIX`. If there is no space in `b`, sets `b'=b` and `f=-1`. +If `x` does not fit into `l` bits, sets `b'=b` and `f=1`. +If the operation succeeds, `b'` is the new _Builder_ and `f=0`. +However, `0 <= l <= 257`, with a range check exception if this is not so." +STUXQ,,#CF05,cell_build,CF05,STUXQ,x b l - x b f or b' 0,26,A quiet version of `STUX`. +STIXRQ,,#CF06,cell_build,CF06,STIXRQ,b x l - b x f or b' 0,26,A quiet version of `STIXR`. +STUXRQ,,#CF07,cell_build,CF07,STUXRQ,b x l - b x f or b' 0,26,A quiet version of `STUXR`. +STI_ALT,,#CF08 cc:uint8,cell_build,CF08cc,[cc+1] STI_l,x b - b',34,A longer version of `[cc+1] STI`. +STU_ALT,,#CF09 cc:uint8,cell_build,CF09cc,[cc+1] STU_l,x b - b',34,A longer version of `[cc+1] STU`. +STIR,,#CF0A cc:uint8,cell_build,CF0Acc,[cc+1] STIR,b x - b',34,Equivalent to `SWAP` `[cc+1] STI`. +STUR,,#CF0B cc:uint8,cell_build,CF0Bcc,[cc+1] STUR,b x - b',34,Equivalent to `SWAP` `[cc+1] STU`. +STIQ,,#CF0C cc:uint8,cell_build,CF0Ccc,[cc+1] STIQ,x b - x b f or b' 0,34,A quiet version of `STI`. +STUQ,,#CF0D cc:uint8,cell_build,CF0Dcc,[cc+1] STUQ,x b - x b f or b' 0,34,A quiet version of `STU`. +STIRQ,,#CF0E cc:uint8,cell_build,CF0Ecc,[cc+1] STIRQ,b x - b x f or b' 0,34,A quiet version of `STIR`. +STURQ,,#CF0F cc:uint8,cell_build,CF0Fcc,[cc+1] STURQ,b x - b x f or b' 0,34,A quiet version of `STUR`. +STREF_ALT,,#CF10,cell_build,CF10,STREF_l,c b - b',26,A longer version of `STREF`. +STBREF,,#CF11,cell_build,CF11,STBREF,b' b - b'',526,Equivalent to `SWAP` `STBREFR`. +STSLICE_ALT,,#CF12,cell_build,CF12,STSLICE_l,s b - b',26,A longer version of `STSLICE`. +STB,,#CF13,cell_build,CF13,STB,b' b - b'',26,Appends all data from _Builder_ `b'` to _Builder_ `b`. +STREFR,,#CF14,cell_build,CF14,STREFR,b c - b',26,Equivalent to `SWAP` `STREF`. +STBREFR_ALT,,#CF15,cell_build,CF15,STBREFR_l,b b' - b'',526,A longer encoding of `STBREFR`. +STSLICER,,#CF16,cell_build,CF16,STSLICER,b s - b',26,Equivalent to `SWAP` `STSLICE`. +STBR,,#CF17,cell_build,CF17,"STBR +BCONCAT",b b' - b'',26,"Concatenates two builders. +Equivalent to `SWAP` `STB`." +STREFQ,,#CF18,cell_build,CF18,STREFQ,c b - c b -1 or b' 0,26,Quiet version of `STREF`. +STBREFQ,,#CF19,cell_build,CF19,STBREFQ,b' b - b' b -1 or b'' 0,526,Quiet version of `STBREF`. +STSLICEQ,,#CF1A,cell_build,CF1A,STSLICEQ,s b - s b -1 or b' 0,26,Quiet version of `STSLICE`. +STBQ,,#CF1B,cell_build,CF1B,STBQ,b' b - b' b -1 or b'' 0,26,Quiet version of `STB`. +STREFRQ,,#CF1C,cell_build,CF1C,STREFRQ,b c - b c -1 or b' 0,26,Quiet version of `STREFR`. +STBREFRQ,,#CF1D,cell_build,CF1D,STBREFRQ,b b' - b b' -1 or b'' 0,526,Quiet version of `STBREFR`. +STSLICERQ,,#CF1E,cell_build,CF1E,STSLICERQ,b s - b s -1 or b'' 0,26,Quiet version of `STSLICER`. +STBRQ,,#CF1F,cell_build,CF1F,"STBRQ +BCONCATQ",b b' - b b' -1 or b'' 0,26,Quiet version of `STBR`. +STREFCONST,,#CF20 c:^Cell,cell_build,CF20,[ref] STREFCONST,b - b’,26,Equivalent to `PUSHREF` `STREFR`. +STREF2CONST,,#CF21 c1:^Cell c2:^Cell,cell_build,CF21,[ref] [ref] STREF2CONST,b - b’,26,Equivalent to `STREFCONST` `STREFCONST`. +ENDXC,,#CF23,cell_build,CF23,,b x - c,526,"If `x!=0`, creates a _special_ or _exotic_ cell from _Builder_ `b`. +The type of the exotic cell must be stored in the first 8 bits of `b`. +If `x=0`, it is equivalent to `ENDC`. Otherwise some validity checks on the data and references of `b` are performed before creating the exotic cell." +STILE4,,#CF28,cell_build,CF28,STILE4,x b - b',26,Stores a little-endian signed 32-bit integer. +STULE4,,#CF29,cell_build,CF29,STULE4,x b - b',26,Stores a little-endian unsigned 32-bit integer. +STILE8,,#CF2A,cell_build,CF2A,STILE8,x b - b',26,Stores a little-endian signed 64-bit integer. +STULE8,,#CF2B,cell_build,CF2B,STULE8,x b - b',26,Stores a little-endian unsigned 64-bit integer. +BDEPTH,,#CF30,cell_build,CF30,BDEPTH,b - x,26,"Returns the depth of _Builder_ `b`. If no cell references are stored in `b`, then `x=0`; otherwise `x` is one plus the maximum of depths of cells referred to from `b`." +BBITS,,#CF31,cell_build,CF31,BBITS,b - x,26,Returns the number of data bits already stored in _Builder_ `b`. +BREFS,,#CF32,cell_build,CF32,BREFS,b - y,26,Returns the number of cell references already stored in `b`. +BBITREFS,,#CF33,cell_build,CF33,BBITREFS,b - x y,26,Returns the numbers of both data bits and cell references in `b`. +BREMBITS,,#CF35,cell_build,CF35,BREMBITS,b - x',26,Returns the number of data bits that can still be stored in `b`. +BREMREFS,,#CF36,cell_build,CF36,BREMREFS,b - y',26,Returns the number of references that can still be stored in `b`. +BREMBITREFS,,#CF37,cell_build,CF37,BREMBITREFS,b - x' y',26,Returns the numbers of both data bits and references that can still be stored in `b`. +BCHKBITS,,#CF38 cc:uint8,cell_build,CF38cc,[cc+1] BCHKBITS#,b -,34/84,"Checks whether `cc+1` bits can be stored into `b`, where `0 <= cc <= 255`." +BCHKBITS_VAR,,#CF39,cell_build,CF39,BCHKBITS,b x - ,26/76,"Checks whether `x` bits can be stored into `b`, `0 <= x <= 1023`. If there is no space for `x` more bits in `b`, or if `x` is not within the range `0...1023`, throws an exception." +BCHKREFS,,#CF3A,cell_build,CF3A,BCHKREFS,b y - ,26/76,"Checks whether `y` references can be stored into `b`, `0 <= y <= 7`." +BCHKBITREFS,,#CF3B,cell_build,CF3B,BCHKBITREFS,b x y - ,26/76,"Checks whether `x` bits and `y` references can be stored into `b`, `0 <= x <= 1023`, `0 <= y <= 7`." +BCHKBITSQ,,#CF3C cc:uint8,cell_build,CF3Ccc,[cc+1] BCHKBITSQ#,b - ?,34,"Checks whether `cc+1` bits can be stored into `b`, where `0 <= cc <= 255`." +BCHKBITSQ_VAR,,#CF3D,cell_build,CF3D,BCHKBITSQ,b x - ?,26,"Checks whether `x` bits can be stored into `b`, `0 <= x <= 1023`." +BCHKREFSQ,,#CF3E,cell_build,CF3E,BCHKREFSQ,b y - ?,26,"Checks whether `y` references can be stored into `b`, `0 <= y <= 7`." +BCHKBITREFSQ,,#CF3F,cell_build,CF3F,BCHKBITREFSQ,b x y - ?,26,"Checks whether `x` bits and `y` references can be stored into `b`, `0 <= x <= 1023`, `0 <= y <= 7`." +STZEROES,,#CF40,cell_build,CF40,STZEROES,b n - b',26,Stores `n` binary zeroes into _Builder_ `b`. +STONES,,#CF41,cell_build,CF41,STONES,b n - b',26,Stores `n` binary ones into _Builder_ `b`. +STSAME,,#CF42,cell_build,CF42,STSAME,b n x - b',26,Stores `n` binary `x`es (`0 <= x <= 1`) into _Builder_ `b`. +STSLICECONST,,#CFC0_ x:(## 2) y:(## 3) c:(x * ^Cell) sss:((8 * y + 2) * Bit),cell_build,CFC0_xysss,[slice] STSLICECONST,b - b',24,"Stores a constant subslice `sss`. +_Details:_ `sss` consists of `0 <= x <= 3` references and up to `8y+2` data bits, with `0 <= y <= 7`. Completion bit is assumed. +Note that the assembler can replace `STSLICECONST` with `PUSHSLICE` `STSLICER` if the slice is too big." +STZERO,STSLICECONST,#CF81,cell_build,CF81,STZERO,b - b',24,Stores one binary zero. +STONE,STSLICECONST,#CF83,cell_build,CF83,STONE,b - b',24,Stores one binary one. +CTOS,,#D0,cell_parse,D0,CTOS,c - s,118/43,"Converts a _Cell_ into a _Slice_. Notice that `c` must be either an ordinary cell, or an exotic cell which is automatically _loaded_ to yield an ordinary cell `c'`, converted into a _Slice_ afterwards." +ENDS,,#D1,cell_parse,D1,ENDS,s - ,18/68,"Removes a _Slice_ `s` from the stack, and throws an exception if it is not empty." +LDI,,#D2 cc:uint8,cell_parse,D2cc,[cc+1] LDI,s - x s',26,"Loads (i.e., parses) a signed `cc+1`-bit integer `x` from _Slice_ `s`, and returns the remainder of `s` as `s'`." +LDU,,#D3 cc:uint8,cell_parse,D3cc,[cc+1] LDU,s - x s',26,Loads an unsigned `cc+1`-bit integer `x` from _Slice_ `s`. +LDREF,,#D4,cell_parse,D4,LDREF,s - c s',18,Loads a cell reference `c` from `s`. +LDREFRTOS,,#D5,cell_parse,D5,LDREFRTOS,s - s' s'',118/43,Equivalent to `LDREF` `SWAP` `CTOS`. +LDSLICE,,#D6 cc:uint8,cell_parse,D6cc,[cc+1] LDSLICE,s - s'' s',26,Cuts the next `cc+1` bits of `s` into a separate _Slice_ `s''`. +LDIX,,#D700,cell_parse,D700,LDIX,s l - x s',26,"Loads a signed `l`-bit (`0 <= l <= 257`) integer `x` from _Slice_ `s`, and returns the remainder of `s` as `s'`." +LDUX,,#D701,cell_parse,D701,LDUX,s l - x s',26,"Loads an unsigned `l`-bit integer `x` from (the first `l` bits of) `s`, with `0 <= l <= 256`." +PLDIX,,#D702,cell_parse,D702,PLDIX,s l - x,26,"Preloads a signed `l`-bit integer from _Slice_ `s`, for `0 <= l <= 257`." +PLDUX,,#D703,cell_parse,D703,PLDUX,s l - x,26,"Preloads an unsigned `l`-bit integer from `s`, for `0 <= l <= 256`." +LDIXQ,,#D704,cell_parse,D704,LDIXQ,s l - x s' -1 or s 0,26,"Quiet version of `LDIX`: loads a signed `l`-bit integer from `s` similarly to `LDIX`, but returns a success flag, equal to `-1` on success or to `0` on failure (if `s` does not have `l` bits), instead of throwing a cell underflow exception." +LDUXQ,,#D705,cell_parse,D705,LDUXQ,s l - x s' -1 or s 0,26,Quiet version of `LDUX`. +PLDIXQ,,#D706,cell_parse,D706,PLDIXQ,s l - x -1 or 0,26,Quiet version of `PLDIX`. +PLDUXQ,,#D707,cell_parse,D707,PLDUXQ,s l - x -1 or 0,26,Quiet version of `PLDUX`. +LDI_ALT,,#D708 cc:uint8,cell_parse,D708cc,[cc+1] LDI_l,s - x s',34,A longer encoding for `LDI`. +LDU_ALT,,#D709 cc:uint8,cell_parse,D709cc,[cc+1] LDU_l,s - x s',34,A longer encoding for `LDU`. +PLDI,,#D70A cc:uint8,cell_parse,D70Acc,[cc+1] PLDI,s - x,34,Preloads a signed `cc+1`-bit integer from _Slice_ `s`. +PLDU,,#D70B cc:uint8,cell_parse,D70Bcc,[cc+1] PLDU,s - x,34,Preloads an unsigned `cc+1`-bit integer from `s`. +LDIQ,,#D70C cc:uint8,cell_parse,D70Ccc,[cc+1] LDIQ,s - x s' -1 or s 0,34,A quiet version of `LDI`. +LDUQ,,#D70D cc:uint8,cell_parse,D70Dcc,[cc+1] LDUQ,s - x s' -1 or s 0,34,A quiet version of `LDU`. +PLDIQ,,#D70E cc:uint8,cell_parse,D70Ecc,[cc+1] PLDIQ,s - x -1 or 0,34,A quiet version of `PLDI`. +PLDUQ,,#D70F cc:uint8,cell_parse,D70Fcc,[cc+1] PLDUQ,s - x -1 or 0,34,A quiet version of `PLDU`. +PLDUZ,,#D714_ c:uint3,cell_parse,D714_c,[32(c+1)] PLDUZ,s - s x,26,"Preloads the first `32(c+1)` bits of _Slice_ `s` into an unsigned integer `x`, for `0 <= c <= 7`. If `s` is shorter than necessary, missing bits are assumed to be zero. This operation is intended to be used along with `IFBITJMP` and similar instructions." +LDSLICEX,,#D718,cell_parse,D718,LDSLICEX,s l - s'' s',26,"Loads the first `0 <= l <= 1023` bits from _Slice_ `s` into a separate _Slice_ `s''`, returning the remainder of `s` as `s'`." +PLDSLICEX,,#D719,cell_parse,D719,PLDSLICEX,s l - s'',26,Returns the first `0 <= l <= 1023` bits of `s` as `s''`. +LDSLICEXQ,,#D71A,cell_parse,D71A,LDSLICEXQ,s l - s'' s' -1 or s 0,26,A quiet version of `LDSLICEX`. +PLDSLICEXQ,,#D71B,cell_parse,D71B,PLDSLICEXQ,s l - s' -1 or 0,26,A quiet version of `LDSLICEXQ`. +LDSLICE_ALT,,#D71C cc:uint8,cell_parse,D71Ccc,[cc+1] LDSLICE_l,s - s'' s',34,A longer encoding for `LDSLICE`. +PLDSLICE,,#D71D cc:uint8,cell_parse,D71Dcc,[cc+1] PLDSLICE,s - s'',34,Returns the first `0 < cc+1 <= 256` bits of `s` as `s''`. +LDSLICEQ,,#D71E cc:uint8,cell_parse,D71Ecc,[cc+1] LDSLICEQ,s - s'' s' -1 or s 0,34,A quiet version of `LDSLICE`. +PLDSLICEQ,,#D71F cc:uint8,cell_parse,D71Fcc,[cc+1] PLDSLICEQ,s - s'' -1 or 0,34,A quiet version of `PLDSLICE`. +SDCUTFIRST,,#D720,cell_parse,D720,SDCUTFIRST,s l - s',26,Returns the first `0 <= l <= 1023` bits of `s`. It is equivalent to `PLDSLICEX`. +SDSKIPFIRST,,#D721,cell_parse,D721,SDSKIPFIRST,s l - s',26,Returns all but the first `0 <= l <= 1023` bits of `s`. It is equivalent to `LDSLICEX` `NIP`. +SDCUTLAST,,#D722,cell_parse,D722,SDCUTLAST,s l - s',26,Returns the last `0 <= l <= 1023` bits of `s`. +SDSKIPLAST,,#D723,cell_parse,D723,SDSKIPLAST,s l - s',26,Returns all but the last `0 <= l <= 1023` bits of `s`. +SDSUBSTR,,#D724,cell_parse,D724,SDSUBSTR,s l l' - s',26,"Returns `0 <= l' <= 1023` bits of `s` starting from offset `0 <= l <= 1023`, thus extracting a bit substring out of the data of `s`." +SDBEGINSX,,#D726,cell_parse,D726,SDBEGINSX,s s' - s'',26,"Checks whether `s` begins with (the data bits of) `s'`, and removes `s'` from `s` on success. On failure throws a cell deserialization exception. Primitive `SDPFXREV` can be considered a quiet version of `SDBEGINSX`." +SDBEGINSXQ,,#D727,cell_parse,D727,SDBEGINSXQ,s s' - s'' -1 or s 0,26,A quiet version of `SDBEGINSX`. +SDBEGINS,,#D72A_ x:(## 7) sss:((8 * x + 3) * Bit),cell_parse,D72A_xsss,[slice] SDBEGINS,s - s'',31,"Checks whether `s` begins with constant bitstring `sss` of length `8x+3` (with continuation bit assumed), where `0 <= x <= 127`, and removes `sss` from `s` on success." +SDBEGINSQ,,#D72E_ x:(## 7) sss:((8 * x + 3) * Bit),cell_parse,D72E_xsss,[slice] SDBEGINSQ,s - s'' -1 or s 0,31,A quiet version of `SDBEGINS`. +SCUTFIRST,,#D730,cell_parse,D730,SCUTFIRST,s l r - s',26,Returns the first `0 <= l <= 1023` bits and first `0 <= r <= 4` references of `s`. +SSKIPFIRST,,#D731,cell_parse,D731,SSKIPFIRST,s l r - s',26,Returns all but the first `l` bits of `s` and `r` references of `s`. +SCUTLAST,,#D732,cell_parse,D732,SCUTLAST,s l r - s',26,Returns the last `0 <= l <= 1023` data bits and last `0 <= r <= 4` references of `s`. +SSKIPLAST,,#D733,cell_parse,D733,SSKIPLAST,s l r - s',26,Returns all but the last `l` bits of `s` and `r` references of `s`. +SUBSLICE,,#D734,cell_parse,D734,SUBSLICE,s l r l' r' - s',26,"Returns `0 <= l' <= 1023` bits and `0 <= r' <= 4` references from _Slice_ `s`, after skipping the first `0 <= l <= 1023` bits and first `0 <= r <= 4` references." +SPLIT,,#D736,cell_parse,D736,SPLIT,s l r - s' s'',26,"Splits the first `0 <= l <= 1023` data bits and first `0 <= r <= 4` references from `s` into `s'`, returning the remainder of `s` as `s''`." +SPLITQ,,#D737,cell_parse,D737,SPLITQ,s l r - s' s'' -1 or s 0,26,A quiet version of `SPLIT`. +XCTOS,,#D739,cell_parse,D739,,c - s ?,,"Transforms an ordinary or exotic cell into a _Slice_, as if it were an ordinary cell. A flag is returned indicating whether `c` is exotic. If that be the case, its type can later be deserialized from the first eight bits of `s`." +XLOAD,,#D73A,cell_parse,D73A,,c - c',,"Loads an exotic cell `c` and returns an ordinary cell `c'`. If `c` is already ordinary, does nothing. If `c` cannot be loaded, throws an exception." +XLOADQ,,#D73B,cell_parse,D73B,,c - c' -1 or c 0,,"Loads an exotic cell `c` and returns an ordinary cell `c'`. If `c` is already ordinary, does nothing. If `c` cannot be loaded, returns 0." +SCHKBITS,,#D741,cell_parse,D741,SCHKBITS,s l - ,26/76,"Checks whether there are at least `l` data bits in _Slice_ `s`. If this is not the case, throws a cell deserialisation (i.e., cell underflow) exception." +SCHKREFS,,#D742,cell_parse,D742,SCHKREFS,s r - ,26/76,Checks whether there are at least `r` references in _Slice_ `s`. +SCHKBITREFS,,#D743,cell_parse,D743,SCHKBITREFS,s l r - ,26/76,Checks whether there are at least `l` data bits and `r` references in _Slice_ `s`. +SCHKBITSQ,,#D745,cell_parse,D745,SCHKBITSQ,s l - ?,26,Checks whether there are at least `l` data bits in _Slice_ `s`. +SCHKREFSQ,,#D746,cell_parse,D746,SCHKREFSQ,s r - ?,26,Checks whether there are at least `r` references in _Slice_ `s`. +SCHKBITREFSQ,,#D747,cell_parse,D747,SCHKBITREFSQ,s l r - ?,26,Checks whether there are at least `l` data bits and `r` references in _Slice_ `s`. +PLDREFVAR,,#D748,cell_parse,D748,PLDREFVAR,s n - c,26,Returns the `n`-th cell reference of _Slice_ `s` for `0 <= n <= 3`. +SBITS,,#D749,cell_parse,D749,SBITS,s - l,26,Returns the number of data bits in _Slice_ `s`. +SREFS,,#D74A,cell_parse,D74A,SREFS,s - r,26,Returns the number of references in _Slice_ `s`. +SBITREFS,,#D74B,cell_parse,D74B,SBITREFS,s - l r,26,Returns both the number of data bits and the number of references in `s`. +PLDREFIDX,,#D74E_ n:uint2,cell_parse,D74E_n,[n] PLDREFIDX,s - c,26,"Returns the `n`-th cell reference of _Slice_ `s`, where `0 <= n <= 3`." +PLDREF,PLDREFIDX,#D74C,cell_parse,D74C,PLDREF,s - c,26,Preloads the first cell reference of a _Slice_. +LDILE4,,#D750,cell_parse,D750,LDILE4,s - x s',26,Loads a little-endian signed 32-bit integer. +LDULE4,,#D751,cell_parse,D751,LDULE4,s - x s',26,Loads a little-endian unsigned 32-bit integer. +LDILE8,,#D752,cell_parse,D752,LDILE8,s - x s',26,Loads a little-endian signed 64-bit integer. +LDULE8,,#D753,cell_parse,D753,LDULE8,s - x s',26,Loads a little-endian unsigned 64-bit integer. +PLDILE4,,#D754,cell_parse,D754,PLDILE4,s - x,26,Preloads a little-endian signed 32-bit integer. +PLDULE4,,#D755,cell_parse,D755,PLDULE4,s - x,26,Preloads a little-endian unsigned 32-bit integer. +PLDILE8,,#D756,cell_parse,D756,PLDILE8,s - x,26,Preloads a little-endian signed 64-bit integer. +PLDULE8,,#D757,cell_parse,D757,PLDULE8,s - x,26,Preloads a little-endian unsigned 64-bit integer. +LDILE4Q,,#D758,cell_parse,D758,LDILE4Q,s - x s' -1 or s 0,26,Quietly loads a little-endian signed 32-bit integer. +LDULE4Q,,#D759,cell_parse,D759,LDULE4Q,s - x s' -1 or s 0,26,Quietly loads a little-endian unsigned 32-bit integer. +LDILE8Q,,#D75A,cell_parse,D75A,LDILE8Q,s - x s' -1 or s 0,26,Quietly loads a little-endian signed 64-bit integer. +LDULE8Q,,#D75B,cell_parse,D75B,LDULE8Q,s - x s' -1 or s 0,26,Quietly loads a little-endian unsigned 64-bit integer. +PLDILE4Q,,#D75C,cell_parse,D75C,PLDILE4Q,s - x -1 or 0,26,Quietly preloads a little-endian signed 32-bit integer. +PLDULE4Q,,#D75D,cell_parse,D75D,PLDULE4Q,s - x -1 or 0,26,Quietly preloads a little-endian unsigned 32-bit integer. +PLDILE8Q,,#D75E,cell_parse,D75E,PLDILE8Q,s - x -1 or 0,26,Quietly preloads a little-endian signed 64-bit integer. +PLDULE8Q,,#D75F,cell_parse,D75F,PLDULE8Q,s - x -1 or 0,26,Quietly preloads a little-endian unsigned 64-bit integer. +LDZEROES,,#D760,cell_parse,D760,LDZEROES,s - n s',26,"Returns the count `n` of leading zero bits in `s`, and removes these bits from `s`." +LDONES,,#D761,cell_parse,D761,LDONES,s - n s',26,"Returns the count `n` of leading one bits in `s`, and removes these bits from `s`." +LDSAME,,#D762,cell_parse,D762,LDSAME,s x - n s',26,"Returns the count `n` of leading bits equal to `0 <= x <= 1` in `s`, and removes these bits from `s`." +SDEPTH,,#D764,cell_parse,D764,SDEPTH,s - x,26,"Returns the depth of _Slice_ `s`. If `s` has no references, then `x=0`; otherwise `x` is one plus the maximum of depths of cells referred to from `s`." +CDEPTH,,#D765,cell_parse,D765,CDEPTH,c - x,26,"Returns the depth of _Cell_ `c`. If `c` has no references, then `x=0`; otherwise `x` is one plus the maximum of depths of cells referred to from `c`. If `c` is a _Null_ instead of a _Cell_, returns zero." +EXECUTE,,#D8,cont_basic,D8,"EXECUTE +CALLX",c - ,18,"_Calls_, or _executes_, continuation `c`." +JMPX,,#D9,cont_basic,D9,JMPX,c - ,18,"_Jumps_, or transfers control, to continuation `c`. +The remainder of the previous current continuation `cc` is discarded." +CALLXARGS,,#DA p:uint4 r:uint4,cont_basic,DApr,[p] [r] CALLXARGS,c - ,26,"_Calls_ continuation `c` with `p` parameters and expecting `r` return values +`0 <= p <= 15`, `0 <= r <= 15`" +CALLXARGS_VAR,,#DB0 p:uint4,cont_basic,DB0p,[p] -1 CALLXARGS,c - ,26,"_Calls_ continuation `c` with `0 <= p <= 15` parameters, expecting an arbitrary number of return values." +JMPXARGS,,#DB1 p:uint4,cont_basic,DB1p,[p] JMPXARGS,c - ,26,"_Jumps_ to continuation `c`, passing only the top `0 <= p <= 15` values from the current stack to it (the remainder of the current stack is discarded)." +RETARGS,,#DB2 r:uint4,cont_basic,DB2r,[r] RETARGS,,26,"_Returns_ to `c0`, with `0 <= r <= 15` return values taken from the current stack." +RET,,#DB30,cont_basic,DB30,"RET +RETTRUE",,26,"_Returns_ to the continuation at `c0`. The remainder of the current continuation `cc` is discarded. +Approximately equivalent to `c0 PUSHCTR` `JMPX`." +RETALT,,#DB31,cont_basic,DB31,"RETALT +RETFALSE",,26,"_Returns_ to the continuation at `c1`. +Approximately equivalent to `c1 PUSHCTR` `JMPX`." +BRANCH,,#DB32,cont_basic,DB32,"BRANCH +RETBOOL",f - ,26,"Performs `RETTRUE` if integer `f!=0`, or `RETFALSE` if `f=0`." +CALLCC,,#DB34,cont_basic,DB34,CALLCC,c - ,26,"_Call with current continuation_, transfers control to `c`, pushing the old value of `cc` into `c`'s stack (instead of discarding it or writing it into new `c0`)." +JMPXDATA,,#DB35,cont_basic,DB35,JMPXDATA,c - ,26,"Similar to `CALLCC`, but the remainder of the current continuation (the old value of `cc`) is converted into a _Slice_ before pushing it into the stack of `c`." +CALLCCARGS,,#DB36 p:uint4 r:uint4,cont_basic,DB36pr,[p] [r] CALLCCARGS,c - ,34,"Similar to `CALLXARGS`, but pushes the old value of `cc` (along with the top `0 <= p <= 15` values from the original stack) into the stack of newly-invoked continuation `c`, setting `cc.nargs` to `-1 <= r <= 14`." +CALLXVARARGS,,#DB38,cont_basic,DB38,CALLXVARARGS,c p r - ,26,"Similar to `CALLXARGS`, but takes `-1 <= p,r <= 254` from the stack. The next three operations also take `p` and `r` from the stack, both in the range `-1...254`." +RETVARARGS,,#DB39,cont_basic,DB39,RETVARARGS,p r - ,26,Similar to `RETARGS`. +JMPXVARARGS,,#DB3A,cont_basic,DB3A,JMPXVARARGS,c p r - ,26,Similar to `JMPXARGS`. +CALLCCVARARGS,,#DB3B,cont_basic,DB3B,CALLCCVARARGS,c p r - ,26,Similar to `CALLCCARGS`. +CALLREF,,#DB3C c:^Cell,cont_basic,DB3C,[ref] CALLREF,,126/51,Equivalent to `PUSHREFCONT` `CALLX`. +JMPREF,,#DB3D c:^Cell,cont_basic,DB3D,[ref] JMPREF,,126/51,Equivalent to `PUSHREFCONT` `JMPX`. +JMPREFDATA,,#DB3E c:^Cell,cont_basic,DB3E,[ref] JMPREFDATA,,126/51,Equivalent to `PUSHREFCONT` `JMPXDATA`. +RETDATA,,#DB3F,cont_basic,DB3F,RETDATA,,26,"Equivalent to `c0 PUSHCTR` `JMPXDATA`. In this way, the remainder of the current continuation is converted into a _Slice_ and returned to the caller." +IFRET,,#DC,cont_conditional,DC,"IFRET +IFNOT:",f - ,18,"Performs a `RET`, but only if integer `f` is non-zero. If `f` is a `NaN`, throws an integer overflow exception." +IFNOTRET,,#DD,cont_conditional,DD,"IFNOTRET +IF:",f - ,18,"Performs a `RET`, but only if integer `f` is zero." +IF,,#DE,cont_conditional,DE,IF,f c - ,18,"Performs `EXECUTE` for `c` (i.e., _executes_ `c`), but only if integer `f` is non-zero. Otherwise simply discards both values." +,,,cont_conditional,DE,"IF:<{ code }> +<{ code }>IF",f -,,Equivalent to `<{ code }> CONT` `IF`. +IFNOT,,#DF,cont_conditional,DF,IFNOT,f c - ,18,"Executes continuation `c`, but only if integer `f` is zero. Otherwise simply discards both values." +,,,cont_conditional,DF,"IFNOT:<{ code }> +<{ code }>IFNOT",f -,,Equivalent to `<{ code }> CONT` `IFNOT`. +IFJMP,,#E0,cont_conditional,E0,IFJMP,f c - ,18,"Jumps to `c` (similarly to `JMPX`), but only if `f` is non-zero." +,,,cont_conditional,E0,IFJMP:<{ code }>,f -,,Equivalent to `<{ code }> CONT` `IFJMP`. +IFNOTJMP,,#E1,cont_conditional,E1,IFNOTJMP,f c - ,18,"Jumps to `c` (similarly to `JMPX`), but only if `f` is zero." +,,,cont_conditional,E1,IFNOTJMP:<{ code }>,f -,,Equivalent to `<{ code }> CONT` `IFNOTJMP`. +IFELSE,,#E2,cont_conditional,E2,IFELSE,f c c' - ,18,"If integer `f` is non-zero, executes `c`, otherwise executes `c'`. Equivalent to `CONDSELCHK` `EXECUTE`." +,,,cont_conditional,E2,IF:<{ code1 }>ELSE<{ code2 }>,f -,,Equivalent to `<{ code1 }> CONT` `<{ code2 }> CONT` `IFELSE`. +IFREF,,#E300 c:^Cell,cont_conditional,E300,[ref] IFREF,f - ,26/126/51,"Equivalent to `PUSHREFCONT` `IF`, with the optimization that the cell reference is not actually loaded into a _Slice_ and then converted into an ordinary _Continuation_ if `f=0`. +Gas consumption of this primitive depends on whether `f=0` and whether the reference was loaded before. +Similar remarks apply other primitives that accept a continuation as a reference." +IFNOTREF,,#E301 c:^Cell,cont_conditional,E301,[ref] IFNOTREF,f - ,26/126/51,Equivalent to `PUSHREFCONT` `IFNOT`. +IFJMPREF,,#E302 c:^Cell,cont_conditional,E302,[ref] IFJMPREF,f - ,26/126/51,Equivalent to `PUSHREFCONT` `IFJMP`. +IFNOTJMPREF,,#E303 c:^Cell,cont_conditional,E303,[ref] IFNOTJMPREF,f - ,26/126/51,Equivalent to `PUSHREFCONT` `IFNOTJMP`. +CONDSEL,,#E304,cont_conditional,E304,CONDSEL,f x y - x or y,26,"If integer `f` is non-zero, returns `x`, otherwise returns `y`. Notice that no type checks are performed on `x` and `y`; as such, it is more like a conditional stack operation. Roughly equivalent to `ROT` `ISZERO` `INC` `ROLLX` `NIP`." +CONDSELCHK,,#E305,cont_conditional,E305,CONDSELCHK,f x y - x or y,26,"Same as `CONDSEL`, but first checks whether `x` and `y` have the same type." +IFRETALT,,#E308,cont_conditional,E308,IFRETALT,f -,26,Performs `RETALT` if integer `f!=0`. +IFNOTRETALT,,#E309,cont_conditional,E309,IFNOTRETALT,f -,26,Performs `RETALT` if integer `f=0`. +IFREFELSE,,#E30D c:^Cell,cont_conditional,E30D,[ref] IFREFELSE,f c -,26/126/51,"Equivalent to `PUSHREFCONT` `SWAP` `IFELSE`, with the optimization that the cell reference is not actually loaded into a _Slice_ and then converted into an ordinary _Continuation_ if `f=0`. Similar remarks apply to the next two primitives: cells are converted into continuations only when necessary." +IFELSEREF,,#E30E c:^Cell,cont_conditional,E30E,[ref] IFELSEREF,f c -,26/126/51,Equivalent to `PUSHREFCONT` `IFELSE`. +IFREFELSEREF,,#E30F c1:^Cell c2:^Cell,cont_conditional,E30F,[ref] [ref] IFREFELSEREF,f -,126/51,Equivalent to `PUSHREFCONT` `PUSHREFCONT` `IFELSE`. +IFBITJMP,,#E39_ n:uint5,cont_conditional,E39_n,[n] IFBITJMP,x c - x,26,"Checks whether bit `0 <= n <= 31` is set in integer `x`, and if so, performs `JMPX` to continuation `c`. Value `x` is left in the stack." +IFNBITJMP,,#E3B_ n:uint5,cont_conditional,E3B_n,[n] IFNBITJMP,x c - x,26,Jumps to `c` if bit `0 <= n <= 31` is not set in integer `x`. +IFBITJMPREF,,#E3D_ n:uint5 c:^Cell,cont_conditional,E3D_n,[ref] [n] IFBITJMPREF,x - x,126/51,Performs a `JMPREF` if bit `0 <= n <= 31` is set in integer `x`. +IFNBITJMPREF,,#E3F_ n:uint5 c:^Cell,cont_conditional,E3F_n,[ref] [n] IFNBITJMPREF,x - x,126/51,Performs a `JMPREF` if bit `0 <= n <= 31` is not set in integer `x`. +REPEAT,,#E4,cont_loops,E4,REPEAT,n c - ,18,"Executes continuation `c` `n` times, if integer `n` is non-negative. If `n>=2^31` or `n<-2^31`, generates a range check exception. +Notice that a `RET` inside the code of `c` works as a `continue`, not as a `break`. One should use either alternative (experimental) loops or alternative `RETALT` (along with a `SETEXITALT` before the loop) to `break` out of a loop." +,,,cont_loops,E4,"REPEAT:<{ code }> +<{ code }>REPEAT",n -,,Equivalent to `<{ code }> CONT` `REPEAT`. +REPEATEND,,#E5,cont_loops,E5,"REPEATEND +REPEAT:",n - ,18,"Similar to `REPEAT`, but it is applied to the current continuation `cc`." +UNTIL,,#E6,cont_loops,E6,UNTIL,c - ,18,"Executes continuation `c`, then pops an integer `x` from the resulting stack. If `x` is zero, performs another iteration of this loop. The actual implementation of this primitive involves an extraordinary continuation `ec_until` with its arguments set to the body of the loop (continuation `c`) and the original current continuation `cc`. This extraordinary continuation is then saved into the savelist of `c` as `c.c0` and the modified `c` is then executed. The other loop primitives are implemented similarly with the aid of suitable extraordinary continuations." +,,,cont_loops,E6,"UNTIL:<{ code }> +<{ code }>UNTIL",-,,Equivalent to `<{ code }> CONT` `UNTIL`. +UNTILEND,,#E7,cont_loops,E7,"UNTILEND +UNTIL:",-,18,"Similar to `UNTIL`, but executes the current continuation `cc` in a loop. When the loop exit condition is satisfied, performs a `RET`." +WHILE,,#E8,cont_loops,E8,WHILE,c' c - ,18,"Executes `c'` and pops an integer `x` from the resulting stack. If `x` is zero, exists the loop and transfers control to the original `cc`. If `x` is non-zero, executes `c`, and then begins a new iteration." +,,,cont_loops,E8,WHILE:<{ cond }>DO<{ code }>,-,,Equivalent to `<{ cond }> CONT` `<{ code }> CONT` `WHILE`. +WHILEEND,,#E9,cont_loops,E9,WHILEEND,c' - ,18,"Similar to `WHILE`, but uses the current continuation `cc` as the loop body." +AGAIN,,#EA,cont_loops,EA,AGAIN,c - ,18,"Similar to `REPEAT`, but executes `c` infinitely many times. A `RET` only begins a new iteration of the infinite loop, which can be exited only by an exception, or a `RETALT` (or an explicit `JMPX`)." +,,,cont_loops,EA,"AGAIN:<{ code }> +<{ code }>AGAIN",-,,Equivalent to `<{ code }> CONT` `AGAIN`. +AGAINEND,,#EB,cont_loops,EB,"AGAINEND +AGAIN:",-,18,"Similar to `AGAIN`, but performed with respect to the current continuation `cc`." +REPEATBRK,,#E314,cont_loops,E314,REPEATBRK,n c -,26,"Similar to `REPEAT`, but also sets `c1` to the original `cc` after saving the old value of `c1` into the savelist of the original `cc`. In this way `RETALT` could be used to break out of the loop body." +,,,cont_loops,E314,"REPEATBRK:<{ code }> +<{ code }>REPEATBRK",n -,,Equivalent to `<{ code }> CONT` `REPEATBRK`. +REPEATENDBRK,,#E315,cont_loops,E315,REPEATENDBRK,n -,26,"Similar to `REPEATEND`, but also sets `c1` to the original `c0` after saving the old value of `c1` into the savelist of the original `c0`. Equivalent to `SAMEALTSAVE` `REPEATEND`." +UNTILBRK,,#E316,cont_loops,E316,UNTILBRK,c -,26,"Similar to `UNTIL`, but also modifies `c1` in the same way as `REPEATBRK`." +,,,cont_loops,E316,UNTILBRK:<{ code }>,-,,Equivalent to `<{ code }> CONT` `UNTILBRK`. +UNTILENDBRK,,#E317,cont_loops,E317,"UNTILENDBRK +UNTILBRK:",-,26,Equivalent to `SAMEALTSAVE` `UNTILEND`. +WHILEBRK,,#E318,cont_loops,E318,WHILEBRK,c' c -,26,"Similar to `WHILE`, but also modifies `c1` in the same way as `REPEATBRK`." +,,,cont_loops,E318,WHILEBRK:<{ cond }>DO<{ code }>,-,,Equivalent to `<{ cond }> CONT` `<{ code }> CONT` `WHILEBRK`. +WHILEENDBRK,,#E319,cont_loops,E319,WHILEENDBRK,c -,26,Equivalent to `SAMEALTSAVE` `WHILEEND`. +AGAINBRK,,#E31A,cont_loops,E31A,AGAINBRK,c -,26,"Similar to `AGAIN`, but also modifies `c1` in the same way as `REPEATBRK`." +,,,cont_loops,E31A,AGAINBRK:<{ code }>,-,,Equivalent to `<{ code }> CONT` `AGAINBRK`. +AGAINENDBRK,,#E31B,cont_loops,E31B,"AGAINENDBRK +AGAINBRK:",-,26,Equivalent to `SAMEALTSAVE` `AGAINEND`. +SETCONTARGS_N,,#EC r:uint4 n:(#<= 14),cont_stack,ECrn,[r] [n] SETCONTARGS,x_1 x_2...x_r c - c',26+s”,"Similar to `[r] -1 SETCONTARGS`, but sets `c.nargs` to the final size of the stack of `c'` plus `n`. In other words, transforms `c` into a _closure_ or a _partially applied function_, with `0 <= n <= 14` arguments missing." +SETNUMARGS,SETCONTARGS_N,#EC0 n:(#<= 14),cont_stack,EC0n,[n] SETNUMARGS,c - c',26,"Sets `c.nargs` to `n` plus the current depth of `c`'s stack, where `0 <= n <= 14`. If `c.nargs` is already set to a non-negative value, does nothing." +SETCONTARGS,,#EC r:uint4 n:(## 4) {n = 15},cont_stack,ECrF,[r] -1 SETCONTARGS,x_1 x_2...x_r c - c',26+s”,"Pushes `0 <= r <= 15` values `x_1...x_r` into the stack of (a copy of) the continuation `c`, starting with `x_1`. If the final depth of `c`'s stack turns out to be greater than `c.nargs`, a stack overflow exception is generated." +RETURNARGS,,#ED0 p:uint4,cont_stack,ED0p,[p] RETURNARGS,-,26+s”,"Leaves only the top `0 <= p <= 15` values in the current stack (somewhat similarly to `ONLYTOPX`), with all the unused bottom values not discarded, but saved into continuation `c0` in the same way as `SETCONTARGS` does." +RETURNVARARGS,,#ED10,cont_stack,ED10,RETURNVARARGS,p -,26+s”,"Similar to `RETURNARGS`, but with Integer `0 <= p <= 255` taken from the stack." +SETCONTVARARGS,,#ED11,cont_stack,ED11,SETCONTVARARGS,x_1 x_2...x_r c r n - c',26+s”,"Similar to `SETCONTARGS`, but with `0 <= r <= 255` and `-1 <= n <= 255` taken from the stack." +SETNUMVARARGS,,#ED12,cont_stack,ED12,SETNUMVARARGS,c n - c',26,"`-1 <= n <= 255` +If `n=-1`, this operation does nothing (`c'=c`). +Otherwise its action is similar to `[n] SETNUMARGS`, but with `n` taken from the stack." +BLESS,,#ED1E,cont_create,ED1E,BLESS,s - c,26,"Transforms a _Slice_ `s` into a simple ordinary continuation `c`, with `c.code=s` and an empty stack and savelist." +BLESSVARARGS,,#ED1F,cont_create,ED1F,BLESSVARARGS,x_1...x_r s r n - c,26+s”,Equivalent to `ROT` `BLESS` `ROTREV` `SETCONTVARARGS`. +BLESSARGS,,#EE r:uint4 n:uint4,cont_create,EErn,[r] [n] BLESSARGS,x_1...x_r s - c,26,"`0 <= r <= 15`, `-1 <= n <= 14` +Equivalent to `BLESS` `[r] [n] SETCONTARGS`. +The value of `n` is represented inside the instruction by the 4-bit integer `n mod 16`." +BLESSNUMARGS,BLESSARGS,#EE0 n:uint4,cont_create,EE0n,[n] BLESSNUMARGS,s - c,26,"Also transforms a _Slice_ `s` into a _Continuation_ `c`, but sets `c.nargs` to `0 <= n <= 14`." +PUSHCTR,,#ED4 i:uint4,cont_registers,ED4i,"c[i] PUSHCTR +c[i] PUSH",- x,26,"Pushes the current value of control register `c(i)`. If the control register is not supported in the current codepage, or if it does not have a value, an exception is triggered." +PUSHROOT,PUSHCTR,#ED44,cont_registers,ED44,"c4 PUSHCTR +c4 PUSH",- x,26,"Pushes the “global data root'' cell reference, thus enabling access to persistent smart-contract data." +POPCTR,,#ED5 i:uint4,cont_registers,ED5i,"c[i] POPCTR +c[i] POP",x - ,26,"Pops a value `x` from the stack and stores it into control register `c(i)`, if supported in the current codepage. Notice that if a control register accepts only values of a specific type, a type-checking exception may occur." +POPROOT,POPCTR,#ED54,cont_registers,ED54,"c4 POPCTR +c4 POP",x -,26,"Sets the “global data root'' cell reference, thus allowing modification of persistent smart-contract data." +SETCONTCTR,,#ED6 i:uint4,cont_registers,ED6i,"c[i] SETCONT +c[i] SETCONTCTR",x c - c',26,"Stores `x` into the savelist of continuation `c` as `c(i)`, and returns the resulting continuation `c'`. Almost all operations with continuations may be expressed in terms of `SETCONTCTR`, `POPCTR`, and `PUSHCTR`." +SETRETCTR,,#ED7 i:uint4,cont_registers,ED7i,c[i] SETRETCTR,x - ,26,Equivalent to `c0 PUSHCTR` `c[i] SETCONTCTR` `c0 POPCTR`. +SETALTCTR,,#ED8 i:uint4,cont_registers,ED8i,c[i] SETALTCTR,x - ,26,Equivalent to `c1 PUSHCTR` `c[i] SETCONTCTR` `c0 POPCTR`. +POPSAVE,,#ED9 i:uint4,cont_registers,ED9i,"c[i] POPSAVE +c[i] POPCTRSAVE",x -,26,"Similar to `c[i] POPCTR`, but also saves the old value of `c[i]` into continuation `c0`. +Equivalent (up to exceptions) to `c[i] SAVECTR` `c[i] POPCTR`." +SAVE,,#EDA i:uint4,cont_registers,EDAi,"c[i] SAVE +c[i] SAVECTR",,26,"Saves the current value of `c(i)` into the savelist of continuation `c0`. If an entry for `c[i]` is already present in the savelist of `c0`, nothing is done. Equivalent to `c[i] PUSHCTR` `c[i] SETRETCTR`." +SAVEALT,,#EDB i:uint4,cont_registers,EDBi,"c[i] SAVEALT +c[i] SAVEALTCTR",,26,"Similar to `c[i] SAVE`, but saves the current value of `c[i]` into the savelist of `c1`, not `c0`." +SAVEBOTH,,#EDC i:uint4,cont_registers,EDCi,"c[i] SAVEBOTH +c[i] SAVEBOTHCTR",,26,Equivalent to `DUP` `c[i] SAVE` `c[i] SAVEALT`. +PUSHCTRX,,#EDE0,cont_registers,EDE0,PUSHCTRX,i - x,26,"Similar to `c[i] PUSHCTR`, but with `i`, `0 <= i <= 255`, taken from the stack. +Notice that this primitive is one of the few “exotic'' primitives, which are not polymorphic like stack manipulation primitives, and at the same time do not have well-defined types of parameters and return values, because the type of `x` depends on `i`." +POPCTRX,,#EDE1,cont_registers,EDE1,POPCTRX,x i - ,26,"Similar to `c[i] POPCTR`, but with `0 <= i <= 255` from the stack." +SETCONTCTRX,,#EDE2,cont_registers,EDE2,SETCONTCTRX,x c i - c',26,"Similar to `c[i] SETCONTCTR`, but with `0 <= i <= 255` from the stack." +COMPOS,,#EDF0,cont_registers,EDF0,"COMPOS +BOOLAND",c c' - c'',26,"Computes the composition `compose0(c, c’)`, which has the meaning of “perform `c`, and, if successful, perform `c'`'' (if `c` is a boolean circuit) or simply “perform `c`, then `c'`''. Equivalent to `SWAP` `c0 SETCONT`." +COMPOSALT,,#EDF1,cont_registers,EDF1,"COMPOSALT +BOOLOR",c c' - c'',26,"Computes the alternative composition `compose1(c, c’)`, which has the meaning of “perform `c`, and, if not successful, perform `c'`'' (if `c` is a boolean circuit). Equivalent to `SWAP` `c1 SETCONT`." +COMPOSBOTH,,#EDF2,cont_registers,EDF2,COMPOSBOTH,c c' - c'',26,"Computes composition `compose1(compose0(c, c’), c’)`, which has the meaning of “compute boolean circuit `c`, then compute `c'`, regardless of the result of `c`''." +ATEXIT,,#EDF3,cont_registers,EDF3,ATEXIT,c - ,26,"Sets `c0` to `compose0(c, c0)`. In other words, `c` will be executed before exiting current subroutine." +,,,cont_registers,EDF3,"ATEXIT:<{ code }> +<{ code }>ATEXIT",-,,Equivalent to `<{ code }> CONT` `ATEXIT`. +ATEXITALT,,#EDF4,cont_registers,EDF4,ATEXITALT,c - ,26,"Sets `c1` to `compose1(c, c1)`. In other words, `c` will be executed before exiting current subroutine by its alternative return path." +,,,cont_registers,EDF4,"ATEXITALT:<{ code }> +<{ code }>ATEXITALT",-,,Equivalent to `<{ code }> CONT` `ATEXITALT`. +SETEXITALT,,#EDF5,cont_registers,EDF5,SETEXITALT,c - ,26,"Sets `c1` to `compose1(compose0(c, c0), c1)`, +In this way, a subsequent `RETALT` will first execute `c`, then transfer control to the original `c0`. This can be used, for instance, to exit from nested loops." +THENRET,,#EDF6,cont_registers,EDF6,THENRET,c - c',26,"Computes `compose0(c, c0)`." +THENRETALT,,#EDF7,cont_registers,EDF7,THENRETALT,c - c',26,"Computes `compose0(c, c1)`" +INVERT,,#EDF8,cont_registers,EDF8,INVERT,-,26,Interchanges `c0` and `c1`. +BOOLEVAL,,#EDF9,cont_registers,EDF9,BOOLEVAL,c - ?,26,"Performs `cc:=compose1(compose0(c, compose0(-1 PUSHINT, cc)), compose0(0 PUSHINT, cc))`. If `c` represents a boolean circuit, the net effect is to evaluate it and push either `-1` or `0` into the stack before continuing." +SAMEALT,,#EDFA,cont_registers,EDFA,SAMEALT,-,26,Sets `c1` to `c0`. Equivalent to `c0 PUSHCTR` `c1 POPCTR`. +SAMEALTSAVE,,#EDFB,cont_registers,EDFB,SAMEALTSAVE,-,26,"Sets `c1` to `c0`, but first saves the old value of `c1` into the savelist of `c0`. +Equivalent to `c1 SAVE` `SAMEALT`." +CALLDICT,,#F0 n:uint8,cont_dict,F0nn,"[nn] CALL +[nn] CALLDICT",- nn,,"Calls the continuation in `c3`, pushing integer `0 <= nn <= 255` into its stack as an argument. +Approximately equivalent to `[nn] PUSHINT` `c3 PUSHCTR` `EXECUTE`." +CALLDICT_LONG,,#F12_ n:uint14,cont_dict,F12_n,"[n] CALL +[n] CALLDICT",- n,,"For `0 <= n < 2^14`, an encoding of `[n] CALL` for larger values of `n`." +JMPDICT,,#F16_ n:uint14,cont_dict,F16_n,[n] JMP, - n,,"Jumps to the continuation in `c3`, pushing integer `0 <= n < 2^14` as its argument. +Approximately equivalent to `n PUSHINT` `c3 PUSHCTR` `JMPX`." +PREPAREDICT,,#F1A_ n:uint14,cont_dict,F1A_n,"[n] PREPARE +[n] PREPAREDICT", - n c,,"Equivalent to `n PUSHINT` `c3 PUSHCTR`, for `0 <= n < 2^14`. +In this way, `[n] CALL` is approximately equivalent to `[n] PREPARE` `EXECUTE`, and `[n] JMP` is approximately equivalent to `[n] PREPARE` `JMPX`. +One might use, for instance, `CALLXARGS` or `CALLCC` instead of `EXECUTE` here." +THROW_SHORT,,#F22_ n:uint6,exceptions,F22_n,[n] THROW, - 0 n,76,"Throws exception `0 <= n <= 63` with parameter zero. +In other words, it transfers control to the continuation in `c2`, pushing `0` and `n` into its stack, and discarding the old stack altogether." +THROWIF_SHORT,,#F26_ n:uint6,exceptions,F26_n,[n] THROWIF,f - ,26/76,Throws exception `0 <= n <= 63` with parameter zero only if integer `f!=0`. +THROWIFNOT_SHORT,,#F2A_ n:uint6,exceptions,F2A_n,[n] THROWIFNOT,f - ,26/76,Throws exception `0 <= n <= 63` with parameter zero only if integer `f=0`. +THROW,,#F2C4_ n:uint11,exceptions,F2C4_n,[n] THROW,- 0 nn,84,"For `0 <= n < 2^11`, an encoding of `[n] THROW` for larger values of `n`." +THROWARG,,#F2CC_ n:uint11,exceptions,F2CC_n,[n] THROWARG,x - x nn,84,"Throws exception `0 <= n < 2^11` with parameter `x`, by copying `x` and `n` into the stack of `c2` and transferring control to `c2`." +THROWIF,,#F2D4_ n:uint11,exceptions,F2D4_n,[n] THROWIF,f - ,34/84,"For `0 <= n < 2^11`, an encoding of `[n] THROWIF` for larger values of `n`." +THROWARGIF,,#F2DC_ n:uint11,exceptions,F2DC_n,[n] THROWARGIF,x f - ,34/84,Throws exception `0 <= nn < 2^11` with parameter `x` only if integer `f!=0`. +THROWIFNOT,,#F2E4_ n:uint11,exceptions,F2E4_n,[n] THROWIFNOT,f - ,34/84,"For `0 <= n < 2^11`, an encoding of `[n] THROWIFNOT` for larger values of `n`." +THROWARGIFNOT,,#F2EC_ n:uint11,exceptions,F2EC_n,[n] THROWARGIFNOT,x f - ,34/84,Throws exception `0 <= n < 2^11` with parameter `x` only if integer `f=0`. +THROWANY,,#F2F0,exceptions,F2F0,THROWANY,n - 0 n,76,"Throws exception `0 <= n < 2^16` with parameter zero. +Approximately equivalent to `ZERO` `SWAP` `THROWARGANY`." +THROWARGANY,,#F2F1,exceptions,F2F1,THROWARGANY,x n - x n,76,"Throws exception `0 <= n < 2^16` with parameter `x`, transferring control to the continuation in `c2`. +Approximately equivalent to `c2 PUSHCTR` `2 JMPXARGS`." +THROWANYIF,,#F2F2,exceptions,F2F2,THROWANYIF,n f - ,26/76,Throws exception `0 <= n < 2^16` with parameter zero only if `f!=0`. +THROWARGANYIF,,#F2F3,exceptions,F2F3,THROWARGANYIF,x n f - ,26/76,Throws exception `0 <= n<2^16` with parameter `x` only if `f!=0`. +THROWANYIFNOT,,#F2F4,exceptions,F2F4,THROWANYIFNOT,n f - ,26/76,Throws exception `0 <= n<2^16` with parameter zero only if `f=0`. +THROWARGANYIFNOT,,#F2F5,exceptions,F2F5,THROWARGANYIFNOT,x n f - ,26/76,Throws exception `0 <= n<2^16` with parameter `x` only if `f=0`. +TRY,,#F2FF,exceptions,F2FF,TRY,c c' - ,26,"Sets `c2` to `c'`, first saving the old value of `c2` both into the savelist of `c'` and into the savelist of the current continuation, which is stored into `c.c0` and `c'.c0`. Then runs `c` similarly to `EXECUTE`. If `c` does not throw any exceptions, the original value of `c2` is automatically restored on return from `c`. If an exception occurs, the execution is transferred to `c'`, but the original value of `c2` is restored in the process, so that `c'` can re-throw the exception by `THROWANY` if it cannot handle it by itself." +,,,exceptions,F2FF,TRY:<{ code1 }>CATCH<{ code2 }>,-,,Equivalent to `<{ code1 }> CONT` `<{ code2 }> CONT` `TRY`. +TRYARGS,,#F3 p:uint4 r:uint4,exceptions,F3pr,[p] [r] TRYARGS,c c' - ,26,"Similar to `TRY`, but with `[p] [r] CALLXARGS` internally used instead of `EXECUTE`. +In this way, all but the top `0 <= p <= 15` stack elements will be saved into current continuation's stack, and then restored upon return from either `c` or `c'`, with the top `0 <= r <= 15` values of the resulting stack of `c` or `c'` copied as return values." +NEWDICT,NULL,#6D,dict_create,6D,NEWDICT, - D,18,"Returns a new empty dictionary. +It is an alternative mnemonics for `PUSHNULL`." +DICTEMPTY,ISNULL,#6E,dict_create,6E,DICTEMPTY,D - ?,18,"Checks whether dictionary `D` is empty, and returns `-1` or `0` accordingly. +It is an alternative mnemonics for `ISNULL`." +STDICTS,STSLICE,#CE,dict_serial,CE,"STDICTS +",s b - b',18,"Stores a _Slice_-represented dictionary `s` into _Builder_ `b`. +It is actually a synonym for `STSLICE`." +STDICT,,#F400,dict_serial,F400,"STDICT +STOPTREF",D b - b',26,"Stores dictionary `D` into _Builder_ `b`, returing the resulting _Builder_ `b'`. +In other words, if `D` is a cell, performs `STONE` and `STREF`; if `D` is _Null_, performs `NIP` and `STZERO`; otherwise throws a type checking exception." +SKIPDICT,,#F401,dict_serial,F401,"SKIPDICT +SKIPOPTREF",s - s',26,Equivalent to `LDDICT` `NIP`. +LDDICTS,,#F402,dict_serial,F402,LDDICTS,s - s' s'',26,"Loads (parses) a (_Slice_-represented) dictionary `s'` from _Slice_ `s`, and returns the remainder of `s` as `s''`. +This is a “split function'' for all `HashmapE(n,X)` dictionary types." +PLDDICTS,,#F403,dict_serial,F403,PLDDICTS,s - s',26,"Preloads a (_Slice_-represented) dictionary `s'` from _Slice_ `s`. +Approximately equivalent to `LDDICTS` `DROP`." +LDDICT,,#F404,dict_serial,F404,"LDDICT +LDOPTREF",s - D s',26,"Loads (parses) a dictionary `D` from _Slice_ `s`, and returns the remainder of `s` as `s'`. May be applied to dictionaries or to values of arbitrary `(^Y)?` types." +PLDDICT,,#F405,dict_serial,F405,"PLDDICT +PLDOPTREF",s - D,26,"Preloads a dictionary `D` from _Slice_ `s`. +Approximately equivalent to `LDDICT` `DROP`." +LDDICTQ,,#F406,dict_serial,F406,LDDICTQ,s - D s' -1 or s 0,26,A quiet version of `LDDICT`. +PLDDICTQ,,#F407,dict_serial,F407,PLDDICTQ,s - D -1 or 0,26,A quiet version of `PLDDICT`. +DICTGET,,#F40A,dict_get,F40A,DICTGET,k D n - x -1 or 0,,"Looks up key `k` (represented by a _Slice_, the first `0 <= n <= 1023` data bits of which are used as a key) in dictionary `D` of type `HashmapE(n,X)` with `n`-bit keys. +On success, returns the value found as a _Slice_ `x`." +DICTGETREF,,#F40B,dict_get,F40B,DICTGETREF,k D n - c -1 or 0,,"Similar to `DICTGET`, but with a `LDREF` `ENDS` applied to `x` on success. +This operation is useful for dictionaries of type `HashmapE(n,^Y)`." +DICTIGET,,#F40C,dict_get,F40C,DICTIGET,i D n - x -1 or 0,,"Similar to `DICTGET`, but with a signed (big-endian) `n`-bit _Integer_ `i` as a key. If `i` does not fit into `n` bits, returns `0`. If `i` is a `NaN`, throws an integer overflow exception." +DICTIGETREF,,#F40D,dict_get,F40D,DICTIGETREF,i D n - c -1 or 0,,Combines `DICTIGET` with `DICTGETREF`: it uses signed `n`-bit _Integer_ `i` as a key and returns a _Cell_ instead of a _Slice_ on success. +DICTUGET,,#F40E,dict_get,F40E,DICTUGET,i D n - x -1 or 0,,"Similar to `DICTIGET`, but with _unsigned_ (big-endian) `n`-bit _Integer_ `i` used as a key." +DICTUGETREF,,#F40F,dict_get,F40F,DICTUGETREF,i D n - c -1 or 0,,"Similar to `DICTIGETREF`, but with an unsigned `n`-bit _Integer_ key `i`." +DICTSET,,#F412,dict_set,F412,DICTSET,x k D n - D',,"Sets the value associated with `n`-bit key `k` (represented by a _Slice_ as in `DICTGET`) in dictionary `D` (also represented by a _Slice_) to value `x` (again a _Slice_), and returns the resulting dictionary as `D'`." +DICTSETREF,,#F413,dict_set,F413,DICTSETREF,c k D n - D',,"Similar to `DICTSET`, but with the value set to a reference to _Cell_ `c`." +DICTISET,,#F414,dict_set,F414,DICTISET,x i D n - D',,"Similar to `DICTSET`, but with the key represented by a (big-endian) signed `n`-bit integer `i`. If `i` does not fit into `n` bits, a range check exception is generated." +DICTISETREF,,#F415,dict_set,F415,DICTISETREF,c i D n - D',,"Similar to `DICTSETREF`, but with the key a signed `n`-bit integer as in `DICTISET`." +DICTUSET,,#F416,dict_set,F416,DICTUSET,x i D n - D',,"Similar to `DICTISET`, but with `i` an _unsigned_ `n`-bit integer." +DICTUSETREF,,#F417,dict_set,F417,DICTUSETREF,c i D n - D',,"Similar to `DICTISETREF`, but with `i` unsigned." +DICTSETGET,,#F41A,dict_set,F41A,DICTSETGET,x k D n - D' y -1 or D' 0,,"Combines `DICTSET` with `DICTGET`: it sets the value corresponding to key `k` to `x`, but also returns the old value `y` associated with the key in question, if present." +DICTSETGETREF,,#F41B,dict_set,F41B,DICTSETGETREF,c k D n - D' c' -1 or D' 0,,Combines `DICTSETREF` with `DICTGETREF` similarly to `DICTSETGET`. +DICTISETGET,,#F41C,dict_set,F41C,DICTISETGET,x i D n - D' y -1 or D' 0,,"`DICTISETGET`, but with `i` a signed `n`-bit integer." +DICTISETGETREF,,#F41D,dict_set,F41D,DICTISETGETREF,c i D n - D' c' -1 or D' 0,,"`DICTISETGETREF`, but with `i` a signed `n`-bit integer." +DICTUSETGET,,#F41E,dict_set,F41E,DICTUSETGET,x i D n - D' y -1 or D' 0,,"`DICTISETGET`, but with `i` an unsigned `n`-bit integer." +DICTUSETGETREF,,#F41F,dict_set,F41F,DICTUSETGETREF,c i D n - D' c' -1 or D' 0,,"`DICTISETGETREF`, but with `i` an unsigned `n`-bit integer." +DICTREPLACE,,#F422,dict_set,F422,DICTREPLACE,x k D n - D' -1 or D 0,,"A _Replace_ operation, which is similar to `DICTSET`, but sets the value of key `k` in dictionary `D` to `x` only if the key `k` was already present in `D`." +DICTREPLACEREF,,#F423,dict_set,F423,DICTREPLACEREF,c k D n - D' -1 or D 0,,A _Replace_ counterpart of `DICTSETREF`. +DICTIREPLACE,,#F424,dict_set,F424,DICTIREPLACE,x i D n - D' -1 or D 0,,"`DICTREPLACE`, but with `i` a signed `n`-bit integer." +DICTIREPLACEREF,,#F425,dict_set,F425,DICTIREPLACEREF,c i D n - D' -1 or D 0,,"`DICTREPLACEREF`, but with `i` a signed `n`-bit integer." +DICTUREPLACE,,#F426,dict_set,F426,DICTUREPLACE,x i D n - D' -1 or D 0,,"`DICTREPLACE`, but with `i` an unsigned `n`-bit integer." +DICTUREPLACEREF,,#F427,dict_set,F427,DICTUREPLACEREF,c i D n - D' -1 or D 0,,"`DICTREPLACEREF`, but with `i` an unsigned `n`-bit integer." +DICTREPLACEGET,,#F42A,dict_set,F42A,DICTREPLACEGET,x k D n - D' y -1 or D 0,,"A _Replace_ counterpart of `DICTSETGET`: on success, also returns the old value associated with the key in question." +DICTREPLACEGETREF,,#F42B,dict_set,F42B,DICTREPLACEGETREF,c k D n - D' c' -1 or D 0,,A _Replace_ counterpart of `DICTSETGETREF`. +DICTIREPLACEGET,,#F42C,dict_set,F42C,DICTIREPLACEGET,x i D n - D' y -1 or D 0,,"`DICTREPLACEGET`, but with `i` a signed `n`-bit integer." +DICTIREPLACEGETREF,,#F42D,dict_set,F42D,DICTIREPLACEGETREF,c i D n - D' c' -1 or D 0,,"`DICTREPLACEGETREF`, but with `i` a signed `n`-bit integer." +DICTUREPLACEGET,,#F42E,dict_set,F42E,DICTUREPLACEGET,x i D n - D' y -1 or D 0,,"`DICTREPLACEGET`, but with `i` an unsigned `n`-bit integer." +DICTUREPLACEGETREF,,#F42F,dict_set,F42F,DICTUREPLACEGETREF,c i D n - D' c' -1 or D 0,,"`DICTREPLACEGETREF`, but with `i` an unsigned `n`-bit integer." +DICTADD,,#F432,dict_set,F432,DICTADD,x k D n - D' -1 or D 0,,"An _Add_ counterpart of `DICTSET`: sets the value associated with key `k` in dictionary `D` to `x`, but only if it is not already present in `D`." +DICTADDREF,,#F433,dict_set,F433,DICTADDREF,c k D n - D' -1 or D 0,,An _Add_ counterpart of `DICTSETREF`. +DICTIADD,,#F434,dict_set,F434,DICTIADD,x i D n - D' -1 or D 0,,"`DICTADD`, but with `i` a signed `n`-bit integer." +DICTIADDREF,,#F435,dict_set,F435,DICTIADDREF,c i D n - D' -1 or D 0,,"`DICTADDREF`, but with `i` a signed `n`-bit integer." +DICTUADD,,#F436,dict_set,F436,DICTUADD,x i D n - D' -1 or D 0,,"`DICTADD`, but with `i` an unsigned `n`-bit integer." +DICTUADDREF,,#F437,dict_set,F437,DICTUADDREF,c i D n - D' -1 or D 0,,"`DICTADDREF`, but with `i` an unsigned `n`-bit integer." +DICTADDGET,,#F43A,dict_set,F43A,DICTADDGET,x k D n - D' -1 or D y 0,,"An _Add_ counterpart of `DICTSETGET`: sets the value associated with key `k` in dictionary `D` to `x`, but only if key `k` is not already present in `D`. Otherwise, just returns the old value `y` without changing the dictionary." +DICTADDGETREF,,#F43B,dict_set,F43B,DICTADDGETREF,c k D n - D' -1 or D c' 0,,An _Add_ counterpart of `DICTSETGETREF`. +DICTIADDGET,,#F43C,dict_set,F43C,DICTIADDGET,x i D n - D' -1 or D y 0,,"`DICTADDGET`, but with `i` a signed `n`-bit integer." +DICTIADDGETREF,,#F43D,dict_set,F43D,DICTIADDGETREF,c i D n - D' -1 or D c' 0,,"`DICTADDGETREF`, but with `i` a signed `n`-bit integer." +DICTUADDGET,,#F43E,dict_set,F43E,DICTUADDGET,x i D n - D' -1 or D y 0,,"`DICTADDGET`, but with `i` an unsigned `n`-bit integer." +DICTUADDGETREF,,#F43F,dict_set,F43F,DICTUADDGETREF,c i D n - D' -1 or D c' 0,,"`DICTADDGETREF`, but with `i` an unsigned `n`-bit integer." +DICTSETB,,#F441,dict_set_builder,F441,DICTSETB,b k D n - D',, +DICTISETB,,#F442,dict_set_builder,F442,DICTISETB,b i D n - D',, +DICTUSETB,,#F443,dict_set_builder,F443,DICTUSETB,b i D n - D',, +DICTSETGETB,,#F445,dict_set_builder,F445,DICTSETGETB,b k D n - D' y -1 or D' 0,, +DICTISETGETB,,#F446,dict_set_builder,F446,DICTISETGETB,b i D n - D' y -1 or D' 0,, +DICTUSETGETB,,#F447,dict_set_builder,F447,DICTUSETGETB,b i D n - D' y -1 or D' 0,, +DICTREPLACEB,,#F449,dict_set_builder,F449,DICTREPLACEB,b k D n - D' -1 or D 0,, +DICTIREPLACEB,,#F44A,dict_set_builder,F44A,DICTIREPLACEB,b i D n - D' -1 or D 0,, +DICTUREPLACEB,,#F44B,dict_set_builder,F44B,DICTUREPLACEB,b i D n - D' -1 or D 0,, +DICTREPLACEGETB,,#F44D,dict_set_builder,F44D,DICTREPLACEGETB,b k D n - D' y -1 or D 0,, +DICTIREPLACEGETB,,#F44E,dict_set_builder,F44E,DICTIREPLACEGETB,b i D n - D' y -1 or D 0,, +DICTUREPLACEGETB,,#F44F,dict_set_builder,F44F,DICTUREPLACEGETB,b i D n - D' y -1 or D 0,, +DICTADDB,,#F451,dict_set_builder,F451,DICTADDB,b k D n - D' -1 or D 0,, +DICTIADDB,,#F452,dict_set_builder,F452,DICTIADDB,b i D n - D' -1 or D 0,, +DICTUADDB,,#F453,dict_set_builder,F453,DICTUADDB,b i D n - D' -1 or D 0,, +DICTADDGETB,,#F455,dict_set_builder,F455,DICTADDGETB,b k D n - D' -1 or D y 0,, +DICTIADDGETB,,#F456,dict_set_builder,F456,DICTIADDGETB,b i D n - D' -1 or D y 0,, +DICTUADDGETB,,#F457,dict_set_builder,F457,DICTUADDGETB,b i D n - D' -1 or D y 0,, +DICTDEL,,#F459,dict_delete,F459,DICTDEL,k D n - D' -1 or D 0,,"Deletes `n`-bit key, represented by a _Slice_ `k`, from dictionary `D`. If the key is present, returns the modified dictionary `D'` and the success flag `-1`. Otherwise, returns the original dictionary `D` and `0`." +DICTIDEL,,#F45A,dict_delete,F45A,DICTIDEL,i D n - D' ?,,"A version of `DICTDEL` with the key represented by a signed `n`-bit _Integer_ `i`. If `i` does not fit into `n` bits, simply returns `D` `0` (“key not found, dictionary unmodified'')." +DICTUDEL,,#F45B,dict_delete,F45B,DICTUDEL,i D n - D' ?,,"Similar to `DICTIDEL`, but with `i` an unsigned `n`-bit integer." +DICTDELGET,,#F462,dict_delete,F462,DICTDELGET,k D n - D' x -1 or D 0,,"Deletes `n`-bit key, represented by a _Slice_ `k`, from dictionary `D`. If the key is present, returns the modified dictionary `D'`, the original value `x` associated with the key `k` (represented by a _Slice_), and the success flag `-1`. Otherwise, returns the original dictionary `D` and `0`." +DICTDELGETREF,,#F463,dict_delete,F463,DICTDELGETREF,k D n - D' c -1 or D 0,,"Similar to `DICTDELGET`, but with `LDREF` `ENDS` applied to `x` on success, so that the value returned `c` is a _Cell_." +DICTIDELGET,,#F464,dict_delete,F464,DICTIDELGET,i D n - D' x -1 or D 0,,"`DICTDELGET`, but with `i` a signed `n`-bit integer." +DICTIDELGETREF,,#F465,dict_delete,F465,DICTIDELGETREF,i D n - D' c -1 or D 0,,"`DICTDELGETREF`, but with `i` a signed `n`-bit integer." +DICTUDELGET,,#F466,dict_delete,F466,DICTUDELGET,i D n - D' x -1 or D 0,,"`DICTDELGET`, but with `i` an unsigned `n`-bit integer." +DICTUDELGETREF,,#F467,dict_delete,F467,DICTUDELGETREF,i D n - D' c -1 or D 0,,"`DICTDELGETREF`, but with `i` an unsigned `n`-bit integer." +DICTGETOPTREF,,#F469,dict_mayberef,F469,DICTGETOPTREF,k D n - c^?,,A variant of `DICTGETREF` that returns _Null_ instead of the value `c^?` if the key `k` is absent from dictionary `D`. +DICTIGETOPTREF,,#F46A,dict_mayberef,F46A,DICTIGETOPTREF,i D n - c^?,,"`DICTGETOPTREF`, but with `i` a signed `n`-bit integer. If the key `i` is out of range, also returns _Null_." +DICTUGETOPTREF,,#F46B,dict_mayberef,F46B,DICTUGETOPTREF,i D n - c^?,,"`DICTGETOPTREF`, but with `i` an unsigned `n`-bit integer. If the key `i` is out of range, also returns _Null_." +DICTSETGETOPTREF,,#F46D,dict_mayberef,F46D,DICTSETGETOPTREF,c^? k D n - D' ~c^?,,"A variant of both `DICTGETOPTREF` and `DICTSETGETREF` that sets the value corresponding to key `k` in dictionary `D` to `c^?` (if `c^?` is _Null_, then the key is deleted instead), and returns the old value `~c^?` (if the key `k` was absent before, returns _Null_ instead)." +DICTISETGETOPTREF,,#F46E,dict_mayberef,F46E,DICTISETGETOPTREF,c^? i D n - D' ~c^?,,"Similar to primitive `DICTSETGETOPTREF`, but using signed `n`-bit _Integer_ `i` as a key. If `i` does not fit into `n` bits, throws a range checking exception." +DICTUSETGETOPTREF,,#F46F,dict_mayberef,F46F,DICTUSETGETOPTREF,c^? i D n - D' ~c^?,,"Similar to primitive `DICTSETGETOPTREF`, but using unsigned `n`-bit _Integer_ `i` as a key." +PFXDICTSET,,#F470,dict_prefix,F470,PFXDICTSET,x k D n - D' -1 or D 0,, +PFXDICTREPLACE,,#F471,dict_prefix,F471,PFXDICTREPLACE,x k D n - D' -1 or D 0,, +PFXDICTADD,,#F472,dict_prefix,F472,PFXDICTADD,x k D n - D' -1 or D 0,, +PFXDICTDEL,,#F473,dict_prefix,F473,PFXDICTDEL,k D n - D' -1 or D 0,, +DICTGETNEXT,,#F474,dict_next,F474,DICTGETNEXT,k D n - x' k' -1 or 0,,"Computes the minimal key `k'` in dictionary `D` that is lexicographically greater than `k`, and returns `k'` (represented by a _Slice_) along with associated value `x'` (also represented by a _Slice_)." +DICTGETNEXTEQ,,#F475,dict_next,F475,DICTGETNEXTEQ,k D n - x' k' -1 or 0,,"Similar to `DICTGETNEXT`, but computes the minimal key `k'` that is lexicographically greater than or equal to `k`." +DICTGETPREV,,#F476,dict_next,F476,DICTGETPREV,k D n - x' k' -1 or 0,,"Similar to `DICTGETNEXT`, but computes the maximal key `k'` lexicographically smaller than `k`." +DICTGETPREVEQ,,#F477,dict_next,F477,DICTGETPREVEQ,k D n - x' k' -1 or 0,,"Similar to `DICTGETPREV`, but computes the maximal key `k'` lexicographically smaller than or equal to `k`." +DICTIGETNEXT,,#F478,dict_next,F478,DICTIGETNEXT,i D n - x' i' -1 or 0,,"Similar to `DICTGETNEXT`, but interprets all keys in dictionary `D` as big-endian signed `n`-bit integers, and computes the minimal key `i'` that is larger than _Integer_ `i` (which does not necessarily fit into `n` bits)." +DICTIGETNEXTEQ,,#F479,dict_next,F479,DICTIGETNEXTEQ,i D n - x' i' -1 or 0,,"Similar to `DICTGETNEXTEQ`, but interprets keys as signed `n`-bit integers." +DICTIGETPREV,,#F47A,dict_next,F47A,DICTIGETPREV,i D n - x' i' -1 or 0,,"Similar to `DICTGETPREV`, but interprets keys as signed `n`-bit integers." +DICTIGETPREVEQ,,#F47B,dict_next,F47B,DICTIGETPREVEQ,i D n - x' i' -1 or 0,,"Similar to `DICTGETPREVEQ`, but interprets keys as signed `n`-bit integers." +DICTUGETNEXT,,#F47C,dict_next,F47C,DICTUGETNEXT,i D n - x' i' -1 or 0,,"Similar to `DICTGETNEXT`, but interprets all keys in dictionary `D` as big-endian unsigned `n`-bit integers, and computes the minimal key `i'` that is larger than _Integer_ `i` (which does not necessarily fit into `n` bits, and is not necessarily non-negative)." +DICTUGETNEXTEQ,,#F47D,dict_next,F47D,DICTUGETNEXTEQ,i D n - x' i' -1 or 0,,"Similar to `DICTGETNEXTEQ`, but interprets keys as unsigned `n`-bit integers." +DICTUGETPREV,,#F47E,dict_next,F47E,DICTUGETPREV,i D n - x' i' -1 or 0,,"Similar to `DICTGETPREV`, but interprets keys as unsigned `n`-bit integers." +DICTUGETPREVEQ,,#F47F,dict_next,F47F,DICTUGETPREVEQ,i D n - x' i' -1 or 0,,"Similar to `DICTGETPREVEQ`, but interprets keys a unsigned `n`-bit integers." +DICTMIN,,#F482,dict_min,F482,DICTMIN,D n - x k -1 or 0,,"Computes the minimal key `k` (represented by a _Slice_ with `n` data bits) in dictionary `D`, and returns `k` along with the associated value `x`." +DICTMINREF,,#F483,dict_min,F483,DICTMINREF,D n - c k -1 or 0,,"Similar to `DICTMIN`, but returns the only reference in the value as a _Cell_ `c`." +DICTIMIN,,#F484,dict_min,F484,DICTIMIN,D n - x i -1 or 0,,"Similar to `DICTMIN`, but computes the minimal key `i` under the assumption that all keys are big-endian signed `n`-bit integers. Notice that the key and value returned may differ from those computed by `DICTMIN` and `DICTUMIN`." +DICTIMINREF,,#F485,dict_min,F485,DICTIMINREF,D n - c i -1 or 0,,"Similar to `DICTIMIN`, but returns the only reference in the value." +DICTUMIN,,#F486,dict_min,F486,DICTUMIN,D n - x i -1 or 0,,"Similar to `DICTMIN`, but returns the key as an unsigned `n`-bit _Integer_ `i`." +DICTUMINREF,,#F487,dict_min,F487,DICTUMINREF,D n - c i -1 or 0,,"Similar to `DICTUMIN`, but returns the only reference in the value." +DICTMAX,,#F48A,dict_min,F48A,DICTMAX,D n - x k -1 or 0,,"Computes the maximal key `k` (represented by a _Slice_ with `n` data bits) in dictionary `D`, and returns `k` along with the associated value `x`." +DICTMAXREF,,#F48B,dict_min,F48B,DICTMAXREF,D n - c k -1 or 0,,"Similar to `DICTMAX`, but returns the only reference in the value." +DICTIMAX,,#F48C,dict_min,F48C,DICTIMAX,D n - x i -1 or 0,,"Similar to `DICTMAX`, but computes the maximal key `i` under the assumption that all keys are big-endian signed `n`-bit integers. Notice that the key and value returned may differ from those computed by `DICTMAX` and `DICTUMAX`." +DICTIMAXREF,,#F48D,dict_min,F48D,DICTIMAXREF,D n - c i -1 or 0,,"Similar to `DICTIMAX`, but returns the only reference in the value." +DICTUMAX,,#F48E,dict_min,F48E,DICTUMAX,D n - x i -1 or 0,,"Similar to `DICTMAX`, but returns the key as an unsigned `n`-bit _Integer_ `i`." +DICTUMAXREF,,#F48F,dict_min,F48F,DICTUMAXREF,D n - c i -1 or 0,,"Similar to `DICTUMAX`, but returns the only reference in the value." +DICTREMMIN,,#F492,dict_min,F492,DICTREMMIN,D n - D' x k -1 or D 0,,"Computes the minimal key `k` (represented by a _Slice_ with `n` data bits) in dictionary `D`, removes `k` from the dictionary, and returns `k` along with the associated value `x` and the modified dictionary `D'`." +DICTREMMINREF,,#F493,dict_min,F493,DICTREMMINREF,D n - D' c k -1 or D 0,,"Similar to `DICTREMMIN`, but returns the only reference in the value as a _Cell_ `c`." +DICTIREMMIN,,#F494,dict_min,F494,DICTIREMMIN,D n - D' x i -1 or D 0,,"Similar to `DICTREMMIN`, but computes the minimal key `i` under the assumption that all keys are big-endian signed `n`-bit integers. Notice that the key and value returned may differ from those computed by `DICTREMMIN` and `DICTUREMMIN`." +DICTIREMMINREF,,#F495,dict_min,F495,DICTIREMMINREF,D n - D' c i -1 or D 0,,"Similar to `DICTIREMMIN`, but returns the only reference in the value." +DICTUREMMIN,,#F496,dict_min,F496,DICTUREMMIN,D n - D' x i -1 or D 0,,"Similar to `DICTREMMIN`, but returns the key as an unsigned `n`-bit _Integer_ `i`." +DICTUREMMINREF,,#F497,dict_min,F497,DICTUREMMINREF,D n - D' c i -1 or D 0,,"Similar to `DICTUREMMIN`, but returns the only reference in the value." +DICTREMMAX,,#F49A,dict_min,F49A,DICTREMMAX,D n - D' x k -1 or D 0,,"Computes the maximal key `k` (represented by a _Slice_ with `n` data bits) in dictionary `D`, removes `k` from the dictionary, and returns `k` along with the associated value `x` and the modified dictionary `D'`." +DICTREMMAXREF,,#F49B,dict_min,F49B,DICTREMMAXREF,D n - D' c k -1 or D 0,,"Similar to `DICTREMMAX`, but returns the only reference in the value as a _Cell_ `c`." +DICTIREMMAX,,#F49C,dict_min,F49C,DICTIREMMAX,D n - D' x i -1 or D 0,,"Similar to `DICTREMMAX`, but computes the minimal key `i` under the assumption that all keys are big-endian signed `n`-bit integers. Notice that the key and value returned may differ from those computed by `DICTREMMAX` and `DICTUREMMAX`." +DICTIREMMAXREF,,#F49D,dict_min,F49D,DICTIREMMAXREF,D n - D' c i -1 or D 0,,"Similar to `DICTIREMMAX`, but returns the only reference in the value." +DICTUREMMAX,,#F49E,dict_min,F49E,DICTUREMMAX,D n - D' x i -1 or D 0,,"Similar to `DICTREMMAX`, but returns the key as an unsigned `n`-bit _Integer_ `i`." +DICTUREMMAXREF,,#F49F,dict_min,F49F,DICTUREMMAXREF,D n - D' c i -1 or D 0,,"Similar to `DICTUREMMAX`, but returns the only reference in the value." +DICTIGETJMP,,#F4A0,dict_special,F4A0,DICTIGETJMP,i D n - ,,"Similar to `DICTIGET`, but with `x` `BLESS`ed into a continuation with a subsequent `JMPX` to it on success. On failure, does nothing. This is useful for implementing `switch`/`case` constructions." +DICTUGETJMP,,#F4A1,dict_special,F4A1,DICTUGETJMP,i D n - ,,"Similar to `DICTIGETJMP`, but performs `DICTUGET` instead of `DICTIGET`." +DICTIGETEXEC,,#F4A2,dict_special,F4A2,DICTIGETEXEC,i D n - ,,"Similar to `DICTIGETJMP`, but with `EXECUTE` instead of `JMPX`." +DICTUGETEXEC,,#F4A3,dict_special,F4A3,DICTUGETEXEC,i D n - ,,"Similar to `DICTUGETJMP`, but with `EXECUTE` instead of `JMPX`." +DICTPUSHCONST,,#F4A6_ d:^Cell n:uint10,dict_special,F4A6_n,[ref] [n] DICTPUSHCONST, - D n,34,"Pushes a non-empty constant dictionary `D` (as a `Cell^?`) along with its key length `0 <= n <= 1023`, stored as a part of the instruction. The dictionary itself is created from the first of remaining references of the current continuation. In this way, the complete `DICTPUSHCONST` instruction can be obtained by first serializing `xF4A4_`, then the non-empty dictionary itself (one `1` bit and a cell reference), and then the unsigned 10-bit integer `n` (as if by a `STU 10` instruction). An empty dictionary can be pushed by a `NEWDICT` primitive instead." +PFXDICTGETQ,,#F4A8,dict_special,F4A8,PFXDICTGETQ,s D n - s' x s'' -1 or s 0,,"Looks up the unique prefix of _Slice_ `s` present in the prefix code dictionary represented by `Cell^?` `D` and `0 <= n <= 1023`. If found, the prefix of `s` is returned as `s'`, and the corresponding value (also a _Slice_) as `x`. The remainder of `s` is returned as a _Slice_ `s''`. If no prefix of `s` is a key in prefix code dictionary `D`, returns the unchanged `s` and a zero flag to indicate failure." +PFXDICTGET,,#F4A9,dict_special,F4A9,PFXDICTGET,s D n - s' x s'',,"Similar to `PFXDICTGET`, but throws a cell deserialization failure exception on failure." +PFXDICTGETJMP,,#F4AA,dict_special,F4AA,PFXDICTGETJMP,s D n - s' s'' or s,,"Similar to `PFXDICTGETQ`, but on success `BLESS`es the value `x` into a _Continuation_ and transfers control to it as if by a `JMPX`. On failure, returns `s` unchanged and continues execution." +PFXDICTGETEXEC,,#F4AB,dict_special,F4AB,PFXDICTGETEXEC,s D n - s' s'',,"Similar to `PFXDICTGETJMP`, but `EXEC`utes the continuation found instead of jumping to it. On failure, throws a cell deserialization exception." +PFXDICTCONSTGETJMP,,#F4AE_ d:^Cell n:uint10,dict_special,F4AE_n,"[ref] [n] PFXDICTCONSTGETJMP +[ref] [n] PFXDICTSWITCH",s - s' s'' or s,,Combines `[n] DICTPUSHCONST` for `0 <= n <= 1023` with `PFXDICTGETJMP`. +DICTIGETJMPZ,,#F4BC,dict_special,F4BC,DICTIGETJMPZ,i D n - i or nothing,,A variant of `DICTIGETJMP` that returns index `i` on failure. +DICTUGETJMPZ,,#F4BD,dict_special,F4BD,DICTUGETJMPZ,i D n - i or nothing,,A variant of `DICTUGETJMP` that returns index `i` on failure. +DICTIGETEXECZ,,#F4BE,dict_special,F4BE,DICTIGETEXECZ,i D n - i or nothing,,A variant of `DICTIGETEXEC` that returns index `i` on failure. +DICTUGETEXECZ,,#F4BF,dict_special,F4BF,DICTUGETEXECZ,i D n - i or nothing,,A variant of `DICTUGETEXEC` that returns index `i` on failure. +SUBDICTGET,,#F4B1,dict_sub,F4B1,SUBDICTGET,k l D n - D',,"Constructs a subdictionary consisting of all keys beginning with prefix `k` (represented by a _Slice_, the first `0 <= l <= n <= 1023` data bits of which are used as a key) of length `l` in dictionary `D` of type `HashmapE(n,X)` with `n`-bit keys. On success, returns the new subdictionary of the same type `HashmapE(n,X)` as a _Slice_ `D'`." +SUBDICTIGET,,#F4B2,dict_sub,F4B2,SUBDICTIGET,x l D n - D',,"Variant of `SUBDICTGET` with the prefix represented by a signed big-endian `l`-bit _Integer_ `x`, where necessarily `l <= 257`." +SUBDICTUGET,,#F4B3,dict_sub,F4B3,SUBDICTUGET,x l D n - D',,"Variant of `SUBDICTGET` with the prefix represented by an unsigned big-endian `l`-bit _Integer_ `x`, where necessarily `l <= 256`." +SUBDICTRPGET,,#F4B5,dict_sub,F4B5,SUBDICTRPGET,k l D n - D',,"Similar to `SUBDICTGET`, but removes the common prefix `k` from all keys of the new dictionary `D'`, which becomes of type `HashmapE(n-l,X)`." +SUBDICTIRPGET,,#F4B6,dict_sub,F4B6,SUBDICTIRPGET,x l D n - D',,"Variant of `SUBDICTRPGET` with the prefix represented by a signed big-endian `l`-bit _Integer_ `x`, where necessarily `l <= 257`." +SUBDICTURPGET,,#F4B7,dict_sub,F4B7,SUBDICTURPGET,x l D n - D',,"Variant of `SUBDICTRPGET` with the prefix represented by an unsigned big-endian `l`-bit _Integer_ `x`, where necessarily `l <= 256`." +ACCEPT,,#F800,app_gas,F800,ACCEPT,-,26,"Sets current gas limit `g_l` to its maximal allowed value `g_m`, and resets the gas credit `g_c` to zero, decreasing the value of `g_r` by `g_c` in the process. +In other words, the current smart contract agrees to buy some gas to finish the current transaction. This action is required to process external messages, which bring no value (hence no gas) with themselves." +SETGASLIMIT,,#F801,app_gas,F801,SETGASLIMIT,g - ,26,"Sets current gas limit `g_l` to the minimum of `g` and `g_m`, and resets the gas credit `g_c` to zero. If the gas consumed so far (including the present instruction) exceeds the resulting value of `g_l`, an (unhandled) out of gas exception is thrown before setting new gas limits. Notice that `SETGASLIMIT` with an argument `g >= 2^63-1` is equivalent to `ACCEPT`." +COMMIT,,#F80F,app_gas,F80F,COMMIT,-,26,Commits the current state of registers `c4` (“persistent data'') and `c5` (“actions'') so that the current execution is considered “successful'' with the saved values even if an exception is thrown later. +RANDU256,,#F810,app_rnd,F810,RANDU256,- x,26+|c7|+|c1_1|,"Generates a new pseudo-random unsigned 256-bit _Integer_ `x`. The algorithm is as follows: if `r` is the old value of the random seed, considered as a 32-byte array (by constructing the big-endian representation of an unsigned 256-bit integer), then its `sha512(r)` is computed; the first 32 bytes of this hash are stored as the new value `r'` of the random seed, and the remaining 32 bytes are returned as the next random value `x`." +RAND,,#F811,app_rnd,F811,RAND,y - z,26+|c7|+|c1_1|,"Generates a new pseudo-random integer `z` in the range `0...y-1` (or `y...-1`, if `y<0`). More precisely, an unsigned random value `x` is generated as in `RAND256U`; then `z:=floor(x*y/2^256)` is computed. +Equivalent to `RANDU256` `256 MULRSHIFT`." +SETRAND,,#F814,app_rnd,F814,SETRAND,x - ,26+|c7|+|c1_1|,Sets the random seed to unsigned 256-bit _Integer_ `x`. +ADDRAND,,#F815,app_rnd,F815,"ADDRAND +RANDOMIZE",x - ,26,"Mixes unsigned 256-bit _Integer_ `x` into the random seed `r` by setting the random seed to `Sha` of the concatenation of two 32-byte strings: the first with the big-endian representation of the old seed `r`, and the second with the big-endian representation of `x`." +GETPARAM,,#F82 i:uint4,app_config,F82i,[i] GETPARAM, - x,26,"Returns the `i`-th parameter from the _Tuple_ provided at `c7` for `0 <= i <= 15`. Equivalent to `c7 PUSHCTR` `FIRST` `[i] INDEX`. +If one of these internal operations fails, throws an appropriate type checking or range checking exception." +NOW,GETPARAM,#F823,app_config,F823,NOW, - x,26,"Returns the current Unix time as an _Integer_. If it is impossible to recover the requested value starting from `c7`, throws a type checking or range checking exception as appropriate. +Equivalent to `3 GETPARAM`." +BLOCKLT,GETPARAM,#F824,app_config,F824,BLOCKLT, - x,26,"Returns the starting logical time of the current block. +Equivalent to `4 GETPARAM`." +LTIME,GETPARAM,#F825,app_config,F825,LTIME, - x,26,"Returns the logical time of the current transaction. +Equivalent to `5 GETPARAM`." +RANDSEED,GETPARAM,#F826,app_config,F826,RANDSEED, - x,26,"Returns the current random seed as an unsigned 256-bit _Integer_. +Equivalent to `6 GETPARAM`." +BALANCE,GETPARAM,#F827,app_config,F827,BALANCE, - t,26,"Returns the remaining balance of the smart contract as a _Tuple_ consisting of an _Integer_ (the remaining Gram balance in nanograms) and a _Maybe Cell_ (a dictionary with 32-bit keys representing the balance of “extra currencies''). +Equivalent to `7 GETPARAM`. +Note that `RAW` primitives such as `SENDRAWMSG` do not update this field." +MYADDR,GETPARAM,#F828,app_config,F828,MYADDR, - s,26,"Returns the internal address of the current smart contract as a _Slice_ with a `MsgAddressInt`. If necessary, it can be parsed further using primitives such as `PARSEMSGADDR` or `REWRITESTDADDR`. +Equivalent to `8 GETPARAM`." +CONFIGROOT,GETPARAM,#F829,app_config,F829,CONFIGROOT, - D,26,Returns the _Maybe Cell_ `D` with the current global configuration dictionary. Equivalent to `9 GETPARAM `. +CONFIGDICT,,#F830,app_config,F830,CONFIGDICT, - D 32,26,"Returns the global configuration dictionary along with its key length (32). +Equivalent to `CONFIGROOT` `32 PUSHINT`." +CONFIGPARAM,,#F832,app_config,F832,CONFIGPARAM,i - c -1 or 0,,"Returns the value of the global configuration parameter with integer index `i` as a _Cell_ `c`, and a flag to indicate success. +Equivalent to `CONFIGDICT` `DICTIGETREF`." +CONFIGOPTPARAM,,#F833,app_config,F833,CONFIGOPTPARAM,i - c^?,,"Returns the value of the global configuration parameter with integer index `i` as a _Maybe Cell_ `c^?`. +Equivalent to `CONFIGDICT` `DICTIGETOPTREF`." +GETGLOBVAR,,#F840,app_global,F840,GETGLOBVAR,k - x,26,"Returns the `k`-th global variable for `0 <= k < 255`. +Equivalent to `c7 PUSHCTR` `SWAP` `INDEXVARQ`." +GETGLOB,,#F85_ k:(## 5) {1 <= k},app_global,F85_k,[k] GETGLOB, - x,26,"Returns the `k`-th global variable for `1 <= k <= 31`. +Equivalent to `c7 PUSHCTR` `[k] INDEXQ`." +SETGLOBVAR,,#F860,app_global,F860,SETGLOBVAR,x k - ,26+|c7’|,"Assigns `x` to the `k`-th global variable for `0 <= k < 255`. +Equivalent to `c7 PUSHCTR` `ROTREV` `SETINDEXVARQ` `c7 POPCTR`." +SETGLOB,,#F87_ k:(## 5) {1 <= k},app_global,F87_k,[k] SETGLOB,x - ,26+|c7’|,"Assigns `x` to the `k`-th global variable for `1 <= k <= 31`. +Equivalent to `c7 PUSHCTR` `SWAP` `k SETINDEXQ` `c7 POPCTR`." +HASHCU,,#F900,app_crypto,F900,HASHCU,c - x,26,Computes the representation hash of a _Cell_ `c` and returns it as a 256-bit unsigned integer `x`. Useful for signing and checking signatures of arbitrary entities represented by a tree of cells. +HASHSU,,#F901,app_crypto,F901,HASHSU,s - x,526,Computes the hash of a _Slice_ `s` and returns it as a 256-bit unsigned integer `x`. The result is the same as if an ordinary cell containing only data and references from `s` had been created and its hash computed by `HASHCU`. +SHA256U,,#F902,app_crypto,F902,SHA256U,s - x,26,"Computes `Sha` of the data bits of _Slice_ `s`. If the bit length of `s` is not divisible by eight, throws a cell underflow exception. The hash value is returned as a 256-bit unsigned integer `x`." +CHKSIGNU,,#F910,app_crypto,F910,CHKSIGNU,h s k - ?,26,"Checks the Ed25519-signature `s` of a hash `h` (a 256-bit unsigned integer, usually computed as the hash of some data) using public key `k` (also represented by a 256-bit unsigned integer). +The signature `s` must be a _Slice_ containing at least 512 data bits; only the first 512 bits are used. The result is `-1` if the signature is valid, `0` otherwise. +Notice that `CHKSIGNU` is equivalent to `ROT` `NEWC` `256 STU` `ENDC` `ROTREV` `CHKSIGNS`, i.e., to `CHKSIGNS` with the first argument `d` set to 256-bit _Slice_ containing `h`. Therefore, if `h` is computed as the hash of some data, these data are hashed _twice_, the second hashing occurring inside `CHKSIGNS`." +CHKSIGNS,,#F911,app_crypto,F911,CHKSIGNS,d s k - ?,26,"Checks whether `s` is a valid Ed25519-signature of the data portion of _Slice_ `d` using public key `k`, similarly to `CHKSIGNU`. If the bit length of _Slice_ `d` is not divisible by eight, throws a cell underflow exception. The verification of Ed25519 signatures is the standard one, with `Sha` used to reduce `d` to the 256-bit number that is actually signed." +CDATASIZEQ,,#F940,app_misc,F940,CDATASIZEQ,c n - x y z -1 or 0,,"Recursively computes the count of distinct cells `x`, data bits `y`, and cell references `z` in the dag rooted at _Cell_ `c`, effectively returning the total storage used by this dag taking into account the identification of equal cells. The values of `x`, `y`, and `z` are computed by a depth-first traversal of this dag, with a hash table of visited cell hashes used to prevent visits of already-visited cells. The total count of visited cells `x` cannot exceed non-negative _Integer_ `n`; otherwise the computation is aborted before visiting the `(n+1)`-st cell and a zero is returned to indicate failure. If `c` is _Null_, returns `x=y=z=0`." +CDATASIZE,,#F941,app_misc,F941,CDATASIZE,c n - x y z,,A non-quiet version of `CDATASIZEQ` that throws a cell overflow exception (8) on failure. +SDATASIZEQ,,#F942,app_misc,F942,SDATASIZEQ,s n - x y z -1 or 0,,"Similar to `CDATASIZEQ`, but accepting a _Slice_ `s` instead of a _Cell_. The returned value of `x` does not take into account the cell that contains the slice `s` itself; however, the data bits and the cell references of `s` are accounted for in `y` and `z`." +SDATASIZE,,#F943,app_misc,F943,SDATASIZE,s n - x y z,,A non-quiet version of `SDATASIZEQ` that throws a cell overflow exception (8) on failure. +LDGRAMS,,#FA00,app_currency,FA00,"LDGRAMS +LDVARUINT16",s - x s',26,"Loads (deserializes) a `Gram` or `VarUInteger 16` amount from _Slice_ `s`, and returns the amount as _Integer_ `x` along with the remainder `s'` of `s`. The expected serialization of `x` consists of a 4-bit unsigned big-endian integer `l`, followed by an `8l`-bit unsigned big-endian representation of `x`. +The net effect is approximately equivalent to `4 LDU` `SWAP` `3 LSHIFT#` `LDUX`." +LDVARINT16,,#FA01,app_currency,FA01,LDVARINT16,s - x s',26,"Similar to `LDVARUINT16`, but loads a _signed_ _Integer_ `x`. +Approximately equivalent to `4 LDU` `SWAP` `3 LSHIFT#` `LDIX`." +STGRAMS,,#FA02,app_currency,FA02,"STGRAMS +STVARUINT16",b x - b',26,"Stores (serializes) an _Integer_ `x` in the range `0...2^120-1` into _Builder_ `b`, and returns the resulting _Builder_ `b'`. The serialization of `x` consists of a 4-bit unsigned big-endian integer `l`, which is the smallest integer `l>=0`, such that `x<2^(8l)`, followed by an `8l`-bit unsigned big-endian representation of `x`. If `x` does not belong to the supported range, a range check exception is thrown." +STVARINT16,,#FA03,app_currency,FA03,STVARINT16,b x - b',26,"Similar to `STVARUINT16`, but serializes a _signed_ _Integer_ `x` in the range `-2^119...2^119-1`." +LDMSGADDR,,#FA40,app_addr,FA40,LDMSGADDR,s - s' s'',26,"Loads from _Slice_ `s` the only prefix that is a valid `MsgAddress`, and returns both this prefix `s'` and the remainder `s''` of `s` as slices." +LDMSGADDRQ,,#FA41,app_addr,FA41,LDMSGADDRQ,s - s' s'' -1 or s 0,26,"A quiet version of `LDMSGADDR`: on success, pushes an extra `-1`; on failure, pushes the original `s` and a zero." +PARSEMSGADDR,,#FA42,app_addr,FA42,PARSEMSGADDR,s - t,26,"Decomposes _Slice_ `s` containing a valid `MsgAddress` into a _Tuple_ `t` with separate fields of this `MsgAddress`. If `s` is not a valid `MsgAddress`, a cell deserialization exception is thrown." +PARSEMSGADDRQ,,#FA43,app_addr,FA43,PARSEMSGADDRQ,s - t -1 or 0,26,A quiet version of `PARSEMSGADDR`: returns a zero on error instead of throwing an exception. +REWRITESTDADDR,,#FA44,app_addr,FA44,REWRITESTDADDR,s - x y,26,"Parses _Slice_ `s` containing a valid `MsgAddressInt` (usually a `msg_addr_std`), applies rewriting from the `anycast` (if present) to the same-length prefix of the address, and returns both the workchain `x` and the 256-bit address `y` as integers. If the address is not 256-bit, or if `s` is not a valid serialization of `MsgAddressInt`, throws a cell deserialization exception." +REWRITESTDADDRQ,,#FA45,app_addr,FA45,REWRITESTDADDRQ,s - x y -1 or 0,26,A quiet version of primitive `REWRITESTDADDR`. +REWRITEVARADDR,,#FA46,app_addr,FA46,REWRITEVARADDR,s - x s',26,"A variant of `REWRITESTDADDR` that returns the (rewritten) address as a _Slice_ `s`, even if it is not exactly 256 bit long (represented by a `msg_addr_var`)." +REWRITEVARADDRQ,,#FA47,app_addr,FA47,REWRITEVARADDRQ,s - x s' -1 or 0,26,A quiet version of primitive `REWRITEVARADDR`. +SENDRAWMSG,,#FB00,app_actions,FB00,SENDRAWMSG,c x - ,526,"Sends a raw message contained in _Cell `c`_, which should contain a correctly serialized object `Message X`, with the only exception that the source address is allowed to have dummy value `addr_none` (to be automatically replaced with the current smart-contract address), and `ihr_fee`, `fwd_fee`, `created_lt` and `created_at` fields can have arbitrary values (to be rewritten with correct values during the action phase of the current transaction). Integer parameter `x` contains the flags. Currently `x=0` is used for ordinary messages; `x=128` is used for messages that are to carry all the remaining balance of the current smart contract (instead of the value originally indicated in the message); `x=64` is used for messages that carry all the remaining value of the inbound message in addition to the value initially indicated in the new message (if bit 0 is not set, the gas fees are deducted from this amount); `x'=x+1` means that the sender wants to pay transfer fees separately; `x'=x+2` means that any errors arising while processing this message during the action phase should be ignored. Finally, `x'=x+32` means that the current account must be destroyed if its resulting balance is zero. This flag is usually employed together with `+128`." +RAWRESERVE,,#FB02,app_actions,FB02,RAWRESERVE,x y - ,526,"Creates an output action which would reserve exactly `x` nanograms (if `y=0`), at most `x` nanograms (if `y=2`), or all but `x` nanograms (if `y=1` or `y=3`), from the remaining balance of the account. It is roughly equivalent to creating an outbound message carrying `x` nanograms (or `b-x` nanograms, where `b` is the remaining balance) to oneself, so that the subsequent output actions would not be able to spend more money than the remainder. Bit `+2` in `y` means that the external action does not fail if the specified amount cannot be reserved; instead, all remaining balance is reserved. Bit `+8` in `y` means `x:=-x` before performing any further actions. Bit `+4` in `y` means that `x` is increased by the original balance of the current account (before the compute phase), including all extra currencies, before performing any other checks and actions. Currently `x` must be a non-negative integer, and `y` must be in the range `0...15`." +RAWRESERVEX,,#FB03,app_actions,FB03,RAWRESERVEX,x D y - ,526,"Similar to `RAWRESERVE`, but also accepts a dictionary `D` (represented by a _Cell_ or _Null_) with extra currencies. In this way currencies other than Grams can be reserved." +SETCODE,,#FB04,app_actions,FB04,SETCODE,c - ,526,Creates an output action that would change this smart contract code to that given by _Cell_ `c`. Notice that this change will take effect only after the successful termination of the current run of the smart contract. +SETLIBCODE,,#FB06,app_actions,FB06,SETLIBCODE,c x - ,526,"Creates an output action that would modify the collection of this smart contract libraries by adding or removing library with code given in _Cell_ `c`. If `x=0`, the library is actually removed if it was previously present in the collection (if not, this action does nothing). If `x=1`, the library is added as a private library, and if `x=2`, the library is added as a public library (and becomes available to all smart contracts if the current smart contract resides in the masterchain); if the library was present in the collection before, its public/private status is changed according to `x`. Values of `x` other than `0...2` are invalid." +CHANGELIB,,#FB07,app_actions,FB07,CHANGELIB,h x - ,526,"Creates an output action similarly to `SETLIBCODE`, but instead of the library code accepts its hash as an unsigned 256-bit integer `h`. If `x!=0` and the library with hash `h` is absent from the library collection of this smart contract, this output action will fail." +DEBUG,,#FE nn:(#<= 239),debug,FEnn,{nn} DEBUG,-,26,`0 <= nn < 240` +DEBUGSTR,,#FEF n:(## 4) ssss:((n * 8 + 8) * Bit),debug,FEFnssss,"{string} DEBUGSTR +{string} {x} DEBUGSTRI",-,26,"`0 <= n < 16`. Length of `ssss` is `n+1` bytes. +`{string}` is a [string literal](https://github.com/Piterden/TON-docs/blob/master/Fift.%20A%20Brief%20Introduction.md#user-content-29-string-literals). +`DEBUGSTR`: `ssss` is the given string. +`DEBUGSTRI`: `ssss` is one-byte integer `0 <= x <= 255` followed by the given string." +DUMPSTK,DEBUG,#FE00,debug,FE00,DUMPSTK,-,26,Dumps the stack (at most the top 255 values) and shows the total stack depth. +DUMP,DEBUG,#FE2 i:uint4,debug,FE2i,s[i] DUMP,-,26,Dumps `s[i]`. +SETCP,,#FF nn:(#<= 239),codepage,FFnn,[nn] SETCP,-,26,"Selects TVM codepage `0 <= nn < 240`. If the codepage is not supported, throws an invalid opcode exception." +SETCP0,SETCP,#FF00,codepage,FF00,SETCP0,-,26,Selects TVM (test) codepage zero as described in this document. +SETCP_SPECIAL,,#FFF z:(## 4) {1 <= z},codepage,FFFz,[z-16] SETCP,-,26,"Selects TVM codepage `z-16` for `1 <= z <= 15`. Negative codepages `-13...-1` are reserved for restricted versions of TVM needed to validate runs of TVM in other codepages. Negative codepage `-14` is reserved for experimental codepages, not necessarily compatible between different TVM implementations, and should be disabled in the production versions of TVM." +SETCPX,,#FFF0,codepage,FFF0,SETCPX,c - ,26,Selects codepage `c` with `-2^15 <= c < 2^15` passed in the top of the stack. diff --git a/versioned_docs/version-1.0.0/learn/tvm-instructions/instructions.md b/versioned_docs/version-1.0.0/learn/tvm-instructions/instructions.md new file mode 100644 index 0000000000..e97560ffc9 --- /dev/null +++ b/versioned_docs/version-1.0.0/learn/tvm-instructions/instructions.md @@ -0,0 +1,956 @@ +# TVM Instructions + +:::caution advanced level +This information is **very low level** and could be hard to understand for newcomers. +So feel free to read about it later. +::: + +## 1 Introduction +This document provides a list of TVM instrucions, their opcodes and mnemonics. + +:::tip +[**Here**](https://ton-blockchain.github.io/tvm.pdf) is a full description of TON Virtual Machine. +::: + +Fift is a stack-based programming language designed to manage TON smart contracts. The Fift assembler is a Fift library that converts mnemonics of TVM instructions to their binary representation. + +A description of Fift, including the introduction to the Fift assembler, can be found [here](https://github.com/Piterden/TON-docs/blob/master/Fift.%20A%20Brief%20Introduction.md). + +This document specifies the corresponding mnemonic for each instruction. Note the following: + +1. Fift is a stack-based language, therefore all arguments of an instruction are written before it (e.g. [`5 PUSHINT`](#instr-pushint-4), [`s0 s4 XCHG`](#instr-xchg-ij)). +2. Stack registers are denoted by `s0, s1, ..., s15`. Other stack registers (up to 255) are denoted by `i s()` (e.g. `100 s()`). +3. Control registers are denoted by `c0, c1, ..., c15`. + +### 1.1 Gas prices +The gas price of each instruction is specified in this document. The basic gas price of an instruction is `10 + b`, where `b` is the instruction length in bits. Some operations have additional fees: +1. _Parsing cells_: Transforming a cell into a slice costs **100 gas units** if the cell is loading for the first time and **25** for subsequent loads during the same transaction. For such instructions, two gas prices are specified (e.g. [`CTOS`](#instr-ctos): `118/43`). +2. _Cell creation_: **500 gas units**. +3. _Throwing exceptions_: **50 gas units**. In this document the exception fee is only specified for an instruction if its primary purpose is to throw (e.g. [`THROWIF`](#instr-throwif-short), [`FITS`](#instr-fits)). If the instruction only throws in some cases, two gas prices are specified (e.g. [`FITS`](#instr-fits): `26/76`). +4. _Tuple creation_: **1 gas unit** for every tuple element. +5. _Implicit jumps_: **10 gas units** for an implicit jump, **5 gas units** for an implicit back jump. This fee is not a part of any instruction. +6. _Moving stack elements between continuations_: **1 gas unit** per element, however first 32 elements moving is free. + +### 1.2 CSV table +Machine-readable list of TVM instructions is available [here](https://github.com/ton-blockchain/blob/master/smart-contracts/tvm-instructions/instructions.csv). + +## 2 Stack manipulation primitives +Here `0 <= i,j,k <= 15` if not stated otherwise. + +### 2.1 Basic stack manipulation primitives +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`00`** | `NOP` | _`-`_ | Does nothing. | `18` | +| **`01`** | `SWAP` | _`x y - y x`_ | Same as [`s1 XCHG0`](#instr-xchg-0i). | `18` | +| **`0i`** | `s[i] XCHG0` | | Interchanges `s0` with `s[i]`, `1 <= i <= 15`. | `18` | +| **`10ij`** | `s[i] s[j] XCHG` | | Interchanges `s[i]` with `s[j]`, `1 <= i < j <= 15`. | `26` | +| **`11ii`** | `s0 [ii] s() XCHG` | | Interchanges `s0` with `s[ii]`, `0 <= ii <= 255`. | `26` | +| **`1i`** | `s1 s[i] XCHG` | | Interchanges `s1` with `s[i]`, `2 <= i <= 15`. | `18` | +| **`2i`** | `s[i] PUSH` | | Pushes a copy of the old `s[i]` into the stack. | `18` | +| **`20`** | `DUP` | _`x - x x`_ | Same as [`s0 PUSH`](#instr-push). | `18` | +| **`21`** | `OVER` | _`x y - x y x`_ | Same as [`s1 PUSH`](#instr-push). | `18` | +| **`3i`** | `s[i] POP` | | Pops the old `s0` value into the old `s[i]`. | `18` | +| **`30`** | `DROP` | _`x -`_ | Same as [`s0 POP`](#instr-pop), discards the top-of-stack value. | `18` | +| **`31`** | `NIP` | _`x y - y`_ | Same as [`s1 POP`](#instr-pop). | `18` | +### 2.2 Complex stack manipulation primitives +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`4ijk`** | `s[i] s[j] s[k] XCHG3` | | Equivalent to [`s2 s[i] XCHG`](#instr-xchg-ij) [`s1 s[j] XCHG`](#instr-xchg-ij) [`s[k] XCHG0`](#instr-xchg-0i). | `26` | +| **`50ij`** | `s[i] s[j] XCHG2` | | Equivalent to [`s1 s[i] XCHG`](#instr-xchg-ij) [`s[j] XCHG0`](#instr-xchg-0i). | `26` | +| **`51ij`** | `s[i] s[j] XCPU` | | Equivalent to [`s[i] XCHG0`](#instr-xchg-0i) [`s[j] PUSH`](#instr-push). | `26` | +| **`52ij`** | `s[i] s[j-1] PUXC` | | Equivalent to [`s[i] PUSH`](#instr-push) [`SWAP`](#instr-swap) [`s[j] XCHG0`](#instr-xchg-0i). | `26` | +| **`53ij`** | `s[i] s[j] PUSH2` | | Equivalent to [`s[i] PUSH`](#instr-push) [`s[j+1] PUSH`](#instr-push). | `26` | +| **`540ijk`** | `s[i] s[j] s[k] XCHG3_l` | | Long form of [`XCHG3`](#instr-xchg3). | `34` | +| **`541ijk`** | `s[i] s[j] s[k] XC2PU` | | Equivalent to [`s[i] s[j] XCHG2`](#instr-xchg2) [`s[k] PUSH`](#instr-push). | `34` | +| **`542ijk`** | `s[i] s[j] s[k-1] XCPUXC` | | Equivalent to [`s1 s[i] XCHG`](#instr-xchg-ij) [`s[j] s[k-1] PUXC`](#instr-puxc). | `34` | +| **`543ijk`** | `s[i] s[j] s[k] XCPU2` | | Equivalent to [`s[i] XCHG0`](#instr-xchg-0i) [`s[j] s[k] PUSH2`](#instr-push2). | `34` | +| **`544ijk`** | `s[i] s[j-1] s[k-1] PUXC2` | | Equivalent to [`s[i] PUSH`](#instr-push) [`s2 XCHG0`](#instr-xchg-0i) [`s[j] s[k] XCHG2`](#instr-xchg2). | `34` | +| **`545ijk`** | `s[i] s[j-1] s[k-1] PUXCPU` | | Equivalent to [`s[i] s[j-1] PUXC`](#instr-puxc) [`s[k] PUSH`](#instr-push). | `34` | +| **`546ijk`** | `s[i] s[j-1] s[k-2] PU2XC` | | Equivalent to [`s[i] PUSH`](#instr-push) [`SWAP`](#instr-swap) [`s[j] s[k-1] PUXC`](#instr-puxc). | `34` | +| **`547ijk`** | `s[i] s[j] s[k] PUSH3` | | Equivalent to [`s[i] PUSH`](#instr-push) [`s[j+1] s[k+1] PUSH2`](#instr-push2). | `34` | +| **`55ij`** | `[i+1] [j+1] BLKSWAP` | | Permutes two blocks `s[j+i+1] … s[j+1]` and `s[j] … s0`.
    `0 <= i,j <= 15`
    Equivalent to [`[i+1] [j+1] REVERSE`](#instr-reverse) [`[j+1] 0 REVERSE`](#instr-reverse) [`[i+j+2] 0 REVERSE`](#instr-reverse). | `26` | +| **`5513`** | `ROT2`
    `2ROT` | _`a b c d e f - c d e f a b`_ | Rotates the three topmost pairs of stack entries. | `26` | +| **`550i`** | `[i+1] ROLL` | | Rotates the top `i+1` stack entries.
    Equivalent to [`1 [i+1] BLKSWAP`](#instr-blkswap). | `26` | +| **`55i0`** | `[i+1] -ROLL`
    `[i+1] ROLLREV` | | Rotates the top `i+1` stack entries in the other direction.
    Equivalent to [`[i+1] 1 BLKSWAP`](#instr-blkswap). | `26` | +| **`56ii`** | `[ii] s() PUSH` | | Pushes a copy of the old `s[ii]` into the stack.
    `0 <= ii <= 255` | `26` | +| **`57ii`** | `[ii] s() POP` | | Pops the old `s0` value into the old `s[ii]`.
    `0 <= ii <= 255` | `26` | +| **`58`** | `ROT` | _`a b c - b c a`_ | Equivalent to [`1 2 BLKSWAP`](#instr-blkswap) or to [`s2 s1 XCHG2`](#instr-xchg2). | `18` | +| **`59`** | `ROTREV`
    `-ROT` | _`a b c - c a b`_ | Equivalent to [`2 1 BLKSWAP`](#instr-blkswap) or to [`s2 s2 XCHG2`](#instr-xchg2). | `18` | +| **`5A`** | `SWAP2`
    `2SWAP` | _`a b c d - c d a b`_ | Equivalent to [`2 2 BLKSWAP`](#instr-blkswap) or to [`s3 s2 XCHG2`](#instr-xchg2). | `18` | +| **`5B`** | `DROP2`
    `2DROP` | _`a b - `_ | Equivalent to [`DROP`](#instr-drop) [`DROP`](#instr-drop). | `18` | +| **`5C`** | `DUP2`
    `2DUP` | _`a b - a b a b`_ | Equivalent to [`s1 s0 PUSH2`](#instr-push2). | `18` | +| **`5D`** | `OVER2`
    `2OVER` | _`a b c d - a b c d a b`_ | Equivalent to [`s3 s2 PUSH2`](#instr-push2). | `18` | +| **`5Eij`** | `[i+2] [j] REVERSE` | | Reverses the order of `s[j+i+1] … s[j]`. | `26` | +| **`5F0i`** | `[i] BLKDROP` | | Equivalent to [`DROP`](#instr-drop) performed `i` times. | `26` | +| **`5Fij`** | `[i] [j] BLKPUSH` | | Equivalent to `PUSH s(j)` performed `i` times.
    `1 <= i <= 15`, `0 <= j <= 15`. | `26` | +| **`60`** | `PICK`
    `PUSHX` | | Pops integer `i` from the stack, then performs [`s[i] PUSH`](#instr-push). | `18` | +| **`61`** | `ROLLX` | | Pops integer `i` from the stack, then performs [`1 [i] BLKSWAP`](#instr-blkswap). | `18` | +| **`62`** | `-ROLLX`
    `ROLLREVX` | | Pops integer `i` from the stack, then performs [`[i] 1 BLKSWAP`](#instr-blkswap). | `18` | +| **`63`** | `BLKSWX` | | Pops integers `i`,`j` from the stack, then performs [`[i] [j] BLKSWAP`](#instr-blkswap). | `18` | +| **`64`** | `REVX` | | Pops integers `i`,`j` from the stack, then performs [`[i] [j] REVERSE`](#instr-reverse). | `18` | +| **`65`** | `DROPX` | | Pops integer `i` from the stack, then performs [`[i] BLKDROP`](#instr-blkdrop). | `18` | +| **`66`** | `TUCK` | _`a b - b a b`_ | Equivalent to [`SWAP`](#instr-swap) [`OVER`](#instr-over) or to [`s1 s1 XCPU`](#instr-xcpu). | `18` | +| **`67`** | `XCHGX` | | Pops integer `i` from the stack, then performs [`s[i] XCHG`](#instr-xchg-ij). | `18` | +| **`68`** | `DEPTH` | _`- depth`_ | Pushes the current depth of the stack. | `18` | +| **`69`** | `CHKDEPTH` | _`i -`_ | Pops integer `i` from the stack, then checks whether there are at least `i` elements, generating a stack underflow exception otherwise. | `18/58` | +| **`6A`** | `ONLYTOPX` | | Pops integer `i` from the stack, then removes all but the top `i` elements. | `18` | +| **`6B`** | `ONLYX` | | Pops integer `i` from the stack, then leaves only the bottom `i` elements. Approximately equivalent to [`DEPTH`](#instr-depth) [`SWAP`](#instr-swap) [`SUB`](#instr-sub) [`DROPX`](#instr-dropx). | `18` | +| **`6Cij`** | `[i] [j] BLKDROP2` | | Drops `i` stack elements under the top `j` elements.
    `1 <= i <= 15`, `0 <= j <= 15`
    Equivalent to [`[i+j] 0 REVERSE`](#instr-reverse) [`[i] BLKDROP`](#instr-blkdrop) [`[j] 0 REVERSE`](#instr-reverse). | `26` | + +## 3 Tuple, List, and Null primitives +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`6D`** | `NULL`
    `PUSHNULL` | _` - null`_ | Pushes the only value of type _Null_. | `18` | +| **`6E`** | `ISNULL` | _`x - ?`_ | Checks whether `x` is a _Null_, and returns `-1` or `0` accordingly. | `18` | +| **`6F0n`** | `[n] TUPLE` | _`x_1 ... x_n - t`_ | Creates a new _Tuple_ `t=(x_1, … ,x_n)` containing `n` values `x_1`,..., `x_n`.
    `0 <= n <= 15` | `26+n` | +| **`6F00`** | `NIL` | _`- t`_ | Pushes the only _Tuple_ `t=()` of length zero. | `26` | +| **`6F01`** | `SINGLE` | _`x - t`_ | Creates a singleton `t:=(x)`, i.e., a _Tuple_ of length one. | `27` | +| **`6F02`** | `PAIR`
    `CONS` | _`x y - t`_ | Creates pair `t:=(x,y)`. | `28` | +| **`6F03`** | `TRIPLE` | _`x y z - t`_ | Creates triple `t:=(x,y,z)`. | `29` | +| **`6F1k`** | `[k] INDEX` | _`t - x`_ | Returns the `k`-th element of a _Tuple_ `t`.
    `0 <= k <= 15`. | `26` | +| **`6F10`** | `FIRST`
    `CAR` | _`t - x`_ | Returns the first element of a _Tuple_. | `26` | +| **`6F11`** | `SECOND`
    `CDR` | _`t - y`_ | Returns the second element of a _Tuple_. | `26` | +| **`6F12`** | `THIRD` | _`t - z`_ | Returns the third element of a _Tuple_. | `26` | +| **`6F2n`** | `[n] UNTUPLE` | _`t - x_1 ... x_n`_ | Unpacks a _Tuple_ `t=(x_1,...,x_n)` of length equal to `0 <= n <= 15`.
    If `t` is not a _Tuple_, or if `\|t\| != n`, a type check exception is thrown. | `26+n` | +| **`6F21`** | `UNSINGLE` | _`t - x`_ | Unpacks a singleton `t=(x)`. | `27` | +| **`6F22`** | `UNPAIR`
    `UNCONS` | _`t - x y`_ | Unpacks a pair `t=(x,y)`. | `28` | +| **`6F23`** | `UNTRIPLE` | _`t - x y z`_ | Unpacks a triple `t=(x,y,z)`. | `29` | +| **`6F3k`** | `[k] UNPACKFIRST` | _`t - x_1 ... x_k`_ | Unpacks first `0 <= k <= 15` elements of a _Tuple_ `t`.
    If `\|t\|`0 <= k <= 15`
    If `k >= \|t\|`, throws a range check exception. | `26+\|t\|` | +| **`6F50`** | `SETFIRST` | _`t x - t'`_ | Sets the first component of _Tuple_ `t` to `x` and returns the resulting _Tuple_ `t'`. | `26+\|t\|` | +| **`6F51`** | `SETSECOND` | _`t x - t'`_ | Sets the second component of _Tuple_ `t` to `x` and returns the resulting _Tuple_ `t'`. | `26+\|t\|` | +| **`6F52`** | `SETTHIRD` | _`t x - t'`_ | Sets the third component of _Tuple_ `t` to `x` and returns the resulting _Tuple_ `t'`. | `26+\|t\|` | +| **`6F6k`** | `[k] INDEXQ` | _`t - x`_ | Returns the `k`-th element of a _Tuple_ `t`, where `0 <= k <= 15`. In other words, returns `x_{k+1}` if `t=(x_1,...,x_n)`. If `k>=n`, or if `t` is _Null_, returns a _Null_ instead of `x`. | `26` | +| **`6F60`** | `FIRSTQ`
    `CARQ` | _`t - x`_ | Returns the first element of a _Tuple_. | `26` | +| **`6F61`** | `SECONDQ`
    `CDRQ` | _`t - y`_ | Returns the second element of a _Tuple_. | `26` | +| **`6F62`** | `THIRDQ` | _`t - z`_ | Returns the third element of a _Tuple_. | `26` | +| **`6F7k`** | `[k] SETINDEXQ` | _`t x - t'`_ | Sets the `k`-th component of _Tuple_ `t` to `x`, where `0 <= k < 16`, and returns the resulting _Tuple_ `t'`.
    If `\|t\| <= k`, first extends the original _Tuple_ to length `n’=k+1` by setting all new components to _Null_. If the original value of `t` is _Null_, treats it as an empty _Tuple_. If `t` is not _Null_ or _Tuple_, throws an exception. If `x` is _Null_ and either `\|t\| <= k` or `t` is _Null_, then always returns `t'=t` (and does not consume tuple creation gas). | `26+\|t’\|` | +| **`6F70`** | `SETFIRSTQ` | _`t x - t'`_ | Sets the first component of _Tuple_ `t` to `x` and returns the resulting _Tuple_ `t'`. | `26+\|t’\|` | +| **`6F71`** | `SETSECONDQ` | _`t x - t'`_ | Sets the second component of _Tuple_ `t` to `x` and returns the resulting _Tuple_ `t'`. | `26+\|t’\|` | +| **`6F72`** | `SETTHIRDQ` | _`t x - t'`_ | Sets the third component of _Tuple_ `t` to `x` and returns the resulting _Tuple_ `t'`. | `26+\|t’\|` | +| **`6F80`** | `TUPLEVAR` | _`x_1 ... x_n n - t`_ | Creates a new _Tuple_ `t` of length `n` similarly to [`TUPLE`](#instr-tuple), but with `0 <= n <= 255` taken from the stack. | `26+n` | +| **`6F81`** | `INDEXVAR` | _`t k - x`_ | Similar to [`k INDEX`](#instr-index), but with `0 <= k <= 254` taken from the stack. | `26` | +| **`6F82`** | `UNTUPLEVAR` | _`t n - x_1 ... x_n`_ | Similar to [`n UNTUPLE`](#instr-untuple), but with `0 <= n <= 255` taken from the stack. | `26+n` | +| **`6F83`** | `UNPACKFIRSTVAR` | _`t n - x_1 ... x_n`_ | Similar to [`n UNPACKFIRST`](#instr-unpackfirst), but with `0 <= n <= 255` taken from the stack. | `26+n` | +| **`6F84`** | `EXPLODEVAR` | _`t n - x_1 ... x_m m`_ | Similar to [`n EXPLODE`](#instr-explode), but with `0 <= n <= 255` taken from the stack. | `26+m` | +| **`6F85`** | `SETINDEXVAR` | _`t x k - t'`_ | Similar to [`k SETINDEX`](#instr-setindex), but with `0 <= k <= 254` taken from the stack. | `26+\|t’\|` | +| **`6F86`** | `INDEXVARQ` | _`t k - x`_ | Similar to [`n INDEXQ`](#instr-indexq), but with `0 <= k <= 254` taken from the stack. | `26` | +| **`6F87`** | `SETINDEXVARQ` | _`t x k - t'`_ | Similar to [`k SETINDEXQ`](#instr-setindexq), but with `0 <= k <= 254` taken from the stack. | `26+\|t’\|` | +| **`6F88`** | `TLEN` | _`t - n`_ | Returns the length of a _Tuple_. | `26` | +| **`6F89`** | `QTLEN` | _`t - n or -1`_ | Similar to [`TLEN`](#instr-tlen), but returns `-1` if `t` is not a _Tuple_. | `26` | +| **`6F8A`** | `ISTUPLE` | _`t - ?`_ | Returns `-1` or `0` depending on whether `t` is a _Tuple_. | `26` | +| **`6F8B`** | `LAST` | _`t - x`_ | Returns the last element of a non-empty _Tuple_ `t`. | `26` | +| **`6F8C`** | `TPUSH`
    `COMMA` | _`t x - t'`_ | Appends a value `x` to a _Tuple_ `t=(x_1,...,x_n)`, but only if the resulting _Tuple_ `t'=(x_1,...,x_n,x)` is of length at most 255. Otherwise throws a type check exception. | `26+\|t’\|` | +| **`6F8D`** | `TPOP` | _`t - t' x`_ | Detaches the last element `x=x_n` from a non-empty _Tuple_ `t=(x_1,...,x_n)`, and returns both the resulting _Tuple_ `t'=(x_1,...,x_{n-1})` and the original last element `x`. | `26+\|t’\|` | +| **`6FA0`** | `NULLSWAPIF` | _`x - x or null x`_ | Pushes a _Null_ under the topmost _Integer_ `x`, but only if `x!=0`. | `26` | +| **`6FA1`** | `NULLSWAPIFNOT` | _`x - x or null x`_ | Pushes a _Null_ under the topmost _Integer_ `x`, but only if `x=0`. May be used for stack alignment after quiet primitives such as [`PLDUXQ`](#instr-plduxq). | `26` | +| **`6FA2`** | `NULLROTRIF` | _`x y - x y or null x y`_ | Pushes a _Null_ under the second stack entry from the top, but only if the topmost _Integer_ `y` is non-zero. | `26` | +| **`6FA3`** | `NULLROTRIFNOT` | _`x y - x y or null x y`_ | Pushes a _Null_ under the second stack entry from the top, but only if the topmost _Integer_ `y` is zero. May be used for stack alignment after quiet primitives such as [`LDUXQ`](#instr-lduxq). | `26` | +| **`6FA4`** | `NULLSWAPIF2` | _`x - x or null null x`_ | Pushes two nulls under the topmost _Integer_ `x`, but only if `x!=0`.
    Equivalent to [`NULLSWAPIF`](#instr-nullswapif) [`NULLSWAPIF`](#instr-nullswapif). | `26` | +| **`6FA5`** | `NULLSWAPIFNOT2` | _`x - x or null null x`_ | Pushes two nulls under the topmost _Integer_ `x`, but only if `x=0`.
    Equivalent to [`NULLSWAPIFNOT`](#instr-nullswapifnot) [`NULLSWAPIFNOT`](#instr-nullswapifnot). | `26` | +| **`6FA6`** | `NULLROTRIF2` | _`x y - x y or null null x y`_ | Pushes two nulls under the second stack entry from the top, but only if the topmost _Integer_ `y` is non-zero.
    Equivalent to [`NULLROTRIF`](#instr-nullrotrif) [`NULLROTRIF`](#instr-nullrotrif). | `26` | +| **`6FA7`** | `NULLROTRIFNOT2` | _`x y - x y or null null x y`_ | Pushes two nulls under the second stack entry from the top, but only if the topmost _Integer_ `y` is zero.
    Equivalent to [`NULLROTRIFNOT`](#instr-nullrotrifnot) [`NULLROTRIFNOT`](#instr-nullrotrifnot). | `26` | +| **`6FBij`** | `[i] [j] INDEX2` | _`t - x`_ | Recovers `x=(t_{i+1})_{j+1}` for `0 <= i,j <= 3`.
    Equivalent to [`[i] INDEX`](#instr-index) [`[j] INDEX`](#instr-index). | `26` | +| **`6FB4`** | `CADR` | _`t - x`_ | Recovers `x=(t_2)_1`. | `26` | +| **`6FB5`** | `CDDR` | _`t - x`_ | Recovers `x=(t_2)_2`. | `26` | +| **`6FE_ijk`** | `[i] [j] [k] INDEX3` | _`t - x`_ | Recovers `x=t_{i+1}_{j+1}_{k+1}`.
    `0 <= i,j,k <= 3`
    Equivalent to [`[i] [j] INDEX2`](#instr-index2) [`[k] INDEX`](#instr-index). | `26` | +| **`6FD4`** | `CADDR` | _`t - x`_ | Recovers `x=t_2_2_1`. | `26` | +| **`6FD5`** | `CDDDR` | _`t - x`_ | Recovers `x=t_2_2_2`. | `26` | + +## 4 Constant, or literal primitives +### 4.1 Integer and boolean constants +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`7i`** | `[x] PUSHINT`
    `[x] INT` | _`- x`_ | Pushes integer `x` into the stack. `-5 <= x <= 10`.
    Here `i` equals four lower-order bits of `x` (`i=x mod 16`). | `18` | +| **`70`** | `ZERO`
    `FALSE` | _`- 0`_ | | `18` | +| **`71`** | `ONE` | _`- 1`_ | | `18` | +| **`72`** | `TWO` | _`- 2`_ | | `18` | +| **`7A`** | `TEN` | _`- 10`_ | | `18` | +| **`7F`** | `TRUE` | _`- -1`_ | | `18` | +| **`80xx`** | `[xx] PUSHINT`
    `[xx] INT` | _`- xx`_ | Pushes integer `xx`. `-128 <= xx <= 127`. | `26` | +| **`81xxxx`** | `[xxxx] PUSHINT`
    `[xxxx] INT` | _`- xxxx`_ | Pushes integer `xxxx`. `-2^15 <= xx < 2^15`. | `34` | +| **`82lxxx`** | `[xxx] PUSHINT`
    `[xxx] INT` | _`- xxx`_ | Pushes integer `xxx`.
    _Details:_ 5-bit `0 <= l <= 30` determines the length `n=8l+19` of signed big-endian integer `xxx`.
    The total length of this instruction is `l+4` bytes or `n+13=8l+32` bits. | `23` | +| **`83xx`** | `[xx+1] PUSHPOW2` | _`- 2^(xx+1)`_ | (Quietly) pushes `2^(xx+1)` for `0 <= xx <= 255`.
    `2^256` is a `NaN`. | `26` | +| **`83FF`** | `PUSHNAN` | _`- NaN`_ | Pushes a `NaN`. | `26` | +| **`84xx`** | `[xx+1] PUSHPOW2DEC` | _`- 2^(xx+1)-1`_ | Pushes `2^(xx+1)-1` for `0 <= xx <= 255`. | `26` | +| **`85xx`** | `[xx+1] PUSHNEGPOW2` | _`- -2^(xx+1)`_ | Pushes `-2^(xx+1)` for `0 <= xx <= 255`. | `26` | +### 4.2 Constant slices, continuations, cells, and references +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`88`** | `[ref] PUSHREF` | _`- c`_ | Pushes the reference `ref` into the stack.
    _Details:_ Pushes the first reference of `cc.code` into the stack as a _Cell_ (and removes this reference from the current continuation). | `18` | +| **`89`** | `[ref] PUSHREFSLICE` | _`- s`_ | Similar to [`PUSHREF`](#instr-pushref), but converts the cell into a _Slice_. | `118/43` | +| **`8A`** | `[ref] PUSHREFCONT` | _`- cont`_ | Similar to [`PUSHREFSLICE`](#instr-pushrefslice), but makes a simple ordinary _Continuation_ out of the cell. | `118/43` | +| **`8Bxsss`** | `[slice] PUSHSLICE`
    `[slice] SLICE` | _`- s`_ | Pushes the slice `slice` into the stack.
    _Details:_ Pushes the (prefix) subslice of `cc.code` consisting of its first `8x+4` bits and no references (i.e., essentially a bitstring), where `0 <= x <= 15`.
    A completion tag is assumed, meaning that all trailing zeroes and the last binary one (if present) are removed from this bitstring.
    If the original bitstring consists only of zeroes, an empty slice will be pushed. | `22` | +| **`8Crxxssss`** | `[slice] PUSHSLICE`
    `[slice] SLICE` | _`- s`_ | Pushes the slice `slice` into the stack.
    _Details:_ Pushes the (prefix) subslice of `cc.code` consisting of its first `1 <= r+1 <= 4` references and up to first `8xx+1` bits of data, with `0 <= xx <= 31`.
    A completion tag is also assumed. | `25` | +| **`8Drxxsssss`** | `[slice] PUSHSLICE`
    `[slice] SLICE` | _`- s`_ | Pushes the slice `slice` into the stack.
    _Details:_ Pushes the subslice of `cc.code` consisting of `0 <= r <= 4` references and up to `8xx+6` bits of data, with `0 <= xx <= 127`.
    A completion tag is assumed. | `28` | +| | `x{} PUSHSLICE`
    `x{ABCD1234} PUSHSLICE`
    `b{01101} PUSHSLICE` | _`- s`_ | Examples of [`PUSHSLICE`](#instr-pushslice).
    `x{}` is an empty slice. `x{...}` is a hexadecimal literal. `b{...}` is a binary literal.
    More on slice literals [here](https://github.com/Piterden/TON-docs/blob/master/Fift.%20A%20Brief%20Introduction.md#user-content-51-slice-literals).
    Note that the assembler can replace [`PUSHSLICE`](#instr-pushslice) with [`PUSHREFSLICE`](#instr-pushrefslice) in certain situations (e.g. if there’s not enough space in the current continuation). | | +| | ` PUSHREF`
    ` PUSHREFSLICE` | _`- c/s`_ | Examples of [`PUSHREF`](#instr-pushref) and [`PUSHREFSLICE`](#instr-pushrefslice).
    More on building cells in fift [here](https://github.com/Piterden/TON-docs/blob/master/Fift.%20A%20Brief%20Introduction.md#user-content-52-builder-primitives). | | +| **`8F_rxxcccc`** | `[builder] PUSHCONT`
    `[builder] CONT` | _`- c`_ | Pushes a continuation made from `builder`.
    _Details:_ Pushes the simple ordinary continuation `cccc` made from the first `0 <= r <= 3` references and the first `0 <= xx <= 127` bytes of `cc.code`. | `26` | +| **`9xccc`** | `[builder] PUSHCONT`
    `[builder] CONT` | _`- c`_ | Pushes a continuation made from `builder`.
    _Details:_ Pushes an `x`-byte continuation for `0 <= x <= 15`. | `18` | +| | `<{ code }> PUSHCONT`
    `<{ code }> CONT`
    `CONT:<{ code }>` | _`- c`_ | Pushes a continuation with code `code`.
    Note that the assembler can replace [`PUSHCONT`](#instr-pushcont) with [`PUSHREFCONT`](#instr-pushrefcont) in certain situations (e.g. if there’s not enough space in the current continuation). | | + +## 5 Arithmetic primitives +### 5.1 Addition, subtraction, multiplication +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`A0`** | `ADD` | _`x y - x+y`_ | | `18` | +| **`A1`** | `SUB` | _`x y - x-y`_ | | `18` | +| **`A2`** | `SUBR` | _`x y - y-x`_ | Equivalent to [`SWAP`](#instr-swap) [`SUB`](#instr-sub). | `18` | +| **`A3`** | `NEGATE` | _`x - -x`_ | Equivalent to [`-1 MULCONST`](#instr-mulconst) or to [`ZERO SUBR`](#instr-subr).
    Notice that it triggers an integer overflow exception if `x=-2^256`. | `18` | +| **`A4`** | `INC` | _`x - x+1`_ | Equivalent to [`1 ADDCONST`](#instr-addconst). | `18` | +| **`A5`** | `DEC` | _`x - x-1`_ | Equivalent to [`-1 ADDCONST`](#instr-addconst). | `18` | +| **`A6cc`** | `[cc] ADDCONST`
    `[cc] ADDINT`
    `[-cc] SUBCONST`
    `[-cc] SUBINT` | _`x - x+cc`_ | `-128 <= cc <= 127`. | `26` | +| **`A7cc`** | `[cc] MULCONST`
    `[cc] MULINT` | _`x - x*cc`_ | `-128 <= cc <= 127`. | `26` | +| **`A8`** | `MUL` | _`x y - x*y`_ | | `18` | +### 5.2 Division +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`A9mscdf`** | | | This is the general encoding of division, with an optional pre-multiplication and an optional replacement of the division or multiplication by a shift. Variable fields are as follows:
    `0 <= m <= 1` - Indicates whether there is pre-multiplication ([`MULDIV`](#instr-muldiv) and its variants), possibly replaced by a left shift.
    `0 <= s <= 2` - Indicates whether either the multiplication or the division have been replaced by shifts: `s=0` - no replacement, `s=1` - division replaced by a right shift, `s=2` - multiplication replaced by a left shift (possible only for `m=1`).
    `0 <= c <= 1` - Indicates whether there is a constant one-byte argument `tt` for the shift operator (if `s!=0`). For `s=0`, `c=0`. If `c=1`, then `0 <= tt <= 255`, and the shift is performed by `tt+1` bits. If `s!=0` and `c=0`, then the shift amount is provided to the instruction as a top-of-stack _Integer_ in range `0...256`.
    `1 <= d <= 3` - Indicates which results of division are required: `1` - only the quotient, `2` - only the remainder, `3` - both.
    `0 <= f <= 2` - Rounding mode: `0` - floor, `1` - nearest integer, `2` - ceiling.
    All instructions below are variants of this. | `26` | +| **`A904`** | `DIV` | _`x y - q`_ | `q=floor(x/y)`, `r=x-y*q` | `26` | +| **`A905`** | `DIVR` | _`x y - q’`_ | `q’=round(x/y)`, `r’=x-y*q’` | `26` | +| **`A906`** | `DIVC` | _`x y - q''`_ | `q’’=ceil(x/y)`, `r’’=x-y*q’’` | `26` | +| **`A908`** | `MOD` | _`x y - r`_ | | `26` | +| **`A90C`** | `DIVMOD` | _`x y - q r`_ | | `26` | +| **`A90D`** | `DIVMODR` | _`x y - q' r'`_ | | `26` | +| **`A90E`** | `DIVMODC` | _`x y - q'' r''`_ | | `26` | +| **`A925`** | `RSHIFTR` | _`x y - round(x/2^y)`_ | | `26` | +| **`A926`** | `RSHIFTC` | _`x y - ceil(x/2^y)`_ | | `34` | +| **`A935tt`** | `[tt+1] RSHIFTR#` | _`x y - round(x/2^(tt+1))`_ | | `34` | +| **`A936tt`** | `[tt+1] RSHIFTC#` | _`x y - ceil(x/2^(tt+1))`_ | | `34` | +| **`A938tt`** | `[tt+1] MODPOW2#` | _`x - x mod 2^(tt+1)`_ | | `26` | +| **`A98`** | `MULDIV` | _`x y z - q`_ | `q=floor(x*y/z)` | `26` | +| **`A985`** | `MULDIVR` | _`x y z - q'`_ | `q'=round(x*y/z)` | `26` | +| **`A98C`** | `MULDIVMOD` | _`x y z - q r`_ | `q=floor(x*y/z)`, `r=x*y-z*q` | `26` | +| **`A9A4`** | `MULRSHIFT` | _`x y z - floor(x*y/2^z)`_ | `0 <= z <= 256` | `26` | +| **`A9A5`** | `MULRSHIFTR` | _`x y z - round(x*y/2^z)`_ | `0 <= z <= 256` | `26` | +| **`A9A6`** | `MULRSHIFTC` | _`x y z - ceil(x*y/2^z)`_ | `0 <= z <= 256` | `34` | +| **`A9B4tt`** | `[tt+1] MULRSHIFT#` | _`x y - floor(x*y/2^(tt+1))`_ | | `34` | +| **`A9B5tt`** | `[tt+1] MULRSHIFTR#` | _`x y - round(x*y/2^(tt+1))`_ | | `34` | +| **`A9B6tt`** | `[tt+1] MULRSHIFTC#` | _`x y - ceil(x*y/2^(tt+1))`_ | | `26` | +| **`A9C4`** | `LSHIFTDIV` | _`x y z - floor(2^z*x/y)`_ | `0 <= z <= 256` | `26` | +| **`A9C5`** | `LSHIFTDIVR` | _`x y z - round(2^z*x/y)`_ | `0 <= z <= 256` | `26` | +| **`A9C6`** | `LSHIFTDIVC` | _`x y z - ceil(2^z*x/y)`_ | `0 <= z <= 256` | `34` | +| **`A9D4tt`** | `[tt+1] LSHIFT#DIV` | _`x y - floor(2^(tt+1)*x/y)`_ | | `34` | +| **`A9D5tt`** | `[tt+1] LSHIFT#DIVR` | _`x y - round(2^(tt+1)*x/y)`_ | | `34` | +| **`A9D6tt`** | `[tt+1] LSHIFT#DIVC` | _`x y - ceil(2^(tt+1)*x/y)`_ | | `26` | +### 5.3 Shifts, logical operations +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`AAcc`** | `[cc+1] LSHIFT#` | _`x - x*2^(cc+1)`_ | `0 <= cc <= 255` | `26` | +| **`ABcc`** | `[cc+1] RSHIFT#` | _`x - floor(x/2^(cc+1))`_ | `0 <= cc <= 255` | `18` | +| **`AC`** | `LSHIFT` | _`x y - x*2^y`_ | `0 <= y <= 1023` | `18` | +| **`AD`** | `RSHIFT` | _`x y - floor(x/2^y)`_ | `0 <= y <= 1023` | `18` | +| **`AE`** | `POW2` | _`y - 2^y`_ | `0 <= y <= 1023`
    Equivalent to [`ONE`](#instr-one) [`SWAP`](#instr-swap) [`LSHIFT`](#instr-lshift-var). | `18` | +| **`B0`** | `AND` | _`x y - x&y`_ | Bitwise and of two signed integers `x` and `y`, sign-extended to infinity. | `18` | +| **`B1`** | `OR` | _`x y - x\|y`_ | Bitwise or of two integers. | `18` | +| **`B2`** | `XOR` | _`x y - x xor y`_ | Bitwise xor of two integers. | `18` | +| **`B3`** | `NOT` | _`x - ~x`_ | Bitwise not of an integer. | `26` | +| **`B4cc`** | `[cc+1] FITS` | _`x - x`_ | Checks whether `x` is a `cc+1`-bit signed integer for `0 <= cc <= 255` (i.e., whether `-2^cc <= x < 2^cc`).
    If not, either triggers an integer overflow exception, or replaces `x` with a `NaN` (quiet version). | `26/76` | +| **`B400`** | `CHKBOOL` | _`x - x`_ | Checks whether `x` is a “boolean value'' (i.e., either 0 or -1). | `26/76` | +| **`B5cc`** | `[cc+1] UFITS` | _`x - x`_ | Checks whether `x` is a `cc+1`-bit unsigned integer for `0 <= cc <= 255` (i.e., whether `0 <= x < 2^(cc+1)`). | `26/76` | +| **`B500`** | `CHKBIT` | _`x - x`_ | Checks whether `x` is a binary digit (i.e., zero or one). | `26/76` | +| **`B600`** | `FITSX` | _`x c - x`_ | Checks whether `x` is a `c`-bit signed integer for `0 <= c <= 1023`. | `26/76` | +| **`B601`** | `UFITSX` | _`x c - x`_ | Checks whether `x` is a `c`-bit unsigned integer for `0 <= c <= 1023`. | `26/76` | +| **`B602`** | `BITSIZE` | _`x - c`_ | Computes smallest `c >= 0` such that `x` fits into a `c`-bit signed integer (`-2^(c-1) <= c < 2^(c-1)`). | `26` | +| **`B603`** | `UBITSIZE` | _`x - c`_ | Computes smallest `c >= 0` such that `x` fits into a `c`-bit unsigned integer (`0 <= x < 2^c`), or throws a range check exception. | `26` | +| **`B608`** | `MIN` | _`x y - x or y`_ | Computes the minimum of two integers `x` and `y`. | `26` | +| **`B609`** | `MAX` | _`x y - x or y`_ | Computes the maximum of two integers `x` and `y`. | `26` | +| **`B60A`** | `MINMAX`
    `INTSORT2` | _`x y - x y or y x`_ | Sorts two integers. Quiet version of this operation returns two `NaN`s if any of the arguments are `NaN`s. | `26` | +| **`B60B`** | `ABS` | _`x - \|x\|`_ | Computes the absolute value of an integer `x`. | `26` | +### 5.4 Quiet arithmetic primitives +Quiet operations return `NaN` instead of throwing exceptions if one of their arguments is a `NaN`, or in case of integer overflow. +Quiet operations has a prefix `Q` as shown below. Another way to make an operation quiet is to add `QUIET` before it (i.e. one can write [`QUIET ADD`](#instr-add) instead of [`QADD`](#instr-qadd)). +Quiet versions of integer comparison primitives are also available ([`QUIET SGN`](#instr-sgn), [`QUIET LESS`](#instr-less) etc). + +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`B7A0`** | `QADD` | _`x y - x+y`_ | | `26` | +| **`B7A1`** | `QSUB` | _`x y - x-y`_ | | `26` | +| **`B7A2`** | `QSUBR` | _`x y - y-x`_ | | `26` | +| **`B7A3`** | `QNEGATE` | _`x - -x`_ | | `26` | +| **`B7A4`** | `QINC` | _`x - x+1`_ | | `26` | +| **`B7A5`** | `QDEC` | _`x - x-1`_ | | `26` | +| **`B7A8`** | `QMUL` | _`x y - x*y`_ | | `26` | +| **`B7A904`** | `QDIV` | _`x y - q`_ | Division returns `NaN` if `y=0`. | `34` | +| **`B7A905`** | `QDIVR` | _`x y - q’`_ | | `34` | +| **`B7A906`** | `QDIVC` | _`x y - q''`_ | | `34` | +| **`B7A908`** | `QMOD` | _`x y - r`_ | | `34` | +| **`B7A90C`** | `QDIVMOD` | _`x y - q r`_ | | `34` | +| **`B7A90D`** | `QDIVMODR` | _`x y - q' r'`_ | | `34` | +| **`B7A90E`** | `QDIVMODC` | _`x y - q'' r''`_ | | `34` | +| **`B7A985`** | `QMULDIVR` | _`x y z - q'`_ | | `34` | +| **`B7A98C`** | `QMULDIVMOD` | _`x y z - q r`_ | | `34` | +| **`B7AC`** | `QLSHIFT` | _`x y - x*2^y`_ | | `26` | +| **`B7AD`** | `QRSHIFT` | _`x y - floor(x/2^y)`_ | | `26` | +| **`B7AE`** | `QPOW2` | _`y - 2^y`_ | | `26` | +| **`B7B0`** | `QAND` | _`x y - x&y`_ | | `26` | +| **`B7B1`** | `QOR` | _`x y - x\|y`_ | | `26` | +| **`B7B2`** | `QXOR` | _`x y - x xor y`_ | | `26` | +| **`B7B3`** | `QNOT` | _`x - ~x`_ | | `26` | +| **`B7B4cc`** | `[cc+1] QFITS` | _`x - x`_ | Replaces `x` with a `NaN` if x is not a `cc+1`-bit signed integer, leaves it intact otherwise. | `34` | +| **`B7B5cc`** | `[cc+1] QUFITS` | _`x - x`_ | Replaces `x` with a `NaN` if x is not a `cc+1`-bit unsigned integer, leaves it intact otherwise. | `34` | +| **`B7B600`** | `QFITSX` | _`x c - x`_ | Replaces `x` with a `NaN` if x is not a c-bit signed integer, leaves it intact otherwise. | `34` | +| **`B7B601`** | `QUFITSX` | _`x c - x`_ | Replaces `x` with a `NaN` if x is not a c-bit unsigned integer, leaves it intact otherwise. | `34` | + +## 6 Comparison primitives +### 6.1 Integer comparison +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`B8`** | `SGN` | _`x - sgn(x)`_ | Computes the sign of an integer `x`:
    `-1` if `x<0`, `0` if `x=0`, `1` if `x>0`. | `18` | +| **`B9`** | `LESS` | _`x y - xy`_ | | `18` | +| **`BD`** | `NEQ` | _`x y - x!=y`_ | Equivalent to [`EQUAL`](#instr-equal) [`NOT`](#instr-not). | `18` | +| **`BE`** | `GEQ` | _`x y - x>=y`_ | Equivalent to [`LESS`](#instr-less) [`NOT`](#instr-not). | `18` | +| **`BF`** | `CMP` | _`x y - sgn(x-y)`_ | Computes the sign of `x-y`:
    `-1` if `xy`.
    No integer overflow can occur here unless `x` or `y` is a `NaN`. | `18` | +| **`C0yy`** | `[yy] EQINT` | _`x - x=yy`_ | Returns `-1` if `x=yy`, `0` otherwise.
    `-2^7 <= yy < 2^7`. | `26` | +| **`C000`** | `ISZERO` | _`x - x=0`_ | Checks whether an integer is zero. Corresponds to Forth's `0=`. | `26` | +| **`C1yy`** | `[yy] LESSINT`
    `[yy-1] LEQINT` | _`x - x`-2^7 <= yy < 2^7`. | `26` | +| **`C100`** | `ISNEG` | _`x - x<0`_ | Checks whether an integer is negative. Corresponds to Forth's `0<`. | `26` | +| **`C101`** | `ISNPOS` | _`x - x<=0`_ | Checks whether an integer is non-positive. | `26` | +| **`C2yy`** | `[yy] GTINT`
    `[yy+1] GEQINT` | _`x - x>yy`_ | Returns `-1` if `x>yy`, `0` otherwise.
    `-2^7 <= yy < 2^7`. | `26` | +| **`C200`** | `ISPOS` | _`x - x>0`_ | Checks whether an integer is positive. Corresponds to Forth's `0>`. | `26` | +| **`C2FF`** | `ISNNEG` | _`x - x >=0`_ | Checks whether an integer is non-negative. | `26` | +| **`C3yy`** | `[yy] NEQINT` | _`x - x!=yy`_ | Returns `-1` if `x!=yy`, `0` otherwise.
    `-2^7 <= yy < 2^7`. | `26` | +| **`C4`** | `ISNAN` | _`x - x=NaN`_ | Checks whether `x` is a `NaN`. | `18` | +| **`C5`** | `CHKNAN` | _`x - x`_ | Throws an arithmetic overflow exception if `x` is a `NaN`. | `18/68` | +### 6.2 Other comparison +Most of these "other comparison" primitives actually compare the data portions of _Slices_ as bitstrings (ignoring references if not stated otherwise). + +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`C700`** | `SEMPTY` | _`s - ?`_ | Checks whether a _Slice_ `s` is empty (i.e., contains no bits of data and no cell references). | `26` | +| **`C701`** | `SDEMPTY` | _`s - ?`_ | Checks whether _Slice_ `s` has no bits of data. | `26` | +| **`C702`** | `SREMPTY` | _`s - ?`_ | Checks whether _Slice_ `s` has no references. | `26` | +| **`C703`** | `SDFIRST` | _`s - ?`_ | Checks whether the first bit of _Slice_ `s` is a one. | `26` | +| **`C704`** | `SDLEXCMP` | _`s s' - x`_ | Compares the data of `s` lexicographically with the data of `s'`, returning `-1`, 0, or 1 depending on the result. | `26` | +| **`C705`** | `SDEQ` | _`s s' - ?`_ | Checks whether the data parts of `s` and `s'` coincide, equivalent to [`SDLEXCMP`](#instr-sdlexcmp) [`ISZERO`](#instr-iszero). | `26` | +| **`C708`** | `SDPFX` | _`s s' - ?`_ | Checks whether `s` is a prefix of `s'`. | `26` | +| **`C709`** | `SDPFXREV` | _`s s' - ?`_ | Checks whether `s'` is a prefix of `s`, equivalent to [`SWAP`](#instr-swap) [`SDPFX`](#instr-sdpfx). | `26` | +| **`C70A`** | `SDPPFX` | _`s s' - ?`_ | Checks whether `s` is a proper prefix of `s'` (i.e., a prefix distinct from `s'`). | `26` | +| **`C70B`** | `SDPPFXREV` | _`s s' - ?`_ | Checks whether `s'` is a proper prefix of `s`. | `26` | +| **`C70C`** | `SDSFX` | _`s s' - ?`_ | Checks whether `s` is a suffix of `s'`. | `26` | +| **`C70D`** | `SDSFXREV` | _`s s' - ?`_ | Checks whether `s'` is a suffix of `s`. | `26` | +| **`C70E`** | `SDPSFX` | _`s s' - ?`_ | Checks whether `s` is a proper suffix of `s'`. | `26` | +| **`C70F`** | `SDPSFXREV` | _`s s' - ?`_ | Checks whether `s'` is a proper suffix of `s`. | `26` | +| **`C710`** | `SDCNTLEAD0` | _`s - n`_ | Returns the number of leading zeroes in `s`. | `26` | +| **`C711`** | `SDCNTLEAD1` | _`s - n`_ | Returns the number of leading ones in `s`. | `26` | +| **`C712`** | `SDCNTTRAIL0` | _`s - n`_ | Returns the number of trailing zeroes in `s`. | `26` | +| **`C713`** | `SDCNTTRAIL1` | _`s - n`_ | Returns the number of trailing ones in `s`. | `26` | + +## 7 Cell primitives +### 7.1 Cell serialization primitives +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`C8`** | `NEWC` | _`- b`_ | Creates a new empty _Builder_. | `18` | +| **`C9`** | `ENDC` | _`b - c`_ | Converts a _Builder_ into an ordinary _Cell_. | `518` | +| **`CAcc`** | `[cc+1] STI` | _`x b - b'`_ | Stores a signed `cc+1`-bit integer `x` into _Builder_ `b` for `0 <= cc <= 255`, throws a range check exception if `x` does not fit into `cc+1` bits. | `26` | +| **`CBcc`** | `[cc+1] STU` | _`x b - b'`_ | Stores an unsigned `cc+1`-bit integer `x` into _Builder_ `b`. In all other respects it is similar to [`STI`](#instr-sti). | `26` | +| **`CC`** | `STREF` | _`c b - b'`_ | Stores a reference to _Cell_ `c` into _Builder_ `b`. | `18` | +| **`CD`** | `STBREFR`
    `ENDCST` | _`b b'' - b`_ | Equivalent to [`ENDC`](#instr-endc) [`SWAP`](#instr-swap) [`STREF`](#instr-stref). | `518` | +| **`CE`** | `STSLICE` | _`s b - b'`_ | Stores _Slice_ `s` into _Builder_ `b`. | `18` | +| **`CF00`** | `STIX` | _`x b l - b'`_ | Stores a signed `l`-bit integer `x` into `b` for `0 <= l <= 257`. | `26` | +| **`CF01`** | `STUX` | _`x b l - b'`_ | Stores an unsigned `l`-bit integer `x` into `b` for `0 <= l <= 256`. | `26` | +| **`CF02`** | `STIXR` | _`b x l - b'`_ | Similar to [`STIX`](#instr-stix), but with arguments in a different order. | `26` | +| **`CF03`** | `STUXR` | _`b x l - b'`_ | Similar to [`STUX`](#instr-stux), but with arguments in a different order. | `26` | +| **`CF04`** | `STIXQ` | _`x b l - x b f or b' 0`_ | A quiet version of [`STIX`](#instr-stix). If there is no space in `b`, sets `b'=b` and `f=-1`.
    If `x` does not fit into `l` bits, sets `b'=b` and `f=1`.
    If the operation succeeds, `b'` is the new _Builder_ and `f=0`.
    However, `0 <= l <= 257`, with a range check exception if this is not so. | `26` | +| **`CF05`** | `STUXQ` | _`x b l - x b f or b' 0`_ | A quiet version of [`STUX`](#instr-stux). | `26` | +| **`CF06`** | `STIXRQ` | _`b x l - b x f or b' 0`_ | A quiet version of [`STIXR`](#instr-stixr). | `26` | +| **`CF07`** | `STUXRQ` | _`b x l - b x f or b' 0`_ | A quiet version of [`STUXR`](#instr-stuxr). | `26` | +| **`CF08cc`** | `[cc+1] STI_l` | _`x b - b'`_ | A longer version of [`[cc+1] STI`](#instr-sti). | `34` | +| **`CF09cc`** | `[cc+1] STU_l` | _`x b - b'`_ | A longer version of [`[cc+1] STU`](#instr-stu). | `34` | +| **`CF0Acc`** | `[cc+1] STIR` | _`b x - b'`_ | Equivalent to [`SWAP`](#instr-swap) [`[cc+1] STI`](#instr-sti). | `34` | +| **`CF0Bcc`** | `[cc+1] STUR` | _`b x - b'`_ | Equivalent to [`SWAP`](#instr-swap) [`[cc+1] STU`](#instr-stu). | `34` | +| **`CF0Ccc`** | `[cc+1] STIQ` | _`x b - x b f or b' 0`_ | A quiet version of [`STI`](#instr-sti). | `34` | +| **`CF0Dcc`** | `[cc+1] STUQ` | _`x b - x b f or b' 0`_ | A quiet version of [`STU`](#instr-stu). | `34` | +| **`CF0Ecc`** | `[cc+1] STIRQ` | _`b x - b x f or b' 0`_ | A quiet version of [`STIR`](#instr-stir). | `34` | +| **`CF0Fcc`** | `[cc+1] STURQ` | _`b x - b x f or b' 0`_ | A quiet version of [`STUR`](#instr-stur). | `34` | +| **`CF10`** | `STREF_l` | _`c b - b'`_ | A longer version of [`STREF`](#instr-stref). | `26` | +| **`CF11`** | `STBREF` | _`b' b - b''`_ | Equivalent to [`SWAP`](#instr-swap) [`STBREFR`](#instr-stbrefr). | `526` | +| **`CF12`** | `STSLICE_l` | _`s b - b'`_ | A longer version of [`STSLICE`](#instr-stslice). | `26` | +| **`CF13`** | `STB` | _`b' b - b''`_ | Appends all data from _Builder_ `b'` to _Builder_ `b`. | `26` | +| **`CF14`** | `STREFR` | _`b c - b'`_ | Equivalent to [`SWAP`](#instr-swap) [`STREF`](#instr-stref). | `26` | +| **`CF15`** | `STBREFR_l` | _`b b' - b''`_ | A longer encoding of [`STBREFR`](#instr-stbrefr). | `526` | +| **`CF16`** | `STSLICER` | _`b s - b'`_ | Equivalent to [`SWAP`](#instr-swap) [`STSLICE`](#instr-stslice). | `26` | +| **`CF17`** | `STBR`
    `BCONCAT` | _`b b' - b''`_ | Concatenates two builders.
    Equivalent to [`SWAP`](#instr-swap) [`STB`](#instr-stb). | `26` | +| **`CF18`** | `STREFQ` | _`c b - c b -1 or b' 0`_ | Quiet version of [`STREF`](#instr-stref). | `26` | +| **`CF19`** | `STBREFQ` | _`b' b - b' b -1 or b'' 0`_ | Quiet version of [`STBREF`](#instr-stbref). | `526` | +| **`CF1A`** | `STSLICEQ` | _`s b - s b -1 or b' 0`_ | Quiet version of [`STSLICE`](#instr-stslice). | `26` | +| **`CF1B`** | `STBQ` | _`b' b - b' b -1 or b'' 0`_ | Quiet version of [`STB`](#instr-stb). | `26` | +| **`CF1C`** | `STREFRQ` | _`b c - b c -1 or b' 0`_ | Quiet version of [`STREFR`](#instr-strefr). | `26` | +| **`CF1D`** | `STBREFRQ` | _`b b' - b b' -1 or b'' 0`_ | Quiet version of [`STBREFR`](#instr-stbrefr). | `526` | +| **`CF1E`** | `STSLICERQ` | _`b s - b s -1 or b'' 0`_ | Quiet version of [`STSLICER`](#instr-stslicer). | `26` | +| **`CF1F`** | `STBRQ`
    `BCONCATQ` | _`b b' - b b' -1 or b'' 0`_ | Quiet version of [`STBR`](#instr-stbr). | `26` | +| **`CF20`** | `[ref] STREFCONST` | _`b - b’`_ | Equivalent to [`PUSHREF`](#instr-pushref) [`STREFR`](#instr-strefr). | `26` | +| **`CF21`** | `[ref] [ref] STREF2CONST` | _`b - b’`_ | Equivalent to [`STREFCONST`](#instr-strefconst) [`STREFCONST`](#instr-strefconst). | `26` | +| **`CF23`** | | _`b x - c`_ | If `x!=0`, creates a _special_ or _exotic_ cell from _Builder_ `b`.
    The type of the exotic cell must be stored in the first 8 bits of `b`.
    If `x=0`, it is equivalent to [`ENDC`](#instr-endc). Otherwise some validity checks on the data and references of `b` are performed before creating the exotic cell. | `526` | +| **`CF28`** | `STILE4` | _`x b - b'`_ | Stores a little-endian signed 32-bit integer. | `26` | +| **`CF29`** | `STULE4` | _`x b - b'`_ | Stores a little-endian unsigned 32-bit integer. | `26` | +| **`CF2A`** | `STILE8` | _`x b - b'`_ | Stores a little-endian signed 64-bit integer. | `26` | +| **`CF2B`** | `STULE8` | _`x b - b'`_ | Stores a little-endian unsigned 64-bit integer. | `26` | +| **`CF30`** | `BDEPTH` | _`b - x`_ | Returns the depth of _Builder_ `b`. If no cell references are stored in `b`, then `x=0`; otherwise `x` is one plus the maximum of depths of cells referred to from `b`. | `26` | +| **`CF31`** | `BBITS` | _`b - x`_ | Returns the number of data bits already stored in _Builder_ `b`. | `26` | +| **`CF32`** | `BREFS` | _`b - y`_ | Returns the number of cell references already stored in `b`. | `26` | +| **`CF33`** | `BBITREFS` | _`b - x y`_ | Returns the numbers of both data bits and cell references in `b`. | `26` | +| **`CF35`** | `BREMBITS` | _`b - x'`_ | Returns the number of data bits that can still be stored in `b`. | `26` | +| **`CF36`** | `BREMREFS` | _`b - y'`_ | Returns the number of references that can still be stored in `b`. | `26` | +| **`CF37`** | `BREMBITREFS` | _`b - x' y'`_ | Returns the numbers of both data bits and references that can still be stored in `b`. | `26` | +| **`CF38cc`** | `[cc+1] BCHKBITS#` | _`b -`_ | Checks whether `cc+1` bits can be stored into `b`, where `0 <= cc <= 255`. | `34/84` | +| **`CF39`** | `BCHKBITS` | _`b x - `_ | Checks whether `x` bits can be stored into `b`, `0 <= x <= 1023`. If there is no space for `x` more bits in `b`, or if `x` is not within the range `0...1023`, throws an exception. | `26/76` | +| **`CF3A`** | `BCHKREFS` | _`b y - `_ | Checks whether `y` references can be stored into `b`, `0 <= y <= 7`. | `26/76` | +| **`CF3B`** | `BCHKBITREFS` | _`b x y - `_ | Checks whether `x` bits and `y` references can be stored into `b`, `0 <= x <= 1023`, `0 <= y <= 7`. | `26/76` | +| **`CF3Ccc`** | `[cc+1] BCHKBITSQ#` | _`b - ?`_ | Checks whether `cc+1` bits can be stored into `b`, where `0 <= cc <= 255`. | `34` | +| **`CF3D`** | `BCHKBITSQ` | _`b x - ?`_ | Checks whether `x` bits can be stored into `b`, `0 <= x <= 1023`. | `26` | +| **`CF3E`** | `BCHKREFSQ` | _`b y - ?`_ | Checks whether `y` references can be stored into `b`, `0 <= y <= 7`. | `26` | +| **`CF3F`** | `BCHKBITREFSQ` | _`b x y - ?`_ | Checks whether `x` bits and `y` references can be stored into `b`, `0 <= x <= 1023`, `0 <= y <= 7`. | `26` | +| **`CF40`** | `STZEROES` | _`b n - b'`_ | Stores `n` binary zeroes into _Builder_ `b`. | `26` | +| **`CF41`** | `STONES` | _`b n - b'`_ | Stores `n` binary ones into _Builder_ `b`. | `26` | +| **`CF42`** | `STSAME` | _`b n x - b'`_ | Stores `n` binary `x`es (`0 <= x <= 1`) into _Builder_ `b`. | `26` | +| **`CFC0_xysss`** | `[slice] STSLICECONST` | _`b - b'`_ | Stores a constant subslice `sss`.
    _Details:_ `sss` consists of `0 <= x <= 3` references and up to `8y+2` data bits, with `0 <= y <= 7`. Completion bit is assumed.
    Note that the assembler can replace [`STSLICECONST`](#instr-stsliceconst) with [`PUSHSLICE`](#instr-pushslice) [`STSLICER`](#instr-stslicer) if the slice is too big. | `24` | +| **`CF81`** | `STZERO` | _`b - b'`_ | Stores one binary zero. | `24` | +| **`CF83`** | `STONE` | _`b - b'`_ | Stores one binary one. | `24` | +### 7.2 Cell deserialization primitives +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`D0`** | `CTOS` | _`c - s`_ | Converts a _Cell_ into a _Slice_. Notice that `c` must be either an ordinary cell, or an exotic cell which is automatically _loaded_ to yield an ordinary cell `c'`, converted into a _Slice_ afterwards. | `118/43` | +| **`D1`** | `ENDS` | _`s - `_ | Removes a _Slice_ `s` from the stack, and throws an exception if it is not empty. | `18/68` | +| **`D2cc`** | `[cc+1] LDI` | _`s - x s'`_ | Loads (i.e., parses) a signed `cc+1`-bit integer `x` from _Slice_ `s`, and returns the remainder of `s` as `s'`. | `26` | +| **`D3cc`** | `[cc+1] LDU` | _`s - x s'`_ | Loads an unsigned `cc+1`-bit integer `x` from _Slice_ `s`. | `26` | +| **`D4`** | `LDREF` | _`s - c s'`_ | Loads a cell reference `c` from `s`. | `18` | +| **`D5`** | `LDREFRTOS` | _`s - s' s''`_ | Equivalent to [`LDREF`](#instr-ldref) [`SWAP`](#instr-swap) [`CTOS`](#instr-ctos). | `118/43` | +| **`D6cc`** | `[cc+1] LDSLICE` | _`s - s'' s'`_ | Cuts the next `cc+1` bits of `s` into a separate _Slice_ `s''`. | `26` | +| **`D700`** | `LDIX` | _`s l - x s'`_ | Loads a signed `l`-bit (`0 <= l <= 257`) integer `x` from _Slice_ `s`, and returns the remainder of `s` as `s'`. | `26` | +| **`D701`** | `LDUX` | _`s l - x s'`_ | Loads an unsigned `l`-bit integer `x` from (the first `l` bits of) `s`, with `0 <= l <= 256`. | `26` | +| **`D702`** | `PLDIX` | _`s l - x`_ | Preloads a signed `l`-bit integer from _Slice_ `s`, for `0 <= l <= 257`. | `26` | +| **`D703`** | `PLDUX` | _`s l - x`_ | Preloads an unsigned `l`-bit integer from `s`, for `0 <= l <= 256`. | `26` | +| **`D704`** | `LDIXQ` | _`s l - x s' -1 or s 0`_ | Quiet version of [`LDIX`](#instr-ldix): loads a signed `l`-bit integer from `s` similarly to [`LDIX`](#instr-ldix), but returns a success flag, equal to `-1` on success or to `0` on failure (if `s` does not have `l` bits), instead of throwing a cell underflow exception. | `26` | +| **`D705`** | `LDUXQ` | _`s l - x s' -1 or s 0`_ | Quiet version of [`LDUX`](#instr-ldux). | `26` | +| **`D706`** | `PLDIXQ` | _`s l - x -1 or 0`_ | Quiet version of [`PLDIX`](#instr-pldix). | `26` | +| **`D707`** | `PLDUXQ` | _`s l - x -1 or 0`_ | Quiet version of [`PLDUX`](#instr-pldux). | `26` | +| **`D708cc`** | `[cc+1] LDI_l` | _`s - x s'`_ | A longer encoding for [`LDI`](#instr-ldi). | `34` | +| **`D709cc`** | `[cc+1] LDU_l` | _`s - x s'`_ | A longer encoding for [`LDU`](#instr-ldu). | `34` | +| **`D70Acc`** | `[cc+1] PLDI` | _`s - x`_ | Preloads a signed `cc+1`-bit integer from _Slice_ `s`. | `34` | +| **`D70Bcc`** | `[cc+1] PLDU` | _`s - x`_ | Preloads an unsigned `cc+1`-bit integer from `s`. | `34` | +| **`D70Ccc`** | `[cc+1] LDIQ` | _`s - x s' -1 or s 0`_ | A quiet version of [`LDI`](#instr-ldi). | `34` | +| **`D70Dcc`** | `[cc+1] LDUQ` | _`s - x s' -1 or s 0`_ | A quiet version of [`LDU`](#instr-ldu). | `34` | +| **`D70Ecc`** | `[cc+1] PLDIQ` | _`s - x -1 or 0`_ | A quiet version of [`PLDI`](#instr-pldi). | `34` | +| **`D70Fcc`** | `[cc+1] PLDUQ` | _`s - x -1 or 0`_ | A quiet version of [`PLDU`](#instr-pldu). | `34` | +| **`D714_c`** | `[32(c+1)] PLDUZ` | _`s - s x`_ | Preloads the first `32(c+1)` bits of _Slice_ `s` into an unsigned integer `x`, for `0 <= c <= 7`. If `s` is shorter than necessary, missing bits are assumed to be zero. This operation is intended to be used along with [`IFBITJMP`](#instr-ifbitjmp) and similar instructions. | `26` | +| **`D718`** | `LDSLICEX` | _`s l - s'' s'`_ | Loads the first `0 <= l <= 1023` bits from _Slice_ `s` into a separate _Slice_ `s''`, returning the remainder of `s` as `s'`. | `26` | +| **`D719`** | `PLDSLICEX` | _`s l - s''`_ | Returns the first `0 <= l <= 1023` bits of `s` as `s''`. | `26` | +| **`D71A`** | `LDSLICEXQ` | _`s l - s'' s' -1 or s 0`_ | A quiet version of [`LDSLICEX`](#instr-ldslicex). | `26` | +| **`D71B`** | `PLDSLICEXQ` | _`s l - s' -1 or 0`_ | A quiet version of [`LDSLICEXQ`](#instr-ldslicexq). | `26` | +| **`D71Ccc`** | `[cc+1] LDSLICE_l` | _`s - s'' s'`_ | A longer encoding for [`LDSLICE`](#instr-ldslice). | `34` | +| **`D71Dcc`** | `[cc+1] PLDSLICE` | _`s - s''`_ | Returns the first `0 < cc+1 <= 256` bits of `s` as `s''`. | `34` | +| **`D71Ecc`** | `[cc+1] LDSLICEQ` | _`s - s'' s' -1 or s 0`_ | A quiet version of [`LDSLICE`](#instr-ldslice). | `34` | +| **`D71Fcc`** | `[cc+1] PLDSLICEQ` | _`s - s'' -1 or 0`_ | A quiet version of [`PLDSLICE`](#instr-pldslice). | `34` | +| **`D720`** | `SDCUTFIRST` | _`s l - s'`_ | Returns the first `0 <= l <= 1023` bits of `s`. It is equivalent to [`PLDSLICEX`](#instr-pldslicex). | `26` | +| **`D721`** | `SDSKIPFIRST` | _`s l - s'`_ | Returns all but the first `0 <= l <= 1023` bits of `s`. It is equivalent to [`LDSLICEX`](#instr-ldslicex) [`NIP`](#instr-nip). | `26` | +| **`D722`** | `SDCUTLAST` | _`s l - s'`_ | Returns the last `0 <= l <= 1023` bits of `s`. | `26` | +| **`D723`** | `SDSKIPLAST` | _`s l - s'`_ | Returns all but the last `0 <= l <= 1023` bits of `s`. | `26` | +| **`D724`** | `SDSUBSTR` | _`s l l' - s'`_ | Returns `0 <= l' <= 1023` bits of `s` starting from offset `0 <= l <= 1023`, thus extracting a bit substring out of the data of `s`. | `26` | +| **`D726`** | `SDBEGINSX` | _`s s' - s''`_ | Checks whether `s` begins with (the data bits of) `s'`, and removes `s'` from `s` on success. On failure throws a cell deserialization exception. Primitive [`SDPFXREV`](#instr-sdpfxrev) can be considered a quiet version of [`SDBEGINSX`](#instr-sdbeginsx). | `26` | +| **`D727`** | `SDBEGINSXQ` | _`s s' - s'' -1 or s 0`_ | A quiet version of [`SDBEGINSX`](#instr-sdbeginsx). | `26` | +| **`D72A_xsss`** | `[slice] SDBEGINS` | _`s - s''`_ | Checks whether `s` begins with constant bitstring `sss` of length `8x+3` (with continuation bit assumed), where `0 <= x <= 127`, and removes `sss` from `s` on success. | `31` | +| **`D72E_xsss`** | `[slice] SDBEGINSQ` | _`s - s'' -1 or s 0`_ | A quiet version of [`SDBEGINS`](#instr-sdbegins). | `31` | +| **`D730`** | `SCUTFIRST` | _`s l r - s'`_ | Returns the first `0 <= l <= 1023` bits and first `0 <= r <= 4` references of `s`. | `26` | +| **`D731`** | `SSKIPFIRST` | _`s l r - s'`_ | Returns all but the first `l` bits of `s` and `r` references of `s`. | `26` | +| **`D732`** | `SCUTLAST` | _`s l r - s'`_ | Returns the last `0 <= l <= 1023` data bits and last `0 <= r <= 4` references of `s`. | `26` | +| **`D733`** | `SSKIPLAST` | _`s l r - s'`_ | Returns all but the last `l` bits of `s` and `r` references of `s`. | `26` | +| **`D734`** | `SUBSLICE` | _`s l r l' r' - s'`_ | Returns `0 <= l' <= 1023` bits and `0 <= r' <= 4` references from _Slice_ `s`, after skipping the first `0 <= l <= 1023` bits and first `0 <= r <= 4` references. | `26` | +| **`D736`** | `SPLIT` | _`s l r - s' s''`_ | Splits the first `0 <= l <= 1023` data bits and first `0 <= r <= 4` references from `s` into `s'`, returning the remainder of `s` as `s''`. | `26` | +| **`D737`** | `SPLITQ` | _`s l r - s' s'' -1 or s 0`_ | A quiet version of [`SPLIT`](#instr-split). | `26` | +| **`D739`** | | _`c - s ?`_ | Transforms an ordinary or exotic cell into a _Slice_, as if it were an ordinary cell. A flag is returned indicating whether `c` is exotic. If that be the case, its type can later be deserialized from the first eight bits of `s`. | | +| **`D73A`** | | _`c - c'`_ | Loads an exotic cell `c` and returns an ordinary cell `c'`. If `c` is already ordinary, does nothing. If `c` cannot be loaded, throws an exception. | | +| **`D73B`** | | _`c - c' -1 or c 0`_ | Loads an exotic cell `c` and returns an ordinary cell `c'`. If `c` is already ordinary, does nothing. If `c` cannot be loaded, returns 0. | | +| **`D741`** | `SCHKBITS` | _`s l - `_ | Checks whether there are at least `l` data bits in _Slice_ `s`. If this is not the case, throws a cell deserialisation (i.e., cell underflow) exception. | `26/76` | +| **`D742`** | `SCHKREFS` | _`s r - `_ | Checks whether there are at least `r` references in _Slice_ `s`. | `26/76` | +| **`D743`** | `SCHKBITREFS` | _`s l r - `_ | Checks whether there are at least `l` data bits and `r` references in _Slice_ `s`. | `26/76` | +| **`D745`** | `SCHKBITSQ` | _`s l - ?`_ | Checks whether there are at least `l` data bits in _Slice_ `s`. | `26` | +| **`D746`** | `SCHKREFSQ` | _`s r - ?`_ | Checks whether there are at least `r` references in _Slice_ `s`. | `26` | +| **`D747`** | `SCHKBITREFSQ` | _`s l r - ?`_ | Checks whether there are at least `l` data bits and `r` references in _Slice_ `s`. | `26` | +| **`D748`** | `PLDREFVAR` | _`s n - c`_ | Returns the `n`-th cell reference of _Slice_ `s` for `0 <= n <= 3`. | `26` | +| **`D749`** | `SBITS` | _`s - l`_ | Returns the number of data bits in _Slice_ `s`. | `26` | +| **`D74A`** | `SREFS` | _`s - r`_ | Returns the number of references in _Slice_ `s`. | `26` | +| **`D74B`** | `SBITREFS` | _`s - l r`_ | Returns both the number of data bits and the number of references in `s`. | `26` | +| **`D74E_n`** | `[n] PLDREFIDX` | _`s - c`_ | Returns the `n`-th cell reference of _Slice_ `s`, where `0 <= n <= 3`. | `26` | +| **`D74C`** | `PLDREF` | _`s - c`_ | Preloads the first cell reference of a _Slice_. | `26` | +| **`D750`** | `LDILE4` | _`s - x s'`_ | Loads a little-endian signed 32-bit integer. | `26` | +| **`D751`** | `LDULE4` | _`s - x s'`_ | Loads a little-endian unsigned 32-bit integer. | `26` | +| **`D752`** | `LDILE8` | _`s - x s'`_ | Loads a little-endian signed 64-bit integer. | `26` | +| **`D753`** | `LDULE8` | _`s - x s'`_ | Loads a little-endian unsigned 64-bit integer. | `26` | +| **`D754`** | `PLDILE4` | _`s - x`_ | Preloads a little-endian signed 32-bit integer. | `26` | +| **`D755`** | `PLDULE4` | _`s - x`_ | Preloads a little-endian unsigned 32-bit integer. | `26` | +| **`D756`** | `PLDILE8` | _`s - x`_ | Preloads a little-endian signed 64-bit integer. | `26` | +| **`D757`** | `PLDULE8` | _`s - x`_ | Preloads a little-endian unsigned 64-bit integer. | `26` | +| **`D758`** | `LDILE4Q` | _`s - x s' -1 or s 0`_ | Quietly loads a little-endian signed 32-bit integer. | `26` | +| **`D759`** | `LDULE4Q` | _`s - x s' -1 or s 0`_ | Quietly loads a little-endian unsigned 32-bit integer. | `26` | +| **`D75A`** | `LDILE8Q` | _`s - x s' -1 or s 0`_ | Quietly loads a little-endian signed 64-bit integer. | `26` | +| **`D75B`** | `LDULE8Q` | _`s - x s' -1 or s 0`_ | Quietly loads a little-endian unsigned 64-bit integer. | `26` | +| **`D75C`** | `PLDILE4Q` | _`s - x -1 or 0`_ | Quietly preloads a little-endian signed 32-bit integer. | `26` | +| **`D75D`** | `PLDULE4Q` | _`s - x -1 or 0`_ | Quietly preloads a little-endian unsigned 32-bit integer. | `26` | +| **`D75E`** | `PLDILE8Q` | _`s - x -1 or 0`_ | Quietly preloads a little-endian signed 64-bit integer. | `26` | +| **`D75F`** | `PLDULE8Q` | _`s - x -1 or 0`_ | Quietly preloads a little-endian unsigned 64-bit integer. | `26` | +| **`D760`** | `LDZEROES` | _`s - n s'`_ | Returns the count `n` of leading zero bits in `s`, and removes these bits from `s`. | `26` | +| **`D761`** | `LDONES` | _`s - n s'`_ | Returns the count `n` of leading one bits in `s`, and removes these bits from `s`. | `26` | +| **`D762`** | `LDSAME` | _`s x - n s'`_ | Returns the count `n` of leading bits equal to `0 <= x <= 1` in `s`, and removes these bits from `s`. | `26` | +| **`D764`** | `SDEPTH` | _`s - x`_ | Returns the depth of _Slice_ `s`. If `s` has no references, then `x=0`; otherwise `x` is one plus the maximum of depths of cells referred to from `s`. | `26` | +| **`D765`** | `CDEPTH` | _`c - x`_ | Returns the depth of _Cell_ `c`. If `c` has no references, then `x=0`; otherwise `x` is one plus the maximum of depths of cells referred to from `c`. If `c` is a _Null_ instead of a _Cell_, returns zero. | `26` | + +## 8 Continuation and control flow primitives +### 8.1 Unconditional control flow primitives +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`D8`** | `EXECUTE`
    `CALLX` | _`c - `_ | _Calls_, or _executes_, continuation `c`. | `18` | +| **`D9`** | `JMPX` | _`c - `_ | _Jumps_, or transfers control, to continuation `c`.
    The remainder of the previous current continuation `cc` is discarded. | `18` | +| **`DApr`** | `[p] [r] CALLXARGS` | _`c - `_ | _Calls_ continuation `c` with `p` parameters and expecting `r` return values
    `0 <= p <= 15`, `0 <= r <= 15` | `26` | +| **`DB0p`** | `[p] -1 CALLXARGS` | _`c - `_ | _Calls_ continuation `c` with `0 <= p <= 15` parameters, expecting an arbitrary number of return values. | `26` | +| **`DB1p`** | `[p] JMPXARGS` | _`c - `_ | _Jumps_ to continuation `c`, passing only the top `0 <= p <= 15` values from the current stack to it (the remainder of the current stack is discarded). | `26` | +| **`DB2r`** | `[r] RETARGS` | | _Returns_ to `c0`, with `0 <= r <= 15` return values taken from the current stack. | `26` | +| **`DB30`** | `RET`
    `RETTRUE` | | _Returns_ to the continuation at `c0`. The remainder of the current continuation `cc` is discarded.
    Approximately equivalent to [`c0 PUSHCTR`](#instr-pushctr) [`JMPX`](#instr-jmpx). | `26` | +| **`DB31`** | `RETALT`
    `RETFALSE` | | _Returns_ to the continuation at `c1`.
    Approximately equivalent to [`c1 PUSHCTR`](#instr-pushctr) [`JMPX`](#instr-jmpx). | `26` | +| **`DB32`** | `BRANCH`
    `RETBOOL` | _`f - `_ | Performs [`RETTRUE`](#instr-ret) if integer `f!=0`, or [`RETFALSE`](#instr-retalt) if `f=0`. | `26` | +| **`DB34`** | `CALLCC` | _`c - `_ | _Call with current continuation_, transfers control to `c`, pushing the old value of `cc` into `c`'s stack (instead of discarding it or writing it into new `c0`). | `26` | +| **`DB35`** | `JMPXDATA` | _`c - `_ | Similar to [`CALLCC`](#instr-callcc), but the remainder of the current continuation (the old value of `cc`) is converted into a _Slice_ before pushing it into the stack of `c`. | `26` | +| **`DB36pr`** | `[p] [r] CALLCCARGS` | _`c - `_ | Similar to [`CALLXARGS`](#instr-callxargs), but pushes the old value of `cc` (along with the top `0 <= p <= 15` values from the original stack) into the stack of newly-invoked continuation `c`, setting `cc.nargs` to `-1 <= r <= 14`. | `34` | +| **`DB38`** | `CALLXVARARGS` | _`c p r - `_ | Similar to [`CALLXARGS`](#instr-callxargs), but takes `-1 <= p,r <= 254` from the stack. The next three operations also take `p` and `r` from the stack, both in the range `-1...254`. | `26` | +| **`DB39`** | `RETVARARGS` | _`p r - `_ | Similar to [`RETARGS`](#instr-retargs). | `26` | +| **`DB3A`** | `JMPXVARARGS` | _`c p r - `_ | Similar to [`JMPXARGS`](#instr-jmpxargs). | `26` | +| **`DB3B`** | `CALLCCVARARGS` | _`c p r - `_ | Similar to [`CALLCCARGS`](#instr-callccargs). | `26` | +| **`DB3C`** | `[ref] CALLREF` | | Equivalent to [`PUSHREFCONT`](#instr-pushrefcont) [`CALLX`](#instr-execute). | `126/51` | +| **`DB3D`** | `[ref] JMPREF` | | Equivalent to [`PUSHREFCONT`](#instr-pushrefcont) [`JMPX`](#instr-jmpx). | `126/51` | +| **`DB3E`** | `[ref] JMPREFDATA` | | Equivalent to [`PUSHREFCONT`](#instr-pushrefcont) [`JMPXDATA`](#instr-jmpxdata). | `126/51` | +| **`DB3F`** | `RETDATA` | | Equivalent to [`c0 PUSHCTR`](#instr-pushctr) [`JMPXDATA`](#instr-jmpxdata). In this way, the remainder of the current continuation is converted into a _Slice_ and returned to the caller. | `26` | +### 8.2 Conditional control flow primitives +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`DC`** | `IFRET`
    `IFNOT:` | _`f - `_ | Performs a [`RET`](#instr-ret), but only if integer `f` is non-zero. If `f` is a `NaN`, throws an integer overflow exception. | `18` | +| **`DD`** | `IFNOTRET`
    `IF:` | _`f - `_ | Performs a [`RET`](#instr-ret), but only if integer `f` is zero. | `18` | +| **`DE`** | `IF` | _`f c - `_ | Performs [`EXECUTE`](#instr-execute) for `c` (i.e., _executes_ `c`), but only if integer `f` is non-zero. Otherwise simply discards both values. | `18` | +| **`DE`** | `IF:<{ code }>`
    `<{ code }>IF` | _`f -`_ | Equivalent to [`<{ code }> CONT`](#instr-pushcont) [`IF`](#instr-if). | | +| **`DF`** | `IFNOT` | _`f c - `_ | Executes continuation `c`, but only if integer `f` is zero. Otherwise simply discards both values. | `18` | +| **`DF`** | `IFNOT:<{ code }>`
    `<{ code }>IFNOT` | _`f -`_ | Equivalent to [`<{ code }> CONT`](#instr-pushcont) [`IFNOT`](#instr-ifnot). | | +| **`E0`** | `IFJMP` | _`f c - `_ | Jumps to `c` (similarly to [`JMPX`](#instr-jmpx)), but only if `f` is non-zero. | `18` | +| **`E0`** | `IFJMP:<{ code }>` | _`f -`_ | Equivalent to [`<{ code }> CONT`](#instr-pushcont) [`IFJMP`](#instr-ifjmp). | | +| **`E1`** | `IFNOTJMP` | _`f c - `_ | Jumps to `c` (similarly to [`JMPX`](#instr-jmpx)), but only if `f` is zero. | `18` | +| **`E1`** | `IFNOTJMP:<{ code }>` | _`f -`_ | Equivalent to [`<{ code }> CONT`](#instr-pushcont) [`IFNOTJMP`](#instr-ifnotjmp). | | +| **`E2`** | `IFELSE` | _`f c c' - `_ | If integer `f` is non-zero, executes `c`, otherwise executes `c'`. Equivalent to [`CONDSELCHK`](#instr-condselchk) [`EXECUTE`](#instr-execute). | `18` | +| **`E2`** | `IF:<{ code1 }>ELSE<{ code2 }>` | _`f -`_ | Equivalent to [`<{ code1 }> CONT`](#instr-pushcont) [`<{ code2 }> CONT`](#instr-pushcont) [`IFELSE`](#instr-ifelse). | | +| **`E300`** | `[ref] IFREF` | _`f - `_ | Equivalent to [`PUSHREFCONT`](#instr-pushrefcont) [`IF`](#instr-if), with the optimization that the cell reference is not actually loaded into a _Slice_ and then converted into an ordinary _Continuation_ if `f=0`.
    Gas consumption of this primitive depends on whether `f=0` and whether the reference was loaded before.
    Similar remarks apply other primitives that accept a continuation as a reference. | `26/126/51` | +| **`E301`** | `[ref] IFNOTREF` | _`f - `_ | Equivalent to [`PUSHREFCONT`](#instr-pushrefcont) [`IFNOT`](#instr-ifnot). | `26/126/51` | +| **`E302`** | `[ref] IFJMPREF` | _`f - `_ | Equivalent to [`PUSHREFCONT`](#instr-pushrefcont) [`IFJMP`](#instr-ifjmp). | `26/126/51` | +| **`E303`** | `[ref] IFNOTJMPREF` | _`f - `_ | Equivalent to [`PUSHREFCONT`](#instr-pushrefcont) [`IFNOTJMP`](#instr-ifnotjmp). | `26/126/51` | +| **`E304`** | `CONDSEL` | _`f x y - x or y`_ | If integer `f` is non-zero, returns `x`, otherwise returns `y`. Notice that no type checks are performed on `x` and `y`; as such, it is more like a conditional stack operation. Roughly equivalent to [`ROT`](#instr-rot) [`ISZERO`](#instr-iszero) [`INC`](#instr-inc) [`ROLLX`](#instr-rollx) [`NIP`](#instr-nip). | `26` | +| **`E305`** | `CONDSELCHK` | _`f x y - x or y`_ | Same as [`CONDSEL`](#instr-condsel), but first checks whether `x` and `y` have the same type. | `26` | +| **`E308`** | `IFRETALT` | _`f -`_ | Performs [`RETALT`](#instr-retalt) if integer `f!=0`. | `26` | +| **`E309`** | `IFNOTRETALT` | _`f -`_ | Performs [`RETALT`](#instr-retalt) if integer `f=0`. | `26` | +| **`E30D`** | `[ref] IFREFELSE` | _`f c -`_ | Equivalent to [`PUSHREFCONT`](#instr-pushrefcont) [`SWAP`](#instr-swap) [`IFELSE`](#instr-ifelse), with the optimization that the cell reference is not actually loaded into a _Slice_ and then converted into an ordinary _Continuation_ if `f=0`. Similar remarks apply to the next two primitives: cells are converted into continuations only when necessary. | `26/126/51` | +| **`E30E`** | `[ref] IFELSEREF` | _`f c -`_ | Equivalent to [`PUSHREFCONT`](#instr-pushrefcont) [`IFELSE`](#instr-ifelse). | `26/126/51` | +| **`E30F`** | `[ref] [ref] IFREFELSEREF` | _`f -`_ | Equivalent to [`PUSHREFCONT`](#instr-pushrefcont) [`PUSHREFCONT`](#instr-pushrefcont) [`IFELSE`](#instr-ifelse). | `126/51` | +| **`E39_n`** | `[n] IFBITJMP` | _`x c - x`_ | Checks whether bit `0 <= n <= 31` is set in integer `x`, and if so, performs [`JMPX`](#instr-jmpx) to continuation `c`. Value `x` is left in the stack. | `26` | +| **`E3B_n`** | `[n] IFNBITJMP` | _`x c - x`_ | Jumps to `c` if bit `0 <= n <= 31` is not set in integer `x`. | `26` | +| **`E3D_n`** | `[ref] [n] IFBITJMPREF` | _`x - x`_ | Performs a [`JMPREF`](#instr-jmpref) if bit `0 <= n <= 31` is set in integer `x`. | `126/51` | +| **`E3F_n`** | `[ref] [n] IFNBITJMPREF` | _`x - x`_ | Performs a [`JMPREF`](#instr-jmpref) if bit `0 <= n <= 31` is not set in integer `x`. | `126/51` | +### 8.3 Control flow primitives: loops +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`E4`** | `REPEAT` | _`n c - `_ | Executes continuation `c` `n` times, if integer `n` is non-negative. If `n>=2^31` or `n<-2^31`, generates a range check exception.
    Notice that a [`RET`](#instr-ret) inside the code of `c` works as a `continue`, not as a `break`. One should use either alternative (experimental) loops or alternative [`RETALT`](#instr-retalt) (along with a [`SETEXITALT`](#instr-setexitalt) before the loop) to `break` out of a loop. | `18` | +| **`E4`** | `REPEAT:<{ code }>`
    `<{ code }>REPEAT` | _`n -`_ | Equivalent to [`<{ code }> CONT`](#instr-pushcont) [`REPEAT`](#instr-repeat). | | +| **`E5`** | `REPEATEND`
    `REPEAT:` | _`n - `_ | Similar to [`REPEAT`](#instr-repeat), but it is applied to the current continuation `cc`. | `18` | +| **`E6`** | `UNTIL` | _`c - `_ | Executes continuation `c`, then pops an integer `x` from the resulting stack. If `x` is zero, performs another iteration of this loop. The actual implementation of this primitive involves an extraordinary continuation `ec_until` with its arguments set to the body of the loop (continuation `c`) and the original current continuation `cc`. This extraordinary continuation is then saved into the savelist of `c` as `c.c0` and the modified `c` is then executed. The other loop primitives are implemented similarly with the aid of suitable extraordinary continuations. | `18` | +| **`E6`** | `UNTIL:<{ code }>`
    `<{ code }>UNTIL` | _`-`_ | Equivalent to [`<{ code }> CONT`](#instr-pushcont) [`UNTIL`](#instr-until). | | +| **`E7`** | `UNTILEND`
    `UNTIL:` | _`-`_ | Similar to [`UNTIL`](#instr-until), but executes the current continuation `cc` in a loop. When the loop exit condition is satisfied, performs a [`RET`](#instr-ret). | `18` | +| **`E8`** | `WHILE` | _`c' c - `_ | Executes `c'` and pops an integer `x` from the resulting stack. If `x` is zero, exists the loop and transfers control to the original `cc`. If `x` is non-zero, executes `c`, and then begins a new iteration. | `18` | +| **`E8`** | `WHILE:<{ cond }>DO<{ code }>` | _`-`_ | Equivalent to [`<{ cond }> CONT`](#instr-pushcont) [`<{ code }> CONT`](#instr-pushcont) [`WHILE`](#instr-while). | | +| **`E9`** | `WHILEEND` | _`c' - `_ | Similar to [`WHILE`](#instr-while), but uses the current continuation `cc` as the loop body. | `18` | +| **`EA`** | `AGAIN` | _`c - `_ | Similar to [`REPEAT`](#instr-repeat), but executes `c` infinitely many times. A [`RET`](#instr-ret) only begins a new iteration of the infinite loop, which can be exited only by an exception, or a [`RETALT`](#instr-retalt) (or an explicit [`JMPX`](#instr-jmpx)). | `18` | +| **`EA`** | `AGAIN:<{ code }>`
    `<{ code }>AGAIN` | _`-`_ | Equivalent to [`<{ code }> CONT`](#instr-pushcont) [`AGAIN`](#instr-again). | | +| **`EB`** | `AGAINEND`
    `AGAIN:` | _`-`_ | Similar to [`AGAIN`](#instr-again), but performed with respect to the current continuation `cc`. | `18` | +| **`E314`** | `REPEATBRK` | _`n c -`_ | Similar to [`REPEAT`](#instr-repeat), but also sets `c1` to the original `cc` after saving the old value of `c1` into the savelist of the original `cc`. In this way [`RETALT`](#instr-retalt) could be used to break out of the loop body. | `26` | +| **`E314`** | `REPEATBRK:<{ code }>`
    `<{ code }>REPEATBRK` | _`n -`_ | Equivalent to [`<{ code }> CONT`](#instr-pushcont) [`REPEATBRK`](#instr-repeatbrk). | | +| **`E315`** | `REPEATENDBRK` | _`n -`_ | Similar to [`REPEATEND`](#instr-repeatend), but also sets `c1` to the original `c0` after saving the old value of `c1` into the savelist of the original `c0`. Equivalent to [`SAMEALTSAVE`](#instr-samealtsave) [`REPEATEND`](#instr-repeatend). | `26` | +| **`E316`** | `UNTILBRK` | _`c -`_ | Similar to [`UNTIL`](#instr-until), but also modifies `c1` in the same way as [`REPEATBRK`](#instr-repeatbrk). | `26` | +| **`E316`** | `UNTILBRK:<{ code }>` | _`-`_ | Equivalent to [`<{ code }> CONT`](#instr-pushcont) [`UNTILBRK`](#instr-untilbrk). | | +| **`E317`** | `UNTILENDBRK`
    `UNTILBRK:` | _`-`_ | Equivalent to [`SAMEALTSAVE`](#instr-samealtsave) [`UNTILEND`](#instr-untilend). | `26` | +| **`E318`** | `WHILEBRK` | _`c' c -`_ | Similar to [`WHILE`](#instr-while), but also modifies `c1` in the same way as [`REPEATBRK`](#instr-repeatbrk). | `26` | +| **`E318`** | `WHILEBRK:<{ cond }>DO<{ code }>` | _`-`_ | Equivalent to [`<{ cond }> CONT`](#instr-pushcont) [`<{ code }> CONT`](#instr-pushcont) [`WHILEBRK`](#instr-whilebrk). | | +| **`E319`** | `WHILEENDBRK` | _`c -`_ | Equivalent to [`SAMEALTSAVE`](#instr-samealtsave) [`WHILEEND`](#instr-whileend). | `26` | +| **`E31A`** | `AGAINBRK` | _`c -`_ | Similar to [`AGAIN`](#instr-again), but also modifies `c1` in the same way as [`REPEATBRK`](#instr-repeatbrk). | `26` | +| **`E31A`** | `AGAINBRK:<{ code }>` | _`-`_ | Equivalent to [`<{ code }> CONT`](#instr-pushcont) [`AGAINBRK`](#instr-againbrk). | | +| **`E31B`** | `AGAINENDBRK`
    `AGAINBRK:` | _`-`_ | Equivalent to [`SAMEALTSAVE`](#instr-samealtsave) [`AGAINEND`](#instr-againend). | `26` | +### 8.4 Manipulating the stack of continuations +Here `s"` is the [fee for moving stack elements between continuations](#11-gas-prices). It is equal to the size of the resulting stack minus 32 (or 0 if the stack is smaller than 32). + +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`ECrn`** | `[r] [n] SETCONTARGS` | _`x_1 x_2...x_r c - c'`_ | Similar to [`[r] -1 SETCONTARGS`](#instr-setcontargs-n), but sets `c.nargs` to the final size of the stack of `c'` plus `n`. In other words, transforms `c` into a _closure_ or a _partially applied function_, with `0 <= n <= 14` arguments missing. | `26+s”` | +| **`EC0n`** | `[n] SETNUMARGS` | _`c - c'`_ | Sets `c.nargs` to `n` plus the current depth of `c`'s stack, where `0 <= n <= 14`. If `c.nargs` is already set to a non-negative value, does nothing. | `26` | +| **`ECrF`** | `[r] -1 SETCONTARGS` | _`x_1 x_2...x_r c - c'`_ | Pushes `0 <= r <= 15` values `x_1...x_r` into the stack of (a copy of) the continuation `c`, starting with `x_1`. If the final depth of `c`'s stack turns out to be greater than `c.nargs`, a stack overflow exception is generated. | `26+s”` | +| **`ED0p`** | `[p] RETURNARGS` | _`-`_ | Leaves only the top `0 <= p <= 15` values in the current stack (somewhat similarly to [`ONLYTOPX`](#instr-onlytopx)), with all the unused bottom values not discarded, but saved into continuation `c0` in the same way as [`SETCONTARGS`](#instr-setcontargs-n) does. | `26+s”` | +| **`ED10`** | `RETURNVARARGS` | _`p -`_ | Similar to [`RETURNARGS`](#instr-returnargs), but with Integer `0 <= p <= 255` taken from the stack. | `26+s”` | +| **`ED11`** | `SETCONTVARARGS` | _`x_1 x_2...x_r c r n - c'`_ | Similar to [`SETCONTARGS`](#instr-setcontargs-n), but with `0 <= r <= 255` and `-1 <= n <= 255` taken from the stack. | `26+s”` | +| **`ED12`** | `SETNUMVARARGS` | _`c n - c'`_ | `-1 <= n <= 255`
    If `n=-1`, this operation does nothing (`c'=c`).
    Otherwise its action is similar to [`[n] SETNUMARGS`](#instr-setnumargs), but with `n` taken from the stack. | `26` | +### 8.5 Creating simple continuations and closures +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`ED1E`** | `BLESS` | _`s - c`_ | Transforms a _Slice_ `s` into a simple ordinary continuation `c`, with `c.code=s` and an empty stack and savelist. | `26` | +| **`ED1F`** | `BLESSVARARGS` | _`x_1...x_r s r n - c`_ | Equivalent to [`ROT`](#instr-rot) [`BLESS`](#instr-bless) [`ROTREV`](#instr-rotrev) [`SETCONTVARARGS`](#instr-setcontvarargs). | `26+s”` | +| **`EErn`** | `[r] [n] BLESSARGS` | _`x_1...x_r s - c`_ | `0 <= r <= 15`, `-1 <= n <= 14`
    Equivalent to [`BLESS`](#instr-bless) [`[r] [n] SETCONTARGS`](#instr-setcontargs-n).
    The value of `n` is represented inside the instruction by the 4-bit integer `n mod 16`. | `26` | +| **`EE0n`** | `[n] BLESSNUMARGS` | _`s - c`_ | Also transforms a _Slice_ `s` into a _Continuation_ `c`, but sets `c.nargs` to `0 <= n <= 14`. | `26` | +### 8.6 Operations with continuation savelists and control registers +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`ED4i`** | `c[i] PUSHCTR`
    `c[i] PUSH` | _`- x`_ | Pushes the current value of control register `c(i)`. If the control register is not supported in the current codepage, or if it does not have a value, an exception is triggered. | `26` | +| **`ED44`** | `c4 PUSHCTR`
    `c4 PUSH` | _`- x`_ | Pushes the “global data root'' cell reference, thus enabling access to persistent smart-contract data. | `26` | +| **`ED5i`** | `c[i] POPCTR`
    `c[i] POP` | _`x - `_ | Pops a value `x` from the stack and stores it into control register `c(i)`, if supported in the current codepage. Notice that if a control register accepts only values of a specific type, a type-checking exception may occur. | `26` | +| **`ED54`** | `c4 POPCTR`
    `c4 POP` | _`x -`_ | Sets the “global data root'' cell reference, thus allowing modification of persistent smart-contract data. | `26` | +| **`ED6i`** | `c[i] SETCONT`
    `c[i] SETCONTCTR` | _`x c - c'`_ | Stores `x` into the savelist of continuation `c` as `c(i)`, and returns the resulting continuation `c'`. Almost all operations with continuations may be expressed in terms of [`SETCONTCTR`](#instr-setcontctr), [`POPCTR`](#instr-popctr), and [`PUSHCTR`](#instr-pushctr). | `26` | +| **`ED7i`** | `c[i] SETRETCTR` | _`x - `_ | Equivalent to [`c0 PUSHCTR`](#instr-pushctr) [`c[i] SETCONTCTR`](#instr-setcontctr) [`c0 POPCTR`](#instr-popctr). | `26` | +| **`ED8i`** | `c[i] SETALTCTR` | _`x - `_ | Equivalent to [`c1 PUSHCTR`](#instr-pushctr) [`c[i] SETCONTCTR`](#instr-setcontctr) [`c0 POPCTR`](#instr-popctr). | `26` | +| **`ED9i`** | `c[i] POPSAVE`
    `c[i] POPCTRSAVE` | _`x -`_ | Similar to [`c[i] POPCTR`](#instr-popctr), but also saves the old value of `c[i]` into continuation `c0`.
    Equivalent (up to exceptions) to [`c[i] SAVECTR`](#instr-save) [`c[i] POPCTR`](#instr-popctr). | `26` | +| **`EDAi`** | `c[i] SAVE`
    `c[i] SAVECTR` | | Saves the current value of `c(i)` into the savelist of continuation `c0`. If an entry for `c[i]` is already present in the savelist of `c0`, nothing is done. Equivalent to [`c[i] PUSHCTR`](#instr-pushctr) [`c[i] SETRETCTR`](#instr-setretctr). | `26` | +| **`EDBi`** | `c[i] SAVEALT`
    `c[i] SAVEALTCTR` | | Similar to [`c[i] SAVE`](#instr-save), but saves the current value of `c[i]` into the savelist of `c1`, not `c0`. | `26` | +| **`EDCi`** | `c[i] SAVEBOTH`
    `c[i] SAVEBOTHCTR` | | Equivalent to [`DUP`](#instr-dup) [`c[i] SAVE`](#instr-save) [`c[i] SAVEALT`](#instr-savealt). | `26` | +| **`EDE0`** | `PUSHCTRX` | _`i - x`_ | Similar to [`c[i] PUSHCTR`](#instr-pushctr), but with `i`, `0 <= i <= 255`, taken from the stack.
    Notice that this primitive is one of the few “exotic'' primitives, which are not polymorphic like stack manipulation primitives, and at the same time do not have well-defined types of parameters and return values, because the type of `x` depends on `i`. | `26` | +| **`EDE1`** | `POPCTRX` | _`x i - `_ | Similar to [`c[i] POPCTR`](#instr-popctr), but with `0 <= i <= 255` from the stack. | `26` | +| **`EDE2`** | `SETCONTCTRX` | _`x c i - c'`_ | Similar to [`c[i] SETCONTCTR`](#instr-setcontctr), but with `0 <= i <= 255` from the stack. | `26` | +| **`EDF0`** | `COMPOS`
    `BOOLAND` | _`c c' - c''`_ | Computes the composition `compose0(c, c’)`, which has the meaning of “perform `c`, and, if successful, perform `c'`'' (if `c` is a boolean circuit) or simply “perform `c`, then `c'`''. Equivalent to [`SWAP`](#instr-swap) [`c0 SETCONT`](#instr-setcontctr). | `26` | +| **`EDF1`** | `COMPOSALT`
    `BOOLOR` | _`c c' - c''`_ | Computes the alternative composition `compose1(c, c’)`, which has the meaning of “perform `c`, and, if not successful, perform `c'`'' (if `c` is a boolean circuit). Equivalent to [`SWAP`](#instr-swap) [`c1 SETCONT`](#instr-setcontctr). | `26` | +| **`EDF2`** | `COMPOSBOTH` | _`c c' - c''`_ | Computes composition `compose1(compose0(c, c’), c’)`, which has the meaning of “compute boolean circuit `c`, then compute `c'`, regardless of the result of `c`''. | `26` | +| **`EDF3`** | `ATEXIT` | _`c - `_ | Sets `c0` to `compose0(c, c0)`. In other words, `c` will be executed before exiting current subroutine. | `26` | +| **`EDF3`** | `ATEXIT:<{ code }>`
    `<{ code }>ATEXIT` | _`-`_ | Equivalent to [`<{ code }> CONT`](#instr-pushcont) [`ATEXIT`](#instr-atexit). | | +| **`EDF4`** | `ATEXITALT` | _`c - `_ | Sets `c1` to `compose1(c, c1)`. In other words, `c` will be executed before exiting current subroutine by its alternative return path. | `26` | +| **`EDF4`** | `ATEXITALT:<{ code }>`
    `<{ code }>ATEXITALT` | _`-`_ | Equivalent to [`<{ code }> CONT`](#instr-pushcont) [`ATEXITALT`](#instr-atexitalt). | | +| **`EDF5`** | `SETEXITALT` | _`c - `_ | Sets `c1` to `compose1(compose0(c, c0), c1)`,
    In this way, a subsequent [`RETALT`](#instr-retalt) will first execute `c`, then transfer control to the original `c0`. This can be used, for instance, to exit from nested loops. | `26` | +| **`EDF6`** | `THENRET` | _`c - c'`_ | Computes `compose0(c, c0)`. | `26` | +| **`EDF7`** | `THENRETALT` | _`c - c'`_ | Computes `compose0(c, c1)` | `26` | +| **`EDF8`** | `INVERT` | _`-`_ | Interchanges `c0` and `c1`. | `26` | +| **`EDF9`** | `BOOLEVAL` | _`c - ?`_ | Performs `cc:=compose1(compose0(c, compose0(-1 PUSHINT, cc)), compose0(0 PUSHINT, cc))`. If `c` represents a boolean circuit, the net effect is to evaluate it and push either `-1` or `0` into the stack before continuing. | `26` | +| **`EDFA`** | `SAMEALT` | _`-`_ | Sets `c1` to `c0`. Equivalent to [`c0 PUSHCTR`](#instr-pushctr) [`c1 POPCTR`](#instr-popctr). | `26` | +| **`EDFB`** | `SAMEALTSAVE` | _`-`_ | Sets `c1` to `c0`, but first saves the old value of `c1` into the savelist of `c0`.
    Equivalent to [`c1 SAVE`](#instr-save) [`SAMEALT`](#instr-samealt). | `26` | +### 8.7 Dictionary subroutine calls and jumps +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`F0nn`** | `[nn] CALL`
    `[nn] CALLDICT` | _`- nn`_ | Calls the continuation in `c3`, pushing integer `0 <= nn <= 255` into its stack as an argument.
    Approximately equivalent to [`[nn] PUSHINT`](#instr-pushint-4) [`c3 PUSHCTR`](#instr-pushctr) [`EXECUTE`](#instr-execute). | | +| **`F12_n`** | `[n] CALL`
    `[n] CALLDICT` | _`- n`_ | For `0 <= n < 2^14`, an encoding of [`[n] CALL`](#instr-calldict) for larger values of `n`. | | +| **`F16_n`** | `[n] JMP` | _` - n`_ | Jumps to the continuation in `c3`, pushing integer `0 <= n < 2^14` as its argument.
    Approximately equivalent to [`n PUSHINT`](#instr-pushint-4) [`c3 PUSHCTR`](#instr-pushctr) [`JMPX`](#instr-jmpx). | | +| **`F1A_n`** | `[n] PREPARE`
    `[n] PREPAREDICT` | _` - n c`_ | Equivalent to [`n PUSHINT`](#instr-pushint-4) [`c3 PUSHCTR`](#instr-pushctr), for `0 <= n < 2^14`.
    In this way, [`[n] CALL`](#instr-calldict) is approximately equivalent to [`[n] PREPARE`](#instr-preparedict) [`EXECUTE`](#instr-execute), and [`[n] JMP`](#instr-jmpdict) is approximately equivalent to [`[n] PREPARE`](#instr-preparedict) [`JMPX`](#instr-jmpx).
    One might use, for instance, [`CALLXARGS`](#instr-callxargs) or [`CALLCC`](#instr-callcc) instead of [`EXECUTE`](#instr-execute) here. | | + +## 9 Exception generating and handling primitives +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`F22_n`** | `[n] THROW` | _` - 0 n`_ | Throws exception `0 <= n <= 63` with parameter zero.
    In other words, it transfers control to the continuation in `c2`, pushing `0` and `n` into its stack, and discarding the old stack altogether. | `76` | +| **`F26_n`** | `[n] THROWIF` | _`f - `_ | Throws exception `0 <= n <= 63` with parameter zero only if integer `f!=0`. | `26/76` | +| **`F2A_n`** | `[n] THROWIFNOT` | _`f - `_ | Throws exception `0 <= n <= 63` with parameter zero only if integer `f=0`. | `26/76` | +| **`F2C4_n`** | `[n] THROW` | _`- 0 nn`_ | For `0 <= n < 2^11`, an encoding of [`[n] THROW`](#instr-throw-short) for larger values of `n`. | `84` | +| **`F2CC_n`** | `[n] THROWARG` | _`x - x nn`_ | Throws exception `0 <= n < 2^11` with parameter `x`, by copying `x` and `n` into the stack of `c2` and transferring control to `c2`. | `84` | +| **`F2D4_n`** | `[n] THROWIF` | _`f - `_ | For `0 <= n < 2^11`, an encoding of [`[n] THROWIF`](#instr-throwif-short) for larger values of `n`. | `34/84` | +| **`F2DC_n`** | `[n] THROWARGIF` | _`x f - `_ | Throws exception `0 <= nn < 2^11` with parameter `x` only if integer `f!=0`. | `34/84` | +| **`F2E4_n`** | `[n] THROWIFNOT` | _`f - `_ | For `0 <= n < 2^11`, an encoding of [`[n] THROWIFNOT`](#instr-throwifnot-short) for larger values of `n`. | `34/84` | +| **`F2EC_n`** | `[n] THROWARGIFNOT` | _`x f - `_ | Throws exception `0 <= n < 2^11` with parameter `x` only if integer `f=0`. | `34/84` | +| **`F2F0`** | `THROWANY` | _`n - 0 n`_ | Throws exception `0 <= n < 2^16` with parameter zero.
    Approximately equivalent to [`ZERO`](#instr-zero) [`SWAP`](#instr-swap) [`THROWARGANY`](#instr-throwargany). | `76` | +| **`F2F1`** | `THROWARGANY` | _`x n - x n`_ | Throws exception `0 <= n < 2^16` with parameter `x`, transferring control to the continuation in `c2`.
    Approximately equivalent to [`c2 PUSHCTR`](#instr-pushctr) [`2 JMPXARGS`](#instr-jmpxargs). | `76` | +| **`F2F2`** | `THROWANYIF` | _`n f - `_ | Throws exception `0 <= n < 2^16` with parameter zero only if `f!=0`. | `26/76` | +| **`F2F3`** | `THROWARGANYIF` | _`x n f - `_ | Throws exception `0 <= n<2^16` with parameter `x` only if `f!=0`. | `26/76` | +| **`F2F4`** | `THROWANYIFNOT` | _`n f - `_ | Throws exception `0 <= n<2^16` with parameter zero only if `f=0`. | `26/76` | +| **`F2F5`** | `THROWARGANYIFNOT` | _`x n f - `_ | Throws exception `0 <= n<2^16` with parameter `x` only if `f=0`. | `26/76` | +| **`F2FF`** | `TRY` | _`c c' - `_ | Sets `c2` to `c'`, first saving the old value of `c2` both into the savelist of `c'` and into the savelist of the current continuation, which is stored into `c.c0` and `c'.c0`. Then runs `c` similarly to [`EXECUTE`](#instr-execute). If `c` does not throw any exceptions, the original value of `c2` is automatically restored on return from `c`. If an exception occurs, the execution is transferred to `c'`, but the original value of `c2` is restored in the process, so that `c'` can re-throw the exception by [`THROWANY`](#instr-throwany) if it cannot handle it by itself. | `26` | +| **`F2FF`** | `TRY:<{ code1 }>CATCH<{ code2 }>` | _`-`_ | Equivalent to [`<{ code1 }> CONT`](#instr-pushcont) [`<{ code2 }> CONT`](#instr-pushcont) [`TRY`](#instr-try). | | +| **`F3pr`** | `[p] [r] TRYARGS` | _`c c' - `_ | Similar to [`TRY`](#instr-try), but with [`[p] [r] CALLXARGS`](#instr-callxargs) internally used instead of [`EXECUTE`](#instr-execute).
    In this way, all but the top `0 <= p <= 15` stack elements will be saved into current continuation's stack, and then restored upon return from either `c` or `c'`, with the top `0 <= r <= 15` values of the resulting stack of `c` or `c'` copied as return values. | `26` | + +## 10 Dictionary manipulation primitives +Gas consumption of most of the dictionary operations is not fixed, it depends on the contents of the given dictionary. +### 10.1 Dictionary creation +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`6D`** | `NEWDICT` | _` - D`_ | Returns a new empty dictionary.
    It is an alternative mnemonics for [`PUSHNULL`](#instr-null). | `18` | +| **`6E`** | `DICTEMPTY` | _`D - ?`_ | Checks whether dictionary `D` is empty, and returns `-1` or `0` accordingly.
    It is an alternative mnemonics for [`ISNULL`](#instr-isnull). | `18` | +### 10.2 Dictionary serialization and deserialization +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`CE`** | `STDICTS`
    `` | _`s b - b'`_ | Stores a _Slice_-represented dictionary `s` into _Builder_ `b`.
    It is actually a synonym for [`STSLICE`](#instr-stslice). | `18` | +| **`F400`** | `STDICT`
    `STOPTREF` | _`D b - b'`_ | Stores dictionary `D` into _Builder_ `b`, returing the resulting _Builder_ `b'`.
    In other words, if `D` is a cell, performs [`STONE`](#instr-stone) and [`STREF`](#instr-stref); if `D` is _Null_, performs [`NIP`](#instr-nip) and [`STZERO`](#instr-stzero); otherwise throws a type checking exception. | `26` | +| **`F401`** | `SKIPDICT`
    `SKIPOPTREF` | _`s - s'`_ | Equivalent to [`LDDICT`](#instr-lddict) [`NIP`](#instr-nip). | `26` | +| **`F402`** | `LDDICTS` | _`s - s' s''`_ | Loads (parses) a (_Slice_-represented) dictionary `s'` from _Slice_ `s`, and returns the remainder of `s` as `s''`.
    This is a “split function'' for all `HashmapE(n,X)` dictionary types. | `26` | +| **`F403`** | `PLDDICTS` | _`s - s'`_ | Preloads a (_Slice_-represented) dictionary `s'` from _Slice_ `s`.
    Approximately equivalent to [`LDDICTS`](#instr-lddicts) [`DROP`](#instr-drop). | `26` | +| **`F404`** | `LDDICT`
    `LDOPTREF` | _`s - D s'`_ | Loads (parses) a dictionary `D` from _Slice_ `s`, and returns the remainder of `s` as `s'`. May be applied to dictionaries or to values of arbitrary `(^Y)?` types. | `26` | +| **`F405`** | `PLDDICT`
    `PLDOPTREF` | _`s - D`_ | Preloads a dictionary `D` from _Slice_ `s`.
    Approximately equivalent to [`LDDICT`](#instr-lddict) [`DROP`](#instr-drop). | `26` | +| **`F406`** | `LDDICTQ` | _`s - D s' -1 or s 0`_ | A quiet version of [`LDDICT`](#instr-lddict). | `26` | +| **`F407`** | `PLDDICTQ` | _`s - D -1 or 0`_ | A quiet version of [`PLDDICT`](#instr-plddict). | `26` | +### 10.3 Get dictionary operations +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`F40A`** | `DICTGET` | _`k D n - x -1 or 0`_ | Looks up key `k` (represented by a _Slice_, the first `0 <= n <= 1023` data bits of which are used as a key) in dictionary `D` of type `HashmapE(n,X)` with `n`-bit keys.
    On success, returns the value found as a _Slice_ `x`. | | +| **`F40B`** | `DICTGETREF` | _`k D n - c -1 or 0`_ | Similar to [`DICTGET`](#instr-dictget), but with a [`LDREF`](#instr-ldref) [`ENDS`](#instr-ends) applied to `x` on success.
    This operation is useful for dictionaries of type `HashmapE(n,^Y)`. | | +| **`F40C`** | `DICTIGET` | _`i D n - x -1 or 0`_ | Similar to [`DICTGET`](#instr-dictget), but with a signed (big-endian) `n`-bit _Integer_ `i` as a key. If `i` does not fit into `n` bits, returns `0`. If `i` is a `NaN`, throws an integer overflow exception. | | +| **`F40D`** | `DICTIGETREF` | _`i D n - c -1 or 0`_ | Combines [`DICTIGET`](#instr-dictiget) with [`DICTGETREF`](#instr-dictgetref): it uses signed `n`-bit _Integer_ `i` as a key and returns a _Cell_ instead of a _Slice_ on success. | | +| **`F40E`** | `DICTUGET` | _`i D n - x -1 or 0`_ | Similar to [`DICTIGET`](#instr-dictiget), but with _unsigned_ (big-endian) `n`-bit _Integer_ `i` used as a key. | | +| **`F40F`** | `DICTUGETREF` | _`i D n - c -1 or 0`_ | Similar to [`DICTIGETREF`](#instr-dictigetref), but with an unsigned `n`-bit _Integer_ key `i`. | | +### 10.4 Set/Replace/Add dictionary operations +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`F412`** | `DICTSET` | _`x k D n - D'`_ | Sets the value associated with `n`-bit key `k` (represented by a _Slice_ as in [`DICTGET`](#instr-dictget)) in dictionary `D` (also represented by a _Slice_) to value `x` (again a _Slice_), and returns the resulting dictionary as `D'`. | | +| **`F413`** | `DICTSETREF` | _`c k D n - D'`_ | Similar to [`DICTSET`](#instr-dictset), but with the value set to a reference to _Cell_ `c`. | | +| **`F414`** | `DICTISET` | _`x i D n - D'`_ | Similar to [`DICTSET`](#instr-dictset), but with the key represented by a (big-endian) signed `n`-bit integer `i`. If `i` does not fit into `n` bits, a range check exception is generated. | | +| **`F415`** | `DICTISETREF` | _`c i D n - D'`_ | Similar to [`DICTSETREF`](#instr-dictsetref), but with the key a signed `n`-bit integer as in [`DICTISET`](#instr-dictiset). | | +| **`F416`** | `DICTUSET` | _`x i D n - D'`_ | Similar to [`DICTISET`](#instr-dictiset), but with `i` an _unsigned_ `n`-bit integer. | | +| **`F417`** | `DICTUSETREF` | _`c i D n - D'`_ | Similar to [`DICTISETREF`](#instr-dictisetref), but with `i` unsigned. | | +| **`F41A`** | `DICTSETGET` | _`x k D n - D' y -1 or D' 0`_ | Combines [`DICTSET`](#instr-dictset) with [`DICTGET`](#instr-dictget): it sets the value corresponding to key `k` to `x`, but also returns the old value `y` associated with the key in question, if present. | | +| **`F41B`** | `DICTSETGETREF` | _`c k D n - D' c' -1 or D' 0`_ | Combines [`DICTSETREF`](#instr-dictsetref) with [`DICTGETREF`](#instr-dictgetref) similarly to [`DICTSETGET`](#instr-dictsetget). | | +| **`F41C`** | `DICTISETGET` | _`x i D n - D' y -1 or D' 0`_ | [`DICTISETGET`](#instr-dictisetget), but with `i` a signed `n`-bit integer. | | +| **`F41D`** | `DICTISETGETREF` | _`c i D n - D' c' -1 or D' 0`_ | [`DICTISETGETREF`](#instr-dictisetgetref), but with `i` a signed `n`-bit integer. | | +| **`F41E`** | `DICTUSETGET` | _`x i D n - D' y -1 or D' 0`_ | [`DICTISETGET`](#instr-dictisetget), but with `i` an unsigned `n`-bit integer. | | +| **`F41F`** | `DICTUSETGETREF` | _`c i D n - D' c' -1 or D' 0`_ | [`DICTISETGETREF`](#instr-dictisetgetref), but with `i` an unsigned `n`-bit integer. | | +| **`F422`** | `DICTREPLACE` | _`x k D n - D' -1 or D 0`_ | A _Replace_ operation, which is similar to [`DICTSET`](#instr-dictset), but sets the value of key `k` in dictionary `D` to `x` only if the key `k` was already present in `D`. | | +| **`F423`** | `DICTREPLACEREF` | _`c k D n - D' -1 or D 0`_ | A _Replace_ counterpart of [`DICTSETREF`](#instr-dictsetref). | | +| **`F424`** | `DICTIREPLACE` | _`x i D n - D' -1 or D 0`_ | [`DICTREPLACE`](#instr-dictreplace), but with `i` a signed `n`-bit integer. | | +| **`F425`** | `DICTIREPLACEREF` | _`c i D n - D' -1 or D 0`_ | [`DICTREPLACEREF`](#instr-dictreplaceref), but with `i` a signed `n`-bit integer. | | +| **`F426`** | `DICTUREPLACE` | _`x i D n - D' -1 or D 0`_ | [`DICTREPLACE`](#instr-dictreplace), but with `i` an unsigned `n`-bit integer. | | +| **`F427`** | `DICTUREPLACEREF` | _`c i D n - D' -1 or D 0`_ | [`DICTREPLACEREF`](#instr-dictreplaceref), but with `i` an unsigned `n`-bit integer. | | +| **`F42A`** | `DICTREPLACEGET` | _`x k D n - D' y -1 or D 0`_ | A _Replace_ counterpart of [`DICTSETGET`](#instr-dictsetget): on success, also returns the old value associated with the key in question. | | +| **`F42B`** | `DICTREPLACEGETREF` | _`c k D n - D' c' -1 or D 0`_ | A _Replace_ counterpart of [`DICTSETGETREF`](#instr-dictsetgetref). | | +| **`F42C`** | `DICTIREPLACEGET` | _`x i D n - D' y -1 or D 0`_ | [`DICTREPLACEGET`](#instr-dictreplaceget), but with `i` a signed `n`-bit integer. | | +| **`F42D`** | `DICTIREPLACEGETREF` | _`c i D n - D' c' -1 or D 0`_ | [`DICTREPLACEGETREF`](#instr-dictreplacegetref), but with `i` a signed `n`-bit integer. | | +| **`F42E`** | `DICTUREPLACEGET` | _`x i D n - D' y -1 or D 0`_ | [`DICTREPLACEGET`](#instr-dictreplaceget), but with `i` an unsigned `n`-bit integer. | | +| **`F42F`** | `DICTUREPLACEGETREF` | _`c i D n - D' c' -1 or D 0`_ | [`DICTREPLACEGETREF`](#instr-dictreplacegetref), but with `i` an unsigned `n`-bit integer. | | +| **`F432`** | `DICTADD` | _`x k D n - D' -1 or D 0`_ | An _Add_ counterpart of [`DICTSET`](#instr-dictset): sets the value associated with key `k` in dictionary `D` to `x`, but only if it is not already present in `D`. | | +| **`F433`** | `DICTADDREF` | _`c k D n - D' -1 or D 0`_ | An _Add_ counterpart of [`DICTSETREF`](#instr-dictsetref). | | +| **`F434`** | `DICTIADD` | _`x i D n - D' -1 or D 0`_ | [`DICTADD`](#instr-dictadd), but with `i` a signed `n`-bit integer. | | +| **`F435`** | `DICTIADDREF` | _`c i D n - D' -1 or D 0`_ | [`DICTADDREF`](#instr-dictaddref), but with `i` a signed `n`-bit integer. | | +| **`F436`** | `DICTUADD` | _`x i D n - D' -1 or D 0`_ | [`DICTADD`](#instr-dictadd), but with `i` an unsigned `n`-bit integer. | | +| **`F437`** | `DICTUADDREF` | _`c i D n - D' -1 or D 0`_ | [`DICTADDREF`](#instr-dictaddref), but with `i` an unsigned `n`-bit integer. | | +| **`F43A`** | `DICTADDGET` | _`x k D n - D' -1 or D y 0`_ | An _Add_ counterpart of [`DICTSETGET`](#instr-dictsetget): sets the value associated with key `k` in dictionary `D` to `x`, but only if key `k` is not already present in `D`. Otherwise, just returns the old value `y` without changing the dictionary. | | +| **`F43B`** | `DICTADDGETREF` | _`c k D n - D' -1 or D c' 0`_ | An _Add_ counterpart of [`DICTSETGETREF`](#instr-dictsetgetref). | | +| **`F43C`** | `DICTIADDGET` | _`x i D n - D' -1 or D y 0`_ | [`DICTADDGET`](#instr-dictaddget), but with `i` a signed `n`-bit integer. | | +| **`F43D`** | `DICTIADDGETREF` | _`c i D n - D' -1 or D c' 0`_ | [`DICTADDGETREF`](#instr-dictaddgetref), but with `i` a signed `n`-bit integer. | | +| **`F43E`** | `DICTUADDGET` | _`x i D n - D' -1 or D y 0`_ | [`DICTADDGET`](#instr-dictaddget), but with `i` an unsigned `n`-bit integer. | | +| **`F43F`** | `DICTUADDGETREF` | _`c i D n - D' -1 or D c' 0`_ | [`DICTADDGETREF`](#instr-dictaddgetref), but with `i` an unsigned `n`-bit integer. | | +### 10.5 Builder-accepting variants of Set dictionary operations +The following primitives accept the new value as a _Builder_ `b` instead of a _Slice_ `x`. + +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`F441`** | `DICTSETB` | _`b k D n - D'`_ | | | +| **`F442`** | `DICTISETB` | _`b i D n - D'`_ | | | +| **`F443`** | `DICTUSETB` | _`b i D n - D'`_ | | | +| **`F445`** | `DICTSETGETB` | _`b k D n - D' y -1 or D' 0`_ | | | +| **`F446`** | `DICTISETGETB` | _`b i D n - D' y -1 or D' 0`_ | | | +| **`F447`** | `DICTUSETGETB` | _`b i D n - D' y -1 or D' 0`_ | | | +| **`F449`** | `DICTREPLACEB` | _`b k D n - D' -1 or D 0`_ | | | +| **`F44A`** | `DICTIREPLACEB` | _`b i D n - D' -1 or D 0`_ | | | +| **`F44B`** | `DICTUREPLACEB` | _`b i D n - D' -1 or D 0`_ | | | +| **`F44D`** | `DICTREPLACEGETB` | _`b k D n - D' y -1 or D 0`_ | | | +| **`F44E`** | `DICTIREPLACEGETB` | _`b i D n - D' y -1 or D 0`_ | | | +| **`F44F`** | `DICTUREPLACEGETB` | _`b i D n - D' y -1 or D 0`_ | | | +| **`F451`** | `DICTADDB` | _`b k D n - D' -1 or D 0`_ | | | +| **`F452`** | `DICTIADDB` | _`b i D n - D' -1 or D 0`_ | | | +| **`F453`** | `DICTUADDB` | _`b i D n - D' -1 or D 0`_ | | | +| **`F455`** | `DICTADDGETB` | _`b k D n - D' -1 or D y 0`_ | | | +| **`F456`** | `DICTIADDGETB` | _`b i D n - D' -1 or D y 0`_ | | | +| **`F457`** | `DICTUADDGETB` | _`b i D n - D' -1 or D y 0`_ | | | +### 10.6 Delete dictionary operations +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`F459`** | `DICTDEL` | _`k D n - D' -1 or D 0`_ | Deletes `n`-bit key, represented by a _Slice_ `k`, from dictionary `D`. If the key is present, returns the modified dictionary `D'` and the success flag `-1`. Otherwise, returns the original dictionary `D` and `0`. | | +| **`F45A`** | `DICTIDEL` | _`i D n - D' ?`_ | A version of [`DICTDEL`](#instr-dictdel) with the key represented by a signed `n`-bit _Integer_ `i`. If `i` does not fit into `n` bits, simply returns `D` `0` (“key not found, dictionary unmodified''). | | +| **`F45B`** | `DICTUDEL` | _`i D n - D' ?`_ | Similar to [`DICTIDEL`](#instr-dictidel), but with `i` an unsigned `n`-bit integer. | | +| **`F462`** | `DICTDELGET` | _`k D n - D' x -1 or D 0`_ | Deletes `n`-bit key, represented by a _Slice_ `k`, from dictionary `D`. If the key is present, returns the modified dictionary `D'`, the original value `x` associated with the key `k` (represented by a _Slice_), and the success flag `-1`. Otherwise, returns the original dictionary `D` and `0`. | | +| **`F463`** | `DICTDELGETREF` | _`k D n - D' c -1 or D 0`_ | Similar to [`DICTDELGET`](#instr-dictdelget), but with [`LDREF`](#instr-ldref) [`ENDS`](#instr-ends) applied to `x` on success, so that the value returned `c` is a _Cell_. | | +| **`F464`** | `DICTIDELGET` | _`i D n - D' x -1 or D 0`_ | [`DICTDELGET`](#instr-dictdelget), but with `i` a signed `n`-bit integer. | | +| **`F465`** | `DICTIDELGETREF` | _`i D n - D' c -1 or D 0`_ | [`DICTDELGETREF`](#instr-dictdelgetref), but with `i` a signed `n`-bit integer. | | +| **`F466`** | `DICTUDELGET` | _`i D n - D' x -1 or D 0`_ | [`DICTDELGET`](#instr-dictdelget), but with `i` an unsigned `n`-bit integer. | | +| **`F467`** | `DICTUDELGETREF` | _`i D n - D' c -1 or D 0`_ | [`DICTDELGETREF`](#instr-dictdelgetref), but with `i` an unsigned `n`-bit integer. | | +### 10.7 "Maybe reference" dictionary operations +The following operations assume that a dictionary is used to store values `c?` of type _Maybe Cell_. The representation is as follows: if `c?` is a _Cell_ , it is stored as a value with no data bits and exactly one reference to this _Cell_. If `c?` is _Null_, then the corresponding key must be absent from the dictionary. + +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`F469`** | `DICTGETOPTREF` | _`k D n - c^?`_ | A variant of [`DICTGETREF`](#instr-dictgetref) that returns _Null_ instead of the value `c^?` if the key `k` is absent from dictionary `D`. | | +| **`F46A`** | `DICTIGETOPTREF` | _`i D n - c^?`_ | [`DICTGETOPTREF`](#instr-dictgetoptref), but with `i` a signed `n`-bit integer. If the key `i` is out of range, also returns _Null_. | | +| **`F46B`** | `DICTUGETOPTREF` | _`i D n - c^?`_ | [`DICTGETOPTREF`](#instr-dictgetoptref), but with `i` an unsigned `n`-bit integer. If the key `i` is out of range, also returns _Null_. | | +| **`F46D`** | `DICTSETGETOPTREF` | _`c^? k D n - D' ~c^?`_ | A variant of both [`DICTGETOPTREF`](#instr-dictgetoptref) and [`DICTSETGETREF`](#instr-dictsetgetref) that sets the value corresponding to key `k` in dictionary `D` to `c^?` (if `c^?` is _Null_, then the key is deleted instead), and returns the old value `~c^?` (if the key `k` was absent before, returns _Null_ instead). | | +| **`F46E`** | `DICTISETGETOPTREF` | _`c^? i D n - D' ~c^?`_ | Similar to primitive [`DICTSETGETOPTREF`](#instr-dictsetgetoptref), but using signed `n`-bit _Integer_ `i` as a key. If `i` does not fit into `n` bits, throws a range checking exception. | | +| **`F46F`** | `DICTUSETGETOPTREF` | _`c^? i D n - D' ~c^?`_ | Similar to primitive [`DICTSETGETOPTREF`](#instr-dictsetgetoptref), but using unsigned `n`-bit _Integer_ `i` as a key. | | +### 10.8 Prefix code dictionary operations +These are some basic operations for constructing prefix code dictionaries. +These primitives are completely similar to their non-prefix code counterparts ([`DICTSET`](#instr-dictset) etc), with the obvious difference that even a _Set_ may fail in a prefix code dictionary, so a success flag must be returned by [`PFXDICTSET`](#instr-pfxdictset) as well. + +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`F470`** | `PFXDICTSET` | _`x k D n - D' -1 or D 0`_ | | | +| **`F471`** | `PFXDICTREPLACE` | _`x k D n - D' -1 or D 0`_ | | | +| **`F472`** | `PFXDICTADD` | _`x k D n - D' -1 or D 0`_ | | | +| **`F473`** | `PFXDICTDEL` | _`k D n - D' -1 or D 0`_ | | | +### 10.9 Variants of GetNext and GetPrev operations +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`F474`** | `DICTGETNEXT` | _`k D n - x' k' -1 or 0`_ | Computes the minimal key `k'` in dictionary `D` that is lexicographically greater than `k`, and returns `k'` (represented by a _Slice_) along with associated value `x'` (also represented by a _Slice_). | | +| **`F475`** | `DICTGETNEXTEQ` | _`k D n - x' k' -1 or 0`_ | Similar to [`DICTGETNEXT`](#instr-dictgetnext), but computes the minimal key `k'` that is lexicographically greater than or equal to `k`. | | +| **`F476`** | `DICTGETPREV` | _`k D n - x' k' -1 or 0`_ | Similar to [`DICTGETNEXT`](#instr-dictgetnext), but computes the maximal key `k'` lexicographically smaller than `k`. | | +| **`F477`** | `DICTGETPREVEQ` | _`k D n - x' k' -1 or 0`_ | Similar to [`DICTGETPREV`](#instr-dictgetprev), but computes the maximal key `k'` lexicographically smaller than or equal to `k`. | | +| **`F478`** | `DICTIGETNEXT` | _`i D n - x' i' -1 or 0`_ | Similar to [`DICTGETNEXT`](#instr-dictgetnext), but interprets all keys in dictionary `D` as big-endian signed `n`-bit integers, and computes the minimal key `i'` that is larger than _Integer_ `i` (which does not necessarily fit into `n` bits). | | +| **`F479`** | `DICTIGETNEXTEQ` | _`i D n - x' i' -1 or 0`_ | Similar to [`DICTGETNEXTEQ`](#instr-dictgetnexteq), but interprets keys as signed `n`-bit integers. | | +| **`F47A`** | `DICTIGETPREV` | _`i D n - x' i' -1 or 0`_ | Similar to [`DICTGETPREV`](#instr-dictgetprev), but interprets keys as signed `n`-bit integers. | | +| **`F47B`** | `DICTIGETPREVEQ` | _`i D n - x' i' -1 or 0`_ | Similar to [`DICTGETPREVEQ`](#instr-dictgetpreveq), but interprets keys as signed `n`-bit integers. | | +| **`F47C`** | `DICTUGETNEXT` | _`i D n - x' i' -1 or 0`_ | Similar to [`DICTGETNEXT`](#instr-dictgetnext), but interprets all keys in dictionary `D` as big-endian unsigned `n`-bit integers, and computes the minimal key `i'` that is larger than _Integer_ `i` (which does not necessarily fit into `n` bits, and is not necessarily non-negative). | | +| **`F47D`** | `DICTUGETNEXTEQ` | _`i D n - x' i' -1 or 0`_ | Similar to [`DICTGETNEXTEQ`](#instr-dictgetnexteq), but interprets keys as unsigned `n`-bit integers. | | +| **`F47E`** | `DICTUGETPREV` | _`i D n - x' i' -1 or 0`_ | Similar to [`DICTGETPREV`](#instr-dictgetprev), but interprets keys as unsigned `n`-bit integers. | | +| **`F47F`** | `DICTUGETPREVEQ` | _`i D n - x' i' -1 or 0`_ | Similar to [`DICTGETPREVEQ`](#instr-dictgetpreveq), but interprets keys a unsigned `n`-bit integers. | | +### 10.10 GetMin, GetMax, RemoveMin, RemoveMax operations +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`F482`** | `DICTMIN` | _`D n - x k -1 or 0`_ | Computes the minimal key `k` (represented by a _Slice_ with `n` data bits) in dictionary `D`, and returns `k` along with the associated value `x`. | | +| **`F483`** | `DICTMINREF` | _`D n - c k -1 or 0`_ | Similar to [`DICTMIN`](#instr-dictmin), but returns the only reference in the value as a _Cell_ `c`. | | +| **`F484`** | `DICTIMIN` | _`D n - x i -1 or 0`_ | Similar to [`DICTMIN`](#instr-dictmin), but computes the minimal key `i` under the assumption that all keys are big-endian signed `n`-bit integers. Notice that the key and value returned may differ from those computed by [`DICTMIN`](#instr-dictmin) and [`DICTUMIN`](#instr-dictumin). | | +| **`F485`** | `DICTIMINREF` | _`D n - c i -1 or 0`_ | Similar to [`DICTIMIN`](#instr-dictimin), but returns the only reference in the value. | | +| **`F486`** | `DICTUMIN` | _`D n - x i -1 or 0`_ | Similar to [`DICTMIN`](#instr-dictmin), but returns the key as an unsigned `n`-bit _Integer_ `i`. | | +| **`F487`** | `DICTUMINREF` | _`D n - c i -1 or 0`_ | Similar to [`DICTUMIN`](#instr-dictumin), but returns the only reference in the value. | | +| **`F48A`** | `DICTMAX` | _`D n - x k -1 or 0`_ | Computes the maximal key `k` (represented by a _Slice_ with `n` data bits) in dictionary `D`, and returns `k` along with the associated value `x`. | | +| **`F48B`** | `DICTMAXREF` | _`D n - c k -1 or 0`_ | Similar to [`DICTMAX`](#instr-dictmax), but returns the only reference in the value. | | +| **`F48C`** | `DICTIMAX` | _`D n - x i -1 or 0`_ | Similar to [`DICTMAX`](#instr-dictmax), but computes the maximal key `i` under the assumption that all keys are big-endian signed `n`-bit integers. Notice that the key and value returned may differ from those computed by [`DICTMAX`](#instr-dictmax) and [`DICTUMAX`](#instr-dictumax). | | +| **`F48D`** | `DICTIMAXREF` | _`D n - c i -1 or 0`_ | Similar to [`DICTIMAX`](#instr-dictimax), but returns the only reference in the value. | | +| **`F48E`** | `DICTUMAX` | _`D n - x i -1 or 0`_ | Similar to [`DICTMAX`](#instr-dictmax), but returns the key as an unsigned `n`-bit _Integer_ `i`. | | +| **`F48F`** | `DICTUMAXREF` | _`D n - c i -1 or 0`_ | Similar to [`DICTUMAX`](#instr-dictumax), but returns the only reference in the value. | | +| **`F492`** | `DICTREMMIN` | _`D n - D' x k -1 or D 0`_ | Computes the minimal key `k` (represented by a _Slice_ with `n` data bits) in dictionary `D`, removes `k` from the dictionary, and returns `k` along with the associated value `x` and the modified dictionary `D'`. | | +| **`F493`** | `DICTREMMINREF` | _`D n - D' c k -1 or D 0`_ | Similar to [`DICTREMMIN`](#instr-dictremmin), but returns the only reference in the value as a _Cell_ `c`. | | +| **`F494`** | `DICTIREMMIN` | _`D n - D' x i -1 or D 0`_ | Similar to [`DICTREMMIN`](#instr-dictremmin), but computes the minimal key `i` under the assumption that all keys are big-endian signed `n`-bit integers. Notice that the key and value returned may differ from those computed by [`DICTREMMIN`](#instr-dictremmin) and [`DICTUREMMIN`](#instr-dicturemmin). | | +| **`F495`** | `DICTIREMMINREF` | _`D n - D' c i -1 or D 0`_ | Similar to [`DICTIREMMIN`](#instr-dictiremmin), but returns the only reference in the value. | | +| **`F496`** | `DICTUREMMIN` | _`D n - D' x i -1 or D 0`_ | Similar to [`DICTREMMIN`](#instr-dictremmin), but returns the key as an unsigned `n`-bit _Integer_ `i`. | | +| **`F497`** | `DICTUREMMINREF` | _`D n - D' c i -1 or D 0`_ | Similar to [`DICTUREMMIN`](#instr-dicturemmin), but returns the only reference in the value. | | +| **`F49A`** | `DICTREMMAX` | _`D n - D' x k -1 or D 0`_ | Computes the maximal key `k` (represented by a _Slice_ with `n` data bits) in dictionary `D`, removes `k` from the dictionary, and returns `k` along with the associated value `x` and the modified dictionary `D'`. | | +| **`F49B`** | `DICTREMMAXREF` | _`D n - D' c k -1 or D 0`_ | Similar to [`DICTREMMAX`](#instr-dictremmax), but returns the only reference in the value as a _Cell_ `c`. | | +| **`F49C`** | `DICTIREMMAX` | _`D n - D' x i -1 or D 0`_ | Similar to [`DICTREMMAX`](#instr-dictremmax), but computes the minimal key `i` under the assumption that all keys are big-endian signed `n`-bit integers. Notice that the key and value returned may differ from those computed by [`DICTREMMAX`](#instr-dictremmax) and [`DICTUREMMAX`](#instr-dicturemmax). | | +| **`F49D`** | `DICTIREMMAXREF` | _`D n - D' c i -1 or D 0`_ | Similar to [`DICTIREMMAX`](#instr-dictiremmax), but returns the only reference in the value. | | +| **`F49E`** | `DICTUREMMAX` | _`D n - D' x i -1 or D 0`_ | Similar to [`DICTREMMAX`](#instr-dictremmax), but returns the key as an unsigned `n`-bit _Integer_ `i`. | | +| **`F49F`** | `DICTUREMMAXREF` | _`D n - D' c i -1 or D 0`_ | Similar to [`DICTUREMMAX`](#instr-dicturemmax), but returns the only reference in the value. | | +### 10.11 Special Get dictionary and prefix code dictionary operations, and constant dictionaries +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`F4A0`** | `DICTIGETJMP` | _`i D n - `_ | Similar to [`DICTIGET`](#instr-dictiget), but with `x` [`BLESS`](#instr-bless)ed into a continuation with a subsequent [`JMPX`](#instr-jmpx) to it on success. On failure, does nothing. This is useful for implementing `switch`/`case` constructions. | | +| **`F4A1`** | `DICTUGETJMP` | _`i D n - `_ | Similar to [`DICTIGETJMP`](#instr-dictigetjmp), but performs [`DICTUGET`](#instr-dictuget) instead of [`DICTIGET`](#instr-dictiget). | | +| **`F4A2`** | `DICTIGETEXEC` | _`i D n - `_ | Similar to [`DICTIGETJMP`](#instr-dictigetjmp), but with [`EXECUTE`](#instr-execute) instead of [`JMPX`](#instr-jmpx). | | +| **`F4A3`** | `DICTUGETEXEC` | _`i D n - `_ | Similar to [`DICTUGETJMP`](#instr-dictugetjmp), but with [`EXECUTE`](#instr-execute) instead of [`JMPX`](#instr-jmpx). | | +| **`F4A6_n`** | `[ref] [n] DICTPUSHCONST` | _` - D n`_ | Pushes a non-empty constant dictionary `D` (as a `Cell^?`) along with its key length `0 <= n <= 1023`, stored as a part of the instruction. The dictionary itself is created from the first of remaining references of the current continuation. In this way, the complete [`DICTPUSHCONST`](#instr-dictpushconst) instruction can be obtained by first serializing `xF4A4_`, then the non-empty dictionary itself (one `1` bit and a cell reference), and then the unsigned 10-bit integer `n` (as if by a `STU 10` instruction). An empty dictionary can be pushed by a [`NEWDICT`](#instr-newdict) primitive instead. | `34` | +| **`F4A8`** | `PFXDICTGETQ` | _`s D n - s' x s'' -1 or s 0`_ | Looks up the unique prefix of _Slice_ `s` present in the prefix code dictionary represented by `Cell^?` `D` and `0 <= n <= 1023`. If found, the prefix of `s` is returned as `s'`, and the corresponding value (also a _Slice_) as `x`. The remainder of `s` is returned as a _Slice_ `s''`. If no prefix of `s` is a key in prefix code dictionary `D`, returns the unchanged `s` and a zero flag to indicate failure. | | +| **`F4A9`** | `PFXDICTGET` | _`s D n - s' x s''`_ | Similar to [`PFXDICTGET`](#instr-pfxdictget), but throws a cell deserialization failure exception on failure. | | +| **`F4AA`** | `PFXDICTGETJMP` | _`s D n - s' s'' or s`_ | Similar to [`PFXDICTGETQ`](#instr-pfxdictgetq), but on success [`BLESS`](#instr-bless)es the value `x` into a _Continuation_ and transfers control to it as if by a [`JMPX`](#instr-jmpx). On failure, returns `s` unchanged and continues execution. | | +| **`F4AB`** | `PFXDICTGETEXEC` | _`s D n - s' s''`_ | Similar to [`PFXDICTGETJMP`](#instr-pfxdictgetjmp), but `EXEC`utes the continuation found instead of jumping to it. On failure, throws a cell deserialization exception. | | +| **`F4AE_n`** | `[ref] [n] PFXDICTCONSTGETJMP`
    `[ref] [n] PFXDICTSWITCH` | _`s - s' s'' or s`_ | Combines [`[n] DICTPUSHCONST`](#instr-dictpushconst) for `0 <= n <= 1023` with [`PFXDICTGETJMP`](#instr-pfxdictgetjmp). | | +| **`F4BC`** | `DICTIGETJMPZ` | _`i D n - i or nothing`_ | A variant of [`DICTIGETJMP`](#instr-dictigetjmp) that returns index `i` on failure. | | +| **`F4BD`** | `DICTUGETJMPZ` | _`i D n - i or nothing`_ | A variant of [`DICTUGETJMP`](#instr-dictugetjmp) that returns index `i` on failure. | | +| **`F4BE`** | `DICTIGETEXECZ` | _`i D n - i or nothing`_ | A variant of [`DICTIGETEXEC`](#instr-dictigetexec) that returns index `i` on failure. | | +| **`F4BF`** | `DICTUGETEXECZ` | _`i D n - i or nothing`_ | A variant of [`DICTUGETEXEC`](#instr-dictugetexec) that returns index `i` on failure. | | +### 10.12 SubDict dictionary operations +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`F4B1`** | `SUBDICTGET` | _`k l D n - D'`_ | Constructs a subdictionary consisting of all keys beginning with prefix `k` (represented by a _Slice_, the first `0 <= l <= n <= 1023` data bits of which are used as a key) of length `l` in dictionary `D` of type `HashmapE(n,X)` with `n`-bit keys. On success, returns the new subdictionary of the same type `HashmapE(n,X)` as a _Slice_ `D'`. | | +| **`F4B2`** | `SUBDICTIGET` | _`x l D n - D'`_ | Variant of [`SUBDICTGET`](#instr-subdictget) with the prefix represented by a signed big-endian `l`-bit _Integer_ `x`, where necessarily `l <= 257`. | | +| **`F4B3`** | `SUBDICTUGET` | _`x l D n - D'`_ | Variant of [`SUBDICTGET`](#instr-subdictget) with the prefix represented by an unsigned big-endian `l`-bit _Integer_ `x`, where necessarily `l <= 256`. | | +| **`F4B5`** | `SUBDICTRPGET` | _`k l D n - D'`_ | Similar to [`SUBDICTGET`](#instr-subdictget), but removes the common prefix `k` from all keys of the new dictionary `D'`, which becomes of type `HashmapE(n-l,X)`. | | +| **`F4B6`** | `SUBDICTIRPGET` | _`x l D n - D'`_ | Variant of [`SUBDICTRPGET`](#instr-subdictrpget) with the prefix represented by a signed big-endian `l`-bit _Integer_ `x`, where necessarily `l <= 257`. | | +| **`F4B7`** | `SUBDICTURPGET` | _`x l D n - D'`_ | Variant of [`SUBDICTRPGET`](#instr-subdictrpget) with the prefix represented by an unsigned big-endian `l`-bit _Integer_ `x`, where necessarily `l <= 256`. | | + +## 11 Application-specific primitives +### 11.1 Gas-related primitives +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`F800`** | `ACCEPT` | _`-`_ | Sets current gas limit `g_l` to its maximal allowed value `g_m`, and resets the gas credit `g_c` to zero, decreasing the value of `g_r` by `g_c` in the process.
    In other words, the current smart contract agrees to buy some gas to finish the current transaction. This action is required to process external messages, which bring no value (hence no gas) with themselves. | `26` | +| **`F801`** | `SETGASLIMIT` | _`g - `_ | Sets current gas limit `g_l` to the minimum of `g` and `g_m`, and resets the gas credit `g_c` to zero. If the gas consumed so far (including the present instruction) exceeds the resulting value of `g_l`, an (unhandled) out of gas exception is thrown before setting new gas limits. Notice that [`SETGASLIMIT`](#instr-setgaslimit) with an argument `g >= 2^63-1` is equivalent to [`ACCEPT`](#instr-accept). | `26` | +| **`F80F`** | `COMMIT` | _`-`_ | Commits the current state of registers `c4` (“persistent data'') and `c5` (“actions'') so that the current execution is considered “successful'' with the saved values even if an exception is thrown later. | `26` | +### 11.2 Pseudo-random number generator primitives +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`F810`** | `RANDU256` | _`- x`_ | Generates a new pseudo-random unsigned 256-bit _Integer_ `x`. The algorithm is as follows: if `r` is the old value of the random seed, considered as a 32-byte array (by constructing the big-endian representation of an unsigned 256-bit integer), then its `sha512(r)` is computed; the first 32 bytes of this hash are stored as the new value `r'` of the random seed, and the remaining 32 bytes are returned as the next random value `x`. | `26+\|c7\|+\|c1_1\|` | +| **`F811`** | `RAND` | _`y - z`_ | Generates a new pseudo-random integer `z` in the range `0...y-1` (or `y...-1`, if `y<0`). More precisely, an unsigned random value `x` is generated as in `RAND256U`; then `z:=floor(x*y/2^256)` is computed.
    Equivalent to [`RANDU256`](#instr-randu256) [`256 MULRSHIFT`](#instr-mulrshift-var). | `26+\|c7\|+\|c1_1\|` | +| **`F814`** | `SETRAND` | _`x - `_ | Sets the random seed to unsigned 256-bit _Integer_ `x`. | `26+\|c7\|+\|c1_1\|` | +| **`F815`** | `ADDRAND`
    `RANDOMIZE` | _`x - `_ | Mixes unsigned 256-bit _Integer_ `x` into the random seed `r` by setting the random seed to `Sha` of the concatenation of two 32-byte strings: the first with the big-endian representation of the old seed `r`, and the second with the big-endian representation of `x`. | `26` | +### 11.3 Configuration primitives +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`F82i`** | `[i] GETPARAM` | _` - x`_ | Returns the `i`-th parameter from the _Tuple_ provided at `c7` for `0 <= i <= 15`. Equivalent to [`c7 PUSHCTR`](#instr-pushctr) [`FIRST`](#instr-first) [`[i] INDEX`](#instr-index).
    If one of these internal operations fails, throws an appropriate type checking or range checking exception. | `26` | +| **`F823`** | `NOW` | _` - x`_ | Returns the current Unix time as an _Integer_. If it is impossible to recover the requested value starting from `c7`, throws a type checking or range checking exception as appropriate.
    Equivalent to [`3 GETPARAM`](#instr-getparam). | `26` | +| **`F824`** | `BLOCKLT` | _` - x`_ | Returns the starting logical time of the current block.
    Equivalent to [`4 GETPARAM`](#instr-getparam). | `26` | +| **`F825`** | `LTIME` | _` - x`_ | Returns the logical time of the current transaction.
    Equivalent to [`5 GETPARAM`](#instr-getparam). | `26` | +| **`F826`** | `RANDSEED` | _` - x`_ | Returns the current random seed as an unsigned 256-bit _Integer_.
    Equivalent to [`6 GETPARAM`](#instr-getparam). | `26` | +| **`F827`** | `BALANCE` | _` - t`_ | Returns the remaining balance of the smart contract as a _Tuple_ consisting of an _Integer_ (the remaining Gram balance in nanograms) and a _Maybe Cell_ (a dictionary with 32-bit keys representing the balance of “extra currencies'').
    Equivalent to [`7 GETPARAM`](#instr-getparam).
    Note that `RAW` primitives such as [`SENDRAWMSG`](#instr-sendrawmsg) do not update this field. | `26` | +| **`F828`** | `MYADDR` | _` - s`_ | Returns the internal address of the current smart contract as a _Slice_ with a `MsgAddressInt`. If necessary, it can be parsed further using primitives such as [`PARSEMSGADDR`](#instr-parsemsgaddr) or [`REWRITESTDADDR`](#instr-rewritestdaddr).
    Equivalent to [`8 GETPARAM`](#instr-getparam). | `26` | +| **`F829`** | `CONFIGROOT` | _` - D`_ | Returns the _Maybe Cell_ `D` with the current global configuration dictionary. Equivalent to `9 GETPARAM `. | `26` | +| **`F830`** | `CONFIGDICT` | _` - D 32`_ | Returns the global configuration dictionary along with its key length (32).
    Equivalent to [`CONFIGROOT`](#instr-configroot) [`32 PUSHINT`](#instr-pushint-4). | `26` | +| **`F832`** | `CONFIGPARAM` | _`i - c -1 or 0`_ | Returns the value of the global configuration parameter with integer index `i` as a _Cell_ `c`, and a flag to indicate success.
    Equivalent to [`CONFIGDICT`](#instr-configdict) [`DICTIGETREF`](#instr-dictigetref). | | +| **`F833`** | `CONFIGOPTPARAM` | _`i - c^?`_ | Returns the value of the global configuration parameter with integer index `i` as a _Maybe Cell_ `c^?`.
    Equivalent to [`CONFIGDICT`](#instr-configdict) [`DICTIGETOPTREF`](#instr-dictigetoptref). | | +### 11.4 Global variable primitives +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`F840`** | `GETGLOBVAR` | _`k - x`_ | Returns the `k`-th global variable for `0 <= k < 255`.
    Equivalent to [`c7 PUSHCTR`](#instr-pushctr) [`SWAP`](#instr-swap) [`INDEXVARQ`](#instr-indexvarq). | `26` | +| **`F85_k`** | `[k] GETGLOB` | _` - x`_ | Returns the `k`-th global variable for `1 <= k <= 31`.
    Equivalent to [`c7 PUSHCTR`](#instr-pushctr) [`[k] INDEXQ`](#instr-indexq). | `26` | +| **`F860`** | `SETGLOBVAR` | _`x k - `_ | Assigns `x` to the `k`-th global variable for `0 <= k < 255`.
    Equivalent to [`c7 PUSHCTR`](#instr-pushctr) [`ROTREV`](#instr-rotrev) [`SETINDEXVARQ`](#instr-setindexvarq) [`c7 POPCTR`](#instr-popctr). | `26+\|c7’\|` | +| **`F87_k`** | `[k] SETGLOB` | _`x - `_ | Assigns `x` to the `k`-th global variable for `1 <= k <= 31`.
    Equivalent to [`c7 PUSHCTR`](#instr-pushctr) [`SWAP`](#instr-swap) [`k SETINDEXQ`](#instr-setindexq) [`c7 POPCTR`](#instr-popctr). | `26+\|c7’\|` | +### 11.5 Hashing and cryptography primitives +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`F900`** | `HASHCU` | _`c - x`_ | Computes the representation hash of a _Cell_ `c` and returns it as a 256-bit unsigned integer `x`. Useful for signing and checking signatures of arbitrary entities represented by a tree of cells. | `26` | +| **`F901`** | `HASHSU` | _`s - x`_ | Computes the hash of a _Slice_ `s` and returns it as a 256-bit unsigned integer `x`. The result is the same as if an ordinary cell containing only data and references from `s` had been created and its hash computed by [`HASHCU`](#instr-hashcu). | `526` | +| **`F902`** | `SHA256U` | _`s - x`_ | Computes `Sha` of the data bits of _Slice_ `s`. If the bit length of `s` is not divisible by eight, throws a cell underflow exception. The hash value is returned as a 256-bit unsigned integer `x`. | `26` | +| **`F910`** | `CHKSIGNU` | _`h s k - ?`_ | Checks the Ed25519-signature `s` of a hash `h` (a 256-bit unsigned integer, usually computed as the hash of some data) using public key `k` (also represented by a 256-bit unsigned integer).
    The signature `s` must be a _Slice_ containing at least 512 data bits; only the first 512 bits are used. The result is `-1` if the signature is valid, `0` otherwise.
    Notice that [`CHKSIGNU`](#instr-chksignu) is equivalent to [`ROT`](#instr-rot) [`NEWC`](#instr-newc) [`256 STU`](#instr-stu) [`ENDC`](#instr-endc) [`ROTREV`](#instr-rotrev) [`CHKSIGNS`](#instr-chksigns), i.e., to [`CHKSIGNS`](#instr-chksigns) with the first argument `d` set to 256-bit _Slice_ containing `h`. Therefore, if `h` is computed as the hash of some data, these data are hashed _twice_, the second hashing occurring inside [`CHKSIGNS`](#instr-chksigns). | `26` | +| **`F911`** | `CHKSIGNS` | _`d s k - ?`_ | Checks whether `s` is a valid Ed25519-signature of the data portion of _Slice_ `d` using public key `k`, similarly to [`CHKSIGNU`](#instr-chksignu). If the bit length of _Slice_ `d` is not divisible by eight, throws a cell underflow exception. The verification of Ed25519 signatures is the standard one, with `Sha` used to reduce `d` to the 256-bit number that is actually signed. | `26` | +### 11.6 Miscellaneous primitives +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`F940`** | `CDATASIZEQ` | _`c n - x y z -1 or 0`_ | Recursively computes the count of distinct cells `x`, data bits `y`, and cell references `z` in the dag rooted at _Cell_ `c`, effectively returning the total storage used by this dag taking into account the identification of equal cells. The values of `x`, `y`, and `z` are computed by a depth-first traversal of this dag, with a hash table of visited cell hashes used to prevent visits of already-visited cells. The total count of visited cells `x` cannot exceed non-negative _Integer_ `n`; otherwise the computation is aborted before visiting the `(n+1)`-st cell and a zero is returned to indicate failure. If `c` is _Null_, returns `x=y=z=0`. | | +| **`F941`** | `CDATASIZE` | _`c n - x y z`_ | A non-quiet version of [`CDATASIZEQ`](#instr-cdatasizeq) that throws a cell overflow exception (8) on failure. | | +| **`F942`** | `SDATASIZEQ` | _`s n - x y z -1 or 0`_ | Similar to [`CDATASIZEQ`](#instr-cdatasizeq), but accepting a _Slice_ `s` instead of a _Cell_. The returned value of `x` does not take into account the cell that contains the slice `s` itself; however, the data bits and the cell references of `s` are accounted for in `y` and `z`. | | +| **`F943`** | `SDATASIZE` | _`s n - x y z`_ | A non-quiet version of [`SDATASIZEQ`](#instr-sdatasizeq) that throws a cell overflow exception (8) on failure. | | +### 11.7 Currency manipulation primitives +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`FA00`** | `LDGRAMS`
    `LDVARUINT16` | _`s - x s'`_ | Loads (deserializes) a `Gram` or `VarUInteger 16` amount from _Slice_ `s`, and returns the amount as _Integer_ `x` along with the remainder `s'` of `s`. The expected serialization of `x` consists of a 4-bit unsigned big-endian integer `l`, followed by an `8l`-bit unsigned big-endian representation of `x`.
    The net effect is approximately equivalent to [`4 LDU`](#instr-ldu) [`SWAP`](#instr-swap) [`3 LSHIFT#`](#instr-lshift) [`LDUX`](#instr-ldux). | `26` | +| **`FA01`** | `LDVARINT16` | _`s - x s'`_ | Similar to [`LDVARUINT16`](#instr-ldgrams), but loads a _signed_ _Integer_ `x`.
    Approximately equivalent to [`4 LDU`](#instr-ldu) [`SWAP`](#instr-swap) [`3 LSHIFT#`](#instr-lshift) [`LDIX`](#instr-ldix). | `26` | +| **`FA02`** | `STGRAMS`
    `STVARUINT16` | _`b x - b'`_ | Stores (serializes) an _Integer_ `x` in the range `0...2^120-1` into _Builder_ `b`, and returns the resulting _Builder_ `b'`. The serialization of `x` consists of a 4-bit unsigned big-endian integer `l`, which is the smallest integer `l>=0`, such that `x<2^(8l)`, followed by an `8l`-bit unsigned big-endian representation of `x`. If `x` does not belong to the supported range, a range check exception is thrown. | `26` | +| **`FA03`** | `STVARINT16` | _`b x - b'`_ | Similar to [`STVARUINT16`](#instr-stgrams), but serializes a _signed_ _Integer_ `x` in the range `-2^119...2^119-1`. | `26` | +### 11.8 Message and address manipulation primitives +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`FA40`** | `LDMSGADDR` | _`s - s' s''`_ | Loads from _Slice_ `s` the only prefix that is a valid `MsgAddress`, and returns both this prefix `s'` and the remainder `s''` of `s` as slices. | `26` | +| **`FA41`** | `LDMSGADDRQ` | _`s - s' s'' -1 or s 0`_ | A quiet version of [`LDMSGADDR`](#instr-ldmsgaddr): on success, pushes an extra `-1`; on failure, pushes the original `s` and a zero. | `26` | +| **`FA42`** | `PARSEMSGADDR` | _`s - t`_ | Decomposes _Slice_ `s` containing a valid `MsgAddress` into a _Tuple_ `t` with separate fields of this `MsgAddress`. If `s` is not a valid `MsgAddress`, a cell deserialization exception is thrown. | `26` | +| **`FA43`** | `PARSEMSGADDRQ` | _`s - t -1 or 0`_ | A quiet version of [`PARSEMSGADDR`](#instr-parsemsgaddr): returns a zero on error instead of throwing an exception. | `26` | +| **`FA44`** | `REWRITESTDADDR` | _`s - x y`_ | Parses _Slice_ `s` containing a valid `MsgAddressInt` (usually a `msg_addr_std`), applies rewriting from the `anycast` (if present) to the same-length prefix of the address, and returns both the workchain `x` and the 256-bit address `y` as integers. If the address is not 256-bit, or if `s` is not a valid serialization of `MsgAddressInt`, throws a cell deserialization exception. | `26` | +| **`FA45`** | `REWRITESTDADDRQ` | _`s - x y -1 or 0`_ | A quiet version of primitive [`REWRITESTDADDR`](#instr-rewritestdaddr). | `26` | +| **`FA46`** | `REWRITEVARADDR` | _`s - x s'`_ | A variant of [`REWRITESTDADDR`](#instr-rewritestdaddr) that returns the (rewritten) address as a _Slice_ `s`, even if it is not exactly 256 bit long (represented by a `msg_addr_var`). | `26` | +| **`FA47`** | `REWRITEVARADDRQ` | _`s - x s' -1 or 0`_ | A quiet version of primitive [`REWRITEVARADDR`](#instr-rewritevaraddr). | `26` | +### 11.9 Outbound message and output action primitives +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`FB00`** | `SENDRAWMSG` | _`c x - `_ | Sends a raw message contained in _Cell `c`_, which should contain a correctly serialized object `Message X`, with the only exception that the source address is allowed to have dummy value `addr_none` (to be automatically replaced with the current smart-contract address), and `ihr_fee`, `fwd_fee`, `created_lt` and `created_at` fields can have arbitrary values (to be rewritten with correct values during the action phase of the current transaction). Integer parameter `x` contains the flags. Currently `x=0` is used for ordinary messages; `x=128` is used for messages that are to carry all the remaining balance of the current smart contract (instead of the value originally indicated in the message); `x=64` is used for messages that carry all the remaining value of the inbound message in addition to the value initially indicated in the new message (if bit 0 is not set, the gas fees are deducted from this amount); `x'=x+1` means that the sender wants to pay transfer fees separately; `x'=x+2` means that any errors arising while processing this message during the action phase should be ignored. Finally, `x'=x+32` means that the current account must be destroyed if its resulting balance is zero. This flag is usually employed together with `+128`. | `526` | +| **`FB02`** | `RAWRESERVE` | _`x y - `_ | Creates an output action which would reserve exactly `x` nanograms (if `y=0`), at most `x` nanograms (if `y=2`), or all but `x` nanograms (if `y=1` or `y=3`), from the remaining balance of the account. It is roughly equivalent to creating an outbound message carrying `x` nanograms (or `b-x` nanograms, where `b` is the remaining balance) to oneself, so that the subsequent output actions would not be able to spend more money than the remainder. Bit `+2` in `y` means that the external action does not fail if the specified amount cannot be reserved; instead, all remaining balance is reserved. Bit `+8` in `y` means `x:=-x` before performing any further actions. Bit `+4` in `y` means that `x` is increased by the original balance of the current account (before the compute phase), including all extra currencies, before performing any other checks and actions. Currently `x` must be a non-negative integer, and `y` must be in the range `0...15`. | `526` | +| **`FB03`** | `RAWRESERVEX` | _`x D y - `_ | Similar to [`RAWRESERVE`](#instr-rawreserve), but also accepts a dictionary `D` (represented by a _Cell_ or _Null_) with extra currencies. In this way currencies other than Grams can be reserved. | `526` | +| **`FB04`** | `SETCODE` | _`c - `_ | Creates an output action that would change this smart contract code to that given by _Cell_ `c`. Notice that this change will take effect only after the successful termination of the current run of the smart contract. | `526` | +| **`FB06`** | `SETLIBCODE` | _`c x - `_ | Creates an output action that would modify the collection of this smart contract libraries by adding or removing library with code given in _Cell_ `c`. If `x=0`, the library is actually removed if it was previously present in the collection (if not, this action does nothing). If `x=1`, the library is added as a private library, and if `x=2`, the library is added as a public library (and becomes available to all smart contracts if the current smart contract resides in the masterchain); if the library was present in the collection before, its public/private status is changed according to `x`. Values of `x` other than `0...2` are invalid. | `526` | +| **`FB07`** | `CHANGELIB` | _`h x - `_ | Creates an output action similarly to [`SETLIBCODE`](#instr-setlibcode), but instead of the library code accepts its hash as an unsigned 256-bit integer `h`. If `x!=0` and the library with hash `h` is absent from the library collection of this smart contract, this output action will fail. | `526` | + +## 12 Debug primitives +Opcodes beginning with `FE` are reserved for the debug primitives. These primitives have known fixed operation length, and behave as (multibyte) [`NOP`](#instr-nop) operations. + +However, when invoked in a TVM instance with debug mode enabled, these primitives can produce specific output into the text debug log of the TVM instance, never affecting the TVM state. + +[`DEBUG`](#instr-debug) and [`DEBUGSTR`](#instr-debugstr) are the two debug primitives, they cover all opcodes that start with `FE`. +Other primitives listed here have opcodes from the same set. When debug is enabled, they have their specified effects. When debug is disabled, they behave as [`NOP`](#instr-nop). + +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`FEnn`** | `{nn} DEBUG` | _`-`_ | `0 <= nn < 240` | `26` | +| **`FEFnssss`** | `{string} DEBUGSTR`
    `{string} {x} DEBUGSTRI` | _`-`_ | `0 <= n < 16`. Length of `ssss` is `n+1` bytes.
    `{string}` is a [string literal](https://github.com/Piterden/TON-docs/blob/master/Fift.%20A%20Brief%20Introduction.md#user-content-29-string-literals).
    [`DEBUGSTR`](#instr-debugstr): `ssss` is the given string.
    [`DEBUGSTRI`](#instr-debugstr): `ssss` is one-byte integer `0 <= x <= 255` followed by the given string. | `26` | +| **`FE00`** | `DUMPSTK` | _`-`_ | Dumps the stack (at most the top 255 values) and shows the total stack depth. | `26` | +| **`FE2i`** | `s[i] DUMP` | _`-`_ | Dumps `s[i]`. | `26` | + +## 13 Codepage primitives +| xxxxxxx
    Opcode | xxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Fift syntax | xxxxxxxxxxxxxxxxx
    Stack | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    Description | xxxx
    Gas | +|:-|:-|:-|:-|:-| +| **`FFnn`** | `[nn] SETCP` | _`-`_ | Selects TVM codepage `0 <= nn < 240`. If the codepage is not supported, throws an invalid opcode exception. | `26` | +| **`FF00`** | `SETCP0` | _`-`_ | Selects TVM (test) codepage zero as described in this document. | `26` | +| **`FFFz`** | `[z-16] SETCP` | _`-`_ | Selects TVM codepage `z-16` for `1 <= z <= 15`. Negative codepages `-13...-1` are reserved for restricted versions of TVM needed to validate runs of TVM in other codepages. Negative codepage `-14` is reserved for experimental codepages, not necessarily compatible between different TVM implementations, and should be disabled in the production versions of TVM. | `26` | +| **`FFF0`** | `SETCPX` | _`c - `_ | Selects codepage `c` with `-2^15 <= c < 2^15` passed in the top of the stack. | `26` | + diff --git a/versioned_docs/version-1.0.0/learn/tvm-instructions/tvm_exit_codes.md b/versioned_docs/version-1.0.0/learn/tvm-instructions/tvm_exit_codes.md new file mode 100644 index 0000000000..db27648712 --- /dev/null +++ b/versioned_docs/version-1.0.0/learn/tvm-instructions/tvm_exit_codes.md @@ -0,0 +1,27 @@ +# TVM Exit codes + +TVM may exit with arbitrary 16-bit unsigned integer `exit_code`. `exit_code` higher than 1 are considered as _error codes_, thus exit with such code may cause transaction revert/bounce. + +## Standard exit codes +* `0` - standard successful execution exit code +* `1` - alternative successful execution exit code +* `2` - stack underflow. Last op-code consume more elements than there are on stacks. 1 +* `3` - stack overflow. More values have been stored on a stack than +allowed by this version of TVM +* `4` - integer overflow. Integer does not fit into −2256 ≤ x < 2256 or a division by zero has occurred +* `5` - integer out of expected range. +* `6` - Invalid opcode. Instruction in unknown to current TVM version +* `7` - Type check error. An argument to a primitive is of incorrect value type. 1 +* `8` - Cell overflow. Writing to builder is not possible since after operation there would be more than 1023 bits or 4 references. +* `9` - Cell underflow. Read from slice primitive tried to read more bits or references than there are. +* `10` - Dictionary error. Error during manipulation with dictionary (hashmaps). +* `13` - Out of gas error. Thrown by TVM when the remaining gas becomes negative. +* `32` - Action list is invalid. Set during action phase if c5 register after execution contains unparsable object. +* `32` (the same as prev) - Method id not found. Returned by tonlib during attempt to execute non-existed get method. +* `34` - Action is invalid or not supported. Set during action phase if current action can not be applied. +* `37` - Not enough TONs. Message sends too much TON (or there is no enough TONs after deducting fees). +* `38` - Not enough extra-currencies. + +1 If you encounter such exception in _func_ contract it most probably means a type error in `asm` declarations. + + diff --git a/versioned_docs/version-1.0.0/learn/tvm-instructions/tvm_overview.md b/versioned_docs/version-1.0.0/learn/tvm-instructions/tvm_overview.md new file mode 100644 index 0000000000..892357b644 --- /dev/null +++ b/versioned_docs/version-1.0.0/learn/tvm-instructions/tvm_overview.md @@ -0,0 +1,87 @@ +# TVM Overview + + + +All TON smart contracts are executed on their own TON Virtual Machine (TVM). TVM is built on the _stack principle_, which makes it efficient and easy to implement. + +This document provides bird's-eye overview of how TVM execute transactions. + +:::tip + +* There is also the detailed specification — [**whitepaper**](https://ton-blockchain.github.io/tvm.pdf) +* Could be useful — [**TVM C++ implementation**](https://github.com/ton-blockchain/ton/tree/master/crypto/vm) + +::: + +## Transactions and phases +When some event happens on the account in one of TON chains it causes a **transaction**. Most common event is "arrival of some message", but generally speaking there could be `tick-tock`, `merge`, `split` and other events. + +Each transaction consists of up to 5 phases. +1. Storage phase - in that phase storage fees accrued by contract due to occupation of some space in chain state are calculated +2. Credit phase - in that phase balance of contract with respect to (possible) incoming message value and collected storage fee are calculated +3. Compute phase - in that phase TVM is executed (see below), result of TVM execution is aggregation of `exit_code`, `actions` (serialized list of actions), `gas_details`, `new_storage` and some others. +4. Action phase - if compute phase was successful, in that phase `actions` from compute phase are processed. In particular actions may include sending of messages, update of smart contract code, update of libraries etc. Note that some actions may fail during processing (for instance we try to send message with more TONs than contract has), in that case the whole transaction may revert or this action may be scipped (it depends on the mode of the actions, in other words contract may send message in regime `send-or-revert` or in regime `try-send-if-no-ignore`). +5. Bounce phase - if compute phase failed (it returned `exit_code >= 2`), in that phase _bounce message_ is formed for transactions initiated by incoming message. + +## Compute phase +In that phase execution of TVM happens. + +### TVM state +In any moment TVM state is fully determined by 6 state properties: +* Stack (see below) +* Control registers - (see below) speaking in simple terms up to 16 variables which may be directly set and read during execution +* Current continuation - object which describe a sequence of instructions which is currently executed +* Current codepage - speaking in simple terms version of TVM which is currently running +* Gas limits - the set of 4 integer values the current gas limit gl, the maximal gas limit gm, the remaining gas gr, and the gas credit gc +* Library context - the hashmap of libraries which can be called by TVM + +### TVM is stack machine +TVM is last-input-first-output stack machine. There are 7 types of variables which may be stored in stack: +* Integer - Signed 257-bit integers +* Tuple - ordered collection of up to 255 elements having arbitrary value types, possibly distinct. +* Null + +And four distinct flavours of cells: +* Cell - basic (possible nested) opaque structure used by TON blockchain for storing all data +* Slice - special object which allows to read from cell +* Builder - special object which allows to create new cells +* Continuation - special object which allows to use cell as source of TVM instructions + +### Control registers +* `c0` — Contains the next continuation or return continuation (similar to the subroutine return address in conventional designs). This value must be a Continuation. +* `c1` — Contains the alternative (return) continuation; this value must be a Continuation. +* `c2` — Contains the exception handler. This value is a Continuation, invoked whenever an exception is triggered. +* `c3` — Supporting register, contains the current dictionary, essentially a hashmap containing the code of all functions used in the program. This value must be a Continuation. +* `c4` — Contains the root of persistent data, or simply the `data` section of the contract. This value is a Cell. +* `c5` — Contains the output actions. This value is a Cell. +* `c7` — Contains the root of temporary data. It is a Tuple. + +### Initialization of TVM +So when transaction execution gets to Computation phase, TVM initialises and then executes commands (op-codes) from _Current continuation_ until there is no more commands to execute (and no continuation for return jumps). + +Detailed description of initialization can be find in [Ton-blockchain 4.4](https://ton-blockchain.github.io/tblkch.pdf). +For ordinary transactions caused by message the initial state is as follows: +* stack: 5 elements are put to the stack + * The balance of the smart contract (after crediting the value of the inbound message) is passed as an Integer amount of nanoTONs. + * The balance of inbound message `m` is passed as an Integer amount of nanoTONs. + * The inbound message is passed as a cell, which contains a serialized value of type Message X, where X is the type of the message body. + * The body of the inbound message, equal to the value of field body of `m`, is passed as a cell slice + * The function selector `s`, an Integer: `0` for tx caused by internal messages, `-1` for external, etc. Generally speaking it is the integer which tells what event caused transaction + * Current continuation : continuation converted from the `code` section of smart contract + * Registers initialise as follows: c0, c1, c2 and c3 are empty. c4 contain the cell from `data` section of smart contract. c5 contains empty list (it is serialized as cell which contain last action in list plus reference to prev one) of output actions. c7 is initialized as tuple with some basic blockchain context data such as time, global config, block_data, etc. See [Ton-blockchain 4.4.10](https://ton-blockchain.github.io/tblkch.pdf) + * Current codepage is set to default value (cp=0) + * Gas limits are initialized in accordance to Credit phase results + * Library context is initialized as result of merging this smart contract library collection, masterchain global library collection and incoming (if any) message library collection + +## TVM instructions + +The list of TVM instructions can be found here: [TVM instructions](/learn/tvm-instructions/instructions). + +### Result of TVM execution +Besides of exit_code and consumed gas data, TVM indirectly outputs the following data: +* c4 register - the cell which will be stored as new `data` of the smart-contract (if execution will not be reverted on this or later phases) +* c5 register - (list of output actions) the cell with last action in the list and reference to the cell with prev action (recursively) + +All other register values will be neglected. + +Note, that since there is limitation on max cell-depth `<1024`, and particularly limitation on c4 and c5 depth `<=512`. Besides there is limitation on number of output actions in one tx `<=255`. If contract need to send more than that it may send message with request `continue_sending` to himself and send all necessary messages in a few subsequent transactions. diff --git a/versioned_docs/version-1.0.0/participate/README.md b/versioned_docs/version-1.0.0/participate/README.md new file mode 100644 index 0000000000..9173304f89 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/README.md @@ -0,0 +1,31 @@ +# Overview + +:::caution draft +This is a concept article. We're still looking for someone experienced to write it. +::: + +## Wallets + +To read more about wallets feel free to start in [WALLET APPS](/participate/wallets/apps) section. + +## Run a Node + +To read more about nodes feel free to start in [NODE TYPES](/participate/nodes/node-types) section. + +## Validators vs Nominators + +If you are familiar with cryptocurrencies, you must have heard about **validators** and **nominators**. These words often appear in crypto-related channels (our channel isn't an exception). Now, the time has come to find out who they are – the two major actors ruling the blockchain. + +### Validators + +First, let's speak about validators. A validator is a network node that helps keep the blockchain running by verifying (or validating) suggested blocks and allowing to record them in the blockchain. + +To become a validator, you must follow two requirements: have a high-performance server and obtain a serious amount of TON, 600,000, to make a stake. At the time of writing, there are 227 validators on TON. + +### Nominators + +It's evident that not everyone can afford to have hundreds of thousand Toncoin on their balance – that's why nominators come into play there. Simply put, the nominator is a user who lends his TON to validators. Every time the validator earns the reward by validating blocks, it is distributed between the involved participants. + +Some time ago, Ton Whales ran the first staking pool on TON with the minimum deposit of 50 TON. Later, TON Foundation launched the first open nominator pool. Now, users may stake Toncoin in a fully-decentralized way, starting with **10,000 TON**. + +_From [TON Community post](https://t.me/toncoin/543)._ \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/participate/explorers.md b/versioned_docs/version-1.0.0/participate/explorers.md new file mode 100644 index 0000000000..90b8b0df9e --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/explorers.md @@ -0,0 +1,10 @@ +# Block explorers + +Right now you could find most of exploers in the Ton.app directory: +* [https://ton.app/explorers](https://ton.app/explorers) + +In the future, we want to describe advantages and disadvantages of the most popular explorers here. + +:::caution draft +This is a concept article. We're still looking for someone experienced to write it. +::: \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/participate/nodes/local-ton.md b/versioned_docs/version-1.0.0/participate/nodes/local-ton.md new file mode 100644 index 0000000000..8a8d314a33 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/nodes/local-ton.md @@ -0,0 +1,11 @@ +# My Local TON + +![MyLocalTon](/img/docs/mylocalton.jpeg) + +Using **MyLocalTon** you can run your own TON blockchain even on your laptop. + +MyLocalTon has convenient UI and is cross-platform. + +[MyLocalTon binaries](https://github.com/neodiX42/MyLocalTon/releases) + +[MyLocalTon source code](https://github.com/neodiX42/MyLocalTon) \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/participate/nodes/node-maintenance-and-security.md b/versioned_docs/version-1.0.0/participate/nodes/node-maintenance-and-security.md new file mode 100644 index 0000000000..595cbdd288 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/nodes/node-maintenance-and-security.md @@ -0,0 +1,166 @@ +# TON Validator node maintenance and security + +## Introduction +This guide provides some basic information on maintaining and securing TON Validator nodes. + +This document assumes that validator is installed using configuration and tools **[recommended by TON Foundation](../nodes/run-node)** but general concepts apply to other scenarios as well and can be useful for savvy sysadmin. + +## Maintenance +### Database grooming +TON node/validator keeps it's database under the path specified by `--db` flag of `validator-engine`, usually `/var/ton-work/db`, this directory is created and managed by the node but it is recommended to perform a database grooming / cleanup task once in a month to remove some artefacts. + +**Important**: You **must** stop validator process before performing the steps outlined below, failure to do that will likely cause database corruption. + +The procedure takes ~5 minutes to complete and will not cause major service disruption. + +#### Switch to root +```sh +sudo -s +``` +#### Stop validator service +```sh +systemctl stop validator +``` +#### Verify that validator is not running +```sh +systemctl status validator +``` +#### Perform database cleanup +```sh +find /var/ton-work/db -name 'LOG.old*' -exec rm {} + +rm -r /var/ton-work/db/files/packages/temp.archive.* +``` +#### Start validator service +```sh +systemctl start validator +``` +Verify that validator process is running by analysing the processes and log. Validator should re-sync with the network within few minutes. + +### Backups +Easies and most efficient way to backup the validator is to copy crucial node configuration files, keys and mytonctrl settings: + +* Node configuration file: `/var/ton-work/db/config.json` +* Node private keyring: `/var/ton-work/db/keyring` +* Node public keys: `/var/ton-work/keys` +* Mytonctrl configuration and wallets: `$HOME/.local/share/myton*` where $HOME is home directory of user you started installation of mytonctrl from. **OR** `/usr/local/bin/mytoncore` if you installed mytonctrl as root. + +This set is everything you need to perform recovery of your node from scratch. + +#### Snapshots +Modern file systems such as ZFS offer snapshot functionality, most cloud providers also allow their customers to make snapshots of machines during which entire disk is preserved for future use. + +The problem with both methods is that you must stop node before performing a snapshot, failure to do so will most likely result in corrupt database with unexpected consequences. Many cloud providers also require you do power down the machine before performing a snapshot. + +Such stops should not be performed often, if you snapshot your node once a week then in the worst case scenario after recovery you will have a node with week old database and it will take your node more time to catch up with the network then to perform a new installation using mytonctrl "install from dump" feature (-d flag added during invocation of `install.sh` script). + +### Disaster recovery +To perform recovery of your node on a new machine: + +#### Install mytonctrl / node +For fastest node initialization add `-d` switch to invocation of installation script. + +#### Switch to root user +```sh +sudo -s +``` +#### Stop mytoncore and validator processes +```sh +systemctl stop validator +systemctl stop mytoncore +``` +#### Apply backed up node configuration files +* Node configuration file: `/var/ton-work/db/config.json` +* Node private keyring: `/var/ton-work/db/keyring` +* Node public keys: `/var/ton-work/keys` + +#### Set node IP address +If your new node has a different IP address then you must edit node configuration file `/var/ton-work/db/config.json` and set the leaf `.addrs[0].ip` to **decimal** representation of new IP address. You can use **[this](https://github.com/sonofmom/ton-tools/blob/master/node/ip2dec.py)** python script to convert your IP to decimal. + +#### Ensure proper database permissions +```sh +chown -R validator:validator /var/ton-work/db +``` +#### Apply backed up mytonctrl configuration files +Replace `$HOME/.local/share/myton*` where $HOME is home directory of user you started installation of mytonctrl from with backed up content, make sure that the user is owner of all files you copy. + +#### Start mytoncore and validator processes +```sh +systemctl start validator +systemctl start mytoncore +``` +## Security +### Host level security +Host level security is huge topic that lies outside of the scope of this document, we do however advise to never install mytonctrl under root user, do use service account to ensure privilege separation. + +### Network level security +TON validators are high value assets that should be protected against external threats, one of the first steps you should take is make your node as invisible as possible, this means locking down all network connections. On a validator node only UDP Port used for node operations should be exposed to the internet. + +#### Tools +We will use **[ufw](https://help.ubuntu.com/community/UFW)** firewall interface as well as **[jq](https://github.com/stedolan/jq)** JSON command line processor. + +#### Management Networks +As a node operator you need to retain full control and access to machine, in order to do this you need at least one fixed IP address or range. + +We also advise to setup a small "jumpstation" VPS with fixed IP Address that can be used by you to access your locked down machine(s) if you do not have fixed IP at home/office or to add alternative way to access secured machines should you lose your primary IP address. + +#### Install ufw and jq1 +```sh +sudo apt install -y ufw jq +``` +#### Basic lockdown of ufw ruleset +```sh +sudo ufw default deny incoming; sudo ufw default allow outgoing +``` +#### Disable automated ICMP echo request accept +```sh +sudo sed -i 's/-A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT/#-A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT/g' /etc/ufw/before.rules +``` +#### Enable all access from management network(s) +```sh +sudo ufw insert 1 allow from +``` +repeat the above command for each management network / address. + +#### Expose node / validator UDP port to public +```sh +sudo ufw allow proto udp from any to any port `sudo jq -r '.addrs[0].port' /var/ton-work/db/config.json` +``` +#### Doublecheck your management networks +Important: before enabling firewall, please do doublecheck that you added correct management addresses!! + +#### Enable ufw firewall +```sh +sudo ufw enable +``` +#### Checking status +To check firewall status use following command: +```sh + sudo ufw status numbered +``` +Here is example output of locked down node with two management networks / addresses: + +``` +Status: active + + To Action From + -- ------ ---- +[ 1] Anywhere ALLOW IN /28 +[ 2] Anywhere ALLOW IN /32 +[ 3] /udp ALLOW IN Anywhere +[ 4] /udp (v6) ALLOW IN Anywhere (v6) +``` + +#### Expose LiteServer port +```sh +sudo ufw allow proto tcp from any to any port `sudo jq -r '.liteservers[0].port' /var/ton-work/db/config.json` +``` + +Please note that LiteServer port should not be exposed to public on a validator. + +#### More information on UFW +See this excellent **[ufw tutorial](https://www.digitalocean.com/community/tutorials/ufw-essentials-common-firewall-rules-and-commands)** from Digital Ocean for more ufw magic. + +### IP Switch +If you feel that your node is under attack then you should consider switching IP Address. The way to achieve the switch depends on your hosting provider you might preorder second address, clone your **stopped** VM into another instance or setup a new instance by performing **[disaster recovery](#disaster-recovery)** process. + +In any case, please do make sure that you **[set your new ip address](#set-node-ip)** in node configuration file! diff --git a/versioned_docs/version-1.0.0/participate/nodes/node-types.md b/versioned_docs/version-1.0.0/participate/nodes/node-types.md new file mode 100644 index 0000000000..8afeb70107 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/nodes/node-types.md @@ -0,0 +1,37 @@ +# TON Node Types + +There are different types of nodes in The Open Network: + +* **Lite clients** + + Clients such as wallets that do not store the full state of the blockchain, but request what is needed from the full nodes. + +* **Full Node** + + A node that is synchronized with the blockchain, stores the current state of the blockchain and the block history or part of the block history. + + In a full node, you can enable one or more additional functionality: + + * **Archive node** + + A full node that stores the entire block history is called an archive node. + + An archive node requires a lot of resources and is needed if you are making a blockchain explorer or something like that. + + For most cases, you will be fine with a regular node that only stores the latest blocks and has significantly lower hardware requirements. + + * **Liteserver** + + If you enable an endpoint in a full node, then it starts to perform the functions of a lite server - it can receive and respond to requests from lite clients. + + Using this node, your product can interact with the TON blockchain. + + The TON Foundation supports a number of **public lite servers** that you can find in the global config ([mainnet](https://ton.org/global-config.json) and [testnet](https://ton-blockchain.github.io/testnet-global.config.json)). + + These are endpoints available to everyone, for example, standard wallets connect to them. + + * **Validator** + + If you enable the validator functionality in the node and you have a sufficient number of Toncoins (stake), then the node will begin to participate in the process of validating new network blocks. + + TON is a Proof-of-Stake blockchain, so validators keep the network running and are rewarded in Toncoins for doing so. \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/participate/nodes/run-node.md b/versioned_docs/version-1.0.0/participate/nodes/run-node.md new file mode 100644 index 0000000000..bfc7da8922 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/nodes/run-node.md @@ -0,0 +1,40 @@ +# Running your own Full Node/Validator + +To install and manage your own node, use **[mytonctrl](https://github.com/ton-blockchain/mytonctrl)** open source tool developed by TON Foundation. + +The majority of TON nodes use reliable and tested **mytonctrl**. + +## Installation + +[Setup Node/Validator video instruction](https://github.com/ton-blockchain/raw/master/nodes/setup_validator.mp4 ':include controls :type=video width=100% height=400px') + +Download and run the installation script. + +Ubuntu: +```bash +wget https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/scripts/install.sh +sudo bash install.sh -m full +``` + +Debian: +```bash +wget https://raw.githubusercontent.com/ton-blockchain/mytonctrl/master/scripts/install.sh +su root -c 'bash install.sh -m full' +``` + +Check the **mycontrol** installation procedure at: + +https://github.com/ton-blockchain/mytonctrl/blob/master/en/manual-ubuntu.md + + +## Become a validator + +To use your full node as an endpoint, skip everything about the validator function. There is no need to send coins to your wallet. + +To become a validator, send Toncoins to your wallet. + +**mytonctrl** automatically joins validation from the next next election round. + +Check the manual here: + +https://github.com/ton-blockchain/mytonctrl/blob/master/en/manual-ubuntu.md diff --git a/versioned_docs/version-1.0.0/participate/nodes/setup_validator.mp4 b/versioned_docs/version-1.0.0/participate/nodes/setup_validator.mp4 new file mode 100644 index 0000000000..85917cf7bf Binary files /dev/null and b/versioned_docs/version-1.0.0/participate/nodes/setup_validator.mp4 differ diff --git a/versioned_docs/version-1.0.0/participate/wallets/apps.md b/versioned_docs/version-1.0.0/participate/wallets/apps.md new file mode 100644 index 0000000000..53870e12b3 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/wallets/apps.md @@ -0,0 +1,24 @@ +# Types of Wallet Apps + +:::caution draft +This is a concept article. We're still looking for someone experienced to write it. +::: + +## Overview + +This article describes wallets from development perspective. + +If you want to find a wallet to install open the [ton.org/wallets](https://ton.org/wallets). + +## Noncustodial wallets + +* [TON Wallet Chrome Extension](https://chrome.google.com/webstore/detail/ton-wallet/nphplpgoakhhjchkkhmiggakijnkhfnd) — one of the first wallets in TON ecosystem. +* Tonkeeper +* Tonhub + +In the future, we want to describe advantages and disadvantages of the most popular wallets and how to use them for everyday life or for development process. + +## Custodial wallets + +* @wallet — bot application to send and receive TON inside Telegram. +* @cryptobot — telegram bot \ No newline at end of file diff --git a/versioned_docs/version-1.0.0/participate/wallets/contracts.md b/versioned_docs/version-1.0.0/participate/wallets/contracts.md new file mode 100644 index 0000000000..77f2333501 --- /dev/null +++ b/versioned_docs/version-1.0.0/participate/wallets/contracts.md @@ -0,0 +1,10 @@ +# Types of Wallet Contracts + +:::caution draft +This is a concept article. We're still looking for someone experienced to write it. +::: + +In the future we want to describe the most important wallet smart contracts types here. + +Right now you could find most of the contracts here: +* [https://github.com/ton-blockchain/ton/tree/master/crypto/smartcont](https://github.com/ton-blockchain/ton/tree/master/crypto/smartcont) \ No newline at end of file diff --git a/versioned_sidebars/version-1.0.0-sidebars.json b/versioned_sidebars/version-1.0.0-sidebars.json new file mode 100644 index 0000000000..dfef342ddf --- /dev/null +++ b/versioned_sidebars/version-1.0.0-sidebars.json @@ -0,0 +1,314 @@ +{ + "learn": [ + "learn/introduction", + { + "type": "html", + "value": "
    " + }, + { + "type": "html", + "value": " TON Concepts " + }, + "learn/overviews/TON_blockchain_overview", + "learn/overviews/Cells", + { + "type": "category", + "label": "TON Virtual Machine (TVM)", + "items": [ + "learn/tvm-instructions/tvm_overview", + "learn/tvm-instructions/tvm_exit_codes", + "learn/tvm-instructions/instructions" + ] + }, + { + "type": "category", + "label": "Typed Language - Binary", + "items": [ + "learn/overviews/TL-B", + "learn/overviews/TL-B_language" + ] + }, + "learn/overviews/ADNL" + ], + "develop": [ + "develop/getting-started", + { + "type": "html", + "value": "
    " + }, + { + "type": "html", + "value": " Development " + }, + { + "type": "category", + "label": "Develop Smart Contracts", + "items": [ + "develop/smart-contracts/README", + { + "type": "category", + "label": "Environment", + "items": [ + "develop/installation", + "develop/tools/ide-plugins", + "develop/tools/testnet/README" + ] + }, + { + "type": "category", + "label": "Choose Your SDK", + "items": [ + "develop/smart-contracts/sdk/tonstarter", + "develop/smart-contracts/sdk/toncli" + ] + }, + { + "type": "category", + "label": "Testing & Debugging", + "items": [ + "develop/smart-contracts/testing/tonstarter", + "develop/smart-contracts/testing/toncli" + ] + }, + { + "type": "category", + "label": "Deploying Contract", + "items": [ + { + "type": "link", + "label": "Using tonstarter-contracts", + "href": "https://github.com/ton-defi-org/tonstarter-contracts" + }, + { + "type": "link", + "label": "Using Online IDE", + "href": "https://glitch.com/edit/#!/remix/clone-from-repo?&REPO_URL=https%3A%2F%2Fgithub.com%2Fton-defi-org%2Ftonstarter-contracts.git" + }, + { + "type": "link", + "label": "Using toncli", + "href": "https://github.com/disintar/toncli" + } + ] + }, + { + "type": "category", + "label": "Best Practices", + "items": [ + "develop/smart-contracts/guidelines", + "develop/smart-contracts/fees", + "develop/smart-contracts/messages", + "develop/smart-contracts/guidelines/internal-messages", + "develop/smart-contracts/guidelines/external-messages", + "develop/smart-contracts/guidelines/non-bouncable-messages", + "develop/smart-contracts/guidelines/get-methods", + "develop/smart-contracts/guidelines/accept", + "develop/smart-contracts/guidelines/processing", + "develop/smart-contracts/governance", + "develop/smart-contracts/guidelines/tips", + { + "type": "link", + "label": "How to shard your TON smart contract and why", + "href": "https://society.ton.org/how-to-shard-your-ton-smart-contract-and-why-studying-theanatomy-of-tons-jettons" + } + ] + }, + { + "type": "link", + "label": "Coming from ETH and Solidity", + "href": "/learn/introduction#ethereum-to-ton" + } + ] + }, + { + "type": "category", + "label": "Develop Web Apps & Bots", + "items": [ + "develop/tools/README", + "develop/tools/apis/README", + { + "type": "category", + "label": "Best Practices", + "items": [ + { + "type": "category", + "label": "Payment Processing", + "items": [ + "develop/howto/payment-processing", + "develop/payment-processing/common", + "develop/payment-processing/deposits-single-wallet", + "develop/payment-processing/deposits-multi-wallet", + "develop/payment-processing/withdrawals" + ] + } + ] + } + ] + }, + { + "type": "html", + "value": "
    " + }, + { + "type": "html", + "value": " References & Documentation " + }, + { + "type": "category", + "label": "FunC language", + "items": [ + { + "type": "doc", + "id": "develop/func/overview" + }, + { + "type": "category", + "label": "Documentation", + "items": [ + "develop/func/types", + "develop/func/comments", + "develop/func/literals_identifiers", + "develop/func/functions", + "develop/func/global_variables", + "develop/func/compiler_directives", + "develop/func/statements", + "develop/func/builtins", + "develop/func/stdlib" + ] + } + ] + }, + { + "type": "link", + "label": "TON Concepts", + "href": "/learn/introduction" + }, + { + "type": "category", + "label": "TON Whitepapers", + "items": [ + { + "type": "doc", + "label": "Overview", + "id": "learn/docs" + }, + { + "type": "link", + "label": "TON", + "href": "https://ton-blockchain.github.io/ton.pdf" + }, + { + "type": "link", + "label": "TON Virtual Machine", + "href": "https://ton-blockchain.github.io/tvm.pdf" + }, + { + "type": "link", + "label": "TON Blockchain", + "href": "https://ton-blockchain.github.io/tblkch.pdf" + }, + { + "type": "link", + "label": "Catchain Consensus Protocol", + "href": "https://ton-blockchain.github.io/catchain.pdf" + } + ] + }, + { + "type": "category", + "label": "TON Services", + "items": [ + "develop/web3/dns", + { + "type": "html", + "value": "TON Proxy [2022 Q3]" + }, + { + "type": "html", + "value": "TON Sites [2022 Q3]" + }, + { + "type": "html", + "value": "TON Storage [2022 Q4]" + } + ] + }, + { + "type": "category", + "label": "Network Configs", + "items": [ + { + "type": "link", + "label": "Mainnet config", + "href": "https://ton.org/global-config.json" + }, + { + "type": "link", + "label": "Testnet config", + "href": "https://ton-blockchain.github.io/testnet-global.config.json" + } + ] + }, + { + "type": "category", + "label": "Low Level Internals", + "items": [ + "develop/howto/step-by-step", + "develop/howto/ton-sites", + "develop/howto/config-params", + "develop/howto/pow-givers" + ] + } + ], + "participate": [ + "participate/README", + { + "type": "html", + "value": "
    " + }, + "participate/explorers", + { + "type": "category", + "label": "Setup Your Wallet", + "items": [ + "participate/wallets/apps", + "participate/wallets/contracts", + { + "type": "link", + "label": "Wallet Contract Versions", + "href": "https://github.com/toncenter/tonweb/blob/master/src/contract/wallet/WalletSources.md" + } + ] + }, + { + "type": "category", + "label": "Run a Node", + "items": [ + "participate/nodes/node-types", + "participate/nodes/run-node", + "participate/nodes/node-maintenance-and-security", + "participate/nodes/local-ton" + ] + }, + { + "type": "link", + "label": "Join in a Nominator Pool", + "href": "https://tonvalidators.org/" + }, + { + "type": "link", + "label": "Run a Validator Node", + "href": "https://ton.org/validator" + } + ], + "contribute": [ + { + "type": "category", + "label": "Become a Contributor", + "items": [ + "contribute/README", + "contribute/maintainers" + ] + } + ] +} diff --git a/versions.json b/versions.json new file mode 100644 index 0000000000..5e1abcd8a6 --- /dev/null +++ b/versions.json @@ -0,0 +1,3 @@ +[ + "1.0.0" +]