# Table of Contents - [How to get NFT item metadata - TON Docs](#how-to-get-nft-item-metadata-ton-docs) - [NFT: Non-fungible token - TON Docs](#nft-non-fungible-token-ton-docs) - [Overview - TON Docs](#overview-ton-docs) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [Unknown](#unknown) - [TxTracer - TON Docs](#txtracer-ton-docs) - [Fift and TVM assembly - TON Docs](#fift-and-tvm-assembly-ton-docs) - [Retracer - TON Docs](#retracer-ton-docs) - [Fift deep dive - TON Docs](#fift-deep-dive-ton-docs) - [TVM Explorer - TON Docs](#tvm-explorer-ton-docs) - [Simple multisig contract with Fift - TON Docs](#simple-multisig-contract-with-fift-ton-docs) - [TON Decompiler - TON Docs](#ton-decompiler-ton-docs) - [FunC language overview - TON Docs](#func-language-overview-ton-docs) - [Wallet V5 - TON Docs](#wallet-v5-ton-docs) - [Mnemonics - TON Docs](#mnemonics-ton-docs) - [Performance benchmark - TON Docs](#performance-benchmark-ton-docs) - [Wallets history - TON Docs](#wallets-history-ton-docs) - [How to interact with wallet - TON Docs](#how-to-interact-with-wallet-ton-docs) - [Wallet V4 - TON Docs](#wallet-v4-ton-docs) - [FunC changelog - TON Docs](#func-changelog-ton-docs) - [Restricted wallet - TON Docs](#restricted-wallet-ton-docs) - [Lockup wallet - TON Docs](#lockup-wallet-ton-docs) - [Known issues of FunC - TON Docs](#known-issues-of-func-ton-docs) - [Wallet V5 API - TON Docs](#wallet-v5-api-ton-docs) - [FunC cookbook - TON Docs](#func-cookbook-ton-docs) - [Other FunC libraries - TON Docs](#other-func-libraries-ton-docs) - [Preprocessed Wallet V2 — specification - TON Docs](#preprocessed-wallet-v2-specification-ton-docs) - [How to interact with Preprocessed Wallet V2 - TON Docs](#how-to-interact-with-preprocessed-wallet-v2-ton-docs) - [Highload Wallet v2 — specification - TON Docs](#highload-wallet-v2-specification-ton-docs) - [FunC comments - TON Docs](#func-comments-ton-docs) - [FunC global variables - TON Docs](#func-global-variables-ton-docs) - [FunC assembler functions - TON Docs](#func-assembler-functions-ton-docs) - [FunC operators - TON Docs](#func-operators-ton-docs) - [Standard library of FunC - TON Docs](#standard-library-of-func-ton-docs) - [Highload Wallet v3 — specification - TON Docs](#highload-wallet-v3-specification-ton-docs) - [FunC types - TON Docs](#func-types-ton-docs) - [FunC literals - TON Docs](#func-literals-ton-docs) - [FunC expressions - TON Docs](#func-expressions-ton-docs) - [FunC program declarations - TON Docs](#func-program-declarations-ton-docs) - [FunC statements - TON Docs](#func-statements-ton-docs) - [FunC reserved words and built-ins - TON Docs](#func-reserved-words-and-built-ins-ton-docs) - [FunC dictionaries - TON Docs](#func-dictionaries-ton-docs) - [FunC functions - TON Docs](#func-functions-ton-docs) - [FunC compiler directives - TON Docs](#func-compiler-directives-ton-docs) - [Reserved functions of FunC - TON Docs](#reserved-functions-of-func-ton-docs) - [How to create Highload Wallet v3 - TON Docs](#how-to-create-highload-wallet-v3-ton-docs) - [How to send a single transfer - TON Docs](#how-to-send-a-single-transfer-ton-docs) - [How to send a batch of transfers - TON Docs](#how-to-send-a-batch-of-transfers-ton-docs) - [How to verify message is processed - TON Docs](#how-to-verify-message-is-processed-ton-docs) --- # How to get NFT item metadata - TON Docs [Skip to main content](https://docs.ton.org/standard/tokens/nft/metadata#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation NFT How to get NFT item metadata NFT [metadata](https://docs.ton.org/standard/tokens/metadata) is split into two parts: the collection stores collection-wide data, and the item stores item-specific data, which may not include the full metadata. ### [​](https://docs.ton.org/standard/tokens/nft/metadata#high-level) High level There is a TON Center [API method](https://docs.ton.org/ecosystem/api/toncenter/v3/accounts/metadata?playground=open) that retrieves NFT metadata. ### [​](https://docs.ton.org/standard/tokens/nft/metadata#low-level) Low level To get full NFT metadata manually: 1. If it is not known, resolve the NFT item address by its index from the collection using [`get_nft_address_by_index(index)`](https://docs.ton.org/standard/tokens/nft/api#get-nft-address-by-index) . 2. Get the individual content from the item contract using [`get_nft_data()`](https://docs.ton.org/standard/tokens/nft/api#get-nft-data) . 3. Get the full metadata from the collection contract using [`get_nft_content(index, individual_content)`](https://docs.ton.org/standard/tokens/nft/api#get-nft-content) . Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/standard/tokens/nft/metadata.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/standard/tokens/nft/metadata) [Previous](https://docs.ton.org/standard/tokens/nft/transfer) [How to verify NFT item\ \ Next](https://docs.ton.org/standard/tokens/nft/verify) ⌘I On this page * [High level](https://docs.ton.org/standard/tokens/nft/metadata#high-level) * [Low level](https://docs.ton.org/standard/tokens/nft/metadata#low-level) --- # NFT: Non-fungible token - TON Docs [Skip to main content](https://docs.ton.org/standard/tokens/nft/overview#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation NFT NFT: Non-fungible token Non‑fungible tokens (NFTs), defined in [TEP‑62](https://github.com/ton-blockchain/TEPs/blob/0d7989fba6f2d9cb08811bf47263a9b314dc5296/text/0062-nft-standard.md) , represent the digital embodiment of uniqueness within the TON ecosystem. Unlike their fungible counterparts, each NFT possesses distinct characteristics that make it irreplaceable and non‑interchangeable. This fundamental property of uniqueness enables NFTs to serve as digital certificates of authenticity for a wide array of digital and physical assets. NFTs can verify ownership of digital assets using blockchain technology. Each token carries a unique identifier and associated metadata that distinguish it from every other token. This uniqueness makes NFTs particularly valuable for representing assets where individual characteristics matter. Use cases: * Digital art * Real-world assets * Access rights The technical implementation of NFTs in TON mirrors the distributed architecture philosophy found in [Jettons](https://docs.ton.org/standard/tokens/jettons/overview) . Individual item contracts represent each NFT, while collection contracts manage overall collection metadata and coordinate minting processes. This distributed approach ensures that NFT operations remain efficient and scalable even as collections grow to encompass thousands or millions of individual tokens. [​](https://docs.ton.org/standard/tokens/nft/overview#architecture-and-smart-contracts) Architecture and smart contracts --------------------------------------------------------------------------------------------------------------------------- NFTs in TON are built using a distributed smart contract architecture consisting of: * NFT collection contracts – serve as the source of truth for items, providing addresses, collection metadata, and coordinating the overall collection. * NFT item contracts – each NFT is represented by its own smart contract account, storing the collection address, index, current owner, and individual metadata. This architecture ensures that each NFT operates independently while maintaining a connection to its collection. [​](https://docs.ton.org/standard/tokens/nft/overview#transfer-mechanism) Transfer mechanism ----------------------------------------------------------------------------------------------- The current owner sends a transfer message to the NFT item contract, which updates the owner field and optionally sends notifications to the new owner along with any excess Toncoin. [This transfer flow](https://docs.ton.org/standard/tokens/nft/how-it-works#transfer-nft-item) ensures atomicity while maintaining flexibility for ownership notifications and handling remaining funds. [​](https://docs.ton.org/standard/tokens/nft/overview#marketplace-ready-templates) Marketplace-ready templates ----------------------------------------------------------------------------------------------------------------- To deploy NFTs compatible with existing TON marketplaces, use contract implementations that follow the [NFT standard](https://docs.ton.org/standard/tokens/nft/how-it-works) . Implementations include: * [TON reference NFT contracts](https://github.com/ton-blockchain/nft-contract) – reference implementation of the TON NFT standard. * [Getgems NFT contracts](https://github.com/getgems-io/nft-contracts) – NFT contracts used by the Getgems marketplace. Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/standard/tokens/nft/overview.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/standard/tokens/nft/overview) [Previous](https://docs.ton.org/standard/tokens/jettons/api) [How it works\ \ Next](https://docs.ton.org/standard/tokens/nft/how-it-works) ⌘I On this page * [Architecture and smart contracts](https://docs.ton.org/standard/tokens/nft/overview#architecture-and-smart-contracts) * [Transfer mechanism](https://docs.ton.org/standard/tokens/nft/overview#transfer-mechanism) * [Marketplace-ready templates](https://docs.ton.org/standard/tokens/nft/overview#marketplace-ready-templates) --- # Overview - TON Docs [Skip to main content](https://docs.ton.org/standard/tokens/jettons/overview#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Jettons Overview Jettons (TEP-74 standard) serve as TON’s counterpart to Ethereum’s [ERC-20 tokens](https://eips.ethereum.org/EIPS/eip-20) , functioning as the primary means of representing monetary value and fungible assets within the TON ecosystem. These tokens embody the principle of fungibility, where each unit holds identical value and can be seamlessly exchanged with any other unit of the same token type. Use cases: * To represent currency on-chain, like USDT. Each Jetton can be arbitrary fraction (1 Jetton = 10\-6 USD) * To empower governance-like voting systems. Each Jetton equals a vote * To represent deposit size in Decentralized Finance The technical architecture of Jettons reflects TON’s distributed design principles. Rather than storing all token information in a single contract, the system employs a distributed approach where each user maintains their own Jetton wallet contract. The main Jetton contract functions as a central registry, storing essential metadata and tracking total supply, while individual wallet contracts handle user-specific balances and execute transfer operations. This architecture enhances scalability and reduces congestion compared to centralized token models. Read more: * [Jetton standard comparison](https://docs.ton.org/standard/tokens/jettons/comparison) * [TEP-74](https://github.com/ton-blockchain/TEPs/blob/0d7989fba6f2d9cb08811bf47263a9b314dc5296/text/0074-jettons-standard.md) Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/standard/tokens/jettons/overview.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/standard/tokens/jettons/overview) [Previous](https://docs.ton.org/standard/tokens/metadata) [How it works\ \ Next](https://docs.ton.org/standard/tokens/jettons/how-it-works) ⌘I --- # Unknown Catchain Consensus: An Outline Nikolai Durov February 19, 2020 Abstract The aim of this text is to provide an outline of the Catchain Consen- sus Protocol, a Byzantine Fault Tolerant (BFT) protocol specifically crafted for block generation and validation in the TON Blockchain \[3\]. This protocol can potentially be used for purposes other than block generation in a proof-of-stake (PoS) blockchain; however, the current implementation uses some optimizations valid only for this specific problem. Contents 1 Overview2 2 Catchain Protocol5 3 Block Consensus Protocol16 1 Chapter1.Overview 1 Overview The Catchain Consensus protocol builds upon the overlay network construc- tion protocol and the overlay network broadcast protocol of TON Network (\[3\]). The Catchain Consensus protocol itself can be decomposed into two separate protocols, one more low-level and general-purpose (theCatchain protocol 1 ), and the other the high-levelBlock Consensus Protocol (BCP), which makes use of the Catchain protocol. Higher levels in the TON proto- col stack are occupied by the block generation and validation levels; however, all of them are executed essentially locally on one (logical) machine, with the problem of achieving consensus on the newly-generated block delegated to the Catchain protocol level. Here is an approximate diagram of the protocol stack employed by TON for block generation and distribution, showing the correct place of the Catchain Consensus protocol (or rather its two component protocols): •Top-level:Block generation and block validation software, logically run- ning on a stand-alone logical machine, with all the inputs provided and outputs handled by the lower-level protocols. The job of this software is to either generate a new valid block for a blockchain (a shardchain or the masterchain of the TON Blockchain; cf. \[3\] for a discussion of shardchains and the masterchain), or to check the validity of a block generated by somebody else. •(TON) Block consensus protocol:Achieves (byzantine fault tolerant) consensus on the block to be accepted as the next one in the current validator group for the masterchain or a shardchain. This level makes use of (the abstract interface of) the block generation and validation software, and builds upon the lower-level Catchain protocol. This pro- tocol is explained in more detail in Section3. •Catchain protocol:Provides secure persistent broadcasts in an overlay network (e.g., the task group of validators for a specific shardchain or the masterchain dedicated to generation, validation, and propagation of new blocks in this shardchain or masterchain), and detects attempts 1 The original name of this protocol used during the initial stage of the research and development phase wascatch-chainorcatchchain, because it essentially is a special blockchaindedicated tocatching all events important for the consensus protocol; after saying and writing this name a lot of times it gradually got contracted to “catchain”. 2 Chapter1.Overview of “cheating” (protocol violation) on the part of some participants. This protocol is explained in more detail in Section2. •(TON Network) overlay broadcast protocol:A simple best-effort broad- cast protocol for overlay networks in the TON Network as described in \[3\]. Simply broadcasts received broadcast messages to all neighbors in the same overlay network that did not receive a copy of these messages before, with minimal effort dedicated to keeping copies of undelivered broadcast messages for a short period of time. •(TON Network) overlay protocol:Creates overlay networks (cf. \[3\]) inside the ADNL protocol network, manages neighbor lists for these overlay networks. Each participant of an overlay network tracks sev- eral neighbors in the same overlay network and keeps dedicated ADNL connections (called“channels”) to them, so that incoming messages can be efficiently broadcast to all neighbors with minimal overhead. •Abstract Datagram Network Layer (ADNL) protocol: The basic pro- tocol of the TON Network, that delivers packets (datagrams) between network nodes identified only by 256-bit abstract (ADNL) addresses, which effectively are cryptographic keys (or their hashes). This text aims to describe only the second and the third protocol in this suite, namely, the (TON) block consensus protocol and the (TON) Catchain protocol. We would like to point out here that the author of this text, while pro- viding the general guidelines of how this protocol should be designed (on the lines of “let’s create a BFT-hardened group broadcast message system, and run a suitably adapted simple two-phase or three-phase commit proto- col on top of this system”) and participating in several discussions during the development and implementation of the protocol, is definitely not the only designer of this protocol and especially of its current implementation. This is the work of several people. A few words on the efficiency of the combined Catchain Consensus proto- col. Firstly, it is a true Byzantine Fault Tolerant (BFT) protocol, in the sense that it eventually achieves consensus on a valid next block of the blockchain even if some participants (validators) exhibit arbitrarily malicious behavior, provided these malicious participants are less than one third of the total number of the validators. It is well-known that achieving BFT consensus 3 Chapter1.Overview is impossible if at least one third of participants are malicious (cf. \[5\]), so the Catchain Consensus protocol is as good as theoretically possible in this respect. Secondly, when the Catchain Consensus was first implemented (in December 2018) and tested on up to 300 nodes distributed all over the world, it achieved consensus on a new block in 6 seconds for 300 nodes and in 4–5 sec- onds for 100 nodes (and in 3 seconds for 10 nodes), even if some of these nodes fail to participate or exhibit incorrect behavior. 2 Since the TON Blockchain task groups are not expected to consist of more than a hundred validators (even if a total of a thousand or ten thousand validators are running, only a hundred of them with the largest stakes will generate new masterchain blocks, and the others will participate only in the creation of new shardchain blocks, each shardchain block generated and validated by 10–30 validators; of course, all numbers given here are configuration parameters (cf. \[3\] and \[4\]) and can be adjusted later by a consensus vote of validators if necessary), this means that the TON Blockchain is able to generate new blocks once every 4–5 seconds, as originally planned. This promise has been further tested and found out to be fulfilled with the launch of the Test Network of the TON Blockchain a couple of months later (in March 2019). Therefore, we see that the Catchain Consensus protocol is a new member of the ever-growing fam- ily of practical BFT protocols (cf. \[2\]), even though it is based on slightly different principles. 2 When the ratio of the malicious or non-participating or very slow validators grows up to one third, the protocol exhibits graceful degradation, with the block consensus time growing very slowly—say, by at most half a second—until the critical value of one third is almost achieved. 4 Chapter2.Catchain Protocol 2 Catchain Protocol We have already explained in the Overview (cf.1) that the BFT consen- sus protocol used by the TON Blockchain for achieving consensus on new blockchain blocks consists of two protocols. We provide here a brief descrip- tion of theCatchain protocol, the lower-lever of these two protocols that could be potentially used for purposes other than BFT consensus for blocks. The source code for the Catchcain protocol resides in subdirectorycatchainof the source tree. 2.1. Prerequisites for running the Catchain protocol.The main pre- requisite for running (an instance of) the Catchain protocol is the ordered list of all nodes that are participating (or allowed to participate) in this spe- cific instance of the protocol. This list consists of public keys and ADNL addresses of all participating nodes. It has to be provided from the outside when an instance of the Catchain protocol is created. 2.2. Nodes participating in the block consensus protocol.For the specific task of creating new blocks for one of the blockchains (i.e., the mas- terchain or one of the active shardchains) of the TON Blockchain, a special task group consisting of several validators is created. The list of members of this task group is used both to create a private overlay network inside ADNL (this means that the only nodes that can join this overlay network are those explicitly listed during its creation) and to run the corresponding instance of the Catchain protocol. The construction of this list of members is the responsibility of the higher levels of the overall protocol stack (the block creation and validation software) and therefore is not the topic of this text (\[4\] would be a more appropriate reference). It is sufficient to know at this point that this list is a deterministic function of the current (most recent) masterchain state (and especially of the current value of the configuration parameters, such as the active list of all validators elected for creating new blocks along with their respective weights). Since the list is computed deterministically, all validators compute the same lists and in particular each validator knows in which task groups (i.e., instances of the Catchain protocol) it participates without any further need for network communication or negotiation. 3 3 If some validators have an outdated masterchain state, they may fail to compute correct task group lists and to participate in the corresponding catchains; in this respect, 5 Chapter2.Catchain Protocol 2.2.1. Catchains are created in advance.In fact, not only the current values of the lists alluded to above are computed, but also their immediately subsequent (future) values are computed as well, so that the Catchain is usually created in advance. In this way it is already in place when the first block has to be created by the new instance of the validator task group. 2.3. The genesis block and the identifier of a catchain.Acatchain (i.e., an instance of the Catchain protocol) is characterized by itsgenesis block orgenesis message. It is a simple data structure containing some magic num- bers, the purpose of the catchain (e.g., the identifier of the shardchain, for which the blocks will be generated, and the so-calledcatchain sequence num- ber, also obtained from the masterchain configuration and used to distinguish subsequent instances of the catchain generating “the same” shardchain, but possibly with different participating validators), and, most importantly, the list of all participating nodes (their ADNL addresses and Ed25519 public keys as explained in2.1). The Catchain protocol itself uses only this list and thesha256hash of the overall data structure; this hash is used as an internal identifier of the catchain, i.e., of this specific instance of the Catchain protocol. 2.3.1. Distribution of the genesis block.Note that the genesis block is not distributed among the participating nodes; it is rather computed in- dependently by each participating node as explained in2.2. Since the hash of the genesis block is used as the catchain identifier (i.e., identifier of the specific instance of the Catchain protocol; cf.2.3), if a node (accidentally or intentionally) computes a different genesis block, it will be effectively locked out from participating in the “correct” instance of the protocol. 2.3.2. List of nodes participating in a catchain.Note that the (ordered) list of nodes participating in a catchain is fixed in the genesis block and hence it is known to all the participants and it is unambiguously determined by the hash of the genesis block (i.e., the catchain identifier), provided there are no (known) collisions forsha256. Therefore, we fix the number of participating nodesNin the discussion of one specific catchain below, and assume that the nodes are numbered from1toN(their real identities may be looked up they are treated as if they were malicious or malfunctioning and do not affect the overall validity of the BFT protocol as long as less than one third of all validators fail in this fashion. 6 Chapter2.Catchain Protocol in the list of participants using this index in range1...N). The set of all participants will be denoted byI; we assume thatI={1...N}. 2.4. Messages in a catchain. Catchain as a process group.One perspective is that a catchain is a(distributed) process groupconsisting ofN known and fixed(communicating) processes(ornodesin the preceding termi- nology), and these processes generatebroadcast messages, that are eventually broadcast to all members of the process group. The set of all processes is de- noted byI; we usually assume thatI={1...N}. The broadcasts generated by each process are numbered starting from one, so then-th broadcast of processiwill receivesequence numberorheightn; each broadcast should be uniquely determined by the identity or the indexiof the originating process and its heightn, so we can think of the pair(i,n)as the natural identifier of a broadcast message inside a process group. 4 The broadcasts generated by the same processiare expected to be delivered to every other process in exactly the same order they have been created, i.e., in increasing order of their height. In this respect a catchain is very similar to a process group in the sense of \[1\] or \[7\]. The principal difference is that a catchain is a “hard- ened” version of a process group tolerant to possible Byzantine (arbitrarily malicious) behavior of some participants. 2.4.1. Dependence relation on messages.One can introduce adepen- dence relationon all messages broadcast in a process group. This relation must be a strict partial order≺, with the property thatm i,k ≺m i,k+1 , wherem i,k denotes thek-th message broadcast by group member process with indexi. The meaning ofm≺m ′ is thatm ′ depends onm, so that the (broadcast) messagem ′ can be processed (by a member of the process group) only ifmhas been processed before. For instance, if the messagem ′ represents the reaction of a group member to another messagem, then it is natural to setm≺m ′ . If a member of the process group receives a message m ′ before all its dependencies, i.e., messagesm≺m ′ , have been processed (ordeliveredto the higher-level protocol), then its processing (ordelivery) is delayed until all its dependencies are delivered. We have defined the dependence relation to be a strict partial order, so it must be transitive (m ′′ ≺m ′ andm ′ ≺mimplym ′′ ≺m), antisymmetric (at most one ofm ′ ≺mandm≺m ′ can hold for any two messagesm andm ′ ) and anti-reflexive (m≺mnever holds). If we have a smaller set 4 In the Byzantine environment of a catchain this is not necessarily true in all situations. 7 Chapter2.Catchain Protocol of “basic dependencies”m ′ →m, we can construct its transitive closure→ + and put≺:=→ + . The only other requirement is that every broadcast of a sender depends on all previous broadcasts of the same sender. It is not strictly necessary to assume this; however, this assumption is quite natural and considerably simplifies the design of a messaging system inside a process group, so the Catchain protocol makes this assumption. 2.4.2. Dependence set or cone of a message.Letmbe a (broadcast) message inside a process group as above. We say that the setD m :={m ′ : m ′ ≺m}is thedependence setordependence coneof messagem. In other words,D m is theprincipal idealgenerated bymin the partially ordered finite set of all messages. It is precisely the set of all messages that must be delivered beforemis delivered. 2.4.3. Extended dependence cone of a message.We also defineD + m , theextended dependence cone ofm,byD + m :=D m ∪{m}. 2.4.4. Cones, or ideals with respect to≺.More generally, we say that a subsetDof messages is aconeif it is an ideal with respect to the dependence relation≺, i.e., ifm∈Dandm ′ ≺mimplym ′ ∈D. Of course, the dependence coneD m and the extended dependence coneD + m of any messagemare cones (because any principal ideal in a partially ordered set is an ideal). 2.4.5. Identification of cones with the aid of vector time.Recall that we have assumed that any message depends on all preceding messages of the same sender, i.e.m i,s ≺m i,s+1 for anyi∈Iand anys >0, such thatm i,s+1 exists. This implies that any coneDis completely characterized byNvalues Vt(D) i indexed byi∈I: Vt(D) i := sup{s∈N:m i,s ∈D}= inf{s∈N 0 :m i,s+1 6∈D}(1) (if no messagem i,s is inD, we setVt(D) i := 0). Indeed, it is clear that m i,s ∈D⇔s≤Vt(D) i (2) We say that the vectorVt(D) = (Vt(D) i ) i∈I ∈N I 0 with non-negative com- ponentsVt(D) i is thevector timeorvector timestampcorresponding to coneD(cf. \[1\] or \[7\] for a more detailed discussion of vector time). 8 Chapter2.Catchain Protocol 2.4.6. Partial order on vector timestamps.We introduce a partial order ≤on the set of all possible vector timesN I 0 , which is the product of the usual orders onN 0 : x= (x i ) i∈I ≤y= (y i ) i∈I iffx i ≤y i for alli∈I(3) It is immediate thatD⊂D ′ iffVt(D)≤Vt(D ′ ); therefore,Vtis a strict order-preserving embedding of the set of all cones contained in the set of all messages intoN I 0 . 2.4.7. Vector timestampVt(m)of a messagem.Given any messagem, we define itsvector timestampVt(m)asVt(D m ). In other words, message mcan be delivered only after the firstVt(m) j messages generated by process jare delivered, and this is true for allj∈I. Ifiis the sender of messagem, andsis the height of messagem, so thatm=m i,s , thenVt(m) i =s−1. We can define theadjusted vector timestampVt + (m)of messagemby settingV T + (m) j =V T(m) j forj6=i, V T + (m) i =Vt(m) i + 1 =s. Alternatively,Vt + (m) =Vt(D + m ), where D + m :=D m ∪{m}is theextended dependence cone ofm(cf.2.4.3). Note thatm ′ miffD + m ′ ⊂D + m iffVt + (m ′ )≤Vt + (m)inN I 0 , where m ′ mmeans “m ′ ≺morm ′ =m”. Similarly,m ′ ≺miffD + m ′ ⊂D m iff Vt + (m ′ )≤Vt(m). In other words,the dependence relation≺on (some or all) messages is completely determined by the adjusted vector timestamps of these messages. 2.4.8. Using vector timestamps to correctly deliver broadcast mes- sages.Vector timestamps can be used (in non-byzantine settings) to cor- rectly deliver messages broadcast in a process group. 5 Namely, suppose that every broadcast messagem=m i,s contains the index of its senderi and the vector timestamp of this messageVt(m). Then each receiverj knows whether the message can be delivered or not. For this,jkeeps track of the coneC j of all messages delivered so far, for example by maintain- ing acurrent timestampVt(j)equal toVt(C j ). In other words,Vt(j) k is the count of messages of senderkprocessed byjso far. IfVt(m)≤ Vt(j), then the messagemis delivered immediately andVt(j)is updated tosup(Vt(j),Vt + (m))afterwards; this is equivalent to increasingVt(j) i by 5 We assume that all broadcast messages in the process group are “causal broadcasts” or “cbcast” in the terminology of \[1\], because we only need cbcasts for the implementation of Catchain protocol and Catchain consensus. 9 Chapter2.Catchain Protocol one, whereiis the original sender of messagem. If this condition is not met, thenmmay be put into a waiting queue untilVt(j)becomes large enough. Instead of passively waiting for the required broadcasts,jcan construct the list of message indices(i ′ ,s ′ )that are implicitly mentioned inVt(m)of some received but not delivered messagem, and request messages with these indices from the neighbors from whichjlearned aboutmandVt(m); an al- ternative strategy (actually employed by the current implementation of the Catchain protocol) is to request these messages from randomly chosen neigh- bors from time to time. The latter strategy is simpler because it does not require remembering the immediate sources of all received messages (which may become unavailable anyway). 2.5. Message structure in a catchain. Catchain as a multi-blockchain. The message structure in a catchain is a bit more complicated than described above because of the necessity to support a BFT protocol. In particular, vector timestamps are not sufficient in a Byzantine setting. They have to be complemented by descriptions based on maximal elements of a depen- dence cone (such descriptions are typically used in non-byzantine settings only when the process group is very large, so that vector timestamp sizes become prohibitive). 2.5.1. Describing cones by means of their maximal elements.An alternative way (to using a vector timestamp) of describing a message cone Dis by listing all itsmaximal elementsMax(D), i.e. elementsm∈D, such thatm≺m ′ does not hold for anym ′ ∈D. Of course, one needs a suitable way of referring to messages without including them completely in order for this representation to be practical. 2.5.2. Message identifiers inside a catchain.Catchain protocol uses sha256hashes of (suitably serialized) messages as their unique identifiers. If we assume that there are no collisions forsha256(computable in reasonable, e.g., polynomial time), then a messagemis completely identified within the process group by its hashsha256(m). 2.5.3. Message headers.The header of a messagem=m i,s inside a catchain (i.e., an instance of the Catchain protocol) always contains the index iof its sender, the heights, the catchain identifier (i.e., the hash of the genesis message, cf.2.3) and the set of hashes of maximal elements of the dependence cone ofm, i.e., the set{sha256(m ′ ) :m ′ ∈Max(D m )}. In particular, the 10 Chapter2.Catchain Protocol hashsha256(m i,s−1 )of the previous message of the same sender is always included sincem i,s−1 ∈Max(D m )ifs >1; for performance reasons, there is a separate field in the message header containingsha256(m i,s−1 ). Ifs= 1, then there is no previous message, so the hash of the genesis message (i.e., the catchain identifier, cf.2.3) is used instead. The vector timestampVt(m)is not included in the message header; however, the header implicitly determinesVt(m)since Vt(m) = sup m ′ ∈D m Vt + (m ′ ) =sup m ′ ∈Max(D m ) Vt + (m ′ )(4) Note that the message header is a part of the message, and in particular the hash of a message (i.e., the message identifier) depends on all data listed in the header. Therefore, we assume that the message identifier implicitly determines all the dependencies of the corresponding message (if there are no known collisions forsha256). 2.5.4. Message signatures.Apart from that, every message in a catchain is signed by its creator. Since the list of participating nodes (processes) in a catchain is known in advance, and this list includes the public keys of all processes, these message signatures can be checked by a receiving process im- mediately after a message is received. If the signature is invalid, the message is discarded without any further processing. 2.5.5. Message encryption.All messages in a catchain are also encrypted before being transferred from a node to its neighbor in the private overlay network underlying the catchain. However, this encryption is performed by lower-level network protocols (such as ADNL) and is not relevant to the discussion here. We would like to mention that correct encryption is possible here only because the list of participating processes includes not only the public keys of all processes, but also their ADNL addresses (which effectively are public encryption keys for network transmission). Notice that even if the encryption had been absent, this would not violate the BFT properties of the protocol, because faking a message from another sender would not be possible because of the signatures. However, this might lead to a leak of information to outside observers, which is often undesirable. 2.5.6. Alternative perspective: a catchain as a multi-blockchain. Note that all messages created by the same senderiin a catchain turn out to have a simple “blockchain structure”, because the header ofm i,s+1 contains 11 Chapter2.Catchain Protocol the hashsha256(m i,s )(among other hashes of messages fromMax(D m i,s+1 )) of the previous message of senderi. In this way each processigenerates a sim- ple blockchain consisting of its messages, with each “block” of this blockchain corresponding to one message and referring to the previous block by its hash, and sometimes includes references to blocks (i.e., messages) of other processes by mentioning the hashes of these blocks in its blocks. Each block is signed by its creator. The resulting structure is very similar to that of an “asyn- chronous payment channel” considered in \[3, 5\], but withNparticipants instead of 2. 2.6. Message propagation in a catchain.Now we are ready to describe message propagation in a catchain. Namely: •The (lower-level) overlay network protocol maintains a list of neighbors in the private overlay network underlying the catchain and provides ADNL channels to each of these neighbors. This private overlay net- work has the same list of members (processes, nodes) as the catchain, and the neighbors of each node form an (oriented) subgraph on the set of all participating nodes. This (essentially random) subgraph is strongly connected with probability very close to one. •Each process generates some new messages from time to time (as needed by the higher-level protocol). These messages are augmented by catchain message headers as outlined in2.5.3, signed, and propagated to all known neighbors using the ADNL channels established by the overlay protocol. •In contrast with the usual simple overlay broadcast protocol, the mes- sages received from neighbors are not immediately rebroadcast to all other neighbors that are not known yet to have a copy of them. Instead, the signature is checked first, and invalid messages are discarded. Then the message is either delivered (if all its dependent messages have al- ready been delivered), or put into a waiting queue. In the latter case, all the required messages mentioned in its header (i.e., the setMax(D m )) are pulled from the neighbor that sent this message (apart from that, attempts to download these missing messages from random neighbors are performed from time to time). If necessary, this process is repeated recursively until some messages can be delivered. Once a message is ready for local delivery (i.e., all its dependencies are already present), it is also rebroadcast to all neighbors in the overlay network. 12 Chapter2.Catchain Protocol •Apart from the recursive “pull” mechanism described above, a faster vector timestamp-based mechanism is also used, so that messages can be queried from neighbors by their senders and heights (learned from the vector timestamps of received messages). Namely, each process sends a special query containing the current vector timestamp to a randomly chosen neighbor from time to time. This peer-to-peer query leads to its receiver sending back all or some messages unknown to the sender (judging by their vector timestamps). •This faster vector timestamp-based mechanism can be disabled for mes- sages originating from certain senders as soon as a “fork” is detected, i.e., a second message with the same senderiand heights, but with a different hash, is learned from a neighbor, for example, during the fast or slow “pull” process. Once a fork created byiis detected, the corresponding componentVt i of all subsequent vector timestamps is set to a special value∞to indicate that comparing the values of these components does not make sense anymore. •When a message is delivered (to the higher-level protocol), this message is added into the coneCof processed messages of the current process (and the current vector timestamp is updated accordingly), and all sub- sequent messages generated by the current process will be assumed to depend on all the messages delivered so far (even if this is not logically necessary from the perspective of the higher-level protocol). •If the setMax(C)of the maximal elements of the cone of processed messages becomes too large (contains more elements than a certain amount fixed in advance by the genesis message of the catchain), then the Catchain protocol asks the higher-level protocol to generate a new message (empty if no useful payload is available). After this new mes- sage is generated (and immediately delivered to the current process),C is updated andMax(C)consists of only one element (the new message). In this way the size ofMax(C)and therefore the size of the message header always remain bounded. •Once a messagemis delivered and the setCis modified to include this message, a timer is set, and after some small delay the higher- level protocol is asked to create a new message (empty if necessary), so that this new messagem ∗ would refer to the newC, similarly to 13 Chapter2.Catchain Protocol the procedure described in the previous item. This new messagem ∗ is pushed to all neighbors; since its header containsMax(C)for the newC, andm∈C, the neighbors learn not only about the newly- generated messagem ∗ , but also about the original received messagem. If some neighbors do not have a copy ofmyet, they would require one (from the current process or not). •All (broadcast) messages received and created in a catchain are stored into a special local database. This is especially important for newly- created messages (cf.3.3.2): if a message is created and sent to neigh- bors, but not saved into the database (and flushed to disk) before the creating process crashes and is restarted, then another message with the same sender and height can be created after restart, thus effectively leading to an involuntary “fork”. 2.7. Forks and their prevention.One can see that the multi-blockchain structure of a catchain outlined above (with references to other blocks by their hashes and with signatures) leaves very little possibility for “cheating” in a consensus protocol built upon a catchain (i.e., using the catchain as a means for broadcasting messages inside a process group). The only possibility that is not detected immediately consists of creating two (or more) different versions of the same messagem i,s (say,m ′ i,s andm ′′ i,s ), and sending one version of this messagem ′ i,s to some peers and a different versionm ′′ i,s to others. If sis minimal (for a fixedi), then this corresponds to aforkin blockchain terminology: two different next blocksm ′ i,s andm ′′ i,s for the same previous blockm i,s−1 . Therefore, the Catchain protocol takes care to detect forks as soon as possible and prevent their propagation. 2.7.1. Detection of forks.The detection of forks is simple: if there are two different blocksm ′ i,s andm ′′ i,s with the same creatori∈Iand the same heights≥1, and with valid signatures ofi, then this is a fork. 2.7.2. Fork proofs.Block signatures in the Catchain protocol are created in such a way that creatingfork proofs(i.e., the proof that a processihas intentionally created a fork) is especially simple since it is the hash of a very small structure (containing a magic number, the values ofiands, and the hash of the remainder of the message) that is actually signed. Therefore, only two such small structures and two signatures are required in a fork proof. 14 Chapter2.Catchain Protocol 2.7.3. External punishment for creating forks.Notice that an external punishment for creating catchain forks may be used in the proof-of-stake blockchain generation context. Namely, the fork proofs may be submitted to a special smart contract (such as the elector smart contract of the TON Blockchain), checked automatically, and some part or all of the stake of the offending party may be confiscated. 2.7.4. Internal processing of forks.Once a fork (created byi) is detected (by another processj), i.e.jlearns about two different messagesm i,s andm ′ i,s created byiand having same heights(usually this happens while recursively downloading dependencies of some other messages),jstarts ignoringiand all of its subsequent messages. They are not accepted and not broadcast further. However, messages created byiprior to the fork detection may be still downloaded if they are referred to in messages (blocks) created by processes that did not see this fork before referring to such messages created byi. 2.7.5. Accepting messages from a “bad” process is bad.Furthermore, if processilearns about a fork created by processj, thenishows this to its neighbors by creating a new service broadcast message that contains the corresponding fork proof (cf.2.7.2). Afterwards, this and all subsequent messages ofjcannot directly depend on any messages by the known “bad” produceri(but they still can refer to messages from another partykthat directly or indirectly refer to messages ofiif no fork byiwas known to kat the time when the referring message was created). Ifjviolates this restriction and creates messages with such invalid references, these messages will be discarded by all honest processes in the group. 2.7.6. The set of “bad” group members is a part of the intrinsic state.Each processikeeps its own copy of the set of known “bad” processes in the group, i.e., those processes that have created at least one fork or have violated2.7.5. This set is updated by addingjinto it as soon asilearns about a fork created byj(or about a violation of2.7.5byj); after that, a callback provided by the higher-level protocol is invoked. This set is used when a new broadcast message arrives: if the sender is bad, then the message is ignored and discarded. 15 Chapter3.Block Consensus Protocol 3 Block Consensus Protocol We explain in this section the basic workings of the TON Block Consensus Protocol (cf.1), which builds upon the generic Catchain protocol (cf.2) to provide the BFT protocol employed for generating and validating new blocks of the TON Blockchain. The source code for the TON Block Consensus protocol resides in subdirectoryvalidator-sessionof the source tree. 3.1. Internal state of the Block Consensus Protocol.The higher-level Block Consensus Protocol introduces a new notion to the catchain: that of aninternal stateof the Block Consensus Protocol (BCP), sometimes also (not quite correctly) called “the internal state of the catchain” or simply catchain state. Namely, each processi∈Ihas a well-determined internal stateσ C i after a subset of messages (actually always a dependence cone)C i is delivered by the Catchain protocol to the higher-level protocol (i.e., to the Block Consensus Protocol in this case). Furthermore, this stateσ C i =σ(C i ) depends only on coneC i , but not on the identity of the processi∈I, and can be defined for any dependence coneS(not necessarily a coneC i of delivered messages for some processiat some point). 3.1.1. Abstract structure of the internal state.We start with an ab- stract structure of the internal state employed by BCP; more specific details will be provided later. 3.1.2. Updating the internal state.The Catchain protocol knows nothing about the internal state; it simply invokes appropriate callbacks supplied by the higher-level protocol (i.e., the BCP) whenever a messagemis delivered. It is the job of the higher-level protocol to compute the new stateσ S ′ starting from the previously computed stateσ S and the messagem, whereS ′ = S∪{m}(and necessarilyS⊃D m , otherwisemcould not have been delivered at this point). 3.1.3. Recursive formula for updating the internal state.The ab- stract setup for computingσ S for all conesSconsists of three components: •A valueσ ∅ for the initial state (this value actually depends on the genesis block of the catchain; we ignore this dependence here because we consider only one catchain at this point). 16 Chapter3.Block Consensus Protocol •A functionfthat computes the stateσ D + m from the previous stateσ D m and the newly-delivered messagem: σ D + m =f(σ D m ,m)(5) whereD m is the dependence cone of messagemandD + m =D m ∪{m} its extended dependence cone (cf.2.4.3). In most cases,fwill actually satisfy the stronger condition σ S∪{m} =f(σ S ,m)ifSandS∪{m}are cones andm6∈S(6) However, this stronger condition is not required by the update algo- rithm. •A “merge function”gthat computesσ S∪T fromσ S andσ T : σ S∪T =g(σ S ,σ T )for any conesSandT(7) (the union of two cones always is a cone). This functionσis applied by the update algorithm only in the specific caseT=D + m andm6∈S. 3.1.4. Commutativity and associativity ofg.Note that (7) (for ar- bitrary conesSandT) implies associativity and commutativity ofg, at least whengis applied to possible states (values of formσ S for some cone S). In this respectgdefines a commutative monoid structure on the set Σ ={σ S :Sis a cone}. Usuallygis defined or partially defined on a larger set ̃ Σof state-like values, and it may be commutative and associative on this larger set ̃ Σ, i.e.,g(x,y) =g(y,x)andg(x,g(y,z)) =g(g(x,y),z)forx,y, z∈ ̃ Σ(whenever both sides of the equality are defined), withσ ∅ as an unit, i.e.,g(x,σ ∅ ) =x=g(σ ∅ ,x)forx∈ ̃ S(under the same condition). However, this property, useful for the formal analysis of the consensus algorithm, is not strictly required by the state update algorithm, because this algorithm usesgin a deterministic fashion to computeσ S . 3.1.5. Commutativity off.Note thatf, if it satisfies the stronger condi- tion (6), must also exhibit a commutativity property f ( f(σ S ,m),m ′ ) =f ( f(σ S ,m ′ ),m ) (8) wheneverSis a cone andmandm ′ are two messages withD m ⊂S,D m ′ ⊂S, m6∈Sandm ′ 6∈S, because in this caseS∪{m},S∪{m ′ }andS∪{m,m ′ } 17 Chapter3.Block Consensus Protocol are also cones, and (6) implies that both sides of (8) are equal toσ S∪{m,m ′ } . Similarly to3.1.4,fis usually defined or partially defined on the product of a larger set ̃ Σof state-like values and of a set of message-like values; it may exhibit the “commutativity” property (8) or not on this larger set. If it does, this might be useful for formal analysis of the algorithms relying onσ S , but this property is not strictly necessary. 3.1.6. The state update algorithm.The state update algorithm (inde- pendently executed by each processi) employed by the catchain (actually by the higher-level BCP) usesσ ∅ ,fandgas follows: •The algorithm keeps track of allσ D + m for all messagesmdelivered so far. •The algorithm keeps track ofσ C i , whereC i is the current dependence cone, i.e., the set of all messagesmdelivered (to the current processi). The initial value ofσ C i isσ ∅ . •When a new messagemis delivered, the value ofσ D m is computed by a repeated application ofgsinceD m = ⋃ m ′ ∈D m D + m ′ = ⋃ m ′ ∈Max(D m ) D + m ′ ; therefore, ifMax(D m ) ={m ′ 1 ,...,m ′ k }, then σ D m =g ( ...g ( g(σ D + m ′ 1 ,σ D + m ′ 2 ),σ D + m ′ 3 ) ,...σ D + m ′ k ) .(9) The setMax(D m )is explicitly listed in the header of messagemin some fixed orderm ′ 1 , . . . ,m ′ k ; the above formula is applied with respect to this order (so the computation ofD m is deterministic). The first element in this list always is the previous message of the sender ofm, i.e., if m=m i,s+1 , thenm ′ 1 =m i,s . •After that, the value ofσ D + m is computed by an application off:σ D + m = f(σ D m ,m). This value is memorized for future use. •Finally, when a new messagemis delivered to the current processi, thus updatingC i toC ′ i :=C i ∪{m}, the algorithm uses the computed valueσ D + m to update the current state σ C ′ i =g(σ C i ,σ D + m )(10) This state, however, is “virtual” in the sense that it can be slightly changed later (especially ifgis not commutative). Nevertheless, it is 18 Chapter3.Block Consensus Protocol used to make some important decisions by the higher-level algorithm (BCP). •Once a new messagemis generated and locally delivered, so thatC i becomes equal toD + m , the previously computed value ofσ C i is discarded and replaced withσ D + m computed according to the general algorithm described above. Ifgis not commutative or not associative (for exam- ple, it may happen thatg(x,y)andg(y,x)are different but equivalent representations of the same state), then this might lead to a slight change of the current “virtual” state of processi. •If the lower-level (catchain) protocol reports to the higher-level protocol that a certain processj6∈iis “bad” (i.e.,jis found out to have created a fork, cf.2.7.6, or to have knowingly endorsed a fork by another pro- cess, cf.2.7.5), then the current (virtual) stateσ C i is recomputed from scratch using the new setC ′ i = ⋃ m∈C i ,mwas created by “good” processk D + m and the “merge” functiongapplied to the set ofσ D + m wheremruns through the set of last messages of the processes known to be good (or through the set of maximal elements of this set). The next created outbound message will depend only on the messages fromC ′ i . 3.1.7. Necessity to know the internal state of the other processes. Formula (9) implies that processimust also keep track ofσ D + m for all messages m, created by this process or not. However, this is possible since these internal states are also computed by appropriate applications of the update algorithm. Therefore, BCP computes and remembers allσ D + m as well. 3.1.8. Functionfwould suffice.Notice that the update algorithm applies gonly to computeσ S∪D + m =g(σ S ,σ D + m )whenSis a cone containingD m , but not containingm. Therefore, every actual application ofgcould have been replaced by an application offsatisfying the extended property (6): σ S∪D + m =g(σ S ,σ D + m ) =f(σ S ,m)(11) However, the update algorithm does not use this “optimization”, because it would disable the more important optimizations described below in3.2.4 and3.2.5. 3.2. The structure of the internal state.The structure of the internal state is optimized to make thetransition functionfof (5) and themerge 19 Chapter3.Block Consensus Protocol functiongof (7) as efficiently computable as possible, preferably without the need of potentially unbounded recursion (just some loops). This motivates the inclusion of additional components into the internal state (even if these components are computable from the remainder of the internal state), which have to be stored and updated as well. This process of including additional components is similar to that employed while solving problems using dynamic programming, or to that used while proving statements by mathematical (or structural) induction. 3.2.1. The internal state is a representation of a value of an abstract algebraic data type.The internal representation of the internal state is essentially a (directed) tree (or rather a directed acyclic graph) or a collection of nodes; each node contains some immediate (usually integer) values and several pointers to other (previously constructed) nodes. If necessary, an extraconstructor tag(a small integer) is added at the beginning of a node to distinguish between several possibilities. This structure is very similar to that used to represent values of abstract algebraic data types in functional programming languages such as Haskell. 3.2.2. The internal state is persistent.The internal state ispersistent, in the sense that the memory used to allocate the nodes which are part of the internal state is never freed up while the catchain is active. Furthermore, the internal state of a catchain is actually allocated inside a huge contiguous memory buffer, and new nodes are always allocated at the end of the used portion of this buffer by advancing a pointer. In this way the references to other nodes from a node inside this buffer may be represented by an integer offset from the start of the buffer. Every internal state is represented by a pointer to its root node inside this buffer; this pointer can be also represented by an integer offset from the start of the buffer. 3.2.3. The internal state of a catchain is flushed to an append-only file.The consequence of the structure of the buffer used to store the internal states of a catchain explained above is that it is updated only by appending some new data at its end. This means that the internal state (or rather the buffer containing all the required internal states) of a catchain can be flushed to an append-only file, and easily recovered after a restart. The only other data that needs to be stored before restarts is the offset (from the start of the buffer, i.e., of this file) of the current state of the catchain. A simple key-value database can be used for this purpose. 20 Chapter3.Block Consensus Protocol 3.2.4. Sharing data between different states.It turns out that the tree (or rather the dag) representing the new stateσ S∪{m} =f(σ S ,m)shares large subtrees with the previous stateσ S , and, similarly,σ S∪T =g(σ S ,σ T )shares large subtrees withσ S andσ T . The persistent structure used for representing the states in BCP makes it possible to reuse the same pointers inside the buffer for representing such shared data structures instead of duplicating them. 3.2.5. Memoizing nodes.Another technique employed while computing new states (i.e., the values of functionf) is that ofmemoizing new nodes, also borrowed from functional programming languages. Namely, whenever a new node is constructed (inside the huge buffer containing all states for a specific catchain), its hash is computed, and a simple hash table is used to look up the latest node with the same hash. If a node with this hash is found, and it has the same contents, then the newly-constructed node is discarded and a reference to the old node with the same contents is returned instead. On the other hand, if no copy of the new node is found, then the hash table is updated, the end-of-buffer (allocation) pointer is advanced, and the pointer to the new node is returned to the caller. In this way if different processes end up making similar computations and having similar states, large portions of these states will be shared even if they are not directly related by application of functionfas explained in3.2.4. 3.2.6. Importance of optimization techniques.The optimization tech- niques3.2.4and3.2.5used for sharing parts of different internal states inside the same catchain are drastically important for improving the memory profile and the performance of BCM in a large process group. The improvement is several orders of magnitude in groups ofN≈100processes. Without these optimizations BCM would not be fit for its intended purpose (BFT consensus on new blocks generated by validators in the TON Blockchain). 3.2.7. Messagemcontains a hash of stateσ D + m .Every messagem contains a (Merkle) hash of (the abstract representation of) the corresponding stateσ D + m . Very roughly, this hash is computed recursively using the tree of nodes representation of3.2.1: all node references inside a node are replaced with (recursively computed) hashes of the referred nodes, and a simple 64-bit hash of the resulting byte sequence is computed. This hash is also used for memoization as described in3.2.5. The purpose of this field in messages is to provide a sanity check for the 21 Chapter3.Block Consensus Protocol computations ofσ D + m performed by different processes (and possibly by differ- ent implementations of the state update algorithm): onceσ D + m is computed for a newly-delivered messagem, the hash of computedσ D + m is compared to the value stored in the header ofm. If these values are not equal, an error message is output into an error log (and no further actions are taken by the software). These error logs can be examined to detect bugs or incompatibil- ities between different versions of BCP. 3.3. State recovery after restart or crashes.A catchain is typically used by the BCP for several minutes; during this period, the program (the validator software) running the Catchain protocol may be terminated and restarted, either deliberately (e.g., because of a scheduled software update) or unintentionally (the program might crash because of a bug in this or some other subsystem, and be restarted afterwards). One way of dealing with this situation would be to ignore all catchains not created after the last restart. However, this would lead to some validators not participating in creating any blocks for several minutes (until the next catchain instances are created), which is undesirable. Therefore, a catchain state recovery protocol is run instead after every restart, so that the validator can continue participating in the same catchain. 3.3.1. Database of all delivered messages.To this end, a special database is created for each active catchain. This database contains all known and delivered messages, indexed by their identifiers (hashes). A sim- ple key-value database suffices for this purpose. The hash of the most recent outbound messagem=m i,s generated by the current processiis also stored in this database. After restart, all messages up tomare recursively de- livered in proper order (in the same way as if all these messages had been just received from the network in an arbitrary order) and processed by the higher-level protocol, untilmfinally is delivered, thus recovering the current state. 3.3.2. Flushing new messages to disk.We have already explained in2.6 that newly-created messages are stored in the database of all delivered mes- sages (cf.3.3.1) and the database is flushed to disk before the new message is sent to all network neighbors. In this way we can be sure that the mes- sage cannot be lost if the system crashes and is restarted, thus avoiding the creation of involuntary forks. 22 Chapter3.Block Consensus Protocol 3.3.3. Avoiding the recomputation of statesσ D + m .An implementation might use an append-only file containing all previously computed states as described in3.2.3to avoid recomputing all states after restart, trading off disk space for computational power. However, the current implementation does not use this optimization. 3.4. High-level description of Block Consensus Protocol.Now we are ready to present a high-level description of the Block Consensus Protocol employed by TON Blockchain validators to generate and achieve consensus on new blockchain blocks. Essentially, it is a three-phase commit protocol that runs over a catchain (an instance of the Catchain protocol), which is used as a “hardened” message broadcast system in a process group. 3.4.1. Creation of new catchain messages.Recall that the lower-level Catchain protocol does not create broadcast messages on its own (with the only exception being service broadcasts with fork proofs, cf.2.7.5). Instead, when a new message needs to be created, the higher-level protocol (BCP) is asked to do this by invoking a callback. Apart from that, the creation of new messages may be triggered by changes in the current virtual state and by timer alarms. 3.4.2. Payload of catchain messages.In this way the payload of catchain messages is always determined by the higher level protocol, such as BCP. For BCP, this payload consists of •Current Unix time. It must be non-decreasing on subsequent messages of the same process. (If this restriction is violated, all processes pro- cessing this message will tacitly replace this Unix time by the maximum Unix time seen in previous messages of the same sender.) •Several (zero or more)BCP eventsof one of the admissible types listed below. 3.4.3. BCP events.We have just explained that the payload of a catchain message contains several (possibly zero) BCP events. Now we list all admis- sible BCP event types. •Submit(round,candidate)— suggest a new block candidate •Approve(round,candidate,signature)— a block candidate has passed local validation 23 Chapter3.Block Consensus Protocol •Reject(round,candidate)— a block candidate has failed local valida- tion •CommitSign(round,candidate,signature)— a block candidate has been accepted and signed •Vote(round,candidate)— a vote for a block candidate •VoteFor(round,candidate)— this block candidate must be voted for in this round (even if the current process has another opinion) •PreCommit(round,candidate)— a preliminary commitment to a block candidate (used in three-phase commit scheme) 3.4.4. Protocol parameters.Several parameters of BCP must be fixed in advance (in the genesis message of the catchain, where they are initialized from the values of the configuration parameters extracted from the current masterchain state): •K— duration of one attempt (in seconds). It is an integer amount of seconds in the current implementation; however, this is an implemen- tation detail, not a restriction of the protocol •Y— number offastattempts to accept a candidate •C— block candidates suggested during one round •∆ i for1≤i≤C— delay before suggesting the block candidate with priorityi •∆ ∞ — delay before approving the null candidate Possible values for these parameters areK= 8,Y= 3,C= 2,∆ i = 2(i−1), ∆ ∞ = 2C. 3.4.5. Protocol overview.The BCP consists of severalroundsthat are executed inside the same catchain. More than one round may be active at one point of time, because some phases of a round may overlap with other phases of other rounds. Therefore, all BCP events contain an explicit round identifierround(a small integer starting from zero). Every round is termi- nated either by (collectively) accepting ablock candidatesuggested by one of the participating processes, or by accepting a specialnull candidate—a 24 Chapter3.Block Consensus Protocol dummy value indicating that no real block candidate was accepted, for ex- ample because no block candidates were suggested at all. After a round is terminated (from the perspective of a participating process), i.e., once a block candidate collectsCommitSignsignatures of more than2/3of all val- idators, onlyCommitSignevents may be added to that round; the process automatically starts participating in the next round (with the next identifier) and ignores all BCP events with different values ofround. 6 Each round is subdivided into severalattempts. Each attempt lasts a predetermined time period ofKseconds (BCP uses clocks to measure time and time intervals and assumes that clocks of “good” processes are more or less in agreement with each other; therefore, BCP is not an asynchronous BFT protocol). Each attempt starts at Unixtime exactly divisible byK and lasts forKseconds. The attempt identifierattemptis the Unixtime of its start divided byK. Therefore, the attempts are numbered more or less consecutively by 32-bit integers, but not starting from zero. The firstY attempts of a round arefast; the remaining attempts areslow. 3.4.6. Attempt identification. Fast and slow attempts.In contrast with rounds, BCP events do not have a parameter to indicate the attempt they belong to. Instead, this attempt is implicitly determined by the Unix time indicated in the payload of the catchain message containing the BCP event (cf.3.4.2). Furthermore, the attempts are subdivided intofast(the firstYattempts of a round in which a process takes part) andslow(the subsequent attempts of the same round). This subdivision is also implicit: the first BCP event sent by a process in a round belongs to a certain attempt, andYattempts starting from this one are considered fast by this process. 3.4.7. Block producers and block candidates.There areCdesignated block producers (member processes) in each round. The (ordered) list of these block producers is computed by a deterministic algorithm (in the simplest case, processesi,i+1, . . . ,i+C−1are used in thei-th round, with the indices taken moduloN, the total number of processes in the catchain) and is known to all participants without any extra communication or negotiation. The processes are ordered in this list by decreasing priority, so the first member of the list has the highest priority (i.e., if it suggests a block candidate in 6 This also means that each process implicitly determines the Unixtime of the start of the next round, and computes all delays, e.g., the block candidate submission delays, starting from this time. 25 Chapter3.Block Consensus Protocol time, this block candidate has a very high chance to be accepted by the protocol). The first block producer may suggest a block candidate immediately after the round starts. Other block producers can suggest block candidates only after some delay∆ i , whereiis the index of the producer in the list of desig- nated block producers, with0 = ∆ 1 ≤∆ 2 ≤.... After some predetermined period of time∆ ∞ elapses from the round start, a specialnull candidateis assumed automatically suggested (even if there are no explicit BCP events to indicate this). Therefore, at mostC+ 1block candidates (including the null candidate) are suggested in a round. 3.4.8. Suggesting a block candidate.A block candidate for the TON Blockchain consists of two large “files” — the block and the collated data, along with a small header containing the description of the block being gen- erated (most importantly, the completeblock identifierfor the block candi- date, containing the workchain and the shard identifier, the block sequence number, its file hash and its root hash) and thesha256hashes of the two large files. Only a part of this small header (including the hashes of the two files and other important data) is used ascandidatein BCP events such as SubmitorCommitSignto refer to a specific block candidate. The bulk of the data (most importantly, the two large files) is propagated in the overlay network associated with the catchain by the streaming broadcast protocol implemented over ADNL for this purpose (cf. \[3, 5\]). This bulk data propa- gation mechanism is unimportant for the validity of the consensus protocol (the only important point is that the hashes of the large files are part of BCP events and hence of the catchain messages, where they are signed by the sender, and these hashes are checked after the large files are received by any participating nodes; therefore, nobody can replace or corrupt these files). ASubmit(round,candidate)BCP event is created in the catchain by the block producer in parallel with the propagation of the block candi- date, indicating the submission of this specific block candidate by this block producer. 3.4.9. Processing block candidates.Once a process observes aSubmit BCP event in a delivered catchain message, it checks the validity of this event (for instance, its originating process must be in the list of designated producers, and current Unixtime must be at least the start of the round plus the minimum delay∆ i , whereiis the index of this producer in the list of designated producers), and if it is valid, remembers it in the current 26 Chapter3.Block Consensus Protocol catchain state (cf.3.1). After that, when a streaming broadcast containing the files associated with this block candidates (with correct hash values) is received (or immediately, if these files are already present), the process invokes a validator instance to validate the new block candidate (even if this block candidate was suggested by this process itself!). Depending on the result of this validation, either anApprove(round,candidate,signature)or aReject(round,candidate)BCP event is created (and embedded into a new catchain message). Note that thesignatureused inApproveevents uses the same private key that will ultimately be used to sign the accepted block, but the signature itself is different from that used inCommitSign(the hash of a structure with different magic number is actually signed). Therefore, this interim signature cannot be used to fake the acceptance of this block by this particular validator process to an outside observer. 3.4.10. Overview of one round.Each round of BCP proceeds as follows: •At the beginning of a round, several processes (from the predetermined list of designated producers) submit their block candidates (with cer- tain delays depending on their producer priority) and reflect this fact by means ofSubmitevents (incorporated into catchain messages). •Once a process receives a submitted block candidate (i.e., observes a Submitevent and receives all necessary files by means external to the consensus protocol), it starts the validation of this candidate and eventually creates either anApproveor aRejectevent for this block candidate. •During eachfast attempt(i.e., one of the firstYattempts) every process votes either for a block candidate that has collected the votes of more than2/3of all processes, or, if there are no such candidates yet, for the valid (i.e.,Approved by more than2/3of all processes) block candidate with the highest priority. The voting is performed by means of creatingVoteevents (embedded into new catchain messages). •During eachslow attempt(i.e., any attempt except the firstY) ev- ery process votes either for a candidate that wasPreCommitted be- fore (by the same process), or for a candidate that was suggested by VoteFor. 27 Chapter3.Block Consensus Protocol •If a block candidate has received votes from more than2/3of all pro- cesses during the current attempt, and the current process observes these votes (which are collected in the catchain state), aPreCommit event is created, indicating that the process will vote only for this can- didate in future. •If a block candidate collectsPreCommits from more than2/3of all processes inside an attempt, then it is assumed to be accepted (by the group), and each process that observes thesePreCommits cre- ates aCommitSignevent with a valid block signature. These block signatures are registered in the catchain, and are ultimately collected to create a “block proof” (containing signatures of more than2/3of the validators for this block). This block proof is the external output of the consensus protocol (along with the block itself, but without its collated data); it is ultimately propagated in the overlay network of all full nodes that have subscribed to new blocks of this shard (or of the masterchain). •Once a block candidate collectsCommitSignsignatures from more than2/3of all validators, the round is considered finished (at least from the perspective of a process that observes all these signatures). After that, only aCommitSigncan be added to that round by this process, and the process automatically starts participating in the next round (and ignores all events related to other rounds). Note that the above protocol may lead to a validator signing (in aCommitSign event) a block candidate that wasRejected by the same validator before (this is a kind of “submitting to the will of majority”). 3.4.11.VoteandPreCommitmessages are created deterministi- cally.Note that each process can create at most oneVoteand at most one PreCommitevent in each attempt. Furthermore, these events are com- pletely determined by the stateσ D m of the sender of catchain messagem containing such an event. Therefore, the receiver can detect invalidVoteor PreCommitevents and ignore them (thus mitigating byzantine behavior of other participants). On the other hand, a messagemthat should contain a Voteor aPreCommitevent according to the corresponding stateσ D m but does not contain one can be received. In this case, the current implementa- tion automatically creates missing events and proceeds as ifmhad contained 28 Chapter3.Block Consensus Protocol them from the very beginning. However, such instances of byzantine behav- ior are either corrected or ignored (and a message is output into the error log), but the offending processes are not otherwise punished (because this would require very large misbehavior proofs for outside observers that do not have access to the internal state of the catchain). 3.4.12. MultipleVotes andPreCommits of the same process.Note that a process usually ignores subsequentVotes andPreCommits gener- ated by the same originating process inside the same attempt, so normally a process can vote for at most one block candidate. However, it may happen that a “good” process indirectly observes a fork created by a byzantine pro- cess, withVotes for different block candidates in different branches of this fork (this can happen if the “good” process learns about these two branches from two other “good” processes that did not see this fork before). In this case, bothVotes (for different candidates) are taken into account (added into the merged state of the current process). A similar logic applies to PreCommits. 3.4.13. Approving or rejecting block candidates.Notice that a block candidate cannot beApproved orRejected before it has beenSubmitted (i.e., anApproveevent that was not preceded by a correspondingSubmit event will be ignored), and that a candidate cannot be approved before the minimum time of its submission (the round start time plus the priority- dependent delay∆ i ) is reached, i.e., any “good” process will postpone the creation of itsApproveuntil this time. Furthermore, one cannotApprove more than one candidate of the same producer in the same round (i.e., even if a processSubmits several candidates, only one of them—presumably the first one—will beApproved by other “good” processes; as usual, this means that subsequentApproveevents will be ignored by “good” processes on receipt). 3.4.14. Approving the null block candidate.The implicit null block candidate is also explicitly approved (by creating anApproveevent) by all (good) processes, once the delay∆ ∞ from the start of the round expires. 3.4.15. Choosing a block candidate for voting.Each process chooses one of the available block candidates (including the implicit null candidate) and votes for this candidate (by creating aVoteevent) by applying the following rules (in the order they are presented): 29 Chapter3.Block Consensus Protocol •If the current process created aPreCommitevent for a candidate dur- ing one of the previous attempts, and no other candidate has collected votes from more than2/3of all processes since (i.e., inside one of the subsequent attempts, including the current one so far; we say that the PreCommitevent is stillactivein this case), then the current process votes for this candidate again. •If the current attempt is fast (i.e., one of the firstYattempts of a round from the perspective of the current process), and a candidate has collected votes from more than2/3of all processes during the current or one of the previous attempts, the current process votes for this candidate. In the case of a tie, the candidate from the latest of all such attempts is chosen. •If the current attempt is fast, and the previous rules do not apply, then the process votes for the candidate with the highest priority among alleligible candidates, i.e., candidates that have collectedApproves (observable by the current process) from more than2/3of all processes. •If the current attempt is slow, then the process votes only after it receives a validVoteForevent in the same attempt. If the first rule is applicable, the process votes according to it (i.e., for the previously PreCommited candidate). Otherwise it votes for the block candidate that is mentioned in theVoteForevent. If there are several such valid events (during the current attempt), the candidate with the smallest hash is selected (this may happen in rare situations related to different VoteForevents created in different branches of a fork, cf.3.4.12). The “null candidate” is considered to have the least priority. It also requires an explicitApprovebefore being voted for (with the exception of the first two rules). 3.4.16. CreatingVoteForevents during slow attempts.AVoteFor event is created at the beginning of a slow attempt by thecoordinator— the process with indexattemptmodNin the ordered list of all processes participating in the catchain (as usual, this means that aVoteForcreated by another process will be ignored by all “good” processes). ThisVoteFor event refers to one of the block candidates (including the null candidate) that have collectedApproves from more than2/3of all processes, usually randomly chosen among all such candidates. Essentially, this is a suggestion 30 Chapter3.Block Consensus Protocol to vote for this block candidate directed to all other processes that do not have an activePreCommit. 3.5. Validity of BCP.Now we present a sketch of the proof of validity of TON Block Consensus Protocol (BCP) described above in3.4, assuming that less than one third of all processes exhibit byzantine (arbitrarily malicious, possibly protocol-violating) behavior, as it is customary for Byzantine Fault Tolerant protocols. During this subsection, we consider only one round of BCP, subdivided into several attempts. 3.5.1. Fundamental assumption.Let us emphasize once again that we assume thatless than one third of all processes are byzantine. All other processes are assumed to begood, i.e., they follow the protocol. 3.5.2. Weighted BCP.The reasoning in this subsection is valid for the weighted variant of BCPas well. In this variant, each processi∈Iis pre-assigned a positive weightw i >0(fixed in the genesis message of the catchain), and statements about “more than2/3of all processes” and “less than one third of all processes” are understood as “more than2/3of all processes by weight”, i.e., “a subsetJ⊂Iof processes with total weight ∑ j∈J w j > 2 3 ∑ i∈I w i ”, and similarly for the second property. In particular, our “fundamental assumption”3.5.1is to be understood in the sense that “the total weight of all byzantine processes is less than one third of the total weight of all processes”. 3.5.3. Useful invariants.We collect here some useful invariants obeyed by all BCP events during one round of BCP (inside a catchain). These invariants are enforced in two ways. Firstly, any “good” (non-byzantine) process will not create events violating these invariants. Secondly, even if a “bad” process creates an event violating these invariants, all “good” processes will detect this when a catchain message containing this event is delivered to BCP and ignore such events. Some possible issues related to forks (cf.3.4.12) remain even after these precautions; we indicate how these issues are resolved separately, and ignore them in this list. So: •There is at most oneSubmitevent by each process (inside one round of BCP). •There is at most oneApproveorRejectevent by each process re- lated to one candidate (more precisely, even if there are multiple candi- dates created by the same designated block producer, only one of them 31 Chapter3.Block Consensus Protocol can beApproved by another process). 7 This is achieved by requiring all “good” processes to ignore (i.e., not to createApproves orRejects for) all candidates suggested by the same producer but the very first one they have learned about. •There is at most oneVoteand at most onePreCommitevent by each process during each attempt. •There is at most oneVoteForevent during each (slow) attempt. •There is at most oneCommitSignevent by each process. •During a slow attempt, each process votes either for its previously PreCommitted candidate, or for the candidate indicated in theVoteFor event of this attempt. One might somewhat improve the above statements by adding the word “valid” where appropriate (e.g., there is at most onevalidSubmitevent. . . ). 3.5.4. More invariants. •There is at most one eligible candidate (i.e., candidate that has received Approves from more than2/3of all processes) from each designated producer, and no eligible candidates from other producers. •There are at mostC+ 1eligible candidates in total (at mostCcandi- dates fromCdesignated producers, plus the null candidate). •A candidate may be accepted only if it has collected more than2/3 PreCommits during the same attempt (more precisely, a candidate is accepted only if there arePreCommitevents created by more than2/3 of all processes for this candidate and belonging to the same attempt). 7 In fact,Rejects appear only in this restriction, and do not affect anything else. Therefore, any process can abstain from sendingRejects without violating the protocol, andRejectevents could have been removed from the protocol altogether. Instead, the current implementation of the protocol still generatesRejects, but does not check any- thing on their receipt and does not remember them in the catchain state. Only a message is output into the error log, and the offending candidate is stored into a special directory for future study, becauseRejects usually indicate either the presence of a byzantine ad- versary, or a bug in the collator (block generation) or validator (block verification) software either on the node that suggested the block or on the node that created theRejectevent. 32 Chapter3.Block Consensus Protocol •A candidate may beVoted for,PreCommitted, or mentioned in a VoteForonly if it is aneligible candidate, meaning that it has pre- viously collectedApproves from more than2/3of all validators (i.e., a validVoteevent may be created for a candidate only ifApprove events for this candidate have been previously created by more than 2/3of all processes and registered in catchain messages observable from the message containing theVoteevent, and similarly forPreCommit andVoteForevents). 3.5.5. At most one block candidate is accepted.Now we claim that at most one block candidate can be accepted (in a round of BCP). Indeed, a candidate can be accepted only if it collectsPreCommits from more than2/3of all processes inside the same attempt. Therefore, two different candidates cannot achieve this during the same attempt (otherwise more than one third of all validators must have createdPreCommits for two different candidates inside an attempt, thus violating the above invariants; but we have assumed that less than one third of all validators exhibit byzantine behavior). Now suppose that two different candidatesc 1 andc 2 have collected PreCommits from more than2/3of all processes in two different attempts a 1 anda 2 . We may assume thata 1 < a 2 . According to the first rule of 3.4.15, each process that has created aPreCommitforc 1 during attempt a 1 must continue voting forc 1 in all subsequent attemptsa ′ > a 1 , or at least cannot vote for any other candidate, unless another candidatec ′ collects Votes of more than2/3of all processes during a subsequent attempt (and this invariant is enforced even if some processes attempt not to create these newVoteevents forc 1 , cf.3.4.11). Therefore, ifc 2 6=c 1 has collected the necessary amount ofPreCommits during attempta 2 > a 1 , there is at least one attempta ′ ,a 1 < a ′ ≤a 2 , such that somec ′ 6=c 1 (not necessarily equal toc 2 ) has collectedVotes of more than2/3of all processes during attempt a ′ . Let us fix the smallest sucha ′ , and the correspondingc ′ 6=c 1 that has collected many votes during attempta ′ . More than2/3of all validators have voted forc ′ during attempta ′ , and more than2/3of all validators have PreCommitted forc 1 during attempta 1 , and by the minimality ofa ′ there was no attempta ′′ witha 1 < a ′′ < a ′ , such that a candidate distinct from c 1 collected more than2/3of all votes during attempta ′′ . Therefore, all validators thatPreCommitted forc 1 could vote only forc 1 during attempt a ′ , and at the same time we supposed thatc ′ has collected votes from more than2/3of all validators during the same attempta ′ . This implies that 33 Chapter3.Block Consensus Protocol more than1/3of all validators have somehow voted both forc 1 andc ′ during this attempt (or voted forc ′ while they could have voted only forc 1 ), i.e., more than1/3of all validators have exhibited byzantine behavior. This is impossible by our fundamental assumption3.5.1. 3.5.6. At most one block candidate may bePreCommitted during one attempt.Note that all validPreCommitevents (if any) created inside the same attempt must refer to the same block candidate, by the same reasoning as in the first part of3.5.5: since a validPreCommitevent for a candidatecmay be created only after votes from more than2/3of all processes are observed for this candidate inside the same attempt (and invalidPreCommits are ignored by all good processes), the existence of validPreCommitevents for different candidatesc 1 andc 2 inside the same attempt would imply that more than one third of all processes have voted both forc 1 andc 2 inside this attempt, i.e., they have exhibited byzantine behavior. This is impossible in view of our fundamental assumption3.5.1. 3.5.7. A previousPreCommitis deactivated by the observation of a newer one.We claim thatwhenever a process with an activePreCommit observes a validPreCommitcreated by any process in a later attempt for a different candidate, its previously activePreCommitis deactivated. Recall that we say that a process has anactivePreCommitif it has created a PreCommitfor a certain candidatecduring a certain attempta, did not create anyPreCommitduring any attemptsa ′ > a, and did not observe votes of more than2/3of all validators for any candidate6=cduring any attemptsa ′ > a. Any process has at most one activePreCommit, and if it has one, it must vote only for the precommitted candidate. Now we see that if a process with an activePreCommitfor a candidate csince attemptaobserves a validPreCommit(usually by another pro- cess) for a candidatec ′ created during some later attempta ′ > a, then the first process must also observe all dependencies of the message that contains the newerPreCommit; these dependencies necessarily include validVotes from more than2/3of all validators for the same candidatec ′ 6=ccreated during the same attempta ′ > a(because otherwise the newerPreCommit would not be valid, and would be ignored by the other process); by definition, the observation of all theseVotes deactivates the originalPreCommit. 3.5.8. Assumptions for proving the convergence of the protocol. Now we are going to prove that the protocol described aboveconverges(i.e., 34 Chapter3.Block Consensus Protocol terminates after accepting a block candidate) with probability one under some assumptions, which essentially tell us that there are enough “good” processes (i.e., processes that diligently follow the protocol and do not in- troduce arbitrary delays before sending their new messages), and that these good processes enjoy good network connectivity at least from time to time. More precisely, our assumptions are as follows: •There is a subsetI + ⊂Iconsisting of “good” processes and containing more than2/3of all processes. •All processes fromI + have well-synchronized clocks (differing by at mostτ, whereτis a bound for network latency described below). •If there are infinitely many attempts, then infinitely many attempts are “good” with respect to network connectivity between processes fromI + , meaning that all messages created by a process fromI + during this attempt or earlier are delivered to any other process fromI + within at mostτ >0seconds after being created with probability at least q >0, whereτ >0and0< q <1are some fixed parameters, such that 5τ < K, whereKis the duration of one attempt. •Furthermore, if the protocol runs for infinitely many attempts, then any arithmetic progression of attempts contains infinitely many “good” attempts in the sense described above. •A process fromI + creates aVoteForduring a slow attempt after some fixed or random delay after the start of the slow attempt, in such a way that this delay belongs to the interval(τ,K−3τ)with probability at leastq ′ , whereq ′ >0is a fixed parameter. •A process fromI + , when it is its turn to be the coordinator of a slow attempt, chooses a candidate forVoteForuniformly at random among all eligible candidates (i.e., those candidates that have collected Approves from more than2/3of all validators). 3.5.9. The protocol terminates under these assumptions.Now we claim that(each round of) the BCP protocol as described above terminates with probability one under the assumptions listed in3.5.8. The proof pro- ceeds as follows. 35 Chapter3.Block Consensus Protocol •Let us assume that the protocol does not converge. Then it continues running forever. We are going to ignore the first several attempts, and consider only attemptsa 0 ,a 0 + 1,a 0 + 2, . . . starting from somea 0 , to be chosen later. •Since all processes fromI + continue participating in the protocol, they will create at least one message not much later than the start of the round (which may be perceived slightly differently by each process). For instance, they will create anApprovefor the null candidate no later than∆ ∞ seconds from the start of the round. Therefore, they will consider all attempts slow at mostKYseconds afterwards. By choosing a 0 appropriately, we can assume that all attempts we consider are slow from the perspective of all processes fromI + . •After a “good” attempta≥a 0 all processes fromI + will see the Approves for the null candidate created by all other processes fromI + , and will deem the null candidate eligible henceforth. Since there are infinitely many “good” attempts, this will happen sooner or later with probability one. Therefore, we can assume (increasinga 0 if necessary) that there is at least one eligible candidate from the perspective of all processes fromI + , namely, the null candidate. •Furthermore, there will be infinitely many attemptsa≥a 0 that are perceived slow by all processes fromI + , that have a coordinator from I + , and that are “good” (with respect to the network connectivity) as defined in3.5.8. Let us call such attempts “very good”. •Consider one “very good” slow attempta. With probabilityq ′ >0, its coordinator (which belongs toI + ) will wait forτ ′ ∈(τ,K−3τ) seconds before creating itsVoteForevent. Consider the most recent PreCommitevent created by any process fromI + ; let us suppose it was created during attempta ′ < afor some candidatec ′ . With prob- abilityqq ′ >0, the catchain message carrying thisPreCommitwill be already delivered to the coordinator at the time of generation of itsVoteForevent. In that case, the catchain message carrying this VoteForwill depend on thisPreCommit(c ′ )event, and all “good” processes that observe thisVoteForwill also observe its dependen- cies, including thisPreCommit(c ′ ). We see thatwith probability at leastqq ′ , all processes fromI + that receive theVoteForevent during 36 Chapter3.Block Consensus Protocol a “very good” slow attempt receive also the most recentPreCommit (if any). •Next, consider any process fromI + that receives thisVoteFor, for a randomly chosen eligible candidatec, and suppose that there are already somePreCommits, and that the previous statement holds. Since there are at mostC+ 1eligible candidates (cf.3.5.4), with prob- ability at least1/(C+ 1)>0we’ll havec=c ′ , wherec ′ is the most re- centlyPreCommitted candidate (there is at most one such candidate by3.5.6). In this case, all processes fromI + will vote forc=c ′ during this attempt immediately after they receive thisVoteFor(which will be delivered to any processj∈I + less thanK−2τseconds after the beginning of the attempt with probabilityqq ′ ). Indeed, if a processj fromI + did not have an activePreCommit, it will vote for the value indicated inVoteFor, which isc. Ifjhad an activePreCommit, and it is as recent as possible, i.e., also created during attempta ′ , then it must have been aPreCommitfor the same valuec ′ =c(because we know about at least one validPreCommitforc ′ during attempt a ′ , and all other validPreCommits during attempta ′ must be for the samec ′ by3.5.6). Finally, ifjhad an activePreCommitfrom an attempt< a ′ , then it will become inactive once theVoteForwith all its dependencies (including the newerPreCommit(c ′ )) has been deliv- ered to this processj(cf.3.5.7), and the process will again vote for the valuecindicated inVoteFor. Therefore, all processes fromI + will vote for the samec=c ′ during this attempt, less thanK−2τseconds after the beginning of the attempt (with some probability bounded away from zero). •If there are noPreCommits yet, then the above reasoning simplifies further: all processes fromI + that receive thisVoteForwill imme- diately vote for the candidatecsuggested by thisVoteFor. •In both cases, all processes fromI + will create aVotefor the same candidatecless thanK−2τseconds from the beginning of the attempt, and this will happen with a positive probability bounded away from zero. •Finally, all processes fromI + will receive theseVotes forcfrom all processes fromI + , again less than(K−2τ) +τ=K−τseconds 37 Chapter3.Block Consensus Protocol after the beginning of this attempt, i.e., still during the same attempt (even after taking into account the imperfect clock synchronization between processes fromI + ). This means that they will all create a validPreCommitforc, i.e., the protocol will acceptcduring this attempt with probability bounded away from zero. •Since there are infinitely many “very good” attempts, and the proba- bility of successful termination during each such attempt is≥p >0 for some fixed value ofp, the protocol will terminate successfully with probability one. 38 References References \[1\]K. Birman,Reliable Distributed Systems: Technologies, Web Services and Applications, Springer, 2005. \[2\]M. Castro, B. Liskov, et al.,Practical byzantine fault tolerance, Proceedings of the Third Symposium on Operating Systems Design and Implementation(1999), p. 173–186, available athttp://pmg.csail.mit. edu/papers/osdi99.pdf. \[3\]N. Durov,Telegram Open Network, 2017. \[4\]N. Durov,Telegram Open Network Blockchain, 2018. \[5\]L. Lamport, R. Shostak, M. Pease,The byzantine generals problem, ACM Transactions on Programming Languages and Systems,4/3(1982), p. 382–401. \[6\]A. Miller, Yu Xia, et al.,The honey badger of BFT protocols, Cryptology e-print archive 2016/99,https://eprint.iacr.org/2016/ 199.pdf, 2016. \[7\]M. van Steen, A. Tanenbaum,Distributed Systems, 3rd ed., 2017. 39 --- # Unknown Fift: A Brief Introduction Nikolai Durov February 6, 2020 Abstract The aim of this text is to provide a brief description of Fift, a new programming language specifically designed for creating and managing TON Blockchain smart contracts, and its features used for interaction with the TON Virtual Machine \[4\] and the TON Blockchain \[5\]. Introduction This document provides a brief description of Fift, a stack-based general- purpose programming language optimized for creating, debugging, and man- aging TON Blockchain smart contracts. Fift has been specifically designed to interact with the TON Virtual Ma- chine (TON VM or TVM) \[4\] and the TON Blockchain \[5\]. In particular, it offers native support for 257-bit integer arithmetic and TVM cell ma- nipulation shared with TVM, as well as an interface to the Ed25519-based cryptography employed by the TON Blockchain. A macro assembler for TVM code, useful for writing new smart contracts, is also included in the Fift distribution. Being a stack-based language, Fift is not unlike Forth. Because of the brevity of this text, some knowledge of Forth might be helpful for under- standing Fift. 1 However, there are significant differences between the two languages. For instance, Fift enforces runtime type-checking, and keeps val- ues of different types (not only integers) in its stack. A list of words (built-in functions, or primitives) defined in Fift, along with their brief descriptions, is presented in Appendix A. 1 Good introductions to Forth exist; we can recommend \[1\]. 1 Introduction Please note that the current version of this document describes a pre- liminary test version of Fift; some minor details are likely to change in the future. 2 Introduction Contents 1 Overview5 2 Fift basics7 2.1 List of Fift stack value types . . . . . . . . . . . . . . . . . . . 7 2.2 Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.3 Terminating Fift . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.4 Simple integer arithmetic . . . . . . . . . . . . . . . . . . . . . 9 2.5 Stack manipulation words . . . . . . . . . . . . . . . . . . . . 11 2.6 Defining new words . . . . . . . . . . . . . . . . . . . . . . . . 12 2.7 Named constants . . . . . . . . . . . . . . . . . . . . . . . . . 13 2.8 Integer and fractional constants, or literals . . . . . . . . . . . 15 2.9 String literals . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 2.10 Simple string manipulation . . . . . . . . . . . . . . . . . . . . 17 2.11 Boolean expressions, or flags . . . . . . . . . . . . . . . . . . . 18 2.12 Integer comparison operations . . . . . . . . . . . . . . . . . . 18 2.13 String comparison operations . . . . . . . . . . . . . . . . . . 19 2.14 Named and unnamed variables . . . . . . . . . . . . . . . . . . 19 2.15 Tuples and arrays . . . . . . . . . . . . . . . . . . . . . . . . . 22 2.16 Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 2.17 Atoms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 2.18 Command line arguments in script mode . . . . . . . . . . . . 28 3 Blocks, loops, and conditionals29 3.1 Defining and executing blocks . . . . . . . . . . . . . . . . . . 29 3.2 Conditional execution of blocks . . . . . . . . . . . . . . . . . 30 3.3 Simple loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 3.4 Loops with an exit condition . . . . . . . . . . . . . . . . . . . 31 3.5 Recursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 3.6 Throwing exceptions . . . . . . . . . . . . . . . . . . . . . . . 35 4 Dictionary, interpreter, and compiler36 4.1 The state of the Fift interpreter . . . . . . . . . . . . . . . . . 36 4.2 Active and ordinary words . . . . . . . . . . . . . . . . . . . . 37 4.3 Compiling literals . . . . . . . . . . . . . . . . . . . . . . . . . 37 4.4 Defining new active words . . . . . . . . . . . . . . . . . . . . 38 4.5 Defining words and dictionary manipulation . . . . . . . . . . 39 3 Introduction 4.6 Dictionary lookup . . . . . . . . . . . . . . . . . . . . . . . . . 40 4.7 Creating and manipulating word lists . . . . . . . . . . . . . . 41 4.8 Custom defining words . . . . . . . . . . . . . . . . . . . . . . 42 5 Cell manipulation43 5.1 Slice literals . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 5.2 Builder primitives . . . . . . . . . . . . . . . . . . . . . . . . . 44 5.3 Slice primitives . . . . . . . . . . . . . . . . . . . . . . . . . . 46 5.4 Cell hash operations . . . . . . . . . . . . . . . . . . . . . . . 49 5.5 Bag-of-cells operations . . . . . . . . . . . . . . . . . . . . . . 49 5.6 Binary file I/O and Bytes manipulation . . . . . . . . . . . . . 51 6 TON-specific operations53 6.1 Ed25519 cryptography . . . . . . . . . . . . . . . . . . . . . . 53 6.2 Smart-contract address parser . . . . . . . . . . . . . . . . . . 53 6.3 Dictionary manipulation . . . . . . . . . . . . . . . . . . . . . 54 6.4 Invoking TVM from Fift . . . . . . . . . . . . . . . . . . . . . 56 7 Using the Fift assembler59 7.1 Loading the Fift assembler . . . . . . . . . . . . . . . . . . . . 59 7.2 Fift assembler basics . . . . . . . . . . . . . . . . . . . . . . . 60 7.3 Pushing integer constants . . . . . . . . . . . . . . . . . . . . 61 7.4 Immediate arguments . . . . . . . . . . . . . . . . . . . . . . . 62 7.5 Immediate continuations . . . . . . . . . . . . . . . . . . . . . 63 7.6 Control flow: loops and conditionals . . . . . . . . . . . . . . . 65 7.7 Macro definitions . . . . . . . . . . . . . . . . . . . . . . . . . 67 7.8 Larger programs and subroutines . . . . . . . . . . . . . . . . 68 A List of Fift words75 4 Chapter1.Overview 1 Overview Fift is a simple stack-based programming language designed for testing and debugging the TON Virtual Machine \[4\] and the TON Blockchain \[5\], but potentially useful for other purposes as well. When Fift is invoked (usually by executing a binary file calledfift), it either reads, parses, and interprets one or several source files indicated in the command line, or enters the interac- tive mode and interprets Fift commands read and parsed from the standard input. There is also a “script mode”, activated by command line switch-s, in which all command line arguments except the first one are passed to the Fift program by means of the variables$nand$#. In this way, Fift can be used both for interactive experimentation and debugging as well as for writing simple scripts. All data manipulated by Fift is kept in a (LIFO) stack. Each stack entry is supplemented by atype tag, which unambiguously determines the type of the value kept in the corresponding stack entry. The types of values supported by Fift includeInteger(representing signed 257-bit integers),Cell (representing a TVM cell, which consists of up to 1023 data bits and up to four references to other cells as explained in \[4\]),Slice(a partial view of aCellused for parsing cells), andBuilder(used for building new cells). These data types (and their implementations) are shared with TVM \[4\], and can be safely passed from the Fift stack to the TVM stack and back when necessary (e.g., when TVM is invoked from Fift by using a Fift primitive such asrunvmcode). In addition to the data types shared with TVM, Fift introduces some unique data types, such asBytes(arbitrary byte sequences),String(UTF-8 strings),WordList, andWordDef(used by Fift to create new “words” and manipulate their definitions). In fact, Fift can be extended to manipulate arbitrary “objects” (represented by the generic typeObject), provided they are derived from C++ classtd::CntObjectin the current implementation. Fift source files and libraries are usually kept in text files with the suf- fix.fif. A search path for libraries and included files is passed to the Fift executable either in a-Icommand line argument or in theFIFTPATHenviron- ment variable. If neither is set, the default library search path/usr/lib/fift is used. On startup, the standard Fift library is read from the fileFift.fifbefore interpreting any other sources. It must be present in the library search path, otherwise Fift execution will fail. 5 Chapter1.Overview A fundamental Fift data structure is its globaldictionary, containing words—or, more precisely,word definitions—that correspond both to built- in primitives and functions and to user-defined functions. 2 A word can be executed in Fift simply by typing its name (a UTF-8 string without space characters) in interactive mode. When Fift starts up, some words (primi- tives) are already defined (by some C++ code in the current implementa- tion); other words are defined in the standard libraryFift.fif. After that, the user may extend the dictionary by defining new words or redefining old ones. The dictionary is supposed to be split into severalvocabularies, orname- spaces; however, namespaces are not implemented yet, so all words are cur- rently defined in the same global namespace. The Fift parser for input source files and for the standard input (in the interactive mode) is rather simple: the input is read line-by-line, then blank characters are skipped, and the longest prefix of the remaining line that is (the name of) a dictionary word is detected and removed from the input line. 3 After that, the word thus found is executed, and the process repeats until the end of the line. When the input line is exhausted, a subsequent line is read from the current input file or the standard input. In order to be detected, most words require a blank character or an end- of-line immediately after them; this is reflected by appending a space to their names in the dictionary. Other words, calledprefix words, do not require a blank character immediately after them. If no word is found, the string consisting of the first remaining characters of the input line until the next blank or end-of-line character is interpreted as anIntegerand pushed into the stack. For instance, if we invoke Fift, type 2 3 + .(and press Enter), Fift first pushes anIntegerconstant equal to2 into its stack, followed by another integer constant equal to3. After that, the built-in primitive “+” is parsed and found in the dictionary; when invoked, it takes the two topmost elements from the stack and replaces them with their sum (5in our example). Finally, “.” is a primitive that prints the decimal representation of the top-of-stackInteger, followed by a space. As a result, we observe “5 ok” printed by the Fift interpreter into the standard output. The string “ok” is printed by the interpreter whenever it finishes interpreting 2 Fift words are typically shorter than functions or subroutines of other programming languages. A nice discussion and some guidelines (for Forth words) may be found in \[2\]. 3 Notice that in contrast to Forth, Fift word names are case-sensitive:dupandDUPare distinct words. 6 2.1. List of Fift stack value types a line read from the standard input in the interactive mode. A list of built-in words may be found in Appendix A. 2 Fift basics This chapter provides an introduction into the basic features of the Fift pro- gramming language. The discussion is informal and incomplete at first, but gradually becomes more formal and more precise. In some cases, later chap- ters and Appendix A provide more details about the words first mentioned in this chapter; similarly, some tricks that will be dutifully explained in later chapters are already used here where appropriate. 2.1 List of Fift stack value types Currently, the values of the following data types can be kept in a Fift stack: •Integer— A signed 257-bit integer. Usually denoted byx,y, orzin the stack notation (when the stack effect of a Fift word is described). •Cell— A TVM cell, consisting of up to 1023 data bits and up to 4 references to other cells (cf. \[4\]). Usually denoted bycor its variants, such asc ′ orc 2 . •Slice— A partial view of a TVM cell, used for parsing data fromCells. Usually denoted bys. •Builder— A partially builtCell, containing up to 1023 data bits and up to four references; can be used to create newCells. Usually denoted byb. •Null— A type with exactly one “null” value. Used to initialize new Boxes. Usually denoted by⊥. •Tuple— An ordered collection of values of any of these types (not nec- essarily the same); can be used to represent values of arbitrary algebraic data types and Lisp-style lists. •String— A (usually printable) UTF-8 string. Usually denoted byS. 7 2.4. Simple integer arithmetic •Bytes— An arbitrary sequence of 8-bit bytes, typically used to repre- sent binary data. Usually denoted byB. •WordList— A (partially created) list of word references, used for cre- ating new Fift word definitions. Usually denoted byl. •WordDef— An execution token, usually representing the definition of an existing Fift word. Usually denoted bye. •Box— A location in memory that can be used to store one stack value. Usually denoted byp. •Atom— A simple entity uniquely identified by its name, a string. Can be used to represent identifiers, labels, operation names, tags, and stack markers. Usually denoted bya. •Object— An arbitrary C++ object of any class derived from base class td::CntObject; may be used by Fift extensions to manipulate other data types and interface with other C++ libraries. The first six types listed above are shared with TVM; the remainder are Fift-specific. Notice that not all TVM stack types are present in Fift. For instance, the TVMContinuationtype is not explicitly recognized by Fift; if a value of this type ends up in a Fift stack, it is manipulated as a generic Object. 2.2 Comments Fift recognizes two kinds of comments: “//” (which must be followed by a space) opens a single-line comment until the end of the line, and/\*defines a multi-line comment until\*/. Both words//and/\*are defined in the standard Fift library (Fift.fif). 2.3 Terminating Fift The wordbyeterminates the Fift interpreter with a zero exit code. If a non-zero exit code is required (for instance, in Fift scripts), one can use word halt, which terminates Fift with the given exit code (passed as anInteger at the top of the stack). In contrast,quitdoes not quit to the operating system, but rather exits to the top level of the Fift interpreter. 8 2.4. Simple integer arithmetic 2.4 Simple integer arithmetic When Fift encounters a word that is absent from the dictionary, but which can be interpreted as an integer constant (or “literal”), its value is pushed into the stack (as explained in2.8in more detail). Apart from that, several integer arithmetic primitives are defined: •+(x y–x+y), replaces twoIntegersxandypassed at the top of the stack with their sumx+y. All deeper stack elements remain intact. If eitherxoryis not anInteger, or if the sum does not fit into a signed 257-bitInteger, an exception is thrown. •-(x y–x−y), computes the differencex−yof twoIntegersxand y. Notice that the first argumentxis the second entry from the top of the stack, while the second argumentyis taken from the top of the stack. •negate(x–−x), changes the sign of anInteger. •\*(x y–xy), computes the productxyof twoIntegersxandy. •/(x y–q:=bx/yc), computes the floor-rounded quotientbx/ycof two Integers. •mod(x y–r:=xmody), computes the remainderxmody=x−y· bx/ycof division ofxbyy. •/mod(x y–q r), computes both the quotient and the remainder. •/c,/r(x y–q), division words similar to/, but using ceiling rounding (q:=dx/ye) and nearest-integer rounding (q:=b1/2 +x/yc), respec- tively. •/cmod,/rmod(x y–q r:=x−qy), division words similar to/mod, but using ceiling or nearest-integer rounding. •<<(x y–x·2 y ), computes an arithmetic left shift of binary numberx byy≥0positions, yieldingx·2 y . •>>(x y–q:=bx·2 −y c), computes an arithmetic right shift byy≥0 positions. 9 2.5. Stack manipulation words •>>c,>>r(x y–q), similar to>>, but using ceiling or nearest-integer rounding. •and,or,xor(x y–x⊕y), compute the bitwise AND, OR, or XOR of twoIntegers. •not(x–−1−x), bitwise complement of anInteger. •\*/(x y z–bxy/zc), “multiply-then-divide”: multiplies two integersx andyproducing a 513-bit intermediate result, then divides the product byz. •\*/mod(x y z–q r), similar to\*/, but computes both the quotient and the remainder. •\*/c,\*/r(x y z–q),\*/cmod,\*/rmod(x y z–q r), similar to\*/or \*/mod, but using ceiling or nearest-integer rounding. •\*>>,\*>>c,\*>>r(x y z–q), similar to\*/and its variants, but with division replaced with a right shift. Computeq=xy/2 z rounded in the indicated fashion (floor, ceiling, or nearest integer). •< nip -trailing0 } : (.GR) { (.GR) ."GR$" type space } : .GR -17239000000 .GR producesGR$-17.239 ok. The above definitions make use of tricks explained in later portions of this document (especially Chapter4). We can also manipulate fractions by themselves by defining suitable “ra- tional arithmetic words”: // a b c d -- (a\*d-b\*c) b\*d { -rot over \* 2swap tuck \* rot - -rot \* } : R- // a b c d -- a\*c b\*d { rot \* -rot \* swap } : R\* // a b -- { swap .\_ ."/" . } : R. 1.7 2/3 R- R. will output “31/30 ok”, indicating that1.7−2/3 = 31/30. Here “.\_” is a variant of “.” that does not print a space after the decimal representation of anInteger. 2.9 String literals String literals are introduced by means of the prefix word", which scans the remainder of the line until the next"character, and pushes the string thus obtained into the stack as a value of typeString. For instance,"Hello, world!"pushes the correspondingStringinto the stack: "Hello, world!" .s 16 2.10. Simple string manipulation 2.10 Simple string manipulation The following words can be used to manipulate strings: •"〈string〉"( –S), pushes aStringliteral into the stack. •."〈string〉"( – ), prints a constant string into the standard output. •type(S– ), prints aStringStaken from the top of the stack into the standard output. •cr( – ), outputs a carriage return (or a newline character) into the standard output. •emit(x– ), prints a UTF-8 encoded character with Unicode codepoint given byIntegerxinto the standard output. •char〈string〉( –x), pushes anIntegerwith the Unicode codepoint of the first character of〈string〉. •bl( –x), pushes the Unicode codepoint of a space, i.e., 32. •space( – ), prints one space, equivalent tobl emit. •$+(S S ′ –S.S ′ ), concatenates two strings. •$len(S–x), computes the byte length (not the UTF-8 character length!) of a string. •+"〈string〉"(S–S ′ ), concatenatesStringSwith a string literal. Equivalent to"〈string〉" $+. •word(x–S), parses a word delimited by the character with the Unicode codepointxfrom the remainder of the current input line and pushes the result as aString. For instance,bl word abracadabra typewill print the string “abracadabra”. Ifx= 0, skips leading spaces, and then scans until the end of the current input line. Ifx= 32, skips leading spaces before parsing the next word. •(.)(x–S), returns theStringwith the decimal representation of Integerx. 17 2.12. Integer comparison operations •(number)(S–0orx1orx y2), attempts to parse theStringSas an integer or fractional literal as explained in2.8. For instance,."\*","\*" type,42 emit, andchar \* emitare four different ways to output a single asterisk. 2.11 Boolean expressions, or flags Fift does not have a separate value type for representing boolean values. Instead, any non-zeroIntegercan be used to represent truth (with−1be- ing the standard representation), while a zeroIntegerrepresents falsehood. Comparison primitives normally return−1to indicate success and0other- wise. Constantstrueandfalsecan be used to push these special integers into the stack: •true( –−1), pushes−1into the stack. •false( –0), pushes0into the stack. If boolean values are standard (either0or−1), they can be manipulated by means of bitwise logical operationsand,or,xor,not(listed in2.4). Otherwise, they must first be reduced to the standard form using0<>: •0<>(x–x6= 0), pushes−1ifIntegerxis non-zero,0otherwise. 2.12 Integer comparison operations Several integer comparison operations can be used to obtain boolean values: •<(x y–?), checks whetherx < y(i.e., pushes−1ifx < y,0otherwise). •>,=,<>,<=,>=(x y–?), comparexandyand push−1or0depending on the result of the comparison. •0<(x–?), checks whetherx <0(i.e., pushes−1ifxis negative,0 otherwise). Equivalent to0 <. •0>,0=,0<>,0<=,0>=(x–?), comparexagainst zero. •cmp(x y–z), pushes1ifx > y,−1ifx < y, and0ifx=y. 18 2.14. Named and unnamed variables •sgn(x–y), pushes1ifx >0,−1ifx <0, and0ifx= 0. Equivalent to0 cmp. Example: 2 3 < . prints “-1 ok”, because2is less than3. A more convoluted example: { "true " "false " rot 0= 1+ pick type 2drop } : ?. 2 3 < ?. 2 3 = ?. 2 3 > ?. prints “true false false ok”. 2.13 String comparison operations Strings can be lexicographically compared by means of the following words: •$=(S S ′ –?), returns−1if stringsSandS ′ are equal,0otherwise. •$cmp(S S ′ –x), returns0if stringsSandS ′ are equal,−1ifSis lexicographically less thanS ′ , and1ifSis lexicographically greater thanS ′ . 2.14 Named and unnamed variables In addition to constants introduced in2.7, Fift supportsvariables, which are a more efficient way to represent changeable values. For instance, the last two code fragments of2.7could have been written with the aid of variables instead of constants as follows: variable x variable y { dup x ! dup \* y ! } : setxy 3 setxy x @ . y @ . x @ y @ + . 7 setxy x @ . y @ . x @ y @ + . { ."( " x @ . .", " y @ . .") " } : showxy 3 setxy showxy producing the same output as before: 19 2.14. Named and unnamed variables 3 9 12 ok 7 49 56 ok ( 3 , 9 ) ok The phrasevariable xcreates a newBox, i.e., a memory location that can be used to store exactly one value of any Fift-supported type, and defines xas a constant equal to thisBox: •variable( – ), scans a blank-delimited word nameSfrom the remain- der of the input, allocates an emptyBox, and defines a new ordinary wordSas a constant, which will push the newBoxwhen invoked. Equivalent tohole constant. •hole( –p), creates a newBoxpthat does not hold any value. Equiv- alent tonull box. •box(x–p), creates a newBoxcontaining specified valuex. Equivalent tohole tuck !. The value currently stored in aBoxmay be fetched by means of word@ (pronounced “fetch”), and modified by means of word!(pronounced “store”): •@(p–x), fetches the value currently stored inBoxp. •!(x p– ), stores new valuexintoBoxp. Several auxiliary words exist that can modify the current value in a more sophisticated fashion: •+!(x p– ), increases the integer value stored inBoxpbyIntegerx. Equivalent totuck @ + swap !. •1+!(p– ), increases the integer value stored inBoxpby one. Equiv- alent to1 swap +!. •0!(p– ), storesInteger0intoBoxp. Equivalent to0 swap !. In this way we can implement a simple counter: variable counter { counter 0! } : reset-counter { counter @ 1+ dup counter ! } : next-counter reset-counter next-counter . next-counter . next-counter . reset-counter next-counter . 20 2.14. Named and unnamed variables produces 1 2 3 ok 1 ok After these definitions are in place, we can even forget the definition of counterby means of the phraseforget counter. Then the only way to access the value of this variable is by means ofreset-counterand next-counter. Variables are usually created byvariablewith no value, or rather with aNullvalue. If one wishes to create initialized variables, one can use the phrasebox constant: 17 box constant x x 1+! x @ . prints “18 ok”. One can even define a special defining word for initialized variables, if they are needed often: { box constant } : init-variable 17 init-variable x "test" init-variable y x 1+! x @ . y @ type prints “18 test ok”. The variables have so far only one disadvantage compared to the con- stants: one has to access their current values by means of an auxiliary word @. Of course, one can mitigate this by defining a “getter” and a “setter” word for a variable, and use these words to write better-looking code: variable x-box { x-box @ } : x { x-box ! } : x! { x x \* 5 x \* + 6 + } : f(x) { ."( " x . .", " f(x) . .") " } : .xy 3 x! .xy 5 x! .xy prints “( 3 , 30 ) ( 5 , 56 ) ok”, which are the points(x,f(x))on the graph off(x) =x 2 + 5x+ 6withx= 3andx= 5. Again, if we want to define “getters” for all our variables, we can first define a defining word as explained in4.8, and use this word to define both a getter and a setter at the same time: 21 2.15. Tuples and arrays { hole dup 1 ’ @ does create 1 ’ ! does create } : variable-set variable-set x x! variable-set y y! { ."x=" x . ."y=" y . ."x\*y=" x y \* . cr } : show { y 1+ y! } : up { x 1+ x! } : right { x y x! y! } : reflect 2 x! 5 y! show up show right show up show reflect show produces x=2 y=5 x\*y=10 x=2 y=6 x\*y=12 x=3 y=6 x\*y=18 x=3 y=7 x\*y=21 x=7 y=3 x\*y=21 2.15 Tuples and arrays Fift also supportsTuples, i.e., immutable ordered collections of arbitrary values of stack value types (cf.2.1). When aTupletconsists of valuesx 1 , . . . ,x n (in that order), we writet= (x 1 ,...,x n ). The numbernis called thelengthofTuplet; it is also denoted by|t|. Tuples of length two are also calledpairs, tuples of length three aretriples. •tuple(x 1 . . .x n n–t), creates newTuplet:= (x 1 ,...,x n )fromn≥0 topmost stack values. •pair(x y–t), creates new pairt= (x,y). Equivalent to2 tuple. •triple(x y z–t), creates new triplet= (x,y,z). Equivalent to3 tuple. •|( –t), creates an emptyTuplet= (). Equivalent to0 tuple. •,(t x–t ′ ), appendsxto the end ofTuplet, and returns the resulting Tuplet ′ . •.dump(x– ), dumps the topmost stack entry in the same way as.s dumps all stack elements. 22 2.15. Tuples and arrays For instance, both | 2 , 3 , 9 , .dump and 2 3 9 triple .dump construct and print triple(2,3,9): \[ 2 3 9 \] ok Notice that the components of aTupleare not necessarily of the same type, and that a component of aTuplecan also be aTuple: 1 2 3 triple 4 5 6 triple 7 8 9 triple triple constant Matrix Matrix .dump cr | 1 "one" pair , 2 "two" pair , 3 "three" pair , .dump produces \[ \[ 1 2 3 \] \[ 4 5 6 \] \[ 7 8 9 \] \] \[ \[ 1 "one" \] \[ 2 "two" \] \[ 3 "three" \] \] ok Once aTuplehas been constructed, we can extract any of its components, or completely unpack theTupleinto the stack: •untuple(t n–x 1 . . .x n ), returns all components of aTuplet= (x 1 ,...,x n ), but only if its length is equal ton. Otherwise throws an exception. •unpair(t–x y), unpacks a pairt= (x,y). Equivalent to2 untuple. •untriple(t–x y z), unpacks a triplet= (x,y,z). Equivalent to3 untuple. •explode(t–x 1 . . .x n n), unpacks aTuplet= (x 1 ,...,x n )of unknown lengthn, and returns that length. •count(t–n), returns the lengthn=|t|ofTuplet. •tuple?(t–?), checks whethertis aTuple, and returns−1or0 accordingly. 23 2.15. Tuples and arrays •\[\](t i–x), returns the(i+ 1)-st componentt i+1 ofTuplet, where 0≤i <|t|. •first(t–x), returns the first component of aTuple. Equivalent to0 \[\]. •second(t–x), returns the second component of aTuple. Equivalent to1 \[\]. •third(t–x), returns the third component of aTuple. Equivalent to 2 \[\]. For instance, we can access individual elements and rows of a matrix: 1 2 3 triple 4 5 6 triple 7 8 9 triple triple constant Matrix Matrix .dump cr Matrix 1 \[\] 2 \[\] . cr Matrix third .dump cr produces \[ \[ 1 2 3 \] \[ 4 5 6 \] \[ 7 8 9 \] \] 6 \[ 7 8 9 \] Notice thatTuples are somewhat similar to arrays of other programming languages, but are immutable: we cannot change one individual component of aTuple. If we still want to create something like an array, we need aTuple ofBoxes (cf.2.14): •allot(n–t), creates aTuplethat consists ofnnew emptyBoxes. Equivalent to| { hole , } rot times. For instance, 10 allot constant A | 3 box , 1 box , 4 box , 1 box , 5 box , 9 box , constant B { over @ over @ swap rot ! swap ! } : swap-values-of { B swap \[\] } : B\[\] { B\[\] swap B\[\] swap-values-of } : swap-B { B\[\] @ . } : .B\[\] 0 1 swap-B 1 3 swap-B 0 2 swap-B 0 .B\[\] 1 .B\[\] 2 .B\[\] 3 .B\[\] 24 2.16. Lists creates an uninitialized arrayAof length 10, an initialized arrayBof length 6, and then interchanges some elements ofBand prints the first four elements of the resultingB: 4 1 1 3 ok 2.16 Lists Lisp-style lists can also be represented in Fift. First of all, two special words are introduced to manipulate values of typeNull, used to represent the empty list (not to be confused with the emptyTuple): •null( –⊥), pushes the only value⊥of typeNull, which is also used to represent an empty list. •null?(x–?), checks whetherxis aNull. Can also be used to check whether a list is empty. After that,consandunconsare defined as aliases forpairandunpair: •cons(h t–l), constructs a list from its head (first element)hand its tail (the list consisting of all remaining elements)t. Equivalent to pair. •uncons(l–h t), decomposes a non-empty list into its head and its tail. Equivalent tounpair. •car(l–h), returns the head of a list. Equivalent tofirst. •cdr(l–t), returns the tail of a list. Equivalent tosecond. •cadr(l–h ′ ), returns the second element of a list. Equivalent tocdr car. •list(x 1 . . .x n n–l), constructs a listlof lengthnwith elementsx 1 , . . . ,x n , in that order. Equivalent tonull ’ cons rot times. •.l(l– ), prints a Lisp-style listl. For instance, 25 2.17. Atoms 2 3 9 3 tuple .dump cr 2 3 9 3 list dup .dump space dup .l cr "test" swap cons .l cr produces \[ 2 3 9 \] \[ 2 \[ 3 \[ 9 (null) \] \] \] (2 3 9) ("test" 2 3 9) Notice that the three-element list(2 3 9)is distinct from the triple(2,3,9). 2.17 Atoms AnAtomis a simple entity uniquely identified by its name.Atoms can be used to represent identifiers, labels, operation names, tags, and stack markers. Fift offers the following words to manipulateAtoms: •(atom)(S x–a−1or0), returns the onlyAtomawith the name given byStringS. If there is no suchAtomyet, either creates it (ifIntegerx is non-zero) or returns a single zero to indicate failure (ifxis zero). •atom(S–a), returns the onlyAtomawith the nameS, creating such an atom if necessary. Equivalent totrue (atom) drop. •‘〈word〉( –a), introduces anAtomliteral, equal to the onlyAtom with the name equal to〈word〉. Equivalent to"〈word〉" atom. •anon( –a), creates a new unique anonymousAtom. •atom?(u–?), checks whetheruis anAtom. •eq?(u v–?), checks whetheruandvare equalIntegers,Atoms, or Nulls. If they are not equal, or if they are of different types, or not of one of the types listed, returns zero. For instance, ‘+ 2 ‘\* 3 4 3 list 3 list .l creates and prints the list 26 2.18. Command line arguments in script mode (+ 2 (\* 3 4)) which is the Lisp-style representation of arithmetical expression2 + 3·4. An interpreter for such expressions might useeq?to check the operation sign (cf.3.5for an explanation of recursive functions in Fift): variable ’eval { ’eval @ execute } : eval { dup tuple? { uncons uncons uncons null? not abort"three-element list expected" swap eval swap eval rot dup ‘+ eq? { drop + } { dup ‘- eq? { drop - } { ‘\* eq? not abort"unknown operation" \* } cond } cond } if } ’eval ! ‘+ 2 ‘\* 3 4 3 list 3 list dup .l cr eval . cr prints (+ 2 (\* 3 4)) 14 If we loadLisp.fifto enable Lisp-style list syntax, we can enter "Lisp.fif" include ( ‘+ 2 ( ‘\* 3 4 ) ) dup .l cr eval . cr with the same result as before. The word(, defined inLisp.fif, uses an anonymousAtomcreated byanonto mark the current stack position, and then)builds a list from several top stack entries, scanning the stack until the anonymousAtommarker is found: variable ’) { ") without (" abort } ’) ! { ’) @ execute } : ) { null { -rot 2dup eq? not } { swap rot cons } while 2drop } : list-until-marker { anon dup ’) @ 2 { ’) ! list-until-marker } does ’) ! } : ( 27 Chapter3.Blocks, loops, and conditionals 2.18 Command line arguments in script mode The Fift interpreter can be invoked inscript modeby passing-sas a com- mand line option. In this mode, all further command line arguments are not scanned for Fift startup command line options. Rather, the next argu- ment after-sis used as the filename of the Fift source file, and all further command line arguments are passed to the Fift program by means of special words$nand$#: •$#( –x), pushes the total number of command-line arguments passed to the Fift program. •$n( –S), pushes then-th command-line argument as aStringS. For instance,$0pushes the name of the script being executed,$1the first command line argument, and so on. •$()(x–S), pushes thex-th command-line argument similarly to$n, but withIntegerxtaken from the stack. Additionally, if the very first line of a Fift source file begins with the two characters “#!”, this line is ignored. In this way simple Fift scripts can be written in a \*ix system. For instance, if #!/usr/bin/fift -s { ."usage: " $0 type ." " cr ."Computes the product of two integers." cr 1 halt } : usage { ’ usage if } : ?usage $# 2 <> ?usage $1 (number) 1- ?usage $2 (number) 1- ?usage \* . cr is saved into a filecmdline.fifin the current directory, and its execu- tion bit is set (e.g., bychmod 755 cmdline.fif), then it can be invoked from the shell or any other program, provided the Fift interpreter is in- stalled as/usr/bin/fift, and its standard libraryFift.fifis installed as /usr/lib/fift/Fift.fif: $ ./cmdline.fif 12 -5 prints -60 when invoked from a \*ix shell such as the Bourne–again shell (Bash). 28 3.2. Conditional execution of blocks 3 Blocks, loops, and conditionals Similarly to the arithmetic operations, the execution flow in Fift is controlled by stack-based primitives. This leads to an inversion typical of reverse Polish notation and stack-based arithmetic: one first pushes a block representing a conditional branch or the body of a loop into the stack, and then invokes a conditional or iterated execution primitive. In this respect, Fift is more similar to PostScript than to Forth. 3.1 Defining and executing blocks A block is normally defined using the special words “{” and “}”. Roughly speaking, all words listed between{and}constitute the body of a new block, which is pushed into the stack as a value of typeWordDef. A block may be stored as a definition of a new Fift word by means of the defining word “:” as explained in2.6, or executed by means of the wordexecute: 17 { 2 \* } execute . prints “34 ok”, being essentially equivalent to “17 2 \* .”. A slightly more convoluted example: { 2 \* } 17 over execute swap execute . applies “anonymous function”x7→2xtwice to17, and prints the result 2·(2·17) = 68. In this way a block is an execution token, which can be duplicated, stored into a constant, used to define a new word, or executed. The word’recovers the current definition of a word. Namely, the con- struct’〈word-name〉pushes the execution token equivalent to the current definition of the word〈word-name〉. For instance, ’ dup execute is equivalent todup, and ’ dup : duplicate definesduplicateas a synonym for (the current definition of)dup. Alternatively, we can duplicate a block to define two new words with the same definition: { dup \* } dup : square : \*\*2 defines bothsquareand\*\*2to be equivalent todup \*. 29 3.3. Simple loops 3.2 Conditional execution of blocks Conditional execution of blocks is achieved using the wordsif,ifnot, and cond: •if(x e– ), executese(which must be an execution token, i.e., a WordDef), 5 but only ifIntegerxis non-zero. •ifnot(x e– ), executes execution tokene, but only ifIntegerxis zero. •cond(x e e ′ – ), ifIntegerxis non-zero, executese, otherwise executes e ′ . For instance, the last example in2.12can be more conveniently rewritten as { { ."true " } { ."false " } cond } : ?. 2 3 < ?. 2 3 = ?. 2 3 > ?. still resulting in “true false false ok”. Notice that blocks can be arbitrarily nested, as already shown in the previous example. One can write, for example, { ?dup { 0< { ."negative " } { ."positive " } cond } { ."zero " } cond } : chksign -17 chksign to obtain “negative ok”, because−17is negative. 5 AWordDefis more general than aWordList. For instance, the definition of the primitive+is aWordDef, but not aWordList, because+is not defined in terms of other Fift words. 30 3.4. Loops with an exit condition 3.3 Simple loops The simplest loops are implemented bytimes: •times(e n– ), executeseexactlyntimes, ifn≥0. Ifnis negative, throws an exception. For instance, 1 { 10 \* } 70 times . computes and prints10 70 . We can use this kind of loop to implement a simple factorial function: { 0 1 rot { swap 1+ tuck \* } swap times nip } : fact 5 fact . prints “120 ok”, because5! = 1·2·3·4·5 = 120. This loop can be modified to compute Fibonacci numbers instead: { 0 1 rot { tuck + } swap times nip } : fibo 6 fibo . computes the sixth Fibonacci numberF 6 = 13. 3.4 Loops with an exit condition More sophisticated loops can be created with the aid ofuntilandwhile: •until(e– ), executese, then removes the top-of-stack integer and checks whether it is zero. If it is, then begins a new iteration of the loop by executinge. Otherwise exits the loop. •while(e e ′ – ), executese, then removes and checks the top-of-stack integer. If it is zero, exits the loop. Otherwise executese ′ , then begins a new loop iteration by executingeand checking the exit condition afterwards. For instance, we can compute the first two Fibonacci numbers greater than 1000: { 1 0 rot { -rot over + swap rot 2dup >= } until drop } : fib-gtr 1000 fib-gtr . . 31 3.5. Recursion prints “1597 2584 ok”. We can use this word to compute the first 70 decimal digits of the golden ratioφ= (1 + √ 5)/2≈1.61803: 1 { 10 \* } 70 times dup fib-gtr \*/ . prints “161803...2604ok”. 3.5 Recursion Notice that, whenever a word is mentioned inside a{ ...}block, the current (compile-time) definition is included in theWordListbeing created. In this way we can refer to the previous definition of a word while defining a new version of it: { + . } : print-sum { ."number " . } : . { 1+ . } : print-next 2 . 3 . 2 3 print-sum 7 print-next produces “number 2 number 3 5 number 8 ok”. Notice thatprint-sum continues to use the original definition of “.”, butprint-nextalready uses the modified “.”. This feature may be convenient on some occasions, but it prevents us from introducing recursive definitions in the most straightforward fashion. For instance, the classical recursive definition of the factorial { ?dup { dup 1- fact \* } { 1 } cond } : fact will fail to compile, becausefacthappens to be an undefined word when the definition is compiled. A simple way around this obstacle is to use the word@’(cf.4.6) that looks up the current definition of the next word during the execution time and then executes it, similarly to what we already did in2.7: { ?dup { dup 1- @’ fact \* } { 1 } cond } : fact 5 fact . produces “120 ok”, as expected. However, this solution is rather inefficient, because it uses a dictionary lookup each timefactis recursively executed. We can avoid this dictionary lookup by using variables (cf.2.14and2.7): 32 3.5. Recursion variable ’fact { ’fact @ execute } : fact { ?dup { dup 1- fact \* } { 1 } cond } ’fact ! 5 fact . This somewhat longer definition of the factorial avoids dictionary lookups at execution time by introducing a special variable’factto hold the final def- inition of the factorial. 6 Thenfactis defined to execute whateverWordDef is currently stored in’fact, and once the body of the recursive definition of the factorial is constructed, it is stored into this variable by means of the phrase’fact !, which replaces the more customary phrase: fact. We could rewrite the above definition by using special “getter” and “setter” words for vector variable’factas we did for variables in2.14: variable ’fact { ’fact @ execute } : fact { ’fact ! } : :fact forget ’fact { ?dup { dup 1- fact \* } { 1 } cond } :fact 5 fact . If we need to introduce a lot of recursive and mutually-recursive definitions, we might first introduce a custom defining word (cf.4.8) for simultaneously defining both the “getter” and the “setter” words for anonymous vector vari- ables, similarly to what we did in2.14: { hole dup 1 { @ execute } does create 1 ’ ! does create } : vector-set vector-set fact :fact { ?dup { dup 1- fact \* } { 1 } cond } :fact 5 fact . The first three lines of this fragment definefactand:factessentially in the same way they had been defined in the first four lines of the previous fragment. If we wish to makefactunchangeable in the future, we can add aforget :factline once the definition of the factorial is complete: 6 Variables that hold aWordDefto beexecuted later are calledvector variables. The process of replacingfactwith’fact @ execute, where’factis a vector variable, is calledvectorization. 33 3.5. Recursion { hole dup 1 { @ execute } does create 1 ’ ! does create } : vector-set vector-set fact :fact { ?dup { dup 1- fact \* } { 1 } cond } :fact forget :fact 5 fact . Alternatively, we can modify the definition ofvector-setin such a way that :factwould forget itself once it is invoked: { hole dup 1 { @ execute } does create bl word tuck 2 { (forget) ! } does swap 0 (create) } : vector-set-once vector-set-once fact :fact { ?dup { dup 1- fact \* } { 1 } cond } :fact 5 fact . However, some vector variables must be modified more than once, for instance, to modify the behavior of the comparison wordlessin a merge sort algorithm: { hole dup 1 { @ execute } does create 1 ’ ! does create } : vector-set vector-set sort :sort vector-set merge :merge vector-set less :less { null null rot { dup null? not } { uncons swap rot cons -rot } while drop } : split { dup null? { drop } { over null? { nip } { over car over car less ’ swap if uncons rot merge cons } cond } cond } :merge { dup null? { dup cdr null? { 34 3.6. Throwing exceptions split sort swap sort merge } ifnot } ifnot } :sort forget :merge forget :sort // set ‘less‘ to compare numbers, sort a list of numbers ’ < :less 3 1 4 1 5 9 2 6 5 9 list dup .l cr sort .l cr // set ‘less‘ to compare strings, sort a list of strings { $cmp 0< } :less "once" "upon" "a" "time" "there" "lived" "a" "kitten" 8 list dup .l cr sort .l cr producing the following output: (3 1 4 1 5 9 2 6 5) (1 1 2 3 4 5 5 6 9) ("once" "upon" "a" "time" "there" "lived" "a" "kitten") ("a" "a" "kitten" "lived" "once" "there" "time" "upon") 3.6 Throwing exceptions Two built-in words are used to throw exceptions: •abort(S– ), throws an exception with an error message taken from StringS. •abort"〈message〉"(x– ), throws an exception with the error message 〈message〉ifxis a non-zero integer. The exception thrown by these words is represented by the C++ exception fift::IntErrorwith its value equal to the specified string. It is normally handled within the Fift interpreter itself by aborting all execution up to the top level and printing a message with the name of the source file being interpreted, the line number, the currently interpreted word, and the specified error message. For instance: { dup 0= abort"Division by zero" / } : safe/ 5 0 safe/ . 35 4.1. The state of the Fift interpreter prints “safe/: Division by zero”, without the usual “ok”. The stack is cleared in the process. Incidentally, when the Fift interpreter encounters an unknown word that cannot be parsed as an integer literal, an exception with the message “-?” is thrown, with the effect indicated above, including the stack being cleared. 4 Dictionary, interpreter, and compiler In this chapter we present several specific Fift words for dictionary manipu- lation and compiler control. The “compiler” is the part of the Fift interpreter that builds lists of word references (represented byWordListstack values) from word names; it is activated by the primitive “{” employed for defining blocks as explained in2.6and3.1. Most of the information included in this chapter is rather sophisticated and may be skipped during a first reading. However, the techniques described here are heavily employed by the Fift assembler, used to compile TVM code. Therefore, this section is indispensable if one wishes to understand the cur- rent implementation of the Fift assembler. 4.1 The state of the Fift interpreter The state of the Fift interpreter is controlled by an internal integer variable calledstate, currently unavailable from Fift itself. Whenstateis zero, all words parsed from the input (i.e., the Fift source file or the standard input in the interactive mode) are looked up in the dictionary and immedi- ately executed afterwards. Whenstateis positive, the words found in the dictionary are not executed. Instead, they (or rather the references to their current definitions) arecompiled, i.e., added to the end of theWordListbeing constructed. Typically,stateequals the number of the currently open blocks. For instance, after interpreting “{ 0= { ."zero"” thestatevariable will be equal to two, because there are two nested blocks. TheWordListbeing constructed is kept at the top of the stack. The primitive “{” simply pushes a new emptyWordListinto the stack, and increasesstateby one. The primitive “}” throws an exception ifstate is already zero; otherwise it decreasesstateby one, and leaves the resulting 36 4.3. Compiling literals WordListin the stack, representing the block just constructed. 7 After that, if the resulting value ofstateis non-zero, the new block is compiled as a literal (unnamed constant) into the encompassing block. 4.2 Active and ordinary words All dictionary words have a special flag indicating whether they areactive words orordinarywords. By default, all words are ordinary. In particular, all words defined with the aid of “:” andconstantare ordinary. When the Fift interpreter finds a word definition in the dictionary, it checks whether it is an ordinary word. If it is, then the current word definition is either executed (ifstateis zero) or “compiled” (ifstateis greater than zero) as explained in4.1. On the other hand, if the word is active, then it is always executed, even ifstateis positive. An active word is expected to leave some valuesx 1 . . .x n n ein the stack, wheren≥0is an integer,x 1 ...x n arenvalues of arbitrary types, andeis an execution token (a value of typeWordDef). After that, the interpreter performs different actions depending onstate: ifstateis zero, thennis discarded andeis executed, as if anip executephrase were found. Ifstateis non-zero, then this collection is “compiled” in the current WordList(located immediately belowx 1 in the stack) in the same way as if the(compile)primitive were invoked. This compilation amounts to adding some code to the end of the currentWordListthat would pushx 1 , . . . ,x n into the stack when invoked, and then adding a reference toe(representing a delayed execution ofe). Ifeis equal to the special value’nop, representing an execution token that does nothing when executed, then this last step is omitted. 4.3 Compiling literals When the Fift interpreter encounters a word that is absent from the dictio- nary, it invokes the primitive(number)to attempt to parse it as an integer or fractional literal. If this attempt succeeds, then the special value’nopis pushed, and the interpretation proceeds in the same way as if an active word 7 The word}also transforms thisWordListinto aWordDef, which has a different type tag and therefore is a different Fift value, even if the same underlying C++ object is used by the C++ implementation. 37 4.5. Defining words and dictionary manipulation were encountered. In other words, ifstateis zero, then the literal is sim- ply left in the stack; otherwise,(compile)is invoked to modify the current WordListso that it would push the literal when executed. 4.4 Defining new active words New active words are defined similarly to new ordinary words, but using “::” instead of “:”. For instance, { bl word 1 ’ type } :: say defines the active wordsay, which scans the next blank-separated word after itself and compiles it as a literal along with a reference to the current defini- tion oftypeinto the currentWordList(ifstateis non-zero, i.e., if the Fift interpreter is compiling a block). When invoked, this addition to the block will push the stored string into the stack and executetype, thus printing the next word aftersay. On the other hand, ifstateis zero, then these two actions are performed by the Fift interpreter immediately. In this way, 1 2 say hello + . will print “hello3 ok”, while { 2 say hello + . } : test 1 test 4 test will print “hello3 hello6 ok”. Of course, a block may be used to represent the required action instead of’ type. For instance, if we want a version ofsaythat prints a space after the stored word, we can write { bl word 1 { type space } } :: say { 2 say hello + . } : test 1 test 4 test to obtain “hello 3 hello 6 ok”. Incidentally, the words"(introducing a string literal) and."(printing a string literal) can be defined as follows: { char " word 1 ’nop } ::\_ " { char " word 1 ’ type } ::\_ ." The new defining word “::\_” defines an activeprefixword, i.e., an active word that does not require a space afterwards. 38 4.5. Defining words and dictionary manipulation 4.5 Defining words and dictionary manipulation Defining wordsare words that define new words in the Fift dictionary. For instance, “:”, “::\_”, andconstantare defining words. All of these defining words might have been defined using the primitive(create); in fact, the user can introduce custom defining words if so desired. Let us list some defining words and dictionary manipulation words: •create〈word-name〉(e– ), defines a new ordinary word with the name equal to the next word scanned from the input, usingWordDefeas its definition. If the word already exists, it is tacitly redefined. •(create)(e S x– ), creates a new word with the name equal toString Sand definition equal toWordDefe, using flags passed inInteger 0≤x≤3. If bit+1is set inx, creates an active word; if bit+2is set inx, creates a prefix word. •:〈word-name〉(e– ), defines a new ordinary word〈word-name〉in the dictionary usingWordDefeas its definition. If the specified word is already present in the dictionary, it is tacitly redefined. •forget〈word-name〉( – ), forgets (removes from the dictionary) the definition of the specified word. •(forget)(S– ), forgets the word with the name specified inStringS. If the word is not found, throws an exception. •:\_〈word-name〉(e– ), defines a new ordinaryprefixword〈word-name〉, meaning that a blank or an end-of-line character is not required by the Fift input parser after the word name. In all other respects it is similar to “:”. •::〈word-name〉(e– ), defines a newactiveword〈word-name〉in the dictionary usingWordDefeas its definition. If the specified word is already present in the dictionary, it is tacitly redefined. •::\_〈word-name〉(e– ), defines a new activeprefixword〈word-name〉, meaning that a blank or an end-of-line character is not required by the Fift input parser after the word name. In all other respects it is similar to “::”. 39 4.6. Dictionary lookup •constant〈word-name〉(x– ), defines a new ordinary word〈word-name〉 that would push the given valuexwhen invoked. •2constant〈word-name〉(x y– ), defines a new ordinary word named 〈word-name〉that would push the given valuesxandy(in that order) when invoked. •=:〈word-name〉(x– ), defines a new ordinary word〈word-name〉that would push the given valuexwhen invoked, similarly toconstant, but works inside blocks and colon definitions. •2=:〈word-name〉(x y– ), defines a new ordinary word〈word-name〉 that would push the given valuesxandy(in that order) when invoked, similarly to2constant, but works inside blocks and colon definitions. Notice that most of the above words might have been defined in terms of (create): { bl word 1 2 ’ (create) } "::" 1 (create) { bl word 0 2 ’ (create) } :: : { bl word 2 2 ’ (create) } :: :\_ { bl word 3 2 ’ (create) } :: ::\_ { bl word 0 (create) } : create { bl word (forget) } : forget 4.6 Dictionary lookup The following words can be used to look up words in the dictionary: •’〈word-name〉( –e), pushes the definition of the word〈word-name〉, recovered at the compile time. If the indicated word is not found, throws an exception. Notice that’〈word-name〉executeis always equivalent to〈word-name〉for ordinary words, but not for active words. •nop( – ), does nothing. •’nop( –e), pushes the default definition ofnop—an execution token that does nothing when executed. •find(S–e−1ore1or0), looks upStringSin the dictionary and returns its definition as aWordDefeif found, followed by−1for ordinary words or1for active words. Otherwise pushes0. 40 4.7. Creating and manipulating word lists •(’)〈word-name〉( –e), similar to’, but returns the definition of the specified word at execution time, performing a dictionary lookup each time it is invoked. May be used to recover current values of con- stants inside word definitions and other blocks by using the phrase(’) 〈word-name〉execute. •@’〈word-name〉( –e), similar to(’), but recovers the definition of the specified word at execution time, performing a dictionary lookup each time it is invoked, and then executes this definition. May be used to recover current values of constants inside word definitions and other blocks by using the phrase@’〈word-name〉, equivalent to(’) 〈word-name〉execute, cf.2.7. •\[compile\]〈word-name〉( – ), compiles〈word-name〉as if it were an or- dinary word, even if it is active. Essentially equivalent to’〈word-name〉 execute. •words( – ), prints the names of all words currently defined in the dictionary. 4.7 Creating and manipulating word lists In the Fift stack, lists of references to word definitions and literals, to be used as blocks or word definitions, are represented by the values of the type WordList. Some words for manipulatingWordLists include: •{( –l), an active word that increases internal variablestateby one and pushes a new emptyWordListinto the stack. •}(l–e), an active word that transforms aWordListlinto aWord- Def(an execution token)e, thus making all further modifications ofl impossible, and decreases internal variablestateby one and pushes the integer1, followed by a’nop. The net effect is to transform the constructedWordListinto an execution token and push this execution token into the stack, either immediately or during the execution of an outer block. •({)( –l), pushes an emptyWordListinto the stack. •(})(l–e), transforms aWordListinto an execution token, making all further modifications impossible. 41 4.8. Custom defining words •(compile)(l x 1 . . .x n n e–l ′ ), extendsWordListlso that it would push0≤n≤255valuesx 1 , . . . ,x n into the stack and execute the execution tokenewhen invoked, where0≤n≤255is anInteger. Ife is equal to the special value’nop, the last step is omitted. •does(x 1 . . .x n n e–e ′ ), creates a new execution tokene ′ that would pushnvaluesx 1 , . . . ,x n into the stack and then executee. It is roughly equivalent to a combination of({),(compile), and(}). 4.8 Custom defining words The worddoesis actually defined in terms of simpler words: { swap ({) over 2+ -roll swap (compile) (}) } : does It is especially useful for defining custom defining words. For instance, constantand2constantmay be defined with the aid ofdoesandcreate: { 1 ’nop does create } : constant { 2 ’nop does create } : 2constant Of course, non-trivial actions may be performed by the words defined by means of such custom defining words. For instance, { 1 { type space } does create } : says "hello" says hello "unknown error" says error { hello error } : test test will print “hello unknown error ok”, becausehellois defined by means of a custom defining wordsaysto print “hello” whenever invoked, and similarlyerrorprints “unknown error” when invoked. The above definitions are essentially equivalent to { ."hello" } : hello { ."unknown error" } : error However, custom defining words may perform more sophisticated actions when invoked, and preprocess their arguments at compile time. For instance, the message can be computed in a non-trivial fashion: 42 5.1. Slice literals "Hello, " "world!" $+ says hw defines wordhw, which prints “Hello, world!” when invoked. The string with this message is computed once at compile time (whensaysis invoked), not at execution time (whenhwis invoked). 5 Cell manipulation We have discussed the basic Fift primitives not related to TVM or the TON Blockchain so far. Now we will turn to TON-specific words, used to manip- ulateCells. 5.1 Slice literals Recall that a (TVM)Cellconsists of at most 1023 data bits and at most four references to otherCells, aSliceis a read-only view of a portion of aCell, and aBuilderis used to create newCells. Fift has special provisions for defining Sliceliterals (i.e., unnamed constants), which can also be transformed into Cellsif necessary. Sliceliterals are introduced by means of active prefix wordsx{andb{: •b{〈binary-data〉}( –s), creates aSlicesthat contains no references and up to 1023 data bits specified in〈binary-data〉, which must be a string consisting only of the characters ‘0’ and ‘1’. •x{〈hex-data〉}( –s), creates aSlicesthat contains no references and up to 1023 data bits specified in〈hex-data〉. More precisely, each hex digit from〈hex-data〉is transformed into four binary digits in the usual fashion. After that, if the last character of〈hex-data〉is an underscore\_, then all trailing binary zeroes and the binary one immediately preceding them are removed from the resulting binary string (cf. \[4, 1.0\] for more details). In this way,b{00011101}andx{1d}both push the sameSliceconsisting of eight data bits and no references. Similarly,b{111010}andx{EA\_}push the sameSliceconsisting of six data bits. An emptySlicecan be represented as b{}orx{}. If one wishes to define constantSlices with someCellreferences, the following words might be used: 43 5.2. Builder primitives •|\_(s s ′ –s ′′ ), given twoSlicessands ′ , creates a newSlices ′′ , which is obtained fromsby appending a new reference to aCellcontainings ′ . •|+(s s ′ –s ′′ ), concatenates twoSlicessands ′ . This means that the data bits of the newSlices ′′ are obtained by concatenating the data bits ofsands ′ , and the list ofCellreferences ofs ′′ is constructed similarly by concatenating the corresponding lists forsands ′ . 5.2 Builder primitives The following words can be used to manipulateBuilders, which can later be used to construct newCells: •(b–c), transforms aBuilderbinto a newCellccontaining the same data asb. •i,(b x y–b ′ ), appends the big-endian binary representation of a signed y-bit integerxtoBuilderb, where0≤y≤257. If there is not enough room inb(i.e., ifbalready contains more than1023−ydata bits), or ifIntegerxdoes not fit intoybits, an exception is thrown. •u,(b x y–b ′ ), appends the big-endian binary representation of an unsignedy-bit integerxtoBuilderb, where0≤y≤256. If the operation is impossible, an exception is thrown. •ref,(b c–b ′ ), appends toBuilderba reference toCellc. Ifbalready contains four references, an exception is thrown. •s,(b s–b ′ ), appends data bits and references taken fromSlicesto Builderb. •sr,(b s–b ′ ), constructs a newCellcontaining all data and refer- ences fromSlices, and appends a reference to this cell toBuilderb. Equivalent to ref,. •$,(b S–b ′ ), appendsStringStoBuilderb. The string is interpreted as a binary string of length8n, wherenis the number of bytes in the UTF-8 representation ofS. 44 5.2. Builder primitives •B,(b B–b ′ ), appendsBytesBtoBuilderb. •b+(b b ′ –b ′′ ), concatenates twoBuildersbandb ′ . •bbits(b–x), returns the number of data bits already stored inBuilderb. The resultxis anIntegerin the range0...1023. •brefs(b–x), returns the number of references already stored in Builderb. The resultxis anIntegerin the range0...4. •bbitrefs(b–x y), returns both the number of data bitsxand the number of referencesyalready stored inBuilderb. •brembits(b–x), returns the maximum number of additional data bits that can be stored inBuilderb. Equivalent tobbits 1023 swap -. •bremrefs(b–x), returns the maximum number of additional cell ref- erences that can be stored inBuilderb. •brembitrefs(b–x y), returns both the maximum number of additional data bits0≤x≤1023and the maximum number of additional cell references0≤y≤4that can be stored inBuilderb. The resultingBuildermay be inspected by means of the non-destructive stack dump primitive.s, or by the phraseb> } : mkTest 17239 -1000000001 mkTest (s– ), throws an exception ifSlicesis non-empty. It usually marks the end of the deserialization of a cell, checking whether there are any unprocessed data bits or references left. •i@(s x–y), fetches a signed big-endianx-bit integer from the first xbits ofSlices. Ifscontains less thanxdata bits, an exception is thrown. •i@+(s x–y s ′ ), fetches a signed big-endianx-bit integer from the first xbits ofSlicessimilarly toi@, but returns the remainder ofsas well. •i@?(s x–y−1or0), fetches a signed integer from aSlicesimilarly to i@, but pushes integer−1afterwards on success. If there are less than xbits left ins, pushes integer0to indicate failure. •i@?+(s x–y s ′ −1ors0), fetches a signed integer fromSlicesand computes the remainder of thisSlicesimilarly toi@+, but pushes−1 afterwards to indicate success. On failure, pushes the unchangedSlices and0to indicate failure. •u@,u@+,u@?,u@?+, counterparts ofi@,i@+,i@?,i@?+for deserializing unsigned integers. 46 5.3. Slice primitives •B@(s x–B), fetches firstxbytes (i.e.,8xbits) fromSlices, and returns them as aBytesvalueB. If there are not enough data bits ins, throws an exception. •B@+(s x–B s ′ ), similar toB@, but returns the remainder ofSlicesas well. •B@?(s x–B−1or0), similar toB@, but uses a flag to indicate failure instead of throwing an exception. •B@?+(s x–B s ′ −1ors0), similar toB@+, but uses a flag to indicate failure instead of throwing an exception. •$@,$@+,$@?,$@?+, counterparts ofB@,B@+,B@?,B@?+, returning the result as a (UTF-8)Stringinstead of aBytesvalue. These primitives do not check whether the byte sequence read is a valid UTF-8 string. •ref@(s–c), fetches the first reference fromSlicesand returns the Cellcreferred to. If there are no references left, throws an exception. •ref@+(s–s ′ c), similar toref@, but returns the remainder ofsas well. •ref@?(s–c−1or0), similar toref@, but uses a flag to indicate failure instead of throwing an exception. •ref@?+(s–s ′ c−1ors0), similar toref@+, but uses a flag to indicate failure instead of throwing an exception. •empty?(s–?), checks whether aSliceis empty (i.e., has no data bits and no references left), and returns−1or0accordingly. •remaining(s–x y), returns both the number of data bitsxand the number of cell referencesyremaining inSlices. •sbits(s–x), returns the number of data bitsxremaining inSlices. •srefs(s–x), returns the number of cell referencesxremaining in Slices. •sbitrefs(s–x y), returns both the number of data bitsxand the number of cell referencesyremaining inSlices. Equivalent to remaining. 47 5.3. Slice primitives •$>s(S–s), transformsStringSinto aSlice. Equivalent to c(s–c), creates aCellcdirectly from aSlices. Equivalent to. •csr.(s– ), recursively prints aSlices. On the first line, the data bits ofsare displayed in hexadecimal form embedded into anx{...} construct similar to the one used forSliceliterals (cf.5.1). On the next lines, the cells referred to bysare printed with larger indentation. For instance, values of the TL-B typeTestdiscussed in5.2 test#4a first:uint16 second:int32 = Test; may be deserialized as follows: { abort"constructor tag mismatch" 16 u@+ 32 i@+ s> } : unpackTest x{4A4357C46535FF} s>c unpackTest swap . . prints “17239 -1000000001 ok” as expected. Of course, if one needs to check constructor tags often, a helper word can be defined for this purpose: { dup remaining abort"references in constructor tag" tuck u@ -rot u@+ -rot <> abort"constructor tag mismatch" } : tag? { } : unpackTest x{4A4357C46535FF} s>c unpackTest swap . . We can do even better with the aid of active prefix words (cf.4.2and4.4): { dup remaining abort"references in constructor tag" dup 256 > abort"constructor tag too long" tuck u@ 2 { -rot u@+ -rot <> abort"constructor tag mismatch" } } : (tagchk) { \[compile\] x{ 2drop (tagchk) } ::\_ ?x{ { \[compile\] b{ 2drop (tagchk) } ::\_ ?b{ { } : unpackTest x{4A4357C46535FF} s>c unpackTest swap . . 48 5.5. Bag-of-cells operations A shorter but less efficient solution would be to reuse the previously defined tag?: { \[compile\] x{ drop ’ tag? } ::\_ ?x{ { \[compile\] b{ drop ’ tag? } ::\_ ?b{ x{11EF55AA} ?x{11E} dup csr. ?b{110} csr. first outputs “x{F55AA}”, and then throws an exception with the message “constructor tag mismatch”. 5.4 Cell hash operations There are few words that operate onCells directly. The most important of them computes the(sha256-based) representation hashof a given cell (cf. \[4, 3.1\]), which can be roughly described as thesha256hash of the cell’s data bits concatenated with recursively computed hashes of the cells referred to by this cell: •hashB(c–B), computes thesha256-based representation hash of Cellc(cf. \[4, 3.1\]), which unambiguously definescand all its de- scendants (provided there are no collisions forsha256). The result is returned as aBytesvalue consisting of exactly 32 bytes. •hashu(c–x), computes thesha256-based representation hash ofcas above, but returns the result as a big-endian unsigned 256-bitInteger. •shash(s–B), computes thesha256-based representation hash of a Sliceby first transforming it into a cell. Equivalent tos>c hashB. 5.5 Bag-of-cells operations Abag of cellsis a collection of one or more cells along with all their descen- dants. It can usually be serialized into a sequence of bytes (represented by aBytesvalue in Fift) and then saved into a file or transferred by network. Afterwards, it can be deserialized to recover the original cells. The TON Blockchain systematically represents different data structures (including the TON Blockchain blocks) as a tree of cells according to a certain TL-B scheme (cf. \[5\], where this scheme is explained in detail), and then these trees of cells are routinely imported into bags of cells and serialized into binary files. Fift words for manipulating bags of cells include: 49 5.6. Binary file I/O and Bytes manipulation •B>boc(B–c), deserializes a “standard” bag of cells (i.e., a bag of cells with exactly one root cell) represented byBytesB, and returns the rootCellc. •boc+>B(c x–B), creates and serializes a “standard” bag of cells, con- taining one rootCellcalong with all its descendants. AnInteger parameter0≤x≤31is used to pass flags indicating the additional options for bag-of-cells serialization, with individual bits having the following effect: –+1enables bag-of-cells index creation (useful for lazy deserializa- tion of large bags of cells). –+2includes the CRC32-C of all data into the serialization (useful for checking data integrity). –+4explicitly stores the hash of the root cell into the serialization (so that it can be quickly recovered afterwards without a complete deserialization). –+8stores hashes of some intermediate (non-leaf) cells (useful for lazy deserialization of large bags of cells). –+16stores cell cache bits to control caching of deserialized cells. Typical values ofxarex= 0orx= 2for very small bags of cells (e.g., TON Blockchain external messages) andx= 31for large bags of cells (e.g., TON Blockchain blocks). •boc>B(c–B), serializes a small “standard” bag of cells with rootCellc and all its descendants. Equivalent to0 boc+>B. For instance, the cell created in5.2with a value of TL-BTesttype may be serialized as follows: { } : mkTest 17239 -1000000001 mkTest boc>B Bx. outputs “B5EE9C7201040101000000000900000E4A4357C46535FF ok”. Here Bx.is the word that prints the hexadecimal representation of aBytesvalue. 50 5.6. Binary file I/O and Bytes manipulation 5.6 Binary file I/O and Bytes manipulation The following words can be used to manipulate values of typeBytes(ar- bitrary byte sequences) and to read them from or write them into binary files: •B{〈hex-digits〉}( –B), pushes aBytesliteral containing data repre- sented by an even number of hexadecimal digits. •Bx.(B– ), prints the hexadecimal representation of aBytesvalue. Each byte is represented by exactly two uppercase hexadecimal digits. •file>B(S–B), reads the (binary) file with the name specified in StringSand returns its contents as aBytesvalue. If the file does not exist, an exception is thrown. •B>file(B S– ), creates a new (binary) file with the name specified in StringSand writes data fromBytesBinto the new file. If the specified file already exists, it is overwritten. •file-exists?(S–?), checks whether the file with the name specified inStringSexists. For instance, the bag of cells created in the example in5.5can be saved to disk assample.bocas follows: { } : mkTest 17239 -1000000001 mkTest boc>B "sample.boc" B>file It can be loaded and deserialized afterwards (even in another Fift session) by means offile>BandB>boc: { abort"constructor tag mismatch" 16 u@+ 32 i@+ s> } : unpackTest "sample.boc" file>B B>boc unpackTest swap . . prints “17239 -1000000001 ok”. Additionally, there are several words for directly packing (serializing) data intoBytesvalues, and unpacking (deserializing) them afterwards. They can be combined withB>fileandfile>Bto save data directly into binary files, and load them afterwards. 51 Chapter6.TON-specific operations •Blen(B–x), returns the length of aBytesvalueBin bytes. •BhashB(B–B ′ ), computes thesha256hash of aBytesvalue. The hash is returned as a 32-byteBytesvalue. •Bhashu(B–x), computes thesha256hash of aBytesvalue and returns the hash as an unsigned 256-bit big-endian integer. •B=(B B ′ –?), checks whether twoBytessequences are equal. •Bcmp(B B ′ –x), lexicographically compares twoBytessequences, and returns−1,0, or1, depending on the comparison result. •B>i@(B x–y), deserializes the firstx/8bytes of aBytesvalueBas a signed big-endianx-bitIntegery. •B>i@+(B x–B ′ y), deserializes the firstx/8bytes ofBas a signed big- endianx-bitIntegerysimilarly toB>i@, but also returns the remaining bytes ofB. •B>u@,B>u@+, variants ofB>i@andB>i@+deserializing unsigned inte- gers. •B>Li@,B>Li@+,B>Lu@,B>Lu@+, little-endian variants ofB>i@,B>i@+, B>u@,B>u@+. •B|(B x–B ′ B ′′ ), cuts the firstxbytes from aBytesvalueB, and returns both the firstxbytes (B ′ ) and the remainder (B ′′ ) as new Bytesvalues. •i>B(x y–B), stores a signed big-endiany-bitIntegerxinto aBytes valueBconsisting of exactlyy/8bytes. Integerymust be a multiple of eight in the range0...256. •u>B(x y–B), stores an unsigned big-endiany-bitIntegerxinto a BytesvalueBconsisting of exactlyy/8bytes, similarly toi>B. •Li>B,Lu>B, little-endian variants ofi>Bandu>B. •B+(B ′ B ′′ –B), concatenates twoBytessequences. 52 6.2. Smart-contract address parser 6 TON-specific operations This chapter describes the TON-specific Fift words, with the exception of the words used forCellmanipulation, already discussed in the previous chapter. 6.1 Ed25519 cryptography Fift offers an interface to the same Ed25519 elliptic curve cryptography used by TVM, described in AppendixAof \[5\]: •now( –x), returns the current Unixtime as anInteger. •newkeypair( –B B ′ ), generates a new Ed25519 private/public key pair, and returns both the private keyBand the public keyB ′ as 32- byteBytesvalues. The quality of the keys is good enough for testing purposes. Real applications must feed enough entropy into OpenSSL PRNG before generating Ed25519 keypairs. •priv>pub(B–B ′ ), computes the public key corresponding to a pri- vate Ed25519 key. Both the public keyB ′ and the private keyBare represented by 32-byteBytesvalues. •ed25519\_sign(B B ′ –B ′′ ), signs dataBwith the Ed25519 private keyB ′ (a 32-byteBytesvalue) and returns the signature as a 64-byte BytesvalueB ′′ . •ed25519\_sign\_uint(x B ′ –B ′′ ), converts a big-endian unsigned 256- bit integerxinto a 32-byte sequence and signs it using the Ed25519 private keyB ′ similarly toed25519\_sign. Equivalent toswap 256 u>B swap ed25519\_sign. The integerxto be signed is typically computed as the hash of some data. •ed25519\_chksign(B B ′ B ′′ –?), checks whetherB ′ is a valid Ed25519 signature of dataBwith the public keyB ′′ . 6.2 Smart-contract address parser Two special words can be used to parse TON smart-contract addresses in human-readable (base64 or base64url) forms: 53 6.3. Dictionary manipulation •smca>$(x y z–S), packs a standard TON smart-contract address with workchainx(a signed 32-bitInteger) and in-workchain addressy (an unsigned 256-bitInteger) into a 48-character stringS(the human- readable representation of the address) according to flagsz. Possi- ble individual flags inzare:+1for non-bounceable addresses,+2for testnet-only addresses, and+4for base64url output instead of base64. •$>smca(S–x y z−1or0), unpacks a standard TON smart-contract address from its human-readable string representationS. On suc- cess, returns the signed 32-bit workchainx, the unsigned 256-bit in- workchain addressy, the flagsz(where+1means that the address is non-bounceable,+2that the address is testnet-only), and−1. On failure, pushes0. A sample human-readable smart-contract address could be deserialized and displayed as follows: "Ef9Tj6fMJP-OqhAdhKXxq36DL-HYSzCc3-9O6UNzqsgPfYFX" $>smca 0= abort"bad address" rot . swap x. . cr outputs “-1 538fa7...0f7d 0”, meaning that the specified address is in workchain−1(the masterchain of the TON Blockchain), and that the 256-bit address inside workchain−1is 0x538. . . f7d. 6.3 Dictionary manipulation Fift has several words forhashmapor(TVM) dictionarymanipulation, cor- responding to values of TL-B typeHashmapEn Xas described in \[4, 3.3\]. These (TVM) dictionaries are not to be confused with the Fift dictionary, which is a completely different thing. A dictionary of TL-B typeHashmapE n Xis essentially a key-value collection with distinctn-bit keys (where 0≤n≤1023) and values of an arbitrary TL-B typeX. Dictionaries are represented by trees of cells (the complete layout may be found in \[4, 3.3\]) and stored as values of typeCellorSlicein the Fift stack. Sometimes empty dictionaries are represented by theNullvalue. •dictnew( –D), pushes aNullvalue that represents a new empty dictionary. 54 6.3. Dictionary manipulation •idict!(v x D n–D ′ −1orD0), adds a new valuev(represented by a Slice) with key given by signed big-endiann-bit integerxinto dictionary D(represented by aCellor aNull) withn-bit keys, and returns the new dictionaryD ′ and−1on success. Otherwise the unchanged dictionary Dand0are returned. •idict!+(v x D n–D ′ −1orD0), adds a new key-value pair(x,v) into dictionaryDsimilarly toidict!, but fails if the key already exists by returning the unchanged dictionaryDand0. •b>idict!,b>idict!+, variants ofidict!andidict!+accepting the new valuevin aBuilderinstead of aSlice. •udict!,udict!+,b>udict!,b>udict!+, variants ofidict!,idict!+, b>idict!,b>idict!+, but with an unsignedn-bit integerxused as a key. •sdict!,sdict!+,b>sdict!,b>sdict!+, variants ofidict!,idict!+, b>idict!,b>idict!+, but with the firstndata bits ofSlicexused as a key. •idict@(x D n–v−1or0), looks up the key represented by signed big-endiann-bitIntegerxin the dictionary represented byCellD. If the key is found, returns the corresponding value as aSlicevand−1. Otherwise returns0. •idict@-(x D n–D ′ v−1orD0), looks up the key represented by signed big-endiann-bitIntegerxin the dictionary represented by CellD. If the key is found, deletes it from the dictionary and returns the modified dictionaryD ′ , the corresponding value as aSlicev, and −1. Otherwise returns the unmodified dictionaryDand0. •idict-(x D n–D ′ −1orD0), deletes integer keyxfrom dictionary Dsimilarly toidict@-, but does not return the value corresponding toxin the old dictionaryD. •udict@,udict@-,udict-, variants ofidict@,idict@-,idict-, but with anunsigned big-endiann-bitIntegerxused as a key. •sdict@,sdict@-,sdict-, variants ofidict@,idict@-,idict-, but with the key provided in the firstnbits ofSlicek. 55 6.4. Invoking TVM from Fift •dictmap(D n e–s ′ ), applies execution tokene(i.e., an anonymous function) to each of the key-value pairs stored in a dictionaryDwith n-bit keys. The execution token is executed once for each key-value pair, with aBuilderband aSlicev(containing the value) pushed into the stack before executinge. After the executionemust leave in the stack either a modifiedBuilderb ′ (containing all data frombalong with the new valuev ′ ) and−1, or0indicating failure. In the latter case, the corresponding key is omitted from the new dictionary. •dictmerge(D D ′ n e–D ′′ ), combines two dictionariesDandD ′ with n-bit keys into one dictionaryD ′′ with the same keys. If a key is present in only one of the dictionariesDandD ′ , this key and the correspond- ing value are copied verbatim to the new dictionaryD ′′ . Otherwise the execution token (anonymous function)eis invoked to merge the two valuesvandv ′ corresponding to the same keykinDandD ′ , respectively. Beforeeis invoked, aBuilderband twoSlicesvandv ′ representing the two values to be merged are pushed. After the execu- tioneleaves either a modifiedBuilderb ′ (containing the original data frombalong with the combined value) and−1, or0on failure. In the latter case, the corresponding key is omitted from the new dictionary. Fift also offers some support for prefix dictionaries: •pfxdict!(v k s n–s ′ −1ors0), adds key-value pair(k,v), both represented bySlices, into a prefix dictionaryswith keys of length at mostn. On success, returns the modified dictionarys ′ and−1. On failure, returns the original dictionarysand0. •pfxdict!+(v k s n–s ′ −1ors0), adds key-value pair(k,v)into prefix dictionaryssimilarly topfxdict!, but fails if the key already exists. •pfxdict@(k s n–v−1or0), looks up keyk(represented by aSlice) in the prefix dictionaryswith the length of keys limited bynbits. On success, returns the value foundvand−1. On failure, returns0. 6.4 Invoking TVM from Fift TVM can be linked with the Fift interpreter. In this case, several Fift prim- itives become available that can be used to invoke TVM with arguments 56 6.4. Invoking TVM from Fift provided from Fift. The arguments can be prepared in the Fift stack, which is passed in its entirety to the new instance of TVM. The resulting stack and the exit code are passed back to Fift and can be examined afterwards. •runvmcode(. . .s– . . .x), invokes a new instance of TVM with the current continuationccinitialized fromSlices, thus executing codes in TVM. The original Fift stack (withouts) is passed in its entirety as the initial stack of TVM. When TVM terminates, its resulting stack is used as the new Fift stack, with the exit codexpushed at its top. Ifx is non-zero, indicating that TVM has been terminated by an unhandled exception, the next stack entry from the top contains the parameter of this exception, andxis the exception code. All other entries are removed from the stack in this case. •runvmdict(. . .s– . . .x), invokes a new instance of TVM with the cur- rent continuationccinitialized fromSlicessimilarly torunvmcode, but also initializes the special registerc3with the same value, and pushes a zero into the initial TVM stack before the TVM execution begins. In a typical applicationSlicesconsists of a subroutine selec- tion code that uses the top-of-stackIntegerto select the subroutine to be executed, thus enabling the definition and execution of several mutually-recursive subroutines (cf. \[4, 4.6\] and7.8). The selector equal to zero corresponds to themain()subroutine in a large TVM program. •runvm(. . .s c– . . .x c ′ ), invokes a new instance of TVM with both the current continuationccand the special registerc3initialized from Slices, similarly torunvmdict(without pushing an extra zero to the initial TVM stack; if necessary, it can be pushed explicitly unders), and also initializes special registerc4(the “root of persistent data”, cf. \[4, 1.4\]) withCellc. The final value ofc4is returned at the top of the final Fift stack as anotherCellc ′ . In this way one can emulate the execution of smart contracts that inspect or modify their persistent storage. •runvmctx(. . .s c t– . . .x c ′ ), a variant ofrunvmthat also initializes c7(the “context”) withTuplet. In this way the execution of a TVM smart contract inside TON Blockchain can be completely emulated, if the correct context is loaded intoc7(cf. \[5, 4.4.10\]). 57 6.4. Invoking TVM from Fift •gasrunvmcode(. . .s z– . . .x z ′ ), a gas-aware version ofrunvmcode that accepts an extraIntegerargumentz(the original gas limit) at the top of the stack, and returns the gas consumed by this TVM run as a new top-of-stackIntegervaluez ′ . •gasrunvmdict(. . .s z– . . .x z ′ ), a gas-aware version ofrunvmdict. •gasrunvm(. . .s c z– . . .x c ′ z ′ ), a gas-aware version ofrunvm. •gasrunvmctx(. . .s c t z– . . .x c ′ z ′ ), a gas-aware version ofrunvmctx. For example, one can create an instance of TVM running some simple code as follows: 2 3 9 x{1221} runvmcode .s The TVM stack is initialized by three integers2,3, and9(in this order;9 is the topmost entry), and then theSlicex{1221}containing 16 data bits and no references is transformed into a TVM continuation and executed. By consulting Appendix A of \[4\], we see thatx{12}is the code of the TVM instructionXCHG s1, s2, and thatx{21}is the code of the TVM instruction OVER(not to be confused with the Fift primitiveover, which incidentally has the same effect on the stack). The result of the above execution is: execute XCHG s1,s2 execute OVER execute implicit RET 3 2 9 2 0 ok Here0is the exit code (indicating successful TVM termination), and3 2 9 2is the final TVM stack state. If an unhandled exception is generated during the TVM execution, the code of this exception is returned as the exit code: 2 3 9 x{122} runvmcode .s produces execute XCHG s1,s2 handling exception code 6: invalid or too short opcode default exception handler, terminating vm with exit code 6 0 6 ok 58 7.2. Fift assembler basics Notice that TVM is executed with internal logging enabled, and its log is displayed in the standard output. Simple TVM programs may be represented bySliceliterals with the aid of thex{...}construct similarly to the above examples. More sophisticated programs are usually created with the aid of the Fift assembler as explained in the next chapter. 7 Using the Fift assembler TheFift assembleris a short program (currently less than 30KiB) written completely in Fift that transforms human-readable mnemonics of TVM in- structions into their binary representation. For instance, one could write<{ s1 s2 XCHG OVER }>sinstead ofx{1221}in the example discussed in6.4, provided the Fift assembler has been loaded beforehand (usually by the phrase"Asm.fif" include). 7.1 Loading the Fift assembler The Fift assembler is usually located in fileAsm.fifin the Fift library direc- tory (which usually contains standard Fift library files such asFift.fif). It is typically loaded by putting the phrase"Asm.fif" includeat the very beginning of a program that needs to use Fift assembler: •include(S– ), loads and interprets a Fift source file from the path given byStringS. If the filenameSdoes not begin with a slash, the Fift include search path, typically taken from theFIFTPATHenvironment variable or the-Icommand-line argument of the Fift interpreter (and equal to/usr/lib/fiftif both are absent), is used to locateS. The current implementation of the Fift assembler makes heavy use of custom defining words (cf.4.8); its source can be studied as a good example of how defining words might be used to write very compact Fift programs (cf. also the original edition of \[1\], where a simple 8080 Forth assembler is discussed). In the future, almost all of the words defined by the Fift assembler will be moved to a separate vocabulary (namespace). Currently they are defined in the global namespace, because Fift does not support namespaces yet. 59 7.2. Fift assembler basics 7.2 Fift assembler basics The Fift assembler inherits from Fift its postfix operation notation, i.e., the arguments or parameters are written before the corresponding instructions. For instance, the TVM assembler instruction represented asXCHG s1,s2in \[4\] is represented in the Fift assembler ass1 s2 XCHG. Fift assembler code is usually opened by a special opening word, such as <{, and terminated by a closing word, such as}>or}>s. For instance, "Asm.fif" include <{ s1 s2 XCHG OVER }>s csr. compiles two TVM instructionsXCHG s1,s2andOVER, and returns the result as aSlice(because}>sis used). The resultingSliceis displayed bycsr., yielding x{1221} One can use Appendix A of \[4\] and verify thatx{12}is indeed the (codepage zero) code of the TVM instructionXCHG s1,s2, and thatx{21}is the code of the TVM instructionOVER(not to be confused with Fift primitiveover). In the future, we will assume that the Fift assember is already loaded and omit the phrase"Asm.fif" includefrom our examples. The Fift assembler uses the Fift stack in a straightforward fashion, using the top several stack entries to hold aBuilderwith the code being assembled, and the arguments to TVM instructions. For example: •<{( –b), begins a portion of Fift assembler code by pushing an empty Builderinto the Fift stack (and potentially switching the namespace to the one containing all Fift assembler-specific words). Approximately equivalent to(b–b ′ ), terminates a portion of Fift assembler code and returns the assembled portion as aBuilder(and potentially recovers the original namespace). Approximately equivalent tonopin most situations. •}>c(b–c), terminates a portion of Fift assembler code and returns the assembled portion as aCell(and potentially recovers the original namespace). Approximately equivalent tob>. 60 7.3. Pushing integer constants •}>s(b–s), terminates a portion of Fift assembler code similarly to}>, but returns the assembled portion as aSlice. Equivalent to}>c sis a valid way to assemble aPUSHINT 4063instruction, because239·17 = 4063. Notice that the multiplication is performed by Fift during assemble time, not during the TVM runtime. The latter computation might be performed by means of<{ 239 INT 17 INT MUL }>s: <{ 239 17 \* INT }>s dup csr. runvmcode .s 2drop <{ 239 INT 17 INT MUL }>s dup csr. runvmcode .s 2drop produces x{810FDF} execute PUSHINT 4063 execute implicit RET 4063 0 ok x{8100EF8011A8} execute PUSHINT 239 execute PUSHINT 17 execute MUL execute implicit RET 4063 0 ok Notice that the Fift assembler chooses the shortest encoding of thePUSHINTx instruction depending on its argumentx. 7.4 Immediate arguments Some TVM instructions (such asPUSHINT) accept immediate arguments. These arguments are usually passed to the Fift word assembling the cor- responding instruction in the Fift stack. Integer immediate arguments are usually represented byIntegers, cells byCells, continuations byBuilders and Cells, and cell slices bySlices. For instance,17 ADDCONSTassembles TVM instructionADDCONST 17, andx{ABCD\_} PUSHSLICEassemblesPUSHSLICE xABCD\_: 62 7.5. Immediate continuations 239 <{ 17 ADDCONST x{ABCD\_} PUSHSLICE }>s dup csr. runvmcode . swap . csr. produces x{A6118B2ABCD0} execute ADDINT 17 execute PUSHSLICE xABCD\_ execute implicit RET 0 256 x{ABCD\_} On some occasions, the Fift assembler pretends to be able to accept imme- diate arguments that are out of range for the corresponding TVM instruction. For instance,ADDCONSTxis defined only for−128≤x <128, but the Fift assembler accepts239 ADDCONST: 17 <{ 239 ADDCONST }>s dup csr. runvmcode .s produces x{8100EFA0} execute PUSHINT 239 execute ADD execute implicit RET 256 0 We can see that “ADDCONST 239” has been tacitly replaced byPUSHINT 239andADD. This feature is convenient when the immediate argument to ADDCONSTis itself a result of a Fift computation, and it is difficult to esti- mate whether it will always fit into the required range. In some cases, there are several versions of the same TVM instructions, one accepting an immediate argument and another without any arguments. For instance, there are bothLSHIFTnandLSHIFTinstructions. In the Fift assembler, such variants are assigned distinct mnemonics. In partic- ular,LSHIFTnis represented bynLSHIFT#, andLSHIFTis represented by itself. 7.5 Immediate continuations When an immediate argument is a continuation, it is convenient to create the correspondingBuilderin the Fift stack by means of a nested<{. . .}> construct. For instance, TVM assembler instructions 63 7.5. Immediate continuations PUSHINT 1 SWAP PUSHCONT { MULCONST 10 } REPEAT can be assembled and executed by 7 <{ 1 INT SWAP <{ 10 MULCONST }> PUSHCONT REPEAT }>s dup csr. runvmcode drop . producing x{710192A70AE4} execute PUSHINT 1 execute SWAP execute PUSHCONT xA70A execute REPEAT repeat 7 more times execute MULINT 10 execute implicit RET repeat 6 more times ... repeat 1 more times execute MULINT 10 execute implicit RET repeat 0 more times execute implicit RET 10000000 More convenient ways to use literal continuations created by means of the Fift assembler exist. For instance, the above example can be also assembled by <{ 1 INT SWAP CONT:<{ 10 MULCONST }> REPEAT }>s csr. or even <{ 1 INT SWAP REPEAT:<{ 10 MULCONST }> }>s csr. 64 7.6. Control flow: loops and conditionals both producing “x{710192A70AE4} ok”. Incidentally, a better way of implementing the above loop is by means of REPEATEND: 7 <{ 1 INT SWAP REPEATEND 10 MULCONST }>s dup csr. runvmcode drop . or 7 <{ 1 INT SWAP REPEAT: 10 MULCONST }>s dup csr. runvmcode drop . both produce “x{7101E7A70A}” and output “10000000” after seven iterations of the loop. Notice that several TVM instructions that store a continuation in a sep- arate cell reference (such asJMPREF) accept their argument in aCell, not in aBuilder. In such situations, the<{ ... }>cconstruct can be used to produce this immediate argument. 7.6 Control flow: loops and conditionals Almost all TVM control flow instructions—such asIF,IFNOT,IFRET,IFNOTRET, IFELSE,WHILE,WHILEEND,REPEAT,REPEATEND,UNTIL, andUNTILEND—can be assembled similarly toREPEATandREPEATENDin the examples of7.5 when applied to literal continuations. For instance, TVM assembler code DUP PUSHINT 1 AND PUSHCONT { MULCONST 3 INC } PUSHCONT { RSHIFT 1 } IFELSE which computes3n+ 1orn/2depending on whether its argumentnis odd or even, can be assembled and applied ton= 7by 65 7.6. Control flow: loops and conditionals <{ DUP 1 INT AND IF:<{ 3 MULCONST INC }>ELSE<{ 1 RSHIFT# }> }>s dup csr. 7 swap runvmcode drop . producing x{2071B093A703A492AB00E2} ok execute DUP execute PUSHINT 1 execute AND execute PUSHCONT xA703A4 execute PUSHCONT xAB00 execute IFELSE execute MULINT 3 execute INC execute implicit RET execute implicit RET 22 ok Of course, a more compact and efficient way to implement this conditional expression would be <{ DUP 1 INT AND IF:<{ 3 MULCONST INC }>ELSE: 1 RSHIFT# }>s dup csr. or <{ DUP 1 INT AND CONT:<{ 3 MULCONST INC }> IFJMP 1 RSHIFT# }>s dup csr. both producing the same code “x{2071B093A703A4DCAB00}”. Fift assembler words that can be used to produce such “high-level” condi- tionals and loops includeIF:<{,IFNOT:<{,IFJMP:<{,}>ELSE<{,}>ELSE:, }>IF,REPEAT:<{,UNTIL:<{,WHILE:<{,}>DO<{,}>DO:,AGAIN:<{,}>AGAIN, }>REPEAT, and}>UNTIL. Their complete list can be found in the source file 66 7.7. Macro definitions Asm.fif. For instance, an UNTIL loop can be created byUNTIL:<{ ... }> or<{ ... }>UNTIL, and a WHILE loop byWHILE:<{ ... }>DO<{ ... }>. If we choose to keep a conditional branch in a separate cell, we can use the<{ ... }>cconstruct along with instructions such asIFJMPREF: <{ DUP 1 INT AND <{ 3 MULCONST INC }>c IFJMPREF 1 RSHIFT# }>s dup csr. 3 swap runvmcode .s has the same effect as the code from the previous example when executed, but it is contained in two separate cells: x{2071B0E302AB00} x{A703A4} execute DUP execute PUSHINT 1 execute AND execute IFJMPREF (2946....A1DD) execute MULINT 3 execute INC execute implicit RET 10 0 7.7 Macro definitions Because TVM instructions are implemented in the Fift assembler using Fift words that have a predictable effect on the Fift stack, the Fift assembler is automatically a macro assembler, supporting macro definitions. For in- stance, suppose that we wish to define a macro definitionRANGEx y, which checks whether the TVM top-of-stack value is between integer literalsxand y(inclusive). This macro definition can be implemented as follows: { 2dup > ’ swap if rot DUP rot GEQINT SWAP swap LEQINT AND } : RANGE <{ DUP 17 239 RANGE IFNOT: DROP ZERO }>s dup csr. 66 swap runvmcode drop . 67 7.8. Larger programs and subroutines which produces x{2020C210018100F0B9B0DC3070} execute DUP execute DUP execute GTINT 16 execute SWAP execute PUSHINT 240 execute LESS execute AND execute IFRET 66 Notice thatGEQINTandLEQINTare themselves macro definitions defined in Asm.fif, because they do not correspond directly to TVM instructions. For instance,xGEQINTcorresponds to the TVM instructionGTINTx−1. Incidentally, the above code can be shortened by two bytes by replacing IFNOT: DROP ZEROwithAND. 7.8 Larger programs and subroutines Larger TVM programs, such as TON Blockchain smart contracts, typically consist of several mutually recursive subroutines, with one or several of them selected as top-level subroutines (calledmain()orrecv\_internal()for smart contracts). The execution starts from one of the top-level subrou- tines, which is free to call any of the other defined subroutines, which in turn can call whatever other subroutines they need. Such TVM programs are implemented by means of a selector function, which accepts an extra integer argument in the TVM stack; this integer selects the actual subroutine to be invoked (cf. \[4, 4.6\]). Before execution, the code of this selector function is loaded both into special registerc3and into the current continuationcc. The selector of the main function (usually zero) is pushed into the initial stack, and the TVM execution is started. Afterwards a subroutine can be invoked by means of a suitable TVM instruction, such as CALLDICTn, wherenis the (integer) selector of the subroutine to be called. The Fift assembler offers several words facilitating the implementation of such large TVM programs. In particular, subroutines can be defined sep- arately and assigned symbolic names (instead of numeric selectors), which 68 7.8. Larger programs and subroutines can be used to call them afterwards. The Fift assembler automatically cre- ates a selector function from these separate subroutines and returns it as the top-level assembly result. Here is a simple example of such a program consisting of several subrou- tines. This program computes the complex number(5 +i) 4 ·(239−i): "Asm.fif" include PROGRAM{ NEWPROC add NEWPROC sub NEWPROC mul sub <{ s3 s3 XCHG2 SUB s2 XCHG0 SUB }>s PROC // compute (5+i)^4 \* (239-i) main PROC:<{ 5 INT 1 INT // 5+i 2DUP mul CALL 2DUP mul CALL 239 INT -1 INT mul JMP }> add PROC:<{ s1 s2 XCHG ADD -ROT ADD SWAP }> // a b c d -- ac-bd ad+bc : complex number multiplication mul PROC:<{ s3 s1 PUSH2 // a b c d a c MUL // a b c d ac s3 s1 PUSH2 // a b c d ac b d MUL // a b c d ac bd 69 7.8. Larger programs and subroutines SUB // a b c d ac-bd s4 s4 XCHG2 // ac-bd b c a d MUL // ac-bd b c ad -ROT MUL ADD }> }END>s dup csr. runvmdict .s This program produces: x{FF00F4A40EF4A0F20B} x{D9\_} x{2\_} x{1D5C573C00D73C00E0403BDFFC5000E\_} x{04A81668006\_} x{2\_} x{140CE840A86\_} x{14CC6A14CC6A2854112A166A282\_} implicit PUSH 0 at start execute SETCP 0 execute DICTPUSHCONST 14 (xC\_,1) execute DICTIGETJMP execute PUSHINT 5 execute PUSHINT 1 execute 2DUP execute CALLDICT 3 execute SETCP 0 execute DICTPUSHCONST 14 (xC\_,1) execute DICTIGETJMP execute PUSH2 s3,s1 execute MUL ... execute ROTREV execute MUL execute ADD execute implicit RET 114244 114244 0 70 7.8. Larger programs and subroutines Some observations and comments based on the previous example follow: •A TVM program is opened byPROGRAM{and closed by either}END>c (which returns the assembled program as aCell) or}END>s(which returns aSlice). •A new subroutine is declared by means of the phraseNEWPROC〈name〉. This declaration assigns the next positive integer as a selector for the newly-declared subroutine, and stores this integer into the constant 〈name〉. For instance, the above declarations defineadd,sub, andmul as integer constants equal to 1, 2, and 3, respectively. •Some subroutines are predeclared and do not need to be declared again byNEWPROC. For instance,mainis a subroutine identifier bound to the integer constant (selector) 0. •Other predefined subroutine selectors such asrecv\_internal(equal to0) orrecv\_external(equal to−1), useful for implementing TON Blockchain smart contracts (cf. \[5, 4.4\]), can be declared by means of constant(e.g.,-1 constant recv\_external). •A subroutine can be defined either with the aid of the wordPROC, which accepts the integer selector of the subroutine and theSlicecontaining the code for this subroutine, or with the aid of the construct〈selector〉 PROC:<{ ... }>, convenient for defining larger subroutines. •CALLDICTandJMPDICTinstructions may be assembled with the aid of the wordsCALLandJMP, which accept the integer selector of the subroutine to be called as an immediate argument passed in the Fift stack. •The current implementation of the Fift assembler collects all subrou- tines into a dictionary with 14-bit signed integer keys. Therefore, all subroutine selectors must be in the range−2 13 ...2 13 −1. •If a subroutine with an unknown selector is called during runtime, an exception with code11is thrown by the code automatically inserted by the Fift assembler. This code also automatically selects codepage zero for instruction encoding by means of aSETCP0instruction. 71 7.8. Larger programs and subroutines •The Fift assembler checks that all subroutines declared byNEWPROCare actually defined byPROCorPROC:<{before the end of the program. It also checks that a subroutine is not redefined. One should bear in mind that very simple programs (including the sim- plest smart contracts) may be made more compact by eliminating this general subroutine selection machinery in favor of custom subroutine selection code and removing unused subroutines. For instance, the above example can be transformed into <{ 11 THROWIF CONT:<{ s3 s1 PUSH2 MUL s3 s1 PUSH2 MUL SUB s4 s4 XCHG2 MUL -ROT MUL ADD }> 5 INT 1 INT 2DUP s4 PUSH CALLX 2DUP s4 PUSH CALLX ROT 239 INT -1 INT ROT JMPX }>s dup csr. runvmdict .s which produces x{F24B9D5331A85331A8A15044A859A8A075715C24D85C24D8588100EF7F58D9} implicit PUSH 0 at start execute THROWIF 11 execute PUSHCONT x5331A85331A8A15044A859A8A0 execute PUSHINT 5 execute PUSHINT 1 execute 2DUP execute PUSH s4 execute EXECUTE execute PUSH2 s3,s1 execute MUL ... execute XCHG2 s4,s4 execute MUL execute ROTREV execute MUL execute ADD 72 7.8. Larger programs and subroutines execute implicit RET 114244 114244 0 73 References References \[1\]L. Brodie,Starting Forth: Introduction to the FORTH Language and Operating System for Beginners and Professionals, 2nd edition, Prentice Hall, 1987. Available athttps://www.forth.com/starting-forth/. \[2\]L. Brodie,Thinking Forth: A language and philosophy for solving problems, Prentice Hall, 1984. Available athttp://thinking-forth. sourceforge.net/. \[3\]N. Durov,Telegram Open Network, 2017. \[4\]N. Durov,Telegram Open Network Virtual Machine, 2018. \[5\]N. Durov,Telegram Open Network Blockchain, 2018. 74 AppendixA.List of Fift words A List of Fift words This Appendix provides an alphabetic list of almost all Fift words—including primitives and definitions from the standard libraryFift.fif, but excluding Fift assembler words defined inAsm.fif(because the Fift assembler is simply an application from the perspective of Fift). Some experimental words have been omitted from this list. Other words may have been added to or removed from Fift after this text was written. The list of all words available in your Fift interpreter may be inspected by executingwords. Each word is described by its name, followed by itsstack notationin parentheses, indicating several values near the top of the Fift stack before and after the execution of the word; all deeper stack entries are usually assumed to be left intact. After that, a text description of the word’s effect is provided. If the word has been discussed in a previous section of this document, a reference to this section is included. Active words and active prefix words that parse a portion of the input stream immediately after their occurrence are listed here in a modified way. Firstly, these words are listed alongside the portion of the input that they parse; the segment of each entry that is actually a Fift word is underlined for emphasis. Secondly, their stack effect is usually described from the user’s perspective, and reflects the actions performed during the execution phase of the encompassing blocks and word definitions. For example, the active prefix wordB{, used for definingBytesliterals (cf.5.6), is listed asB{ 〈hex-digits〉}, and its stack effect is shown as ( – B) instead of ( –B1e), even though the real effect of the execution of the active wordB{during the compilation phase of an encompassing block or word definition is the latter one (cf.4.2). •!(x p– ), stores new valuexintoBoxp, cf.2.14. •" 〈string〉"( –S), pushes aStringliteral into the stack, cf.2.9and2.10. •#(x S–x ′ S ′ ), performs one step of the conversion ofIntegerxinto its decimal representation by appending toStringSone decimal digit representingxmod 10. The quotientx ′ :=bx/10cis returned as well. •#>(S–S ′ ), finishes the conversion of anIntegerinto its human- readable representation (decimal or otherwise) started with<#by re- versingStringS. Equivalent to$reverse. 75 AppendixA.List of Fift words •#s(x S–x ′ S ′ ), performs#one or more times until the quotientx ′ becomes non-positive. Equivalent to{ # over 0<= } until. •$#( –x), pushes the total number of command-line arguments passed to the Fift program, cf.2.18. Defined only when the Fift interpreter is invoked in script mode (with the-scommand line argument). •$( 〈string〉)( – . . . ), looks up the word$〈string〉during execu- tion time and executes its current definition. Typically used to access the current values of command-line arguments, e.g.,$(2)is essentially equivalent to@’ $2. •$()(x–S), pushes thex-th command-line argument similarly to$n, but withIntegerx≥0taken from the stack, cf.2.18. Defined only when the Fift interpreter is invoked in script mode (with the-scom- mand line argument). •$+(S S ′ –S.S ′ ), concatenates two strings, cf.2.10. •$,(b S–b ′ ), appendsStringStoBuilderb, cf.5.2. The string is interpreted as a binary string of length8n, wherenis the number of bytes in the UTF-8 representation ofS. •$n( –S), pushes then-th command-line argument as aStringS, cf.2.18. For instance,$0pushes the name of the script being executed, $1the first command line argument, and so on. Defined only when the Fift interpreter is invoked in script mode (with the-scommand line argument). •$=(S S ′ –?), returns−1if stringsSandS ′ are equal,0otherwise, cf.2.13. Equivalent to$cmp 0=. •$>s(S–s), transforms theStringSinto aSlice, cf.5.3. Equivalent to smca(S–x y z−1or0), unpacks a standard TON smart-contract address from its human-readable string representationS, cf.6.2. On success, returns the signed 32-bit workchainx, the unsigned 256-bit in-workchain addressy, the flagsz(where+1means that the address is non-bounceable,+2that the address is testnet-only), and−1. On failure, pushes0. 76 AppendixA.List of Fift words •$@(s x–S), fetches the firstxbytes (i.e.,8xbits) fromSlices, and returns them as a UTF-8StringS, cf.5.3. If there are not enough data bits ins, throws an exception. •$@+(s x–S s ′ ), similar to$@, but returns the remainder ofSlicesas well, cf.5.3. •$@?(s x–S−1or0), similar to$@, but uses a flag to indicate failure instead of throwing an exception, cf.5.3. •$@?+(s x–S s ′ −1ors0), similar to$@+, but uses a flag to indicate failure instead of throwing an exception, cf.5.3. •$cmp(S S ′ –x), returns0if stringsSandS ′ are equal,−1ifSis lexicographically less thanS ′ , and1ifSis lexicographically greater thanS ′ , cf.2.13. •$len(S–x), computes the byte length (not the UTF-8 character length!) of a string, cf.2.10. •$pos(S S ′ –xor−1), returns the position (byte offset)xof the first occurence of substringS ′ in stringSor−1. •$reverse(S–S ′ ), reverses the order of UTF-8 characters inStringS. IfSis not a valid UTF-8 string, the return value is undefined and may be also invalid. •%1<<(x y–z), computesz:=xmod 2 y =x&(2 y −1)for twoIntegers xand0≤y≤256. •’ 〈word-name〉( –e), returns the execution token equal to the current (compile-time) definition of〈word-name〉, cf.3.1. If the specified word is not found, throws an exception. •’nop( –e), pushes the default definition ofnop—an execution token that does nothing when executed, cf.4.6. •(’)〈word-name〉( –e), similar to’, but returns the definition of the specified word at execution time, performing a dictionary lookup each time it is invoked, cf.4.6. May be used to recover the current values of constants inside word definitions and other blocks by using the phrase (’)〈word-name〉execute. 77 AppendixA.List of Fift words •(-trailing)(S x–S ′ ), removes fromStringSall trailing characters with UTF-8 codepointx. •(.)(x–S), returns theStringwith the decimal representation of Integerx. Equivalent todup abs <# #s rot sign #> nip. •(atom)(S x–a−1or0), returns the onlyAtomawith the name given byStringS, cf.2.17. If there is no suchAtomyet, either creates it (if Integerxis non-zero) or returns a single zero to indicate failure (ifx is zero). •(b.)(x–S), returns theStringwith the binary representation of Integerx. •(compile)(l x 1 . . .x n n e–l ′ ), extendsWordListlso that it would push0≤n≤255valuesx 1 , . . . ,x n into the stack and execute the execution tokenewhen invoked, where0≤n≤255is anInteger, cf.4.7. Ifeis equal to the special value’nop, the last step is omitted. •(create)(e S x– ), creates a new word with the name equal toStringS and definition equal toWordDefe, using flags passed inInteger0≤ x≤3, cf.4.5. If bit+1is set inx, creates an active word; if bit+2is set inx, creates a prefix word. •(def?)(S–?), checks whether the wordSis defined. •(dump)(x–S), returns aStringwith a dump of the topmost stack valuex, in the same format as employed by.dump. •(execute)(x 1 . . .x n n e– . . . ), executes execution tokene, but first checks that there are at least0≤n≤255values in the stack apart fromnandethemselves. It is a counterpart of(compile)that may be used to immediately “execute” (perform the intended runtime action of) an active word after its immediate execution, as explained in4.2. •(forget)(S– ), forgets the word with the name specified inStringS, cf.4.5. If the word is not found, throws an exception. •(number)(S–0orx1orx y2), attempts to parse theStringSas an integer or fractional literal, cf.2.10and2.8. On failure, returns a single0. On success, returnsx1ifSis a valid integer literal with value x, orx y2ifSis a valid fractional literal with valuex/y. 78 AppendixA.List of Fift words •(x.)(x–S), returns theStringwith the hexadecimal representation ofIntegerx. •({)( –l), pushes an emptyWordListinto the stack, cf.4.7 •(})(l–e), transforms aWordListinto an execution token (WordDef), making all further modifications impossible, cf.4.7. •\*(x y–xy), computes the productxyof twoIntegersxandy, cf.2.4. •\*/(x y z–bxy/zc), “multiply-then-divide”: multiplies two integersx andyproducing a 513-bit intermediate result, then divides the product byz, cf.2.4. •\*/c(x y z–dxy/ze), “multiply-then-divide” with ceiling rounding: multiplies two integersxandyproducing a 513-bit intermediate result, then divides the product byz, cf.2.4. •\*/cmod(x y z–q r), similar to\*/c, but computes both the quotient q:=dxy/zeand the remainderr:=xy−qz, cf.2.4. •\*/mod(x y z–q r), similar to\*/, but computes both the quotient q:=bxy/zcand the remainderr:=xy−qz, cf.2.4. •\*/r(x y z–q:=bxy/z+ 1/2c), “multiply-then-divide” with nearest- integer rounding: multiplies two integersxandywith 513-bit interme- diate result, then divides the product byz, cf.2.4. •\*/rmod(x y z–q r), similar to\*/r, but computes both the quotient q:=bxy/z+ 1/2cand the remainderr:=xy−qz, cf.2.4. •\*>>(x y z–q), similar to\*/, but with division replaced with a right shift, cf.2.4. Computesq:=bxy/2 z cfor0≤z≤256. Equivalent to 1<< \*/. •\*>>c(x y z–q), similar to\*/c, but with division replaced with a right shift, cf.2.4. Computesq:=dxy/2 z efor0≤z≤256. Equivalent to 1<< \*/c. •\*>>r(x y z–q), similar to\*/r, but with division replaced with a right shift, cf.2.4. Computesq:=bxy/2 z + 1/2cfor0≤z≤256. Equivalent to1<< \*/r. 79 AppendixA.List of Fift words •\*mod(x y z–r), similar to\*/mod, but computes only the remainder r:=xy−qz, whereq:=bxy/zc. Equivalent to\*/mod nip. •+(x y–x+y), computes the sumx+yof twoIntegersxandy, cf.2.4. •+!(x p– ), increases the integer value stored inBoxpbyIntegerx, cf.2.14. Equivalent totuck @ + swap !. •+" 〈string〉"(S–S ′ ), concatenatesStringSwith a string literal, cf.2.10. Equivalent to"〈string〉" $+. •,(t x–t ′ ), appendsxto the end ofTuplet, and returns the resulting Tuplet ′ , cf.2.15. •-(x y–x−y), computes the differencex−yof twoIntegersxandy, cf.2.4. •-!(x p– ), decreases the integer value stored inBoxpbyIntegerx. Equivalent toswap negate swap +!. •-1( –−1), pushesInteger−1. •-1<<(x–−2 x ), computes−2 x for0≤x≤256. Approximately equivalent to1<< negateor-1 swap <<, but works forx= 256as well. •-roll(x n . . .x 0 n–x 0 x n . . .x 1 ), rotates the topnstack entries in the opposite direction, wheren≥0is also passed in the stack, cf.2.5. In particular,1 -rollis equivalent toswap, and2 -rollto-rot. •-rot(x y z–z x y), rotates the three topmost stack entries in the opposite direction, cf.2.5. Equivalent torot rot. •-trailing(S–S ′ ), removes fromStringSall trailing spaces. Equiv- alent tobl (-trailing). •-trailing0(S–S ′ ), removes fromStringSall trailing ‘0’ characters. Equivalent tochar 0 (-trailing). •.(x– ), prints the decimal representation ofIntegerx, followed by a single space, cf.2.4. Equivalent to.\_ space. 80 AppendixA.List of Fift words •."〈string〉"( – ), prints a constant string into the standard output, cf.2.10. •.\_(x– ), prints the decimal representation ofIntegerxwithout any spaces. Equivalent to(.) type. •.dump(x– ), dumps the topmost stack entry in the same way as.s dumps all stack elements, cf.2.15. Equivalent to(dump) type space. •.l(l– ), prints a Lisp-style listl, cf.2.16. •.s( – ), dumps all stack entries starting from the deepest, leaving them intact, cf.2.5. Human-readable representations of stack entries are output separated by spaces, followed by an end-of-line character. •.sl( – ), dumps all stack entries leaving them intact similarly to.s, but showing each entry as a List-style listlas.ldoes. •.tc( – ), outputs the total number of allocated cells into the standard error stream. •/(x y–q:=bx/yc), computes the floor-rounded quotientbx/ycof two Integers, cf.2.4. •/\* 〈multiline-comment〉\*/( – ), skips a multi-line comment delim- ited by word “\*/” (followed by a blank or an end-of-line character), cf.2.2. •// 〈comment-to-eol〉( – ), skips a single-line comment until the end of the current line, cf.2.2. •/c(x y–q:=dx/ye), computes the ceiling-rounded quotientdx/yeof twoIntegers, cf.2.4. •/cmod(x y–q r), computes both the ceiling-rounded quotientq:= dx/yeand the remainderr:=x−qy, cf.2.4. •/mod(x y–q r), computes both the floor-rounded quotientq:=bx/yc and the remainderr:=x−qy, cf.2.4. •/r(x y–q), computes the nearest-integer-rounded quotientbx/y+1/2c of twoIntegers, cf.2.4. 81 AppendixA.List of Fift words •/rmod(x y–q r), computes both the nearest-integer-rounded quotient q:=bx/y+ 1/2cand the remainderr:=x−qy, cf.2.4. •0( –0), pushesInteger0. •0!(p– ), storesInteger0intoBoxp, cf.2.14. Equivalent to0 swap !. •0<(x–?), checks whetherx <0(i.e., pushes−1ifxis negative,0 otherwise), cf.2.12. Equivalent to0 <. •0<=(x–?), checks whetherx≤0(i.e., pushes−1ifxis non-positive, 0otherwise), cf.2.12. Equivalent to0 <=. •0<>(x–?), checks whetherx6= 0(i.e., pushes−1ifxis non-zero,0 otherwise), cf.2.12. Equivalent to0 <>. •0=(x–?), checks whetherx= 0(i.e., pushes−1ifxis zero,0other- wise), cf.2.12. Equivalent to0 =. •0>(x–?), checks whetherx >0(i.e., pushes−1ifxis positive,0 otherwise), cf.2.12. Equivalent to0 >. •0>=(x–?), checks whetherx≥0(i.e., pushes−1ifxis non-negative, 0otherwise), cf.2.12. Equivalent to0 >=. •1( –1), pushesInteger1. •1+(x–x+ 1), computesx+ 1. Equivalent to1 +. •1+!(p– ), increases the integer value stored inBoxpby one, cf.2.14. Equivalent to1 swap +!. •1-(x–x−1), computesx−1. Equivalent to1 -. •1-!(p– ), decreases the integer value stored inBoxpby one. Equiv- alent to-1 swap +!. •1<<(x–2 x ), computes2 x for0≤x≤255. Equivalent to1 swap <<. •1<<1-(x–2 x −1), computes2 x −1for0≤x≤256. Almost equivalent to1<< 1-, but works forx= 256. 82 AppendixA.List of Fift words •2( –2), pushesInteger2. •2\*(x–2x), computes2x. Equivalent to2 \*. •2+(x–x+ 2), computesx+ 2. Equivalent to2 +. •2-(x–x−2), computesx−2. Equivalent to2 -. •2/(x–bx/2c), computesbx/2c. Equivalent to2 /or to1 >>. •2=:〈word-name〉(x y– ), an active variant of2constant: defines a new ordinary word〈word-name〉that would push the given valuesx andywhen invoked, cf.2.7. •2constant(x y– ), scans a blank-delimited word nameSfrom the remainder of the input, and defines a new ordinary wordSas a double constant, which will push the given valuesxandy(of arbitrary types) when invoked, cf.4.5. •2drop(x y– ), removes the two topmost stack entries, cf.2.5. Equiv- alent todrop drop. •2dup(x y–x y x y), duplicates the topmost pair of stack entries, cf.2.5. Equivalent toover over. •2over(x y z w–x y z w x y), duplicates the second topmost pair of stack entries. •2swap(a b c d–c d a b), interchanges the two topmost pairs of stack entries, cf.2.5. •: 〈word-name〉(e– ), defines a new ordinary word〈word-name〉in the dictionary usingWordDefeas its definition, cf.4.5. If the specified word is already present in the dictionary, it is tacitly redefined. •::〈word-name〉(e– ), defines a new active word〈word-name〉in the dictionary usingWordDefeas its definition, cf.4.5. If the specified word is already present in the dictionary, it is tacitly redefined. •::\_ 〈word-name〉(e– ), defines a new active prefix word〈word-name〉 in the dictionary usingWordDefeas its definition, cf.4.5. If the specified word is already present in the dictionary, it is tacitly redefined. 83 AppendixA.List of Fift words •:\_〈word-name〉(e– ), defines a new ordinary prefix word〈word-name〉 in the dictionary usingWordDefeas its definition, cf.4.5. If the specified word is already present in the dictionary, it is tacitly redefined. •<(x y–?), checks whetherx < y(i.e., pushes−1ifIntegerxis less thanIntegery,0otherwise), cf.2.12. •<#( –S), pushes an emptyString. Typically used for starting the con- version of anIntegerinto its human-readable representation, decimal or in another base. Equivalent to"". •<<(x y–x·2 y ), computes an arithmetic left shift of binary numberx byy≥0positions, yieldingx·2 y , cf.2.4. •<(x y–?), checks whetherx6=y(i.e., pushes−1ifIntegersxandy are not equal,0otherwise), cf.2.12. •(x y–?), checks whetherx > y(i.e., pushes−1ifIntegerxis greater thanIntegery,0otherwise), cf.2.12. •>=(x y–?), checks whetherx≥y(i.e., pushes−1ifIntegerxis greater than or equal toIntegery,0otherwise), cf.2.12. •>>(x y–q:=bx·2 −y c), computes an arithmetic right shift of binary numberxby0≤y≤256positions, cf.2.4. Equivalent to1<< /. •>>c(x y–q:=dx·2 −y e), computes the ceiling-rounded quotientqof xby2 y for0≤y≤256, cf.2.4. Equivalent to1<< /c. •>>r(x y–q:=bx·2 −y + 1/2c), computes the nearest-integer-rounded quotientqofxby2 y for0≤y≤256, cf.2.4. Equivalent to1<< /r. •?dup(x–x xor0), duplicates anIntegerx, but only if it is non-zero, cf.2.5. Otherwise leaves it intact. •@(p–x), fetches the value currently stored inBoxp, cf.2.14. •@’ 〈word-name〉( –e), recovers the definition of the specified word at execution time, performing a dictionary lookup each time it is in- voked, and then executes this definition, cf.2.7and4.6. May be used to recover current values of constants inside word definitions and other blocks by using the phrase@’〈word-name〉, equivalent to(’) 〈word-name〉execute. •B+(B ′ B ′′ –B), concatenates twoBytesvalues, cf.5.6. •B,(b B–b ′ ), appendsBytesBtoBuilderb, cf.5.2. If there is no room inbforB, throws an exception. •B=(B B ′ –?), checks whether twoBytessequences are equal, and returns−1or0depending on the comparison outcome, cf.5.6. •B>Li@(B x–y), deserializes the firstx/8bytes of aBytesvalueBas a signed little-endianx-bitIntegery, cf.5.6. 85 AppendixA.List of Fift words •B>Li@+(B x–B ′ y), deserializes the firstx/8bytes ofBas a signed little-endianx-bitIntegerysimilarly toB>Li@, but also returns the remaining bytes ofB, cf.5.6. •B>Lu@(B x–y), deserializes the firstx/8bytes of aBytesvalueBas an unsigned little-endianx-bitIntegery, cf.5.6. •B>Lu@+(B x–B ′ y), deserializes the firstx/8bytes ofBas an unsigned little-endianx-bitIntegerysimilarly toB>Lu@, but also returns the remaining bytes ofB, cf.5.6. •B>boc(B–c), deserializes a “standard” bag of cells (i.e., a bag of cells with exactly one root cell) represented byBytesB, and returns the rootCellc, cf.5.5. •B>file(B S– ), creates a new (binary) file with the name specified inStringSand writes data fromBytesBinto the new file, cf.5.6. If the specified file already exists, it is overwritten. •B>i@(B x–y), deserializes the firstx/8bytes of aBytesvalueBas a signed big-endianx-bitIntegery, cf.5.6. •B>i@+(B x–B ′ y), deserializes the firstx/8bytes ofBas a signed big- endianx-bitIntegerysimilarly toB>i@, but also returns the remaining bytes ofB, cf.5.6. •B>u@(B x–y), deserializes the firstx/8bytes of aBytesvalueBas an unsigned big-endianx-bitIntegery, cf.5.6. •B>u@+(B x–B ′ y), deserializes the firstx/8bytes ofBas an un- signed big-endianx-bitIntegerysimilarly toB>u@, but also returns the remaining bytes ofB, cf.5.6. •B@(s x–B), fetches the firstxbytes (i.e.,8xbits) fromSlices, and returns them as aBytesvalueB, cf.5.3. If there are not enough data bits ins, throws an exception. •B@+(s x–B s ′ ), similar toB@, but returns the remainder ofSlicesas well, cf.5.3. •B@?(s x–B−1or0), similar toB@, but uses a flag to indicate failure instead of throwing an exception, cf.5.3. 86 AppendixA.List of Fift words •B@?+(s x–B s ′ −1ors0), similar toB@+, but uses a flag to indicate failure instead of throwing an exception, cf.5.3. •Bcmp(B B ′ –x), lexicographically compares twoBytessequences, and returns−1,0, or1, depending on the comparison result, cf.5.6. •Bhash(B–x), deprecated version ofBhashu. UseBhashuorBhashB instead. •BhashB(B–B ′ ), computes thesha256hash of aBytesvalue, cf.5.6. The hash is returned as a 32-byteBytesvalue. •Bhashu(B–x), computes thesha256hash of aBytesvalue, cf.5.6. The hash is returned as a big-endian unsigned 256-bitIntegervalue. •Blen(B–x), returns the length of aBytesvalueBin bytes, cf.5.6. •Bx.(B– ), prints the hexadecimal representation of aBytesvalue, cf.5.6. Each byte is represented by exactly two uppercase hexadecimal digits. •B{ 〈hex-digits〉}( –B), pushes aBytesliteral containing data repre- sented by an even number of hexadecimal digits, cf.5.6. •B|(B x–B ′ B ′′ ), cuts the firstxbytes from aBytesvalueB, and returns both the firstxbytes (B ′ ) and the remainder (B ′′ ) as new Bytesvalues, cf.5.6. •Li>B(x y–B), stores a signed little-endiany-bitIntegerxinto aBytes valueBconsisting of exactlyy/8bytes. Integerymust be a multiple of eight in the range0...256, cf.5.6. •Lu>B(x y–B), stores an unsigned little-endiany-bitIntegerxinto aBytesvalueBconsisting of exactlyy/8bytes. Integerymust be a multiple of eight in the range0...256, cf.5.6. •\[ ( – ), opens an internal interpreter session even ifstateis greater than zero, i.e., all subsequent words are executed immediately instead of being compiled. •\[\](t i–x), returns the(i+ 1)-st componentt i+1 ofTuplet, where 0≤i <|t|, cf.2.15. 87 AppendixA.List of Fift words •\[compile\]〈word-name〉( – ), compiles〈word-name〉as if it were an ordinary word, even if it is active, cf.4.6. Essentially equivalent to’ 〈word-name〉execute. •\](x 1 . . .x n n– ), closes an internal interpreter session opened by\[ and invokes(compile)or(execute)afterwards depending on whether stateis greater than zero. For instance,{ \[ 2 3 + 1 \] \* }is equiv- alent to{ 5 \* }. •‘ 〈word〉( –a), introduces anAtomliteral, equal to the onlyAtomwith the name equal to〈word〉, cf.2.17. Equivalent to"〈word〉" atom. •abort(S– ), throws an exception with an error message taken from StringS, cf.3.6. •abort" 〈message〉"(x– ), throws an exception with the error message 〈message〉if theIntegerxis non-zero, cf.3.6. •abs(x–|x|), computes the absolute value|x|= max(x,−x)ofInte- gerx. Equivalent todup negate max. •allot(n–t), creates a new array, i.e., aTuplethat consists ofnnew emptyBoxes, cf.2.15. Equivalent to| { hole , } rot times. •and(x y–x&y), computes the bitwise AND of twoIntegers, cf.2.4. •anon( –a), creates a new unique anonymousAtom, cf.2.17. •atom(S–a), returns the onlyAtomawith the nameS, creating such an atom if necessary, cf.2.17. Equivalent totrue (atom) drop. •atom?(u–?), checks whetheruis anAtom, cf.2.17. •b+(b b ′ –b ′′ ), concatenates twoBuildersbandb ′ , cf.5.2. •b.(x– ), prints the binary representation of anIntegerx, followed by a single space. Equivalent tob.\_ space. •b.\_(x– ), prints the binary representation of anIntegerxwithout any spaces. Equivalent to(b.) type. •b>(b–c), transforms aBuilderbinto a newCellccontaining the same data asb, cf.5.2. 88 AppendixA.List of Fift words •b>idict!(v x D n–D ′ −1orD0), adds a new valuev(represented by aBuilder) with key given by signed big-endiann-bit integerxinto dictionaryDwithn-bit keys, and returns the new dictionaryD ′ and −1on success, cf.6.3. Otherwise the unchanged dictionaryDand0 are returned. •b>idict!+(v x D n–D ′ −1orD0), adds a new key-value pair(x,v) into dictionaryDsimilarly tob>idict!, but fails if the key already exists by returning the unchanged dictionaryDand0, cf.6.3. •b>sdict!(v k D n–D ′ −1orD0), adds a new valuev(represented by aBuilder) with key given by the firstnbits ofSlicekinto dictionaryD withn-bit keys, and returns the new dictionaryD ′ and−1on success, cf.6.3. Otherwise the unchanged dictionaryDand0are returned. •b>sdict!+(v k D n–D ′ −1orD0), adds a new key-value pair(k,v) into dictionaryDsimilarly tob>sdict!, but fails if the key already exists by returning the unchanged dictionaryDand0, cf.6.3. •b>udict!(v x D n–D ′ −1orD0), adds a new valuev(represented by aBuilder) with key given by unsigned big-endiann-bit integerx into dictionaryDwithn-bit keys, and returns the new dictionaryD ′ and−1on success, cf.6.3. Otherwise the unchanged dictionaryDand 0are returned. •b>udict!+(v x D n–D ′ −1orD0), adds a new key-value pair(x,v) into dictionaryDsimilarly tob>udict!, but fails if the key already exists by returning the unchanged dictionaryDand0, cf.6.3. •bbitrefs(b–x y), returns both the number of data bitsxand the number of referencesyalready stored inBuilderb, cf.5.2. •bbits(b–x), returns the number of data bits already stored inBuilderb. The resultxis anIntegerin the range0...1023, cf.5.2. •bl( –x), pushes the Unicode codepoint of a space, i.e., 32, cf.2.10. •boc+>B(c x–B), creates and serializes a “standard” bag of cells, con- taining one rootCellcalong with all its descendants, cf.5.5. An 89 AppendixA.List of Fift words Integerparameter0≤x≤31is used to pass flags indicating the addi- tional options for bag-of-cells serialization, with individual bits having the following effect: –+1enables bag-of-cells index creation (useful for lazy deserializa- tion of large bags of cells). –+2includes the CRC32-C of all data into the serialization (useful for checking data integrity). –+4explicitly stores the hash of the root cell into the serialization (so that it can be quickly recovered afterwards without a complete deserialization). –+8stores hashes of some intermediate (non-leaf) cells (useful for lazy deserialization of large bags of cells). –+16stores cell cache bits to control caching of deserialized cells. Typical values ofxarex= 0orx= 2for very small bags of cells (e.g., TON Blockchain external messages) andx= 31for large bags of cells (e.g., TON Blockchain blocks). •boc>B(c–B), serializes a small “standard” bag of cells with rootCellc and all its descendants, cf.5.5. Equivalent to0 boc+>B. •box(x–p), creates a newBoxcontaining specified valuex, cf.2.14. Equivalent tohole tuck !. •brefs(b–x), returns the number of references already stored in Builderb, cf.5.2. The resultxis anIntegerin the range0...4. •brembitrefs(b–x y), returns both the maximum number of additional data bits0≤x≤1023and the maximum number of additional cell references0≤y≤4that can be stored inBuilderb, cf.5.2. •brembits(b–x), returns the maximum number of additional data bits that can be stored inBuilderb, cf.5.2. Equivalent tobbits 1023 swap -. •bremrefs(b–x), returns the maximum number of additional cell ref- erences that can be stored inBuilderb, cf.5.2. 90 AppendixA.List of Fift words •bye( – ), quits the Fift interpreter to the operating system with a zero exit code, cf.2.3. Equivalent to0 halt. •b{〈binary-data〉}( –s), creates aSlicesthat contains no references and up to 1023 data bits specified in〈binary-data〉, which must be a string consisting only of the characters ‘0’ and ‘1’, cf.5.1. •caddr(l–h ′′ ), returns the third element of a list. Equivalent tocddr car. •cadr(l–h ′ ), returns the second element of a list, cf.2.16. Equivalent tocdr car. •car(l–h), returns the head of a list, cf.2.16. Equivalent tofirst. •cddr(l–t ′ ), returns the tail of the tail of a list. Equivalent tocdr cdr. •cdr(l–t), returns the tail of a list, cf.2.16. Equivalent tosecond. •char 〈string〉( –x), pushes anIntegerwith the Unicode codepoint of the first character of〈string〉, cf.2.10. For instance,char \*is equivalent to42. •chr(x–S), returns a newStringSconsisting of one UTF-8 encoded character with Unicode codepointx. •cmp(x y–z), compares twoIntegersxandy, and pushes1ifx > y, −1ifx < y, and0ifx=y, cf.2.12. Approximately equivalent to- sgn. •cond(x e e ′ – ), ifIntegerxis non-zero, executese, otherwise executes e ′ , cf.3.2. •cons(h t–l), constructs a list from its head (first element)hand its tail (the list consisting of all remaining elements)t, cf.2.16. Equivalent topair. •constant(x– ), scans a blank-delimited word nameSfrom the re- mainder of the input, and defines a new ordinary wordSas a constant, which will push the given valuex(of arbitrary type) when invoked, cf.4.5and2.7. 91 AppendixA.List of Fift words •count(t–n), returns the lengthn=|t|ofTuplet, cf.2.15. •cr( – ), outputs a carriage return (or a newline character) into the standard output, cf.2.10. •create(e– ), defines a new ordinary word with the name equal to the next word scanned from the input, usingWordDefeas its definition, cf.4.5. If the word already exists, it is tacitly redefined. •csr.(s– ), recursively prints aSlices, cf.5.3. On the first line, the data bits ofsare displayed in hexadecimal form embedded into anx{...}construct similar to the one used forSliceliterals (cf.5.1). On the next lines, the cells referred to bysare printed with larger indentation. •def? 〈word-name〉( –?), checks whether the word〈word-name〉is defined at execution time, and returns−1or0accordingly. •depth( –n), returns the current depth (the total number of entries) of the Fift stack as anIntegern≥0. •dictmap(D n e–D ′ ), applies execution tokene(i.e., an anonymous function) to each of the key-value pairs stored in a dictionaryDwith n-bit keys, cf.6.3. The execution token is executed once for each key- value pair, with aBuilderband aSlicev(containing the value) pushed into the stack before executinge. After the executionemust leave in the stack either a modifiedBuilderb ′ (containing all data frombalong with the new valuev ′ ) and−1, or0indicating failure. In the latter case, the corresponding key is omitted from the new dictionary. •dictmerge(D D ′ n e–D ′′ ), combines two dictionariesDandD ′ withn-bit keys into one dictionaryD ′′ with the same keys, cf.6.3. If a key is present in only one of the dictionariesDandD ′ , this key and the corresponding value are copied verbatim to the new dictionary D ′′ . Otherwise the execution token (anonymous function)eis invoked to merge the two valuesvandv ′ corresponding to the same keyk inDandD ′ , respectively. Beforeeis invoked, aBuilderband two Slicesvandv ′ representing the two values to be merged are pushed. After the executioneleaves either a modifiedBuilderb ′ (containing the original data frombalong with the combined value) and−1, or0 92 AppendixA.List of Fift words on failure. In the latter case, the corresponding key is omitted from the new dictionary. •dictnew( –D), pushes theNullvalue that represents a new empty dictionary, cf.6.3. Equivalent tonull. •does(x 1 . . .x n n e–e ′ ), creates a new execution tokene ′ that would pushnvaluesx 1 , . . . ,x n into the stack and then executeewhen invoked, cf.4.7. It is roughly equivalent to a combination of({), (compile), and(}). •drop(x– ), removes the top-of-stack entry, cf.2.5. •dup(x–x x), duplicates the top-of-stack entry, cf.2.5. If the stack is empty, throws an exception. •ed25519\_chksign(B B ′ B ′′ –?), checks whetherB ′ is a valid Ed25519- signature of dataBwith the public keyB ′′ , cf.6.1. •ed25519\_sign(B B ′ –B ′′ ), signs dataBwith the Ed25519 private keyB ′ (a 32-byteBytesvalue) and returns the signature as a 64-byte BytesvalueB ′′ , cf.6.1. •ed25519\_sign\_uint(x B ′ –B ′′ ), converts a big-endian unsigned 256- bit integerxinto a 32-byte sequence and signs it using the Ed25519 private keyB ′ similarly toed25519\_sign, cf.6.1. Equivalent toswap 256 u>B swap ed25519\_sign. The integerxto be signed is typically computed as the hash of some data. •emit(x– ), prints a UTF-8 encoded character with Unicode codepoint given byIntegerxinto the standard output, cf.2.10. For instance,42 emitprints an asterisk “\*”, and916 emitprints a Greek Delta “∆”. Equivalent tochr type. •empty?(s–?), checks whether aSliceis empty (i.e., has no data bits and no references left), and returns−1or0accordingly, cf.5.3. •eq?(u v–?), checks whetheruandvare equalIntegers,Atoms, or Nulls, cf.2.17. If they are not equal, or if they are of different types, or not of one of the types listed, returns zero. 93 AppendixA.List of Fift words •exch(x n . . .x 0 n–x 0 . . .x n ), interchanges the top of the stack with then-th stack entry from the top, wheren≥0is also taken from the stack, cf.2.5. In particular,1 exchis equivalent toswap, and2 exch toswap rot. •exch2(. . .n m– . . . ), interchanges then-th stack entry from the top with them-th stack entry from the top, wheren≥0,m≥0are taken from the stack, cf.2.5. •execute(e– . . . ), executes the execution token (WordDef)e, cf.3.1. •explode(t–x 1 . . .x n n), unpacks aTuplet= (x 1 ,...,x n )of unknown lengthn, and returns that length, cf.2.15. •false( –0), pushes0into the stack, cf.2.11. Equivalent to0. •file-exists?(S–?), checks whether the file with the name specified inStringSexists, cf.5.6. •file>B(S–B), reads the (binary) file with the name specified in StringSand returns its contents as aBytesvalue, cf.5.6. If the file does not exist, an exception is thrown. •find(S–e−1ore1or0), looks upStringSin the dictionary and returns its definition as aWordDefeif found, followed by−1for ordinary words or1for active words, cf.4.6. Otherwise pushes0. •first(t–x), returns the first component of aTuple, cf.2.15. Equiv- alent to0 \[\]. •fits(x y–?), checks whetherIntegerxis a signedy-bit integer (i.e., whether−2 y−1 ≤x <2 y−1 for0≤y≤1023), and returns−1or0 accordingly. •forget( – ), forgets (removes from the dictionary) the definition of the next word scanned from the input, cf.4.5. •gasrunvm(. . .s c z– . . .x c ′ z ′ ), a gas-aware version ofrunvm, cf.6.4: invokes a new instance of TVM with both the current continuationcc and the special registerc3initialized fromSlices, and initializes special registerc4(the “root of persistent data”, cf. \[4, 1.4\]) withCellc. Then 94 AppendixA.List of Fift words starts the new TVM instance with the gas limit set toz. The actually consumed gasz ′ is returned at the top of the final Fift stack, and the final value ofc4is returned immediately below the top of the final Fift stack as anotherCellc ′ . •gasrunvmcode(. . .s z– . . .x z ′ ), a gas-aware version ofrunvmcode, cf.6.4: invokes a new instance of TVM with the current continuation ccinitialized fromSlicesand with the gas limit set toz, thus executing codesin TVM. The original Fift stack (withouts) is passed in its entirety as the initial stack of the new TVM instance. When TVM terminates, its resulting stack is used as the new Fift stack, with the exit codexand the actually consumed gasz ′ pushed at its top. Ifxis non-zero, indicating that TVM has been terminated by an unhandled exception, the next stack entry from the top contains the parameter of this exception, andxis the exception code. All other entries are removed from the stack in this case. •gasrunvmctx(. . .s c t z– . . .x c ′ z ′ ), a gas-aware version ofrunvmctx, cf.6.4. Differs fromgasrunmvin that it initializesc7withTuplet. •gasrunvmdict(. . .s z– . . .x z ′ ), a gas-aware version ofrunvmdict, cf.6.4: invokes a new instance of TVM with the current continua- tionccinitialized fromSlicesand sets the gas limit tozsimilarly togasrunvmcode, but also initializes the special registerc3with the same value, and pushes a zero into the initial TVM stack before the TVM execution begins. The actually consumed gas is returned as an Integerz ′ . In a typical applicationSlicesconsists of a subroutine se- lection code that uses the top-of-stackIntegerto select the subroutine to be executed, thus enabling the definition and execution of several mutually-recursive subroutines (cf. \[4, 4.6\] and7.8). The selector equal to zero corresponds to themain()subroutine in a large TVM program. •halt(x– ), quits to the operating system similarly tobye, but uses Integerxas the exit code, cf.2.3. •hash(c–x), a deprecated version ofhashu. UsehashuorhashB instead. •hashB(c–B), computes thesha256-based representation hash of Cellc(cf. \[4, 3.1\]), which unambiguously definescand all its descen- 95 AppendixA.List of Fift words dants (provided there are no collisions forsha256), cf.5.4. The result is returned as aBytesvalue consisting of exactly 32 bytes. •hashu(c–x), computes thesha256-based representation hash ofCellc similarly tohashB, but returns the result as a big-endian unsigned 256- bitInteger. •hold(S x–S ′ ), appends toStringSone UTF-8 encoded character with Unicode codepointx. Equivalent tochr $+. •hole( –p), creates a newBoxpthat does not hold any value, cf.2.14. Equivalent tonull box. •i,(b x y–b ′ ), appends the big-endian binary representation of a signed y-bit integerxtoBuilderb, where0≤y≤257, cf.5.2. If there is not enough room inb(i.e., ifbalready contains more than1023−ydata bits), or ifIntegerxdoes not fit intoybits, an exception is thrown. •i>B(x y–B), stores a signed big-endiany-bitIntegerxinto aBytes valueBconsisting of exactlyy/8bytes. Integerymust be a multiple of eight in the range0...256, cf.5.6. •i@(s x–y), fetches a signed big-endianx-bit integer from the firstx bits ofSlices, cf.5.3. Ifscontains less thanxdata bits, an exception is thrown. •i@+(s x–y s ′ ), fetches a signed big-endianx-bit integer from the first xbits ofSlicessimilarly toi@, but returns the remainder ofsas well, cf.5.3. •i@?(s x–y−1or0), fetches a signed big-endian integer from aSlice similarly toi@, but pushes integer−1afterwards on success, cf.5.3. If there are less thanxbits left ins, pushes integer0to indicate failure. •i@?+(s x–y s ′ −1ors0), fetches a signed big-endian integer from Slicesand computes the remainder of thisSlicesimilarly toi@+, but pushes−1afterwards to indicate success, cf.5.3. On failure, pushes the unchangedSlicesand0to indicate failure. •idict!(v x D n–D ′ −1orD0), adds a new valuev(represented by aSlice) with key given by signed big-endiann-bit integerxinto 96 AppendixA.List of Fift words dictionaryDwithn-bit keys, and returns the new dictionaryD ′ and −1on success, cf.6.3. Otherwise the unchanged dictionaryDand0 are returned. •idict!+(v x D n–D ′ −1orD0), adds a new key-value pair(x,v) into dictionaryDsimilarly toidict!, but fails if the key already exists by returning the unchanged dictionaryDand0, cf.6.3. •idict-(x D n–D ′ −1orD0), deletes the key represented by signed big-endiann-bitIntegerxfrom the dictionary represented byCellD, cf.6.3. If the key is found, deletes it from the dictionary and returns the modified dictionaryD ′ and−1. Otherwise returns the unmodified dictionaryDand0. •idict@(x D n–v−1or0), looks up key represented by signed big- endiann-bitIntegerxin the dictionary represented byCellorNullD, cf.6.3. If the key is found, returns the corresponding value as aSlicev and−1. Otherwise returns0. •idict@-(x D n–D ′ v−1orD0), looks up the key represented by signed big-endiann-bitIntegerxin the dictionary represented by CellD, cf.6.3. If the key is found, deletes it from the dictionary and returns the modified dictionaryD ′ , the corresponding value as a Slicev, and−1. Otherwise returns the unmodified dictionaryDand 0. •if(x e– ), executes execution token (i.e., aWordDef)e, but only if Integerxis non-zero, cf.3.2. •ifnot(x e– ), executes execution tokene, but only ifIntegerxis zero, cf.3.2. •include(S– ), loads and interprets a Fift source file from the path given byStringS, cf.7.1. If the filenameSdoes not begin with a slash, the Fift include search path, typically taken from theFIFTPATH environment variable or the-Icommand-line argument of the Fift interpreter (and equal to/usr/lib/fiftif both are absent), is used to locateS. 97 AppendixA.List of Fift words •list(x 1 . . .x n n–l), constructs a listlof lengthnwith elements x 1 , . . . ,x n , in that order, cf.2.16. Equivalent tonull ’ cons rot times. •max(x y–z), computes the maximumz:= max(x,y)of twoIntegers xandy. Equivalent tominmax nip. •min(x y–z), computes the minimumz:= min(x,y)of twoIntegersx andy. Equivalent tominmax drop. •minmax(x y–z t), computes both the minimumz:= min(x,y)and the maximumt:= max(x,y)of twoIntegersxandy. •mod(x y–r:=xmody), computes the remainderxmody=x−y· bx/ycof division ofxbyy, cf.2.4. •negate(x–−x), changes the sign of anInteger, cf.2.4. •newkeypair( –B B ′ ), generates a new Ed25519 private/public key pair, and returns both the private keyBand the public keyB ′ as 32-byteBytesvalues, cf.6.1. The quality of the keys is good enough for testing purposes. Real applications must feed enough entropy into OpenSSL PRNG before generating Ed25519 keypairs. •nil( –t), pushes the emptyTuplet= (). Equivalent to0 tuple. •nip(x y–y), removes the second stack entry from the top, cf.2.5. Equivalent toswap drop. •nop( – ), does nothing, cf.4.6. •not(x–−1−x), computes the bitwise complement of anInteger, cf.2.4. •now( –x), returns the current Unixtime as anInteger, cf.6.1. •null( –⊥), pushes theNullvalue, cf.2.16 •null!(p– ), stores aNullvalue intoBoxp. Equivalent tonull swap !. •null?(x–?), checks whetherxisNull, cf.2.16. 98 AppendixA.List of Fift words •or(x y–x|y), computes the bitwise OR of twoIntegers, cf.2.4. •over(x y–x y x), creates a copy of the second stack entry from the top over the top-of-stack entry, cf.2.5. •pair(x y–t), creates new pairt= (x,y), cf.2.15. Equivalent to2 tupleor to| rot , swap ,. •pfxdict!(v k s n–s ′ −1ors0), adds key-value pair(k,v), both represented bySlices, into a prefix dictionaryswith keys of length at mostn, cf.6.3. On success, returns the modified dictionarys ′ and−1. On failure, returns the original dictionarysand0. •pfxdict!+(v k s n–s ′ −1ors0), adds key-value pair(k,v)into prefix dictionaryssimilarly topfxdict!, but fails if the key already exists, cf.6.3. •pfxdict@(k s n–v−1or0), looks up keyk(represented by aSlice) in the prefix dictionaryswith the length of keys limited bynbits, cf.6.3. On success, returns the value found as aSlicevand−1. On failure, returns0. •pick(x n . . .x 0 n–x n . . .x 0 x n ), creates a copy of then-th entry from the top of the stack, wheren≥0is also passed in the stack, cf.2.5. In particular,0 pickis equivalent todup, and1 picktoover. •priv>pub(B–B ′ ), computes the public key corresponding to a private Ed25519 key, cf.6.1. Both the public keyB ′ and the private keyB are represented by 32-byteBytesvalues. •quit(...– ), exits to the topmost level of the Fift interpreter (without printing anokin interactive mode) and clears the stack, cf.2.3. •ref,(b c–b ′ ), appends toBuilderba reference toCellc, cf.5.2. Ifb already contains four references, an exception is thrown. •ref@(s–c), fetches the first reference from theSlicesand returns theCellcreferred to, cf.5.3. If there are no references left, throws an exception. •ref@+(s–s ′ c), fetches the first reference from theSlicessimilarly to ref@, but returns the remainder ofsas well, cf.5.3. 99 AppendixA.List of Fift words •ref@?(s–c−1or0), fetches the first reference from theSlices similarly toref@, but uses a flag to indicate failure instead of throwing an exception, cf.5.3. •ref@?+(s–s ′ c−1ors0), similar toref@+, but uses a flag to indicate failure instead of throwing an exception, cf.5.3. •remaining(s–x y), returns both the number of data bitsxand the number of cell referencesyremaining in theSlices, cf.5.3. •reverse(x 1 . . .x n y 1 . . .y m n m–x n . . .x 1 y 1 . . .y m ), reverses the order ofnstack entries located immediately below the topmostmelements, where both0≤m,n≤255are passed in the stack. •roll(x n . . .x 0 n–x n−1 . . .x 0 x n ), rotates the topnstack entries, wheren≥0is also passed in the stack, cf.2.5. In particular,1 roll is equivalent toswap, and2 rolltorot. •rot(x y z–y z x), rotates the three topmost stack entries. •runvm(. . .s c– . . .x c ′ ), invokes a new instance of TVM with both the current continuationccand the special registerc3initialized from Slices, and initializes special registerc4(the “root of persistent data”, cf. \[4, 1.4\]) withCellc, cf.6.4. In contrast withrunvmdict, does not push an implicit zero into the initial TVM stack; if necessary, it can be explicitly passed unders. The final value ofc4is returned at the top of the final Fift stack as anotherCellc ′ . In this way one can emulate the execution of smart contracts that inspect or modify their persistent storage. •runvmcode(. . .s– . . .x), invokes a new instance of TVM with the current continuationccinitialized fromSlices, thus executing codes in TVM, cf.6.4. The original Fift stack (withouts) is passed in its entirety as the initial stack of the new TVM instance. When TVM terminates, its resulting stack is used as the new Fift stack, with the exit codexpushed at its top. Ifxis non-zero, indicating that TVM has been terminated by an unhandled exception, the next stack entry from the top contains the parameter of this exception, andxis the exception code. All other entries are removed from the stack in this case. 100 AppendixA.List of Fift words •runvmctx(. . .s c t– . . .x c ′ ), a variant ofrunvmthat also initializesc7 (the “context register” of TVM) withTuplet, cf.6.4. •runvmdict(. . .s– . . .x), invokes a new instance of TVM with the current continuationccinitialized fromSlicessimilarly torunvmcode, but also initializes the special registerc3with the same value, and pushes a zero into the initial TVM stack before start, cf.6.4. In a typical applicationSlicesconsists of a subroutine selection code that uses the top-of-stackIntegerto select the subroutine to be executed, thus enabling the definition and execution of several mutually-recursive subroutines (cf. \[4, 4.6\] and7.8). The selector equal to zero corresponds to themain()subroutine in a large TVM program. •s,(b s–b ′ ), appends data bits and references taken fromSlicesto Builderb, cf.5.2. •s>(s– ), throws an exception ifSlicesis non-empty, cf.5.3. It usually marks the end of the deserialization of a cell, checking whether there are any unprocessed data bits or references left. •s>c(s–c), creates aCellcdirectly from aSlices, cf.5.3. Equivalent to. •sbitrefs(s–x y), returns both the number of data bitsxand the number of cell referencesyremaining inSlices, cf.5.3. Equivalent to remaining. •sbits(s–x), returns the number of data bitsxremaining inSlices, cf.5.3. •sdict!(v k D n–D ′ −1orD0), adds a new valuev(represented by aSlice) with key given by the firstnbits ofSlicekinto dictionaryD withn-bit keys, and returns the new dictionaryD ′ and−1on success, cf.6.3. Otherwise the unchanged dictionaryDand0are returned. •sdict!+(v k D n–D ′ −1orD0), adds a new key-value pair(k,v) into dictionaryDsimilarly tosdict!, but fails if the key already exists by returning the unchanged dictionaryDand0, cf.6.3. •sdict-(x D n–D ′ −1orD0), deletes the key given by the firstndata bits ofSlicexfrom the dictionary represented byCellD, cf.6.3. If the 101 AppendixA.List of Fift words key is found, deletes it from the dictionary and returns the modified dictionaryD ′ and−1. Otherwise returns the unmodified dictionaryD and0. •sdict@(k D n–v−1or0), looks up the key given by the firstndata bits ofSlicexin the dictionary represented byCellorNullD, cf.6.3. If the key is found, returns the corresponding value as aSlicevand −1. Otherwise returns0. •sdict@-(x D n–D ′ v−1orD0), looks up the key given by the firstndata bits ofSlicexin the dictionary represented byCellD, cf.6.3. If the key is found, deletes it from the dictionary and returns the modified dictionaryD ′ , the corresponding value as aSlicev, and −1. Otherwise returns the unmodified dictionaryDand0. •second(t–x), returns the second component of aTuple, cf.2.15. Equivalent to1 \[\]. •sgn(x–y), computes the sign of anIntegerx(i.e., pushes1ifx >0, −1ifx <0, and0ifx= 0), cf.2.12. Equivalent to0 cmp. •shash(s–B), computes thesha256-based representation hash of a Sliceby first transforming it into a cell, cf.5.4. Equivalent tos>c hashB. •sign(S x–S ′ ), appends a minus sign “-” toStringSifIntegerxis negative. Otherwise leavesSintact. •single(x–t), creates new singletont= (x), i.e., a one-elementTuple. Equivalent to1 tuple. •skipspc( – ), skips blank characters from the current input line until a non-blank or an end-of-line character is found. •smca>$(x y z–S), packs a standard TON smart-contract address with workchainx(a signed 32-bitInteger) and in-workchain addressy (an unsigned 256-bitInteger) into a 48-character stringS(the human- readable representation of the address) according to flagsz, cf.6.2. Possible individual flags inzare:+1for non-bounceable addresses, +2for testnet-only addresses, and+4for base64url output instead of base64. 102 AppendixA.List of Fift words •space( – ), outputs a single space. Equivalent tobl emitor to." ". •sr,(b s–b ′ ), constructs a newCellcontaining all data and references fromSlices, and appends a reference to this cell toBuilderb, cf.5.2. Equivalent tos>c ref,. •srefs(s–x), returns the number of cell referencesxremaining in Slices, cf.5.3. •swap(x y–y x), interchanges the two topmost stack entries, cf.2.5. •ten( –10), pushesIntegerconstant 10. •third(t–x), returns the third component of aTuple, cf.2.15. Equiv- alent to2 \[\]. •times(e n– ), executes execution token (WordDef)eexactlyntimes, ifn≥0, cf.3.3. Ifnis negative, throws an exception. •triple(x y z–t), creates new triplet= (x,y,z), cf.2.15. Equivalent to3 tuple. •true( –−1), pushes−1into the stack, cf.2.11. Equivalent to-1. •tuck(x y–y x y), equivalent toswap over, cf.2.5. •tuple(x 1 . . .x n n–t), creates newTuplet:= (x 1 ,...,x n )fromn≥ 0topmost stack values, cf.2.15. Equivalent todup 1 reverse | { swap , } rot times, but more efficient. •tuple?(t–?), checks whethertis aTuple, and returns−1or0 accordingly. •type(s– ), prints aStringstaken from the top of the stack into the standard output, cf.2.10. •u,(b x y–b ′ ), appends the big-endian binary representation of an unsignedy-bit integerxtoBuilderb, where0≤y≤256, cf.5.2. If the operation is impossible, an exception is thrown. •u>B(x y–B), stores an unsigned big-endiany-bitIntegerxinto a BytesvalueBconsisting of exactlyy/8bytes. Integerymust be a multiple of eight in the range0...256, cf.5.6. 103 AppendixA.List of Fift words •u@(s x–y), fetches an unsigned big-endianx-bit integer from the first xbits ofSlices, cf.5.3. Ifscontains less thanxdata bits, an exception is thrown. •u@+(s x–y s ′ ), fetches an unsigned big-endianx-bit integer from the firstxbits ofSlicessimilarly tou@, but returns the remainder ofsas well, cf.5.3. •u@?(s x–y−1or0), fetches an unsigned big-endian integer from aSlicesimilarly tou@, but pushes integer−1afterwards on success, cf.5.3. If there are less thanxbits left ins, pushes integer0to indicate failure. •u@?+(s x–y s ′ −1ors0), fetches an unsigned big-endian integer from Slicesand computes the remainder of thisSlicesimilarly tou@+, but pushes−1afterwards to indicate success, cf.5.3. On failure, pushes the unchangedSlicesand0to indicate failure. •udict!(v x D n–D ′ −1orD0), adds a new valuev(represented by aSlice) with key given by big-endian unsignedn-bit integerxinto dictionaryDwithn-bit keys, and returns the new dictionaryD ′ and −1on success, cf.6.3. Otherwise the unchanged dictionaryDand0 are returned. •udict!+(v x D n–D ′ −1orD0), adds a new key-value pair(x,v) into dictionaryDsimilarly toudict!, but fails if the key already exists by returning the unchanged dictionaryDand0, cf.6.3. •udict-(x D n–D ′ −1orD0), deletes the key represented by unsigned big-endiann-bitIntegerxfrom the dictionary represented byCellD, cf.6.3. If the key is found, deletes it from the dictionary and returns the modified dictionaryD ′ and−1. Otherwise returns the unmodified dictionaryDand0. •udict@(x D n–v−1or0), looks up key represented by unsigned big- endiann-bitIntegerxin the dictionary represented byCellorNullD, cf.6.3. If the key is found, returns the corresponding value as aSlicev and−1. Otherwise returns0. •udict@-(x D n–D ′ v−1orD0), looks up the key represented by unsigned big-endiann-bitIntegerxin the dictionary represented by 104 AppendixA.List of Fift words CellD, cf.6.3. If the key is found, deletes it from the dictionary and returns the modified dictionaryD ′ , the corresponding value as a Slicev, and−1. Otherwise returns the unmodified dictionaryDand 0. •ufits(x y–?), checks whetherIntegerxis an unsignedy-bit integer (i.e., whether0≤x <2 y for0≤y≤1023), and returns−1or0 accordingly. •uncons(l–h t), decomposes a non-empty list into its head and its tail, cf.2.16. Equivalent tounpair. •undef? 〈word-name〉( –?), checks whether the word〈word-name〉is undefined at execution time, and returns−1or0accordingly. •unpair(t–x y), unpacks a pairt= (x,y), cf.2.15. Equivalent to2 untuple. •unsingle(t–x), unpacks a singletont= (x). Equivalent to1 untuple. •until(e– ), an until loop, cf.3.4: executesWordDefe, then removes the top-of-stack integer and checks whether it is zero. If it is, then begins a new iteration of the loop by executinge. Otherwise exits the loop. •untriple(t–x y z), unpacks a triplet= (x,y,z), cf.2.15. Equivalent to3 untuple. •untuple(t n–x 1 . . .x n ), returns all components of aTuplet= (x 1 ,...,x n ), but only if its length is equal ton, cf.2.15. Otherwise throws an exception. •variable( – ), scans a blank-delimited word nameSfrom the remain- der of the input, allocates an emptyBox, and defines a new ordinary wordSas a constant, which will push the newBoxwhen invoked, cf.2.14. Equivalent tohole constant. •while(e e ′ – ), a while loop, cf.3.4: executesWordDefe, then re- moves and checks the top-of-stack integer. If it is zero, exits the loop. Otherwise executesWordDefe ′ , then begins a new loop iteration by executingeand checking the exit condition afterwards. 105 AppendixA.List of Fift words •word(x–s), parses a word delimited by the character with the Unicode codepointxfrom the remainder of the current input line and pushes the result as aString, cf.2.10. For instance,bl word abracadabra type will print the string “abracadabra”. Ifx= 0, skips leading spaces, and then scans until the end of the current input line. Ifx= 32, skips leading spaces before parsing the next word. •words( – ), prints the names of all words currently defined in the dictionary, cf.4.6. •x.(x– ), prints the hexadecimal representation (without the0xprefix) of anIntegerx, followed by a single space. Equivalent tox.\_ space. •x.\_(x– ), prints the hexadecimal representation (without the0xpre- fix) of anIntegerxwithout any spaces. Equivalent to(x.) type. •xor(x y–x⊕y), computes the bitwise eXclusive OR of twoIntegers, cf.2.4. •x{ 〈hex-data〉}( –s), creates aSlicesthat contains no references and up to 1023 data bits specified in〈hex-data〉, cf.5.1. More precisely, each hex digit from〈hex-data〉is transformed into four binary digits in the usual fashion. After that, if the last character of〈hex-data〉 is an underscore\_, then all trailing binary zeroes and the binary one immediately preceding them are removed from the resulting binary string (cf. \[4, 1.0\] for more details). For instance,x{6C\_}is equivalent tob{01101}. •{ ( –l), an active word that increases internal variablestateby one and pushes a new emptyWordListinto the stack, cf.4.7. •|( –t), creates an emptyTuplet= (), cf.2.15. Equivalent tonil and to0 tuple. •|+(s s ′ –s ′′ ), concatenates twoSlicessands ′ , cf.5.1. This means that the data bits of the newSlices ′′ are obtained by concatenating the data bits ofsands ′ , and the list ofCellreferences ofs ′′ is con- structed similarly by concatenating the corresponding lists forsands ′ . Equivalent to c ref, b> Lt(e ′ )wheneveree ′ (i.e.,elogically depends one ′ ), (9) without insisting thatLt(e)be the smallest non-negative integer with this property. In such cases we can speak aboutrelaxedlogical time, as opposed to thestrictlogical time defined above (cf.1.4.1). Notice, however, that the condition (9) is a fundamental property of logical time and cannot be relaxed further. 1.4.3. Logical time intervals.It makes sense to assign to some events or collections of eventsCanintervalof logical timesLt • (C) = \[Lt − (C),Lt + (C)), meaning that the collection of eventsCtook place in the specified “interval” of logical times, whereLt − (C)Lt(m), orLt(m ′ ) =Lt(m)andHash(m ′ )>Hash(m). 2.2.7. Deleting a message fromOutMsgQueue.A message must be deleted fromOutMsgQueuesooner or later; otherwise, the storage used by OutMsgQueuewould grow to infinity. To this end, several “garbage collection 19 In particular, if the hash of a recent block of a neighboring shardchain is not yet reflected in the latest masterchain block, its modifications toOutMsgQueuemust not be taken into account. 43 2.2. Hypercube Routing protocol rules” are introduced. They allow the deletion of a message fromOutMs- gQueueduring the evaluation of a block only if an explicit special “delivery record” is present in theOutMsgDescrof that block. This record contains either a reference to the neighboring shardchain block that has included the message into itsInMsgDescr(the hash of the block is sufficient, but collated material for the block may contain the relevant Merkle proof), or a Merkle proof of the fact that the message has been delivered to its final destination via Instant Hypercube Routing. 2.2.8. Guaranteed message delivery via Hypercube Routing.In this way, a message cannot be deleted from the outbound message queue unless it has been either relayed to its next-hop shardchain or delivered to its final destination (cf.2.2.7). Meanwhile, the message import monotonicity con- dition (cf.2.2.5) ensures that any message will sooner or later be relayed into the next shardchain, taking into account other conditions which require the validators to use at least half of the block’s space or gas limits for im- porting inbound internal messages (otherwise the validators might choose to create empty blocks or import only external messages even in the presence of non-empty outbound message queues at their neighbors). 2.2.9. Message processing order.When several imported messages are processed by transactions inside a block, themessage processing order con- ditionsensure that older messages are processed first. More precisely, if a block contains two transactionstandt ′ of the same account, which process inbound messagesmandm ′ , respectively, andLt(m) k, andξ l+1 =NextHop(ξ l ,η)are obtained, such that ξ l lies inS k+1 , butξ l+1 does not (cf.2.1.11). After that, a newly- enveloped copy ofmwith transit address set toξ l and next-hop address ξ l+1 is included into both theOutMsgDescrof the current block of S k+1 and theOutMsgQueueof the new state ofS k+1 . The entry ofm inInMsgDescrcontains a flag indicating that the message has been forwarded; the entry inOutMsgDescrcontains the newly-enveloped message and a flag indicating that this is a forwarded message. Then all the steps starting from \[OutboundQueueing\] are repeated, forlinstead ofk. •\[Processing?\] — If the final destinationηofmresides inS k+1 , then the block ofS k+1 that imported the message must process it by a transactiontincluded in the same block. In this case,InMsgDescr contains a reference totby its logical timeLt(t), and a flag indicating that the message has been processed. The above message routing algorithm does not take into account some fur- ther modifications required to implement Instant Hypercube Routing (IHR). For instance, a message may bediscardedafter being imported (listed in InMsgDescr) into its final or intermediate shardchain block, because a proof of delivery via IHR to the final destination is presented. In this case, such a proof must be included intoInMsgDescrto explain why the message was not forwarded further or processed. 2.3 Instant Hypercube Routing and combined delivery guarantees This section describes the Instant Hypercube Routing protocol, normally applied by TON Blockchain in parallel to the previously discussed Hypercube Routing protocol to achieve faster message delivery. However, when both Hypercube Routing and Instant Hypercube Routing are applied to the same message in parallel, achieving delivery and unique delivery guarantees is more complicated. This topic is also discussed in this section. 2.3.1. An overview of Instant Hypercube Routing.Let us explain the major steps applied when the Instant Hypercube Routing (IHR) mechanism is applied to a message. (Notice that normally both the usual HR and IHR 47 2.3. Instant Hypercube Routing and combined delivery guarantees work in parallel for the same message; some provisions must be taken to guarantee the uniqueness of delivery of any message.) Consider the routing and delivery of the same messagemwith sourceξ and destinationηas discussed in2.2.12: •\[NetworkSend\] — After the validators ofS 0 have agreed on and signed the block containing the creating transactiontform, and observed that the destinationηofmdoes not reside insideS 0 , they may send a datagram (encrypted network message), containing the messagem along with a Merkle proof of its inclusion into theOutMsgDescrof the block just generated, to the validator group of the shardchainT currently owning the destinationη. •\[NetworkReceive\] — If the validators of shardchainTreceive such a message, they check its validity starting from the most recent master- chain block and the shardchain block hashes listed in it, including the most recent “canonical” block of shardchainS 0 as well. If the message is invalid, they silently discard it. If that block of shardchainS 0 has a larger sequence number than the one listed in the most recent mas- terchain block, they may either discard it or postpone the verification until the next masterchain block appears. •\[InclusionConditions\] — The validators check inclusion conditions for messagem. In particular, they must check that this message has not been delivered before, and that theOutMsgQueues of the neighbors do not have unprocessed outbound messages with destinations inTwith smaller logical creation times thanLt(m). •\[Deliver\] — The validators deliver and process the message, by includ- ing it into theInMsgDescrof the current shardchain block along with a bit indicating that it is an IHR message, the Merkle proof of its inclu- sion into theOutMsgDescrof the original block, and the logical time of the transactiont ′ processing this inbound message into the currently generated block. •\[Confirm\] — Finally, the validators send encrypted datagrams to all the validator groups of the intermediate shardchains on the path from ξtoη, containing a Merkle proof of the inclusion of messageminto theInMsgDescrof its final destination. The validators of an interme- diate shardchain may use this proof todiscardthe copy of message 48 2.3. Instant Hypercube Routing and combined delivery guarantees mtravelling by the rules of HR, by importing the message into their InMsgDescralong with the Merkle proof of final delivery and setting a flag indicating that the message has been discarded. The overall procedure is even simpler than that for Hypercube Routing. Notice, however, that IHR comes with no delivery or FIFO guarantees: the network datagram may be lost in transit, or the validators of the destination shardchain may decide not to act on it, or they may discard it due to buffer overflow. This is the reason why IHR is used as a complement to HR, and not as a replacement. 2.3.2. Overall eventual delivery guarantees.Notice that the combina- tion of HR and IHR guarantees the ultimate delivery of any internal message to its final destination. Indeed, the HR by itself is guaranteed to deliver any message eventually, and the HR for messagemcan be cancelled at an inter- mediate stage only by a Merkle proof of delivery ofmto its final destination (via IHR). 2.3.3. Overall unique delivery guarantees.However, theuniqueness of message delivery for the combination of HR and IHR is more difficult to achieve. In particular, one must check the following conditions, and, if necessary, be able to provide short Merkle proofs that they do or don’t hold: •When a messagemis imported into its next intermediate shardchain block via HR, we must check thatmhas not already been imported via HR. •Whenmis imported and processed in its final destination shardchain, we must check thatmhas not already been processed. If it has, there are three subcases: –Ifmis being considered for import via HR, and it has already been imported via HR, it must not be imported at all. –Ifmis being considered for import via HR, and it has already been imported via IHR (but not HR), then it must be imported and immediately discarded (without being processed by a trans- action). This is necessary to removemfrom theOutMsgQueueof its previous intermediate shardchain. 49 2.3. Instant Hypercube Routing and combined delivery guarantees –Ifmis being considered for import via IHR, and it has already been imported via either IHR or HR, it must not be imported at all. 2.3.4. Checking whether a message has already been delivered to its final destination.Consider the following general algorithm for checking whether a messagemhas already been delivered to its final destinationη: One can simply scan the last several blocks belonging to the shardchain containing the destination address, starting from the latest block and working backwards through the previous block references. (If there are two previous blocks—i.e., if a shardchain merge event occurred at some point—one would follow the chain containing the destination address.) TheInMsgDescrof each of these blocks can be checked for an entry with keyHash(m). If such an entry is found, the messagemhas already been delivered, and we can easily construct a Merkle proof of this fact. If we do not find such an entry before arriving at a blockBwithLt + (B)Lt(m)ifmis the inbound message processed by transactiont. In this way, the logical time intervals of transactions of the same account do not intersect each other, and as a consequence, the logical time intervals of all outbound messages generated by an account do 75 4.2. Transactions not intersect each other either. In other words, allLt(m)are different, when mruns through all outbound messages of the same accountξ. In this way,Lt(t)andLt(m), when combined with an account identifier ξ, uniquely determine a transactiontor an outbound messagemof that account. Furthermore, if one has an ordered list of all transactions of an account along with their logical times, it is easy to find the transaction that generated a given outbound messagem, simply by looking up the transaction twith logical timeLt(t)nearest toLt(m)from below. 4.2.3. Generic components of a transaction.Each transactiontcon- tains or indirectly refers to the following data: •The accountξto which the transaction belongs. •The logical timeLt(t)of the transaction. •One or zero inbound messagesmprocessed by the transaction. •The number of generated outbound messagesn≥0. •The outbound messagesm 1 , . . . ,m n . •The initial state of accountξ(including its balance). •The final state of accountξ(including its balance). •The total fees collected by the validators. •A detailed description of the transaction containing all or some data needed to validate it, including the kind of the transaction (cf.4.2.4) and some of the intermediate steps performed. Of these components, all but the very last one are quite general and might appear in other workchains as well. 4.2.4. Kinds of transactions.There are different kinds of transactions al- lowed in the masterchain and the shardchains.Ordinarytransactions consist in the delivery of one inbound message to an account, and its processing by that account’s code; this is the most common kind of transaction. Addition- ally, there are several kinds ofexotictransactions. Altogether, there are six kinds of transactions: 76 4.2. Transactions •Ordinary transactions— Belong to an accountξ. They process exactly one inbound messagem(described inInMsgDescrof the encompassing block) with destinationξ, compute the new state of the account, and generate several outbound messages (registered inOutMsgDescr) with sourceξ. •Storage transactions— Can be inserted by validators at their discre- tion. They do not process any inbound message and do not invoke any code. Their only effect is to collect storage payments from an account, affecting its storage statistics and its balance. If the resulting Gram balance of the account becomes less than a certain amount, the account may be frozen and its code and data replaced by their combined hash. •Tick transactions— Automatically invoked for certain special accounts (smart contracts) in the masterchain that have thetickflag set in their state, as the very first transactions in every masterchain block. They have no inbound message, but may generate outbound messages and change the account state. For instance,validator electionsare performed by tick transactions of special smart contracts in the mas- terchain. •Tock transactions— Similarly automatically invoked as the very last transactions in every masterchain block for certain special accounts. •Split transactions— Invoked as the last transactions of shardchain blocks immediately preceding a shardchain split event. They are trig- gered automatically for instances of large smart contracts that need to produce a new instance after splitting. •Merge transactions— Similarly invoked as the first transactions of shardchain blocks immediately after a shardchain merge event, if an instance of a large smart contract needs to be merged with another instance of the same smart contract. Notice that out of these six kinds of transactions, only four can occur in the masterchain, and another subset of four can occur in the basic workchain. 4.2.5. Phases of an ordinary transaction.An ordinary transaction is performed in severalphases, which may be thought of as several “sub- transactions” tightly bound into one: 77 4.2. Transactions •Storage phase— Collects due storage payments for the account state (including smart-contract code and data, if present) up to the present time. The smart contract may befrozenas a result. If the smart contract did not exist before, the storage phase is absent. •Credit phase— The account is credited with the value of the inbound message received. •Computing phase— The code of the smart contract is invoked inside an instance of TVM with adequate parameters, including a copy of the inbound message and of the persistent data, and terminates with an exit code, the new persistent data, and anaction list(which includes, for instance, outbound messages to be sent). The processing phase may lead to the creation of a new account (uninitialized or active), or to the activation of a previously uninitialized or frozen account. Thegas payment, equal to the product of the gas price and the gas consumed, is exacted from the account balance. •Action phase— If the smart contract has terminated successfully (with exit code 0 or 1), the actions from the list are performed. If it is impossible to perform all of them—for example, because of insufficient funds to transfer with an outbound message—then the transaction is aborted and the account state is rolled back. The transaction is also aborted if the smart contract did not terminate successfully, or if it was not possible to invoke the smart contract at all because it is uninitialized or frozen. •Bounce phase— If the transaction has been aborted, and the inbound message has itsbounceflag set, then it is “bounced” by automatically generating an outbound message (with thebounceflag clear) to its original sender. Almost all value of the original inbound message (mi- nus gas payments and forwarding fees) is transferred to the generated message, which otherwise has an empty body. 4.2.6. Bouncing inbound messages to non-existent accounts.Notice that if an inbound message with itsbounceflag set is sent to a previously non-existent account, and the transaction is aborted (for instance, because there is no code and data with the correct hash in the inbound message, so the virtual machine could not be invoked at all), then the account is not 78 4.2. Transactions created even as an uninitialized account, since it would have zero balance and no code and data anyways. 31 4.2.7. Processing of an inbound message is split between computing and action phases.Notice that the processing of an inbound message is in fact split into two phases: thecomputingphase and theactionphase. During the computing phase, the virtual machine is invoked and the necessary computations are performed, but no actions outside the virtual machine are taken. In other words,the execution of a smart contract in TVM has no side effects; there is no way for a smart contract to interact with the blockchain directly during its execution. Instead, TVM primitives such asSENDMSG simply store the required action (e.g., the outbound message to be sent) into the action list being gradually accumulated in TVM control registerc5. The actions themselves are postponed until the action phase, during which the user smart contract is not invoked at all. 4.2.8. Reasons for splitting the processing into computation and action phases.Some reasons for such an arrangement are: •It is simpler to abort the transaction if the smart contract eventually terminates with an exit code other than 0 or 1. •The rules for processing output actions may be changed without mod- ifying the virtual machine. (For instance, new output actions may be introduced.) •The virtual machine itself may be modified or even replaced by another one (for instance, in a new workchain) without changing the rules for processing output actions. •The execution of the smart contract inside the virtual machine is com- pletely isolated from the blockchain and is apure computation. As a consequence, this execution may bevirtualizedinside the virtual ma- chine itself by means of TVM’sRUNVMprimitive, a useful feature for validator smart contracts and for smart contracts controlling payment 31 In particular, if a user mistakenly sends some funds to a non-existent address in a bounceable message, the funds will not be wasted, but rather will be returned (bounced) back. Therefore, a user wallet application should set thebounceflag in all generated mes- sages by default unless explicitly instructed otherwise. However, non-bounceable messages are indispensable in some situations (cf.1.7.6). 79 4.2. Transactions channels and other sidechains. Additionally, the virtual machine may beemulatedinside itself or a stripped-down version of itself, a useful feature for validating the execution of smart contracts inside TVM. 32 4.2.9. Storage, tick, and tock transactions.Storage transactions are very similar to a stand-alone storage phase of an ordinary transaction. Tick and tock transactions are similar to ordinary transactions without credit and bounce phases, because there is no inbound message. 4.2.10. Split transactions.Split transactions in fact consist of two trans- actions. If an accountξneeds to be split into two accountsξandξ ′ : •First asplit prepare transaction, similar to a tock transaction (but in a shardchain instead of the masterchain), is issued for accountξ. It must be the last transaction forξin a shardchain block. The output of the processing stage of a split prepare transaction consists not only of the new state of accountξ, but also of the new state of accountξ ′ , represented by a constructor message toξ ′ (cf.4.1.7). •Then asplit install transactionis added for accountξ ′ , with a refer- ence to the corresponding split prepare transaction. The split install transaction must be the only transaction for a previously non-existent accountξ ′ in the block. It effectively sets the state ofξ ′ as defined by the split prepare transaction. 4.2.11. Merge transactions.Merge transactions also consist of two trans- actions each. If an accountξ ′ needs to be merged into accountξ: •First amerge prepare transactionis issued forξ ′ , which converts all of its persistent state and balance into a special constructor message with destinationξ(cf.4.1.7). •Then amerge install transactionforξ, referring to the corresponding merge prepare transaction, processes that constructor message. The merge install transaction is similar to a tick transaction in that it must be the first transaction forξin a block, but it is located in a shardchain block, not in the masterchain, and it has a special inbound message. 32 A reference implementation of a TVM emulator running in a stripped-down version of TVM may be committed into the masterchain to be used when a disagreement between the validators on a specific run of TVM arises. In this way, flawed implementations of TVM may be detected. The reference implementation then serves as an authoritative source on the operational semantics of TVM. (Cf. \[4, B.2\]) 80 4.2. Transactions 4.2.12. Serialization of a general transaction.Any transaction con- tains the fields listed in4.2.3. As a consequence, there are some common components in all transactions: transaction$\_ account\_addr:uint256 lt:uint64 outmsg\_cnt:uint15 orig\_status:AccountStatus end\_status:AccountStatus in\_msg:(Maybe ^(Message Any)) out\_msgs:(HashmapE 15 ^(Message Any)) total\_fees:Grams state\_update:^(MERKLE\_UPDATE Account) description:^TransactionDescr = Transaction; !merkle\_update#02 {X:Type} old\_hash:uint256 new\_hash:uint256 old:^X new:^X = MERKLE\_UPDATE X; The exclamation mark in the TL-B declaration of amerkle\_updateindicates special processing required for such values. In particular, they must be kept in a separate cell, which must be marked asexoticby a bit in its header (cf. \[4, 3.1\]). A full explanation of the serialization ofTransactionDescr, which de- scribes one transaction according to its kind listed in4.2.4, can be found in4.3. 4.2.13. Representation of outbound messages generated by a trans- action.The outbound messages generated by a transactiontare kept in a dictionaryout\_msgswith 15-bit keys equal to 0, 1, . . . ,n−1, where n=outmsg\_cntis the number of generated outbound messages. Message m i+1 with index0≤i < nmust haveLt(m i+1 ) =Lt(t) +i+ 1, and Lt(t) =Lt − (t)is explicitly stored in theltfield. 4.2.14. Consistency conditions for transactions.The common serial- ization of the fields present in aTransaction, independent of its type and description, enables us to impose several “external” consistency conditions on any transaction. The most important of them involves thevalue flowin- side the transaction: the sum of all inputs (the import value of the inbound message plus the original balance of the account) must equal the sum of all outputs (the resulting balance of the account, plus the sum of the export values of all outbound messages, plus all storage, processing, and forwarding fees collected by the validators). In this way, a surface inspection of a trans- action, which processes an inbound message with an import value of 1 Gram 81 4.2. Transactions received by an account with an initial balance of 10 Grams, generating an outbound message with an export value of 100 Grams in the process, will reveal its invalidity even before checking all the details of the TVM execution. Other consistency conditions may slightly depend on the description of the transaction. For instance, the inbound message processed by an ordinary transaction must be registered in theInMsgDescrof the encompassing block, and the corresponding record must contain a reference to this transaction. Similarly, all outbound messages generated by all transactions (with the ex- ception of one special message generated by a split prepare or merge prepare transaction) must be registered inOutMsgDescr. 4.2.15. Collection of all transactions of an account.All transactions in a block belonging to the same accountξare collected into an “accountchain block”AccountBlock,which essentially is a dictionarytransactionswith 64-bit keys, each equal to the logical time of the corresponding transaction: acc\_trans$\_ account\_addr:uint256 transactions:(HashmapAug 64 ^Transaction Grams) state\_update:^(MERKLE\_UPDATE Account) = AccountBlock; Thetransactionsdictionary is sum-augmented by aGramsvalue, which aggregates the total fees collected from these transactions. In addition to this dictionary, anAccountBlockcontains a Merkle update (cf. \[4, 3.1\]) of the total state of the account. If an account did not exist before the block, its state is represented by anaccount\_none. 4.2.16. Consistency conditions forAccountBlocks.There are several general consistency conditions imposed on anAccountBlock. In particular: •The transaction appearing as a value in the augmentedtransactions dictionary must have itsltvalue equal to its key. •All transactions must belong to an account whose addressaccount\_addr is indicated in theAccountBlock. •Iftandt ′ are two transactions withLt(t) x acst\_frozen$10 = AccStatusChange; // init -> frozen acst\_deleted$11 = AccStatusChange; // frozen -> deleted 4.3.4. Description of a credit phase.The credit phase can result in the collection of some due payments: tr\_phase\_credit$\_ due\_fees\_collected:(Maybe Grams) credit:CurrencyCollection = TrCreditPhase; The sum ofdue\_fees\_collectedandcreditmust equal the value of the message received, plus itsihr\_feeif the message has not been received via IHR (otherwise theihr\_feeis awarded to the validators). 4.3.5. Description of a computing phase.The computing phase consists in invoking TVM with correct inputs. On some occasions, TVM cannot be invoked at all (e.g., if the account is absent, not initialized, or frozen, and the inbound message being processed has no code or data fields or these fields have an incorrect hash); this is reflected by corresponding constructors. tr\_phase\_compute\_skipped$0 reason:ComputeSkipReason = TrComputePhase; tr\_phase\_compute\_vm$1 success:Bool msg\_state\_used:Bool account\_activated:Bool gas\_fees:Grams \_:^\[ gas\_used:(VarUInteger 7) gas\_limit:(VarUInteger 7) gas\_credit:(Maybe (VarUInteger 3)) 85 4.3. Transaction descriptions mode:int8 exit\_code:int32 exit\_arg:(Maybe int32) vm\_steps:uint32 vm\_init\_state\_hash:uint256 vm\_final\_state\_hash:uint256 \] = TrComputePhase; cskip\_no\_state$00 = ComputeSkipReason; cskip\_bad\_state$01 = ComputeSkipReason; cskip\_no\_gas$10 = ComputeSkipReason; The TL-B construct\_:ˆ\[...\]describes a reference to a cell containing the fields listed inside the square brackets. In this way, several fields can be moved from a cell containing a large record into a separate subcell. 4.3.6. Skipped computing phase.If the computing phase has been skipped, possible reasons include: •The absence of funds to buy gas. •The absence of a state (i.e., smart-contract code and data) in both the account (non-existing, uninitialized, or frozen) and the message. •An invalid state passed in the message (i.e., the state’s hash differs from the expected value) to a frozen or uninitialized account. 4.3.7. Valid computing phase.If there is no reason to skip the comput- ing phase, TVM is invoked and the results of the computation are logged. Possible parameters are as follows: •Thesuccessflag is set if and only ifexit\_codeis either 0 or 1. •Themsg\_state\_usedparameter reflects whether the state passed in the message has been used. If it is set, theaccount\_activatedflag re- flects whether this has resulted in the activation of a previously frozen, uninitialized or non-existent account. •Thegas\_feesparameter reflects the total gas fees collected by the val- idators for executing this transaction. It must be equal to the product ofgas\_usedandgas\_pricefrom the current block header. •Thegas\_limitparameter reflects the gas limit for this instance of TVM. It equals the lesser of either the Grams credited in the credit phase from the value of the inbound message divided by the current gas price, or the global per-transaction gas limit. 86 4.3. Transaction descriptions •Thegas\_creditparameter may be non-zero only for external inbound messages. It is the lesser of either the amount of gas that can be paid from the account balance or the maximum gas credit. •Theexit\_codeandexit\_argsparameters represent the status values returned by TVM. •Thevm\_init\_state\_hashandvm\_final\_state\_hashparameters are the representation hashes of the original and resulting states of TVM, andvm\_stepsis the total number of steps performed by TVM (usu- ally equal to two plus the number of instructions executed, including implicitRETs). 33 4.3.8. Description of the action phase.The action phase occurs after a valid computation phase. It attempts to perform the actions stored by TVM during the computing phase into theaction list. It may fail, because the action list may turn out to be too long, contain invalid actions, or contain actions that cannot be completed (for instance, because of insufficient funds to create an outbound message with the required value). tr\_phase\_action$\_ success:Bool valid:Bool no\_funds:Bool status\_change:AccStatusChange total\_fwd\_fees:(Maybe Grams) total\_action\_fees:(Maybe Grams) result\_code:int32 result\_arg:(Maybe int32) tot\_actions:int16 spec\_actions:int16 msgs\_created:int16 action\_list\_hash:uint256 tot\_msg\_size:StorageUsed = TrActionPhase; 4.3.9. Description of the bounce phase. tr\_phase\_bounce\_negfunds$00 = TrBouncePhase; tr\_phase\_bounce\_nofunds$01 msg\_size:StorageUsed req\_fwd\_fees:Grams = TrBouncePhase; tr\_phase\_bounce\_ok$1 msg\_size:StorageUsed msg\_fees:Grams fwd\_fees:Grams = TrBouncePhase; 4.3.10. Description of an ordinary transaction. 33 Notice that this record does not represent a change in the state of the account, because the transaction may still be aborted during the action phase. In that case, the new persistent data indirectly referenced byvm\_final\_state\_hashwill be discarded. 87 4.3. Transaction descriptions trans\_ord$0000 storage\_ph:(Maybe TrStoragePhase) credit\_ph:(Maybe TrCreditPhase) compute\_ph:TrComputePhase action:(Maybe ^TrActionPhase) aborted:Bool bounce:(Maybe TrBouncePhase) destroyed:Bool = TransactionDescr; Several consistency conditions are imposed on this structure: •actionis absent if and only if the computing phase was unsuccessful. •Theabortedflag is set either if there is no action phase or if the action phase was unsuccessful. •The bounce phase occurs only if theabortedflag is set and the inbound message was bounceable. 4.3.11. Description of a storage transaction.A storage transaction consists just of one stand-alone storage phase: trans\_storage$0001 storage\_ph:TrStoragePhase = TransactionDescr; 4.3.12. Description of tick and tock transactions.Tick and tock trans- actions are similar to ordinary transactions without an inbound message, so there are no credit or bounce phases: trans\_tick\_tock$001 is\_tock:Bool storage:TrStoragePhase compute\_ph:TrComputePhase action:(Maybe ^TrActionPhase) aborted:Bool destroyed:Bool = TransactionDescr; 4.3.13. Split prepare and install transactions.A split prepare trans- action is similar to a tock transaction in a masterchain, but it must gener- ate exactly one special constructor message; otherwise, the action phase is aborted. split\_merge\_info$\_ cur\_shard\_pfx\_len:(## 6) acc\_split\_depth:(## 6) this\_addr:uint256 sibling\_addr:uint256 = SplitMergeInfo; trans\_split\_prepare$0100 split\_info:SplitMergeInfo compute\_ph:TrComputePhase action:(Maybe ^TrActionPhase) 88 4.4. Invoking smart contracts in TVM aborted:Bool destroyed:Bool = TransactionDescr; trans\_split\_install$0101 split\_info:SplitMergeInfo prepare\_transaction:^Transaction installed:Bool = TransactionDescr; Notice that the split install transaction for the new sibling accountξ ′ refers to its corresponding split prepare transaction of the previously existing account ξ. 4.3.14. Merge prepare and install transactions.A merge prepare trans- action converts the state and balance of an account into a message, and a subsequent merge install transaction processes this state: trans\_merge\_prepare$0110 split\_info:SplitMergeInfo storage\_ph:TrStoragePhase aborted:Bool = TransactionDescr; trans\_merge\_install$0111 split\_info:SplitMergeInfo prepare\_transaction:^Transaction credit\_ph:(Maybe TrCreditPhase) compute\_ph:TrComputePhase action:(Maybe ^TrActionPhase) aborted:Bool destroyed:Bool = TransactionDescr; 4.4 Invoking smart contracts in TVM This section describes the exact parameters with which TVM is invoked during the computing phase of ordinary and other transactions. 4.4.1. Smart-contract code.Thecodeof a smart contract is normally a part of the account’s persistent state, at least if the account isactive (cf.4.1.6). However, a frozen or uninitialized (or non-existent) account has no persistent state, with the possible exception of the account’s balance and the hash of its intended state (equal to the account address for uninitialized accounts). In this case, the code must be supplied in theinitfield of the inbound message being processed by the transaction (cf.3.1.7). 4.4.2. Smart-contract persistent data.Thepersistent dataof a smart contract is kept alongside its code, and remarks similar to those made above in4.4.1apply. In this respect, the code and persistent data of a smart 89 4.4. Invoking smart contracts in TVM contract are just two parts of its persistent state, which differ only in the way they are treated by TVM during smart-contract execution. 4.4.3. Smart-contract library environment.Thelibrary environmentof a smart contract is a hashmap mapping 256-bit cell (representation) hashes into the corresponding cells themselves. When an external cell reference is accessed during the execution of a smart contract, the cell referred to is looked up in the library environment and the external cell reference is transparently replaced by the cell found. The library environment for an invocation of a smart contract is computed as follows: 1. The global library environment for the workchain in question is taken from the current state of the masterchain. 34 2. Next, it is augmented by the local library environment of the smart con- tract, stored in thelibraryfield of the smart contract’s state. Only 256-bit keys equal to the hashes of the corresponding value cells are taken into account. If a key is present in both the global and lo- cal library environments, the local environment takes precedence while merging the two library environments. 3. Finally, the message library stored in thelibraryfield of theinit field of the inbound message is similarly taken into account. Notice, however, that if the account is frozen or uninitialized, thelibrary field of the message is part of the suggested state of the account, and is used instead of the local library environment in the previous step. The message library has lower precedence than both the local and the global library environments. 4.4.4. The initial state of TVM.A new instance of TVM is initialized prior to the execution of a smart contract as follows: •The originalcc(current continuation) is initialized using the cell slice created from the cellcode, containing the code of the smart contract computed as described in4.4.1. 34 The most common way of creating shared libraries for TVM is to publish a reference to the root cell of the library in the masterchain. 90 4.4. Invoking smart contracts in TVM •Thecp(TVM codepage) is set to zero. If the smart contract wants to use another TVM codepagex, it must switch to it by usingSETCODEPAGE xas the first instruction of its code. •Control registerc0(return continuation) is initialized by extraordinary continuationec\_quitwith parameter 0. When executed, this contin- uation leads to a termination of TVM with exit code 0. •Control registerc1(alternative return continuation) is initialized by extraordinary continuationec\_quitwith parameter 1. When invoked, it leads to a termination of TVM with exit code 1. (Notice that termi- nating with exit code 0 or 1 is considered a successful termination.) •Control registerc2(exception handler) is initialized by extraordinary continuationec\_quit\_exc. When invoked, it takes the top integer from the stack (equal to the exception number) and terminates TVM with exit code equal to that integer. In this way, by default all exceptions terminate the smart-contract execution with exit code equal to the exception number. •Control registerc3(code dictionary) is initialized by the cell with the smart-contract code, similarly to the initial current continuation (cc). •Control registerc4(root of persistent data) is initialized by the persis- tent data of the smart contract. 35 •Control registerc5(root of actions) is initialized by an empty cell. The “output action” primitives of TVM, such asSENDMSG, usec5to accumu- late the list of actions (e.g., outbound messages) to be performed upon successful termination of the smart contract (cf.4.2.7and4.2.8). •Control registerc7(root of temporary data) is initialized by a sin- gletonTuple, the only component of which is aTuplecontaining an instance ofSmartContractInfowith smart contract balance and other useful information (cf.4.4.10). The smart contract may replace the temporary data, especially all components of theTupleatc7but the first one, with whatever other temporary data it may require. However, 35 The persistent data of the smart contract need not be loaded in its entirety for this to occur. Instead the root is loaded, and TVM may load other cells by their references from the root only when they are accessed, thus providing a form of virtual memory. 91 4.4. Invoking smart contracts in TVM the original content of theSmartContractInfoat the first component of theTupleheld inc7is inspected and sometimes modified bySENDMSG TVM primitives and other “output action” primitives of TVM. •Thegas limitsgas= (g m ,g l ,g c ,g r )are initialized as follows: –Themaximal gas limitg m is set to the lesser of either the total Gram balance of the smart contract (after the the credit phase— i.e., combined with the value of the inbound message) divided by the current gas price, or the per-execution global gas limit. 36 –Thecurrent gas limitg l is set to the lesser of either the Gram value of the inbound message divided by the gas price, or the global per-execution gas limit. In this way, alwaysg l ≤g m . For inbound external messagesg l = 0, since they cannot carry any value. –Thegas creditg c is set to zero for inbound internal messages, and to the lesser of eitherg m or a fixed small value (the default external message gas credit, a configurable parameter) for inbound external messages. –Finally, theremaining gas limitg r is automatically initialized by g l +g c . 4.4.5. The initial stack of TVM for processing an internal mes- sage.After TVM is initialized as described in4.4.4, its stack is initialized by pushing the arguments to themain()function of the smart contract as follows: •The Gram balancebof the smart contract (after crediting the value of the inbound message) is passed as anIntegeramount of nanograms. •The Gram balanceb m of inbound messagemis passed as anInteger amount of nanograms. •The inbound messagemis passed as a cell, which contains a serialized value of typeMessageX, whereXis the type of the message body. 36 Both the global gas limit and the gas price are configurable parameters determined by the current state of the masterchain. 92 4.4. Invoking smart contracts in TVM •The bodym b :Xof the inbound message, equal to the value of field bodyofm, is passed as a cell slice. •Finally, thefunction selectors, anIntegernormally equal to zero, is pushed into the stack. After that, the code of the smart contract, equal to its initial value ofc3, is executed. It selects the correct function according tos, which is expected to process the remaining arguments to the function and terminate afterwards. 4.4.6. Processing an inbound external message.An inbound exter- nal message is processed similarly to4.4.4and4.4.5, with the following modifications: •The function selectorsis set to−1, not to 0. •The Gram balanceb m of inbound message is always 0. •The initial current gas limitg l is always 0. However, the initial gas creditg c >0. The smart contract must terminate withg c = 0org r ≥g c ; otherwise, the transaction and the block containing it are invalid. Validators or collators suggesting a block candidate must never include transactions processing in- bound external messages that are invalid. 4.4.7. Processing tick and tock transactions.The TVM stack for pro- cessing tick and tock transactions (cf.4.2.4) is initialized by pushing the following values: •The Gram balancebof the current account in nanograms (anInteger). •The 256-bit addressξof the current account inside the masterchain, represented by an unsignedInteger. •An integer equal to0for tick transactions and to−1for tock transac- tions. •The function selectors, equal to−2. 4.4.8. Processing split prepare transactions.For processing split pre- pare transactions (cf.4.3.13), the TVM stack is initialized by pushing the following values: 93 4.4. Invoking smart contracts in TVM •The Gram balancebof the current account. •ASlicecontainingSplitMergeInfo(cf.4.3.13). •The 256-bit addressξof the current account. •The 256-bit address ̃ ξof the sibling account. •An integer0≤d≤63, equal to the position of the only bit in whichξ and ̃ ξdiffer. •The function selectors, equal to−3. 4.4.9. Processing merge install transactions.For processing merge install transactions (cf.4.3.14), the TVM stack is initialized by pushing the following values: •The Gram balancebof the current account (already combined with the Gram balance of the sibling account). •The Gram balanceb ′ of the sibling account, taken from the inbound messagem. •The messagemfrom the sibling account, automatically generated by a merge prepare transaction. Itsinitfield contains the final state ̃ S of the sibling account. •The state ̃ Sof the sibling account, represented by aStateInit(cf.3.1.7). •ASlicecontainingSplitMergeInfo(cf.4.3.13). •The 256-bit addressξof the current account. •The 256-bit address ̃ ξof the sibling account. •An integer0≤d≤63, equal to the position of the only bit in whichξ and ̃ ξdiffer. •The function selectors, equal to−4. 4.4.10. Smart-contract information.The smart-contract information structureSmartContractInfo, passed in the first component of theTuplecon- tained in control registerc7, is also aTuplecontaining the following data: 94 4.4. Invoking smart contracts in TVM \[ magic:0x076ef1ea actions:Integer msgs\_sent:Integer unixtime:Integer block\_lt:Integer trans\_lt:Integer rand\_seed:Integer balance\_remaining:\[Integer (Maybe Cell)\] myself:MsgAddressInt global\_config:(Maybe Cell) \] = SmartContractInfo; In other words, the first component of this tuple is anIntegermagicalways equal to0x076ef1ea, the second component is anIntegeractions, originally initialized by zero, but incremented by one whenever an output action is installed by a non-RAWoutput action primitive of the TVM, and so on. The remaining balance is represented by a pair, i.e., a two-componentTuple: the first component is the nanogram balance, and the second component is a dictionary with 32-bit keys representing all other currencies, if any (cf.3.1.6). Therand\_seedfield (an unsigned 256-bit integer) here is initialized deter- ministically starting from therand\_seedof the block, the account address, the hash of the inbound message being processed (if any), and the transaction logical timetrans\_lt. 4.4.11. Serialization of output actions.Theoutput actionsof a smart contract are accumulated in a linked list stored in control registerc5. The list of output actions is serialized as a value of typeOutListn, wherenis the length of the list: out\_list\_empty$\_ = OutList 0; out\_list$\_ {n:#} prev:^(OutList n) action:OutAction = OutList (n + 1); action\_send\_msg#0ec3c86d out\_msg:^(Message Any) = OutAction; action\_set\_code#ad4de08e new\_code:^Cell = OutAction; 95 5.1. Shardchain block layout 5 Block layout This chapter presents the block layout used by the TON Blockchain, combin- ing the data structures described separately in previous chapters to produce a complete description of a shardchain block. In addition to the TL-B schemes that define the representation of a shardchain block by a tree of cells, this chapter describes exact serialization formats for the resulting bags (collec- tions) of cells, which are necessary to represent a shardchain block as a file. Masterchain blocks are similar to shardchain blocks, but have some ad- ditional fields. The necessary modifications are discussed separately in5.2. 5.1 Shardchain block layout This section lists the data structures that must be contained in a shardchain block and in the shardchain state, and concludes by presenting a formal TL-B scheme for a shardchain block. 5.1.1. Components of the shardchain state.The shardchain state con- sists of: •ShardAccounts, the split part of the shardchain state (cf.1.2.2) con- taining the state of all accounts assigned to this shard (cf.4.1.9). •OutMsgQueue, the output message queue of the shardchain (cf.3.3.6). •SharedLibraries, the description of all shared libraries of the shardchain (for now, non-empty only in the masterchain). •The logical time and the unixtime of the last modification of the state. •The total balance of the shard. •A hash reference to the most recent masterchain block, indirectly de- scribing the state of the masterchain and, through it, the state of all other shardchains of the TON Blockchain (cf.1.5.2). 5.1.2. Components of a shardchain block.A shardchain block must contain: •A list ofvalidator signatures(cf.1.2.6), which is external with respect to all other contents of the block. 96 5.1. Shardchain block layout •BlockHeader, containing general information about the block (cf.1.2.5) •Hash references to the immediately preceding block or blocks of the same shardchain, and to the most recent masterchain block. •InMsgDescrandOutMsgDescr, the inbound and outbound message descriptors (cf.3.2.8and3.3.5). •ShardAccountBlocks, the collection of all transactions processed in the block (cf.4.2.17) along with all updates of the states of the accounts assigned to the shard. This is thesplitpart of the shardchain block (cf.1.2.2). •Thevalue flow, describing the total value imported from the preceding blocks of the same shardchain and from inbound messages, the total value exported by outbound message, the total fees collected by val- idators, and the total value remaining in the shard. •AMerkle update(cf. \[4, 3.1\]) of the shardchain state. Such a Merkle update contains the hashes of the initial and final shardchain states with respect to the block, along with all new cells of the final state that have been created while processing the block. 37 5.1.3. Common parts of the block layout for all workchains.Recall that different workchains may define their own rules for processing messages, other types of transactions, other components of the state, and other ways to serialize all this data. However, some components of the block and its state must be common for all workchains in order to maintain the interoperability between different workchains. Such common components include: •OutMsgQueue, the outbound message queue of a shardchain, which is scanned by neighboring shardchains for messages addressed to them. •The outer structure ofInMsgDescras a hashmap with 256-bit keys equal to the hashes of the imported messages. (The inbound message descriptors themselves need not have the same structure.) 37 In principle, an experimental version of TON Blockchain might choose to keep only the hashes of the initial and final states of the shardchain. The Merkle update increases the block size, but it is handy for full nodes that want to keep and update their copy of the shardchain state. Otherwise, the full nodes would have to repeat all the computations contained in a block to compute the updated state of the shardchain by themselves. 97 5.1. Shardchain block layout •Some fields in the block header identifying the shardchain and the block, along with the paths from the block header to the other infor- mation indicated in this list. •The value flow information. 5.1.4. TL-B scheme for the shardchain state.The shardchain state (cf.1.2.1and5.1.1) is serialized according to the following TL-B scheme: ext\_blk\_ref$\_ start\_lt:uint64 end\_lt:uint64 seq\_no:uint32 hash:uint256 = ExtBlkRef; master\_info$\_ master:ExtBlkRef = BlkMasterInfo; shard\_ident$00 shard\_pfx\_bits:(## 6) workchain\_id:int32 shard\_prefix:uint64 = ShardIdent; shard\_state shard\_id:ShardIdent out\_msg\_queue:OutMsgQueue total\_balance:CurrencyCollection total\_validator\_fees:CurrencyCollection accounts:ShardAccounts libraries:(HashmapE 256 LibDescr) master\_ref:(Maybe BlkMasterInfo) custom:(Maybe ^McStateExtra) = ShardState; The fieldcustomis usually present only in the masterchain and contains all the masterchain-specific data. However, other workchains may use the same cell reference to refer to their specific state data. 5.1.5. Shared libraries description.Shared libraries currently can be present only in masterchain blocks. They are described by an instance of HashmapE(256,LibDescr), where the 256-bit key is the representation hash of the library, andLibDescrdescribes one library: shared\_lib\_descr$00 lib:^Cell publishers:(Hashmap 256 True) = LibDescr; Herepublishersis a hashmap with keys equal to the addresses of all ac- counts that have published the corresponding shared library. The shared 98 5.1. Shardchain block layout library is preserved as long as at least one account keeps it in its published libraries collection. 5.1.6. TL-B scheme for an unsigned shardchain block.The precise format of anunsigned(cf.1.2.6) shardchain block is given by the following TL-B scheme: block\_info version:uint32 not\_master:(## 1) after\_merge:(## 1) before\_split:(## 1) flags:(## 13) seq\_no:# vert\_seq\_no:# shard:ShardIdent gen\_utime:uint32 start\_lt:uint64 end\_lt:uint64 master\_ref:not\_master?^BlkMasterInfo prev\_ref:seq\_no?^(BlkPrevInfo after\_merge) prev\_vert\_ref:vert\_seq\_no?^(BlkPrevInfo 0) = BlockInfo; prev\_blk\_info#\_ {merged:#} prev:ExtBlkRef prev\_alt:merged?ExtBlkRef = BlkPrevInfo merged; unsigned\_block info:^BlockInfo value\_flow:^ValueFlow state\_update:^(MERKLE\_UPDATE ShardState) extra:^BlockExtra = Block; block\_extra in\_msg\_descr:^InMsgDescr out\_msg\_descr:^OutMsgDescr account\_blocks:ShardAccountBlocks rand\_seed:uint256 custom:(Maybe ^McBlockExtra) = BlockExtra; The fieldcustomis usually present only in the masterchain and contains all the masterchain-specific data. However, other workchains may use the same cell reference to refer to their specific block data. 5.1.7. Description of total value flow through a block.The total value flow through a block is serialized according to the following TL-B scheme: value\_flow \_:^\[ from\_prev\_blk:CurrencyCollection to\_next\_blk:CurrencyCollection 99 5.1. Shardchain block layout imported:CurrencyCollection exported:CurrencyCollection \] fees\_collected:CurrencyCollection \_:^\[ fees\_imported:CurrencyCollection created:CurrencyCollection minted:CurrencyCollection \] = ValueFlow; Recall that\_:ˆ\[. . .\]is a TL-B construction indicating that a group of fields has been moved into a separate cell. The last three fields may be non-zero only in masterchain blocks. 5.1.8. Signed shardchain block.A signed shardchain block is just an unsigned block augmented by a collection of validator signatures: ed25519\_signature#5 R:uint256 s:uint256 = CryptoSignature; signed\_block block:^Block blk\_serialize\_hash:uint256 signatures:(HashmapE 64 CryptoSignature) = SignedBlock; Theserialization hashblk\_serialize\_hashof the unsigned blockblockis essentially a hash of a specific serialization of the block into an octet string (cf.5.3.12for a more detailed explanation). The signatures collected in signaturesare Ed25519-signatures (cf.A.3) made with a validator’s private keys of thesha256of the concatenation of the 256-bit representation hash of the blockblockand of its 256-bit serialization hashblk\_serialize\_hash. The 64-bit keys in dictionarysignaturesrepresent the first 64 bits of the public keys of the corresponding validators. 5.1.9. Serialization of a signed block.The overall procedure of serializing and signing a block may be described as follows: 1. An unsigned blockBis generated, transformed into a complete bag of cells (cf.5.3.2), and serialized into an octet stringS B . 2. Validators sign the 256-bit combined hash H B :=sha256 ( Hash ∞ (B).Hash M (S B ) ) (18) of the representation hash ofBand of the Merkle hash of its serializa- tionS B . 100 5.2. Masterchain block layout 3. A signed shardchain block ̃ Bis generated fromBand these validator signatures as described above (cf.5.1.8). 4. This signed block ̃ Bis transformed into an incomplete bag of cells, which contains only the validator signatures, but the unsigned block itself is absent from this bag of cells, being its only absent cell. 5. This incomplete bag of cells is serialized, and its serialization is prepended to the previously constructed serialization of the unsigned block. The result is the serialization of the signed block into an octet string. It may be propagated by network or stored into a disk file. 5.2 Masterchain block layout Masterchain blocks are very similar to shardchain blocks of the basic work- chain. This section lists some of the modifications needed to obtain the description of a masterchain block from the description of a shardchain block given in5.1. 5.2.1. Additional components present in the masterchain state.In addition to the components listed in5.1.1, the masterchain state must con- tain: •ShardHashes— Describes the current shard configuration, and contains the hashes of the latest blocks of the corresponding shardchains. •ShardFees— Describes the total fees collected by the validators of each shardchain. •ShardSplitMerge— Describes future shard split/merge events. It is serialized as a part ofShardHashes. •ConfigParams— Describes the values of all configurable parameters of the TON Blockchain. 5.2.2. Additional components present in masterchain blocks.In addition to the components listed in5.1.2, each masterchain block must contain: 101 5.2. Masterchain block layout •ShardHashes— Describes the current shard configuration, and con- tains the hashes of the latest blocks of the corresponding shardchains. (Notice that this component is also present in the masterchain state.) 5.2.3. Description ofShardHashes.ShardHashesis represented by a dictionary with 32-bitworkchain\_ids as keys, and “shard binary trees”, rep- resented by TL-B typeBinTree ShardDescr, as values. Each leaf of this shard binary tree contains a value of typeShardDescr, which describes a sin- gle shard by indicating the sequence numberseq\_no, the logical timelt, and the hashhashof the latest (signed) block of the corresponding shardchain. bt\_leaf$0 {X:Type} leaf:X = BinTree X; bt\_fork$1 {X:Type} left:^(BinTree X) right:^(BinTree X) = BinTree X; fsm\_none$0 = FutureSplitMerge; fsm\_split$10 mc\_seqno:uint32 = FutureSplitMerge; fsm\_merge$11 mc\_seqno:uint32 = FutureSplitMerge; shard\_descr$\_ seq\_no:uint32 lt:uint64 hash:uint256 split\_merge\_at:FutureSplitMerge = ShardDescr; \_ (HashmapE 32 ^(BinTree ShardDescr)) = ShardHashes; Fieldsmc\_seqnooffsm\_splitandfsm\_mergeare used to signal future shard merge or split events. Shardchain blocks referring to masterchain blocks with sequence numbers up to, but not including, the one indicated inmc\_seqnoare generated in the usual way. Once the indicated sequence number is reached, a shard merge or split event must occur. Notice that the masterchain itself is omitted fromShardHashes(i.e., 32- bit index−1is absent from this dictionary). 5.2.4. Description ofShardFees.ShardFeesis a masterchain structure used to reflect the total fees collected so far by the validators of a shardchain. The total fees reflected in this structure are accumulated in the masterchain by crediting them to a special account, whose address is a configurable pa- rameter. Typically this account is the smart contract that computes and distributes the rewards to all validators. bta\_leaf$0 {X:Type} {Y:Type} leaf:X extra:Y = BinTreeAug X Y; 102 5.2. Masterchain block layout bta\_fork$1 {X:Type} {Y:Type} left:^(BinTreeAug X Y) right:^(BinTreeAug X Y) extra:Y = BinTreeAug X Y; \_ (HashmapAugE 32 ^(BinTreeAug True CurrencyCollection) CurrencyCollection) = ShardFees; The structure ofShardFeesis similar to that ofShardHashes(cf.5.2.3), but the dictionary and binary trees involved are augmented by currency values, equal to thetotal\_validator\_feesvalues of the final states of the corre- sponding shardchain blocks. The value aggregated at the root ofShardFees is added together with thetotal\_validator\_feesof the masterchain state, yielding the total TON Blockchain validator fees. The increase of the value aggregated at the root ofShardFeesfrom the initial to the final state of a masterchain block is reflected in thefees\_importedin the value flow of that masterchain block. 5.2.5. Description ofConfigParams.Recall that theconfigurable pa- rametersor theconfiguration dictionaryis a dictionaryconfigwith 32-bit keys kept inside the first cell reference of the persistent data of the configu- ration smart contractγ(cf.1.6). The addressγof the configuration smart contract and a copy of the configuration dictionary are duplicated in fields config\_addrandconfigof aConfigParamsstructure, explicitly included into masterchain state to facilitate access to the current values of the config- urable parameters (cf.1.6.3): \_ config\_addr:uint256 config:^(Hashmap 32 ^Cell) = ConfigParams; 5.2.6. Masterchain state data.The data specific to the masterchain state is collected intoMcStateExtra, already mentioned in5.1.4: masterchain\_state\_extra#cc1f shard\_hashes:ShardHashes shard\_fees:ShardFees config:ConfigParams = McStateExtra; 5.2.7. Masterchain block data.Similarly, the data specific to the mas- terchain blocks is collected intoMcBlockExtra: 103 5.3. Serialization of a bag of cells masterchain\_block\_extra#cc9f shard\_hashes:ShardHashes = McBlockExtra; 5.3 Serialization of a bag of cells The description provided in the previous section defines the way a shardchain block is represented as a tree of cells. However, this tree of cells needs to be serialized into a file, suitable for disk storage or network transfer. This section discusses the standard ways of serializing a tree, a DAG, or a bag of cells into an octet string. 5.3.1. Transforming a tree of cells into a bag of cells.Recall that values of arbitrary (dependent) algebraic data types are represented in the TON Blockchain bytrees of cells. Such a tree of cells is transformed into a directed acyclic graph, orDAG, of cells, by identifying identical cells in the tree. After that, we might replace each of the references of each cell by the 32-byte representation hash of the cell referred to and obtain abag of cells. By convention, the root of the original tree of cells is a marked element of the resulting bag of cells, so that anybody receiving this bag of cells and knowing the marked element can reconstruct the original DAG of cells, hence also the original tree of cells. 5.3.2. Complete bags of cells.Let us say that a bag of cells iscompleteif it contains all cells referred to by any of its cells. In other words, a complete bag of cells does not have any “unresolved” hash references to cells outside that bag of cells. In most cases, we need to serialize only complete bags of cells. 5.3.3. Internal references inside a bag of cells.Let us say that a reference of a cellcbelonging to a bag of cellsBisinternal (with respect to B)if the cellc i referred to by this reference belongs toBas well. Otherwise, the reference is calledexternal. A bag of cells is complete if and only if all references of its constituent cells are internal. 5.3.4. Assigning indices to the cells from a bag of cells.Letc 0 , . . . , c n−1 be thendistinct cells belonging to a bag of cellsB. We can list these cells in some order, and then assign indices from0ton−1, so that cellc i gets indexi. Some options for ordering cells are: 104 5.3. Serialization of a bag of cells •Order cells by their representation hash. ThenHash(c i )= 1 } absent:(##(size \* 8)) { roots + absent <= cells } tot\_cells\_size:(##(off\_bytes \* 8)) root\_list:(roots \* ##(size \* 8)) index:has\_idx?(cells \* ##(off\_bytes \* 8)) cell\_data:(tot\_cells\_size \* \[ uint8 \]) crc32c:has\_crc32c?uint32 = BagOfCells; Fieldcellsisn,rootsisk,absentisl, andtot\_cells\_sizeisL n (the total size of the serialization of all cells in bytes). If an index is present, parameters s/8andt/8are serialized separately assizeandoff\_bytes, respectively, and the flaghas\_idxis set. The index itself is contained inindex, present only ifhas\_idxis set. The fieldroot\_listcontains the (zero-based) indices of the root nodes of the bag of cells. 108 5.3. Serialization of a bag of cells Two older constructors are still supported in the bag-of-cells deserializa- tion functions: serialized\_boc\_idx#68ff65f3 size:(## 8) { size <= 4 } off\_bytes:(## 8) { off\_bytes <= 8 } cells:(##(size \* 8)) roots:(##(size \* 8)) { roots = 1 } absent:(##(size \* 8)) { roots + absent <= cells } tot\_cells\_size:(##(off\_bytes \* 8)) index:(cells \* ##(off\_bytes \* 8)) cell\_data:(tot\_cells\_size \* \[ uint8 \]) = BagOfCells; serialized\_boc\_idx\_crc32c#acc3a728 size:(## 8) { size <= 4 } off\_bytes:(## 8) { off\_bytes <= 8 } cells:(##(size \* 8)) roots:(##(size \* 8)) { roots = 1 } absent:(##(size \* 8)) { roots + absent <= cells } tot\_cells\_size:(##(off\_bytes \* 8)) index:(cells \* ##(off\_bytes \* 8)) cell\_data:(tot\_cells\_size \* \[ uint8 \]) crc32c:uint32 = BagOfCells; 5.3.10. Storing compiled TVM code in files.Notice that the above procedure for serializing bags of cells may be used to serialize compiled smart contracts and other TVM code. One must define a TL-B constructor similar to the following: compiled\_smart\_contract compiled\_at:uint32 code:^Cell data:^Cell description:(Maybe ^TinyString) \_:^\[ source\_file:(Maybe ^TinyString) compiler\_version:(Maybe ^TinyString) \] = CompiledSmartContract; tiny\_string#\_ len:(#<= 126) str:(len \* \[ uint8 \]) = TinyString; Then a compiled smart contract may be represented by a value of typeCom- piledSmartContract, transformed into a tree of cells and then into a bag of 109 5.3. Serialization of a bag of cells cells, and then serialized using one of the constructors listed in5.3.9. The resulting octet string may be then written into a file with suffix.tvc(“TVM smart contract”), and this file may be used to distribute the compiled smart contract, download it into a wallet application for deploying into the TON Blockchain, and so on. 5.3.11. Merkle hashes for an octet string.On some occasions, we must define a Merkle hashHash M (s)of an arbitrary octet stringsof length|s|. We do this as follows: •If|s|≤256octets, then the Merkle hash ofsis just itssha256: Hash M (s) :=sha256(s)if|s|≤256.(19) •If|s|>256, letn= 2 k be the largest power of two less than|s|(i.e., k:=blog 2 (|s|−1)c,n:= 2 k ). Ifs ′ is the prefix ofsof lengthn, ands ′′ is the suffix ofsof length|s|−n, so thatsis the concatenations ′ .s ′′ ofs ′ ands ′′ , we define Hash M (s) :=sha256 ( int 64 (|s|).Hash M (s ′ ).Hash M (s ′′ ) ) (20) In other words, we concatenate the 64-bit big-endian representation of|s|and the recursively computed Merkle hashes ofs ′ ands ′′ , and computesha256of the resulting string. One can check thatHash M (s) =Hash M (t)for octet stringssandtof length less than2 64 −2 56 impliess=tunless a hash collision forsha256has been found. 5.3.12. The serialization hash of a block.The construction of5.3.11 is applied in particular to the serialization of the bag of cells representing an unsigned shardchain or masterchain block. The validators sign not only the representation hash of the unsigned block, but also the “serialization hash” of the unsigned block, defined asHash M of the serialization of the unsigned block. In this way, the validators certify that this octet string is indeed a serialization of the corresponding block. 110 References References \[1\]Daniel J. Bernstein,Curve25519: New Diffie–Hellman Speed Records (2006), in: M. Yung, Ye. Dodis, A. Kiayas et al,Public Key Cryptogra- phy, Lecture Notes in Computer Science3958, pp. 207–228. Available at https://cr.yp.to/ecdh/curve25519-20060209.pdf. \[2\]Daniel J. Bernstein, Niels Duif, Tanja Lange et al.,High- speed high-security signatures(2012),Journal of Cryptographic Engi- neering2(2), pp. 77–89. Available athttps://ed25519.cr.yp.to/ ed25519-20110926.pdf. \[3\]N. Durov,Telegram Open Network, 2017. \[4\]N. Durov,Telegram Open Network Virtual Machine, 2018. 111 A.1. Elliptic curves A Elliptic curve cryptography This appendix contains a formal description of the elliptic curve cryptography currently used in TON, particularly in the TON Blockchain and the TON Network. TON uses two forms of elliptic curve cryptography: Ed25519 is used for cryptographic Schnorr signatures, while Curve25519 is used for asymmetric cryptography. These curves are used in the standard way (as defined in the original articles \[1\] and \[2\] by D. Bernstein and RFCs 7748 and 8032); however, some serialization details specific to TON must be explained. One unique adaptation of these curves for TON is that TON supports automatic conversion of Ed25519 keys into Curve25519 keys, so that the same keys can be used for signatures and for asymmetric cryptography. A.1 Elliptic curves Some general facts on elliptic curves over finite fields, relevant for elliptic curve cryptography, are collected in this section. A.1.1. Finite fields.We consider elliptic curves over finite fields. For the purposes of the Curve25519 and Ed25519 algorithms, we will be mostly concerned with elliptic curves over the finite prime fieldk:=F p of residues modulop, wherep= 2 255 −19is a prime number, and over finite extensions F q ofF p , especially the quadratic extensionF p 2 . 41 A.1.2. Elliptic curves.Anelliptic curveE= (E,O)over a fieldkis a geometrically integral smooth projective curveE/kof genusg= 1, along with a markedk-rational pointO∈E(k). It is well-known that an elliptic curveEover a fieldkcan be represented in (generalized) Weierstrass form: y 2 +a 1 xy+a 3 y=x 3 +a 2 x 2 +a 4 x+a 6 for somea 1 , . . . ,a 6 ∈k. (21) More precisely, this is only the affine part of the elliptic curve, written in coordinates(x,y). For any field extensionKofk,E(K)consists of all solutions(x,y)∈K 2 of equation (21), calledfinite points ofE(K), along with a point at infinity, which is the marked pointO. 41 Arithmetic modulopfor a moduluspnear a power of two can be implemented very efficiently. On the other hand, residues modulo2 255 −19can be represented by 255-bit integers. This is the reason this particular value ofphas been chosen by D. Bernstein. 112 A.1. Elliptic curves A.1.3. Weierstrass form in homogeneous coordinates.In homoge- neous coordinates\[X:Y:Z\], (21) corresponds to Y 2 Z+a 1 XY Z+a 3 Y Z 2 =X 3 +a 2 X 2 Z+a 4 XZ 2 +a 6 Z 3 (22) WhenZ6= 0, we can setx:=X/Z,y:=Y/Z, and obtain a solution(x,y) of (21) (i.e., a finite point ofE). On the other hand, the only solution (up to proportionality) of (22) withZ= 0is\[0 : 1 : 0\]; this is the point at infinityO. A.1.4. Standard Weierstrass form.When the characteristiccharkof fieldkis6= 2,3, the Weierstrass form of (21) or (22) can be simplified with the aid of linear transformationsy ′ :=y+a 1 x/2 +a 3 /2,x ′ :=x+a 2 /3, thus makinga 1 =a 3 =a 2 = 0and obtaining y 2 =x 3 +a 4 x+a 6 (23) and Y 2 Z=X 3 +a 4 XZ 2 +a 6 Z 3 (24) Such an equation defines an elliptic curve if and only if the cubic polynomial P(x) :=x 3 +a 4 x+a 6 has no multiple roots, i.e., if the discriminantD:= −4a 3 4 −27a 2 6 is non-zero. A.1.5. Addition of points on elliptic curveE.LetKbe a field extension of fieldk, and letE= (E,O)be any elliptic curve in Weierstrass form defined overk. Then any linel⊂P 2 K intersects the elliptic curveE (K) (which is the base change of curveEto fieldK, i.e., the curve defined by the same equations over a larger fieldK) at exactly three pointsP,Q,R, considered with multiplicities. We define theaddition of pointson elliptic curveE(or rather the addition of itsK-valued pointsE(K)) by requiring that P+Q+R=Owhenever{P,Q,R}=l∩Efor some linel⊂P 2 K . (25) It is well-known that this requirement defines a unique commutative law \[+\] :E× k E→Eon the points of the elliptic curveE, havingOas its neutral element. When elliptic curveEis represented by its Weierstrass form (21), one can write explicit formulas expressing the coordinatesx P+Q , y P+Q of the sumP+Qof twoK-valued pointsP,Q∈E(K)of elliptic curve Eas rational functions of the coordinatesx P ,y P ,x Q ,y Q ∈Kof pointsP andQand of the coefficientsa i ∈kof (21). 113 A.1. Elliptic curves A.1.6. Power maps.SinceE(K)is an abelian group, one can definemul- tiplesorpowers\[n\]Xfor any pointX∈E(K)and any integern∈Z. If n= 0, then\[0\]X=O; ifn >0, then\[n\]X= \[n−1\]X+X; ifn <0, then \[n\]X=−\[−n\]X. The map\[n\] = \[n\] E :E→Eforn6= 0is anisogeny, meaning that it is a non-constant homomorphism for the group law ofE: \[n\](P+Q) = \[n\]P+ \[n\]Qfor anyP,Q∈E(K)andn∈Z.(26) In particular,\[−1\] E :E→E,P7→ −P, is an involutive automorphism of elliptic curveE. IfEis in Weierstrass form,\[−1\] E maps(x,y)7→(x,−y), and two pointsP,Q∈E(F q )have equalx-coordinates if and only ifQ=±P. A.1.7. The order of the group of rational points ofE.LetEbe an elliptic curve defined over a finite base fieldk, and letK=F q be a finite extension ofk. ThenE(F q )is a finite abelian group. By a well-known result of Hasse, the ordernof this group is not too distant fromq: n=|E(F q )|=q−t+ 1wheret 2 ≤4q, i.e.,|t|≤2 √ q.(27) We will be mostly interested in the caseK=k=F p , withq=pa prime number. A.1.8. Cyclic subgroups of large prime order.Elliptic curve cryptog- raphy is usually performed using elliptic curves that admit a (necessarily cyclic) subgroupC⊂E(F q )of prime order\`. Equivalently, a rational point G∈E(F q )of prime order\`may be given; thenCcan be recovered as the cyclic subgroup〈G〉generated byG. In order to verify that a point G∈E(F q )generates a cyclic group of prime order\`, one can check that G6=O, but\[\`\]G=O. By the Legendre theorem,\`is necessarily a divisor of the ordern= |E(F q )|of the finite abelian groupE(F q ): n=|E(F q )|=c\`for some integerc≥1(28) The integercis called thecofactor; one usually wants the cofactor to be as small as possible, so as to make\`=n/cas large as possible. Recall thatn always has the same order of magnitude asqby (27), so it cannot be changed much by varyingEonceqis fixed. 114 A.1. Elliptic curves A.1.9. Data for elliptic curve cryptography.In order to define specific elliptic curve cryptography, one must fix a finite base fieldF q (ifq=p is a prime, it is sufficient to fix primep), an elliptic curveE/F q (usually represented by the coefficients of its Weierstrass form (23) or (21)), the base pointO(which usually is the point at infinity of an elliptic curve written in Weierstrass form), and the generatorG∈E(F q )(usually determined by its coordinates(x,y)with respect to the equation of the elliptic curve) of a cyclic subgroup of large prime order\`. Prime number\`and the cofactorc are usually also part of the elliptic cryptography data. A.1.10. Main operations of elliptic curve cryptography.Elliptic curve cryptography usually deals with a fixed cyclic subgroupCof a large prime order\`inside the group of points of an elliptic curveEover a finite fieldF q . A generatorGofCis usually fixed. It is usually assumed that, given a point XofC, one cannot find its “discrete logarithm baseG” (i.e., a residuen modulo\`such thatX= \[n\]G) faster than inO( √ \`)operations. The most important operations used in elliptic curve cryptography are the addition of points fromC⊂E(F q )and the computation of their powers, or multiples. A.1.11. Private and public keys for elliptic curve cryptography. Usually a private key for elliptic curve cryptography described by the data listed inA.1.9is a “random” integer0< a < \`, called thesecret exponent, and the corresponding public key is the pointA:= \[a\]G(or just itsx- coordinatex A ), suitably serialized. A.1.12. Montgomery curves.Elliptic curves with the specific Weierstrass equation y 2 =x 3 +Ax 2 +xwhereA= 4a−2for somea∈k,a6= 0,a6= 1(29) are calledMontgomery curves. They have the convenient property that x P+Q x P−Q can be expressed as a simple rational function ofx P andx Q : x P+Q x P−Q = ( x P x Q −A x P −x Q ) 2 (30) This means thatx P+Q can be computed providedx P−Q ,x P , andx Q are known. In particular, ifx P ,x \[n\]P , andx \[n+1\]P are known, thenx \[2n\]P ,x \[2n+1\]P , andx \[2n+2\]P can be computed. Using the binary representation of0< n <2 s , one can computex \[bn/2 s−i c\]P ,x \[bn/2 s−i c+1\]P fori= 0,1, . . . ,s, thus obtaining 115 A.2. Curve25519 cryptography x \[n\]P (this algorithm for quickly computingx \[n\]P starting fromx P on Mont- gomery curves is called aMontgomery ladder). Hence we see the importance of Montgomery curves for elliptic curve cryptography. A.2 Curve25519 cryptography This section describes the well-known Curve25519 cryptography proposed by Daniel Bernstein \[1\] and its usage in TON. A.2.1. Curve25519.Curve25519is defined as the Montgomery curve y 2 =x 3 +Ax 2 +xoverF p , wherep= 2 255 −19andA= 486662. (31) The order of this curve is8\`, where\`is a prime number, andc= 8is the cofactor. The cyclic subgroup of order\`is generated by a pointGwith x G = 9(this determinesGup to the sign ofy G , which is unimportant). The order of the quadratic twist2y 2 =x 3 +Ax 2 +xof Curve25519 is4\` ′ for another prime number\` ′ . 42 A.2.2. Parameters of Curve25519.The parameters of Curve25519 are as follows: •Base field: Prime finite fieldF p forp= 2 255 −19. •Equation:y 2 =x 3 +Ax 2 +xforA= 486662. •Base pointG: Characterized byx G = 9(nine is the smallest positive integerx-coordinate of a generator of the subgroup of large prime order ofE(F p )). •Order ofE(F p ): |E(F p )|=p−t+ 1 = 8\`,where(32) \`= 2 252 + 27742317777372353535851937790883648493is prime. (33) 42 Actually, D. Bernstein choseA= 486662because it is the smallest positive integer A≡2 (mod 4)such that both the corresponding Montgomery curve (31) overF p forp= 2 255 −19and the quadratic twist of this curve have small cofactors. Such an arrangement avoids the necessity to check whether anx-coordinatex P ∈F p of a pointPdefines a point (x P ,y P )∈F 2 p lying on the Montgomery curve itself or on its quadratic twist. 116 A.2. Curve25519 cryptography •Order of ̃ E(F p ), where ̃ Eis the quadratic twist ofE: | ̃ E(F p )|=p+t+ 1 = 2p+ 2−8\`= 4\` ′ ,where(34) \` ′ = 2 253 −55484635554744707071703875581767296995is prime. (35) A.2.3. Private and public keys for standard Curve25519 cryptog- raphy.A private key for Curve25519 cryptography is usually defined as a secret exponenta, while the corresponding public key isx A , thex-coordinate of pointA:= \[a\]G. This is usually sufficient for performing ECDH (elliptic curve Diffie–Hellman key exchange) and asymmetric elliptic curve cryptog- raphy, as follows: If a party wants to send a messageMto another party, which has public keyx A (and private keya), the following computations are performed. A one-time random secret exponentbis generated, andx B :=x \[b\]G andx \[b\]A are computed using a Montgomery ladder. After that, the messageMis encrypted by a symmetric cypher such as AES using the 256-bit “shared secret”S:=x \[b\]A as a key, and 256-bit integer (“one-time public key”)x B is prepended to the encrypted message. Once the party with public keyx A receives this message, it can computex \[a\]B starting fromx B (transmitted with the encrypted message) and the private keya. Sincex \[a\]B =x \[ab\]G = x \[b\]A =S, the receiving party recovers the shared secretSand is able to decrypt the remainder of the message. A.2.4. Public and private keys for TON Curve25519 cryptography. TON uses another form for public and private keys of Curve25519 cryptog- raphy, borrowed from Ed25519 cryptography. A private key for TON Curve25519 cryptography is just a random 256-bit stringk. It is used by computingsha512(k), taking the first 256 bits of the result, interpreting them as a little-endian 256-bit integera, clearing bits0, 1,2, and255ofa, and setting bit254so as to obtain a value2 254 ≤a <2 255 , divisible by eight. The valueathus obtained is thesecret exponentcorre- sponding tok; meanwhile, the remaining 256 bits ofsha512(k)constitute thesecret saltk ′′ . The public key corresponding tok—or to the secret exponenta—is just thex-coordinatex A of the pointA:= \[a\]G. Onceaandx A are computed, they are used in exactly the same way as inA.2.3. In particular, ifx A needs to be serialized, it is serialized into 32 octets as an unsigned little-endian 256-bit integer. 117 A.3. Ed25519 cryptography A.2.5. Curve25519 is used in the TON Network.Notice that the asymmetric Curve25519 cryptography described inA.2.4is extensively used by the TON Network, especially the ADNL (Abstract Datagram Network Layer) protocol. However, TON Blockchain needs elliptic curve cryptography mostly for signatures. For this purpose, Ed25519 signatures described in the next section are used. A.3 Ed25519 cryptography Ed25519 cryptography is extensively used for fast cryptographic signatures by both the TON Blockchain and the TON Network. This section describes the variant of Ed25519 cryptography used by TON. An important differ- ence from the standard approaches (as defined by D. Bernstein et al. in \[2\]) is that TON provides automatic conversion of private and public Ed25519 keys into Curve25519 keys, so that the same keys could be used both for encrypting/decrypting and for signing messages. A.3.1. Twisted Edwards curves.Atwisted Edwards curveE a,d with parametersa6= 0andd6= 0,aover a fieldkis given by equation E a,d :ax 2 +y 2 = 1 +dx 2 y 2 overk(36) Ifa= 1, this equation defines an (untwisted) Edwards curve. PointO(0,1) is usually chosen as the marked point ofE a,d . A.3.2. Twisted Edwards curves are birationally equivalent to Mont- gomery curves.A twisted Edwards curveE a,d is birationally equivalent to a Montgomery elliptic curve M A :v 2 =u 3 +Au 2 +u(37) whereA= 2(a+d)/(a−d)andd/a= (A−2)/(A+ 2). The birational equivalenceφ:E a,d 99KM A and its inverseφ −1 are given by φ: (x,y)7→ ( 1 +y 1−y , c(1 +y) x(1−y) ) (38) and φ −1 : (u,v)7→ ( cu v , u−1 u+ 1 ) (39) 118 A.3. Ed25519 cryptography where c= √ A+ 2 a (40) Notice thatφtransforms the marked pointO(0,1)ofE a,d into the marked point ofM A (i.e., its point at infinity). A.3.3. Addition of points on a twisted Edwards curve.SinceE a,d is birationally equivalent to an elliptic curveM A , the addition of points onM A can be transferred toE a,d by setting P+Q:=φ −1 ( φ(P) +φ(Q) ) for anyP,Q∈E a,d (k).(41) Notice that the marked pointO(0,1)is the neutral element with respect to this addition, and that−(x P ,y P ) = (−x P ,y P ). A.3.4. Formulas for adding points on a twisted Edwards curve.The coordinatesx P+Q andy P+Q admit simple expressions as rational functions ofx P ,y P ,x Q ,y Q : x P+Q = x P y Q +x Q y P 1 +dx P x Q y P y Q (42) y P+Q = y P y Q −ax P x Q 1−dx P x Q y P y Q (43) These expressions can be efficiently computed, especially ifa=−1. This is the reason twisted Edwards curves are important for fast elliptic curve cryptography. A.3.5. Ed25519 twisted Edwards curve.Ed25519 is the twisted Ed- wards curveE −1,d overF p , wherep= 2 255 −19is the same prime number as that used for Curve25519, andd=−(A−2)/(A+ 2) =−121665/121666, whereA= 486662is the same as in the equation (31): −x 2 +y 2 = 1− 121665 121666 x 2 y 2 forx,y∈F p ,p= 2 255 −19. (44) In this way, Ed25519-curveE −1,d is birationally equivalent to Curve25519 (31), and one can useE −1,d and formulas (42)–(43) for point addition on either Ed25519 or Curve25519, using (38) and (39) to convert points on Ed25519 into corresponding points on Curve25519, and vice versa. 119 A.3. Ed25519 cryptography A.3.6. Generator of Ed25519.The generator of Ed25519 is the pointG ′ withy(G ′ ) = 4/5and0≤x(G ′ )< peven. According to (38), it corresponds to the point(u,v)of Curve25519 withu= (1 + 4/5)/(1−4/5) = 9(i.e., to the generatorGof Curve25519 chosen inA.2.2). In particular,G=φ(G ′ ), G ′ generates a cyclic subgroup of the same large prime order\`given in (32), and for any integera, φ(\[a\]G ′ ) = \[a\]G .(45) In this way, we can perform computations with Curve25519 and its generator G, or with Ed25519 and generatorG ′ , and obtain essentially the same results. A.3.7. Standard representation of points on Ed25519.A pointP(x,y) on Ed25519 may be represented by its two coordinatesx P andy P , residues modulop= 2 255 −19. In their turn, both these coordinates may be repre- sented by unsigned 255- or 256-bit integers0≤x P ,y P < p <2 255 . However, a more compact representation ofPby one little-endian un- signed 256-bit integer ̃ Pis commonly used (and is used by TON as well). Namely, the 255 lower-order bits of ̃ Pcontainy P ,0≤y P < p <2 255 , and bit 255 is used to storex P mod 2, the lower-order bit ofx P . Sincey P always determinesx P up to sign (i.e., up to replacingx P withp−x P ),x P andp−x P can always be distinguished by their lower-order bit,pbeing odd. If it is sufficient to know±Pup to sign, one can ignorex P mod 2and con- sider only the little-endian 255-bit integery P , setting the bit 255 arbitrarily, ignoring its previously defined value, or clearing it. A.3.8. Private key for Ed25519.Aprivate keyfor Ed25519 is just an arbitrary 256-bit stringk. Asecret exponentaandsecret saltk ′′ are derived fromkby first computingsha512(k), and then taking the first 256 bits of thissha512as the little-endian representation ofa(but with bits 255, 2, 1, and 0 cleared, and bit 254 set); the last 256 bits ofsha512(k)then constitute k ′′ . This is essentially the same procedure as described inA.2.4, but with Curve25519 replaced by the birationally equivalent curve Ed25519. (In fact, it is the other way around: this procedure is standard for Ed25519-based elliptic curve cryptography, and TON extends the procedure to Curve25519.) A.3.9. Public key for Ed25519.Apublic keycorresponding to a private keykfor Ed25519 is the standard representation (cf.A.3.7) of the point A= \[a\]G ′ , whereais the secret exponent (cf.A.3.8) defined by the private keyk. 120 A.3. Ed25519 cryptography Notice thatφ(A)is the public key for Curve25519 defined by the same private keykaccording toA.2.4and (45). In this way, we can convert public keys for Ed25519 into corresponding public keys for Curve25519, and vice versa. Private keys do not need to be transformed at all. A.3.10. Cryptographic Ed25519-signatures.If a message (octet string) Mneeds to be signed by a private keykdefining secret exponentaand secret saltk ′′ , the following computations are performed: •r:=sha512(k ′′ |M), interpreted as a little-endian 512-bit integer. Here s|tdenotes the concatenation of octet stringssandt. •R:= \[r\]G ′ is a point on Ed25519. • ̃ Ris the standard representation (cf.A.3.7) of pointRas a 32-octet string. •s:=r+a·sha512( ̃ R| ̃ A|M) mod\`, encoded as a little-endian 256-bit integer. Here ̃ Ais the standard representation of pointA= \[a\]G ′ , the public key corresponding tok. The (Schnorr) signature is a 64-octet string( ̃ R,s), consisting of the standard representation of the pointRand of the 256-bit integers. A.3.11. Checking Ed25519-signatures.In order to verify signature ( ̃ R,s)of a messageM, supposedly made by the owner of the private key kcorresponding to a known public keyA, the following steps are performed: •Points\[s\]G ′ andR+ \[sha512( ̃ R| ̃ A|M)\]Aof Ed25519 are computed. •If these two points coincide, the signature is correct. 121 --- # Unknown TheOpenNetwork basedontheworkofDr.NikolaiDurov July26,2021 Abstract TheaimofthistextistoprovidearstdescriptionoftheTheOp en Network(TON)andrelatedblo ckchain,p eer-to-p eer,distributedstor- ageandservicehostingtechnologies.Toreducethesizeofthisdo c- umenttoreasonableprop ortions,wefo cusmainlyontheuniqueand deningfeaturesoftheTONplatformthatareimp ortantforitto achieveitsstatedgoals. Intro duction TheTheOpenNetwork(TON)isafast,secureandscalableblo ckchainand networkpro ject,capableofhandlingmillionsoftransactionsp ersecondif necessary,andb othuser-friendlyandserviceprovider-friendly.Weaimfor ittob eabletohostallreasonableapplicationscurrentlyprop osedandcon- ceived.Onemightthinkab outTONasahugedistributedsup ercomputer, orratherahugesup erserver,intendedtohostandprovideavarietyof services. Thistextisnotintendedtob etheultimatereferencewithresp ectto allimplementationdetails.Someparticularsarelikelytochangeduringthe developmentandtestingphases. 1 Intro duction Contents 1BriefDescriptionofTONComp onents3 2TONBlo ckchain5 2.1TONBlo ckchainasaCollectionof2-Blo ckchains.......5 2.2GeneralitiesonBlo ckchains...................15 2.3Blo ckchainState,AccountsandHashmaps...........19 2.4MessagesBetweenShardchains.................29 2.5GlobalShardchainState.BagofCellsPhilosophy.......38 2.6CreatingandValidatingNewBlo cks..............44 2.7SplittingandMergingShardchains...............57 2.8ClassicationofBlo ckchainPro jects..............61 2.9ComparisontoOtherBlo ckchainPro jects...........74 3TONNetworking80 3.1AbstractDatagramNetworkLayer...............80 3.2TONDHT:Kademlia-likeDistributedHashTable.......84 3.3OverlayNetworksandMulticastingMessages.........90 4TONServicesandApplications98 4.1TONServiceImplementationStrategies............98 4.2ConnectingUsersandServiceProviders.............102 4.3AccessingTONServices.....................104 5TONPayments111 5.1PaymentChannels........................111 5.2PaymentChannelNetwork,orLightningNetwork......118 Conclusion122 ATheTONCoin125 2 Chapter1.BriefDescriptionofTONComponents 1BriefDescriptionofTONComp onents TheTheOpenNetwork(TON)isacombinationofthefollowingcomp onents: ˆAexiblemulti-blo ckchainplatform(TONBlockchain;cf.Chapter2), capableofpro cessingmillionsoftransactionsp ersecond,withTuring- completesmartcontracts,upgradableformalblo ckchainsp ecications, multi-crypto currencyvaluetransfer,supp ortformicropaymentchan- nelsando-chainpaymentnetworks.TONBlockchainpresentssome newanduniquefeatures,suchastheself-healingverticalblo ckchain mechanism(cf.2.1.17)andInstantHyp ercub eRouting(cf.2.4.20), whichenableittob efast,reliable,scalableandself-consistentatthe sametime. ˆAp eer-to-p eernetwork(TONP2PNetwork,orjustTONNetwork;cf. Chapter3),usedforaccessingtheTONBlo ckchain,sendingtransac- tioncandidates,andreceivingup datesab outonlythosepartsofthe blo ckchainaclientisinterestedin(e.g.,thoserelatedtotheclient's accountsandsmartcontracts),butalsoabletosupp ortarbitrarydis- tributedservices,blo ckchain-relatedornot. ˆAdistributedlestoragetechnology(TONStorage;cf.4.1.7),acces- siblethroughTONNetwork,usedbytheTONBlo ckchaintostore archivecopiesofblo cksandstatusdata(snapshots),butalsoavail- ableforstoringarbitrarylesforusersorotherservicesrunningonthe platform,withtorrent-likeaccesstechnology. ˆAnetworkproxy/anonymizerlayer(TONProxy;cf.4.1.10and3.1.6), similartotheI 2 P(InvisibleInternetPro ject),usedtohidetheiden- tityandIPaddressesofTONNetworkno desifnecessary(e.g.,no des committingtransactionsfromaccountswithlargeamountsofcryp- to currency,orhigh-stakeblo ckchainvalidatorno deswhowishtohide theirexactIPaddressandgeographicallo cationasameasureagainst DDoSattacks). ˆAKademlia-likedistributedhashtable(TONDHT;cf.3.2),usedas atorrenttrackerforTONStorage(cf.3.2.10),asaninputtunnel lo catorforTONProxy(cf.3.2.14),andasaservicelo catorforTON Services(cf.3.2.12). 3 Chapter1.BriefDescriptionofTONComponents ˆAplatformforarbitraryservices(TONServices;cf.Chapter4),re- sidinginandavailablethroughTONNetworkandTONProxy,with formalizedinterfaces(cf.4.3.14)enablingbrowser-likeorsmartphone applicationinteraction.Theseformalinterfacesandp ersistentservice entryp ointscanb epublishedintheTONBlo ckchain(cf.4.3.17);ac- tualno desprovidingserviceatanygivenmomentcanb elo okedup throughtheTONDHTstartingfrominformationpublishedinthe TONBlo ckchain(cf.3.2.12).Servicesmaycreatesmartcontractsin theTONBlo ckchaintooersomeguaranteestotheirclients(cf.4.1.6). ˆTONDNS(cf.4.3.1),aserviceforassigninghuman-readablenames toaccounts,smartcontracts,servicesandnetworkno des. ˆTONPayments(cf.Chapter5),aplatformformicropayments,micro- paymentchannelsandamicropaymentchannelnetwork.Itcanb eused forfasto-chainvaluetransfers,andforpayingforservicesp owered byTONServices. ˆTONwillalloweasyintegrationwiththird-partymessagingandso- cialnetworkingapplications,thusmakingblo ckchaintechnologiesand distributedservicesnallyavailableandaccessibletoordinaryusers (cf.4.3.23),ratherthanjusttoahandfulofearlycrypto currency adopters. WhiletheTONBlo ckchainisthecoreoftheTONpro ject,andthe othercomp onentsmightb econsideredasplayingasupp ortiveroleforthe blo ckchain,theyturnouttohaveusefulandinterestingfunctionalityby themselves.Combined,theyallowtheplatformtohostmoreversatileap- plicationsthanitwouldb ep ossiblebyjustusingtheTONBlo ckchain (cf.2.9.13and4.1). 4 2.1.TONBlockchainasaCollectionof2-Blockchains 2TONBlo ckchain WestartwithadescriptionoftheTheOp enNetwork(TON)Blo ckchain, thecorecomp onentofthepro ject.Ourapproachhereistop-down:wegive ageneraldescriptionofthewholerst,andthenprovidemoredetailoneach comp onent. Forsimplicity,wesp eakhereab outtheTONBlo ckchain,eventhough inprincipleseveralinstancesofthisblo ckchainproto colmayb erunning indep endently(forexample,asaresultofhardforks).Weconsideronlyone ofthem. 2.1TONBlo ckchainasaCollectionof2-Blo ckchains TheTONBlo ckchainisactuallyacol lectionofblo ckchains(evenacollection ofblockchainsofblockchains,or2-blockchainsthisp ointwillb eclaried laterin2.1.17),b ecausenosingleblo ckchainpro jectiscapableofachieving ourgoalofpro cessingmillionsoftransactionsp ersecond,asopp osedtothe now-standarddozensoftransactionsp ersecond. 2.1.1.Listofblo ckchaintyp es.Theblo ckchainsinthiscollectionare: ˆTheuniquemasterblockchain,ormasterchainforshort,containing generalinformationab outtheproto colandthecurrentvaluesofits parameters,thesetofvalidatorsandtheirstakes,thesetofcurrently activeworkchainsandtheirshards,and,mostimp ortantly,thesetof hashesofthemostrecentblo cksofallworkchainsandshardchains. ˆSeveral(upto2 32 )workingblockchains,orworkchainsforshort,which areactuallytheworkhorses,containingthevalue-transferandsmart- contracttransactions.Dierentworkchainsmayhavedierentrules, meaningdierentformatsofaccountaddresses,dierentformatsof transactions,dierentvirtualmachines(VMs)forsmartcontracts,dif- ferentbasiccrypto currenciesandsoon.However,theyallmustsatisfy certainbasicinterop erabilitycriteriatomakeinteractionb etweendif- ferentworkchainsp ossibleandrelativelysimple.Inthisresp ect,the TONBlo ckchainisheterogeneous(cf.2.8.8),similarlytotheEOS (cf.2.9.7)andPolkaDot(cf.2.9.8)pro jects. ˆEachworkchainisinturnsub dividedintoupto2 60 shardblockchains, orshardchainsforshort,havingthesamerulesandblo ckformatas 5 2.1.TONBlockchainasaCollectionof2-Blockchains theworkchainitself,butresp onsibleonlyforasubsetofaccounts,de- p endingonseveralrst(mostsignicant)bitsoftheaccountaddress. Inotherwords,aformofshardingisbuiltintothesystem(cf.2.8.12). Becausealltheseshardchainsshareacommonblo ckformatandrules, theTONBlo ckchainishomogeneousinthisresp ect(cf.2.8.8),simi- larlytowhathasb eendiscussedinoneofEthereumscalingprop osals. 1 ˆEachblo ckinashardchain(andinthemasterchain)isactuallynotjust ablo ck,butasmallblo ckchain.Normally,thisblo ckblo ckchainor verticalblo ckchainconsistsofexactlyoneblo ck,andthenwemight thinkthisisjustthecorresp ondingblo ckoftheshardchain(alsocalled horizontalblo ckchaininthissituation).However,ifitb ecomesnec- essarytoxincorrectshardchainblo cks,anewblo ckiscommittedinto theverticalblo ckchain,containingeitherthereplacementforthein- validhorizontalblo ckchainblo ck,orablo ckdierence,containing onlyadescriptionofthosepartsofthepreviousversionofthisblo ck thatneedtob echanged.ThisisaTON-sp ecicmechanismtoreplace detectedinvalidblo ckswithoutmakingatrueforkofallshardchains involved;itwillb eexplainedinmoredetailin2.1.17.Fornow,we justremarkthateachshardchain(andthemasterchain)isnotacon- ventionalblo ckchain,butablockchainofblockchains,or2D-blockchain, orjusta2-blockchain. 2.1.2.InniteShardingParadigm.Almostallblo ckchainshardingpro- p osalsaretop-down:onerstimaginesasingleblo ckchain,andthendis- cusseshowtosplititintoseveralinteractingshardchainstoimprovep erfor- manceandachievescalability. TheTONapproachtoshardingisb ottom-up,explainedasfollows. Imaginethatshardinghasb eentakentoitsextreme,sothatexactlyone accountorsmartcontractremainsineachshardchain.Thenwehaveahuge numb erofaccount-chains,eachdescribingthestateandstatetransitions ofonlyoneaccount,andsendingvalue-b earingmessagestoeachotherto transfervalueandinformation. Ofcourse,itisimpracticaltohavehundredsofmillionsofblo ckchains, withup dates(i.e.,newblo cks)usuallyapp earingquiterarelyineachof them.Inordertoimplementthemmoreeciently,wegrouptheseaccount- chainsintoshardchains,sothateachblo ckoftheshardchainisessentiallya 1 https://github.com/ethereum/wiki/wiki/Sharding- FAQ 6 2.1.TONBlockchainasaCollectionof2-Blockchains collectionofblo cksofaccount-chainsthathaveb eenassignedtothisshard. Thustheaccount-chainshaveonlyapurelyvirtualorlogicalexistence insidetheshardchains. Wecallthisp ersp ectivetheInniteShardingParadigm.Itexplainsmany ofthedesigndecisionsfortheTONBlo ckchain. 2.1.3.Messages.InstantHyp ercub eRouting.TheInniteSharding Paradigminstructsustoregardeachaccount(orsmartcontract)asifit wereinitsownshardchainbyitself.Thentheonlywayoneaccountmight aectthestateofanotherisbysendingamessagetoit(thisisasp ecial instanceoftheso-calledActormo del,withaccountsasActors;cf.2.4.2). Therefore,asystemofmessagesb etweenaccounts(andshardchains,b ecause thesourceanddestinationaccountsare,generallysp eaking,lo catedindif- ferentshardchains)isofparamountimp ortancetoascalablesystemsuchas theTONBlo ckchain.Infact,anovelfeatureoftheTONBlo ckchain,called InstantHypercubeRouting(cf.2.4.20),enablesittodeliverandpro cessa messagecreatedinablo ckofoneshardchainintotheverynextblo ckofthe destinationshardchain,regard lessofthetotalnumberofshardchainsinthe system. 2.1.4.Quantityofmasterchains,workchainsandshardchains.A TONBlo ckchaincontainsexactlyonemasterchain.However,thesystem canp otentiallyaccommo dateupto2 32 workchains,eachsub dividedintoup to2 60 shardchains. 2.1.5.Workchainscanb evirtualblo ckchains,nottrueblo ckchains. Becauseaworkchainisusuallysub dividedintoshardchains,theexistenceof theworkchainisvirtual,meaningthatitisnotatrueblo ckchaininthe senseofthegeneraldenitionprovidedin2.2.1b elow,butjustacollection ofshardchains.Whenonlyoneshardchaincorresp ondstoaworkchain,this uniqueshardchainmayb eidentiedwiththeworkchain,whichinthiscase b ecomesatrueblo ckchain,atleastforsometime,thusgainingasup er- cialsimilaritytocustomarysingle-blo ckchaindesign.However,theInnite ShardingParadigm(cf.2.1.2)tellsusthatthissimilarityisindeedsup er- cial:itisjustacoincidencethatthep otentiallyhugenumb erofaccount- chainscantemp orarilyb egroup edintooneblo ckchain. 2.1.6.Identicationofworkchains.Eachworkchainisidentiedbyits numberorworkchainidentier(workchain\_id:uint 32 ),whichissimplyan 7 2.1.TONBlockchainasaCollectionof2-Blockchains unsigned32-bitinteger.Workchainsarecreatedbysp ecialtransactionsin themasterchain,deningthe(previouslyunused)workchainidentierand theformaldescriptionoftheworkchain,sucientatleastfortheinteraction ofthisworkchainwithotherworkchainsandforsup ercialvericationofthis workchain'sblo cks. 2.1.7.Creationandactivationofnewworkchains.Thecreationofa newworkchainmayb einitiatedbyessentiallyanymemb erofthecommunity, readytopaythe(high)masterchaintransactionfeesrequiredtopublishthe formalsp ecicationofanewworkchain.However,inorderforthenew workchaintob ecomeactive,atwo-thirdsconsensusofvalidatorsisrequired, b ecausetheywillneedtoupgradetheirsoftwaretopro cessblo cksofthenew workchain,andsignaltheirreadinesstoworkwiththenewworkchainby sp ecialmasterchaintransactions.Thepartyinterestedintheactivationof thenewworkchainmightprovidesomeincentiveforthevalidatorstosupp ort thenewworkchainbymeansofsomerewardsdistributedbyasmartcontract. 2.1.8.Identicationofshardchains.Eachshardchainisidentiedbya couple(w,s) = (workchain\_id,shard\_prex),whereworkchain\_id:uint 32 identiesthecorresp ondingworkchain,andshard\_prex:2 0...60 isabit stringoflengthatmost60,deningthesubsetofaccountsforwhichthis shardchainisresp onsible.Namely,allaccountswithaccount\_idstarting withshard\_prex(i.e.,havingshard\_prexasmostsignicantbits)willb e assignedtothisshardchain. 2.1.9.Identicationofaccount-chains.Recallthataccount-chainshave onlyavirtualexistence(cf.2.1.2).However,theyhaveanaturalidentier namely,(workchain\_id,account\_id)b ecauseanyaccount-chaincontains informationab outthestateandup datesofexactlyoneaccount(eithera simpleaccountorsmartcontractthedistinctionisunimp ortanthere). 2.1.10.Dynamicsplittingandmergingofshardchains;cf.2.7.A lesssophisticatedsystemmightusestaticshardingforexample,byusing thetopeightbitsoftheaccount\_idtoselectoneof256pre-denedshards. Animp ortantfeatureoftheTONBlo ckchainisthatitimplementsdy- namicsharding,meaningthatthenumb erofshardsisnotxed.Instead, shard(w,s)canb eautomaticallysub dividedintoshards(w,s.0)and(w,s.1) ifsomeformalconditionsaremet(essentially,ifthetransactionloadonthe originalshardishighenoughforaprolongedp erio doftime).Conversely, 8 2.1.TONBlockchainasaCollectionof2-Blockchains iftheloadstaysto olowforsomep erio doftime,theshards(w,s.0)and (w,s.1)canb eautomaticallymergedbackintoshard(w,s). Initially,onlyoneshard(w,∅)iscreatedforworkchainw.Later,itis sub dividedintomoreshards,ifandwhenthisb ecomesnecessary(cf.2.7.6 and2.7.8). 2.1.11.BasicworkchainorWorkchainZero.Whileupto2 32 workchains canb edenedwiththeirsp ecicrulesandtransactions,weinitiallydene onlyone,withworkchain\_id= 0.Thisworkchain,calledWorkchainZeroor thebasicworkchain,istheoneusedtoworkwithTONsmartcontractsand transferTONcoins(cf.App endixA).Mostapplicationsarelikelytorequire onlyWorkchainZero.Shardchainsofthebasicworkchainwillb ecalledbasic shardchains. 2.1.12.Blo ckgenerationintervals.Weexp ectanewblo cktob egener- atedineachshardchainandthemasterchainapproximatelyonceeveryve seconds.Thiswillleadtoreasonablysmalltransactionconrmationtimes. Newblo cksofallshardchainsaregeneratedapproximatelysimultaneously; anewblo ckofthemasterchainisgeneratedapproximatelyonesecondlater, b ecauseitmustcontainthehashesofthelatestblo cksofallshardchains. 2.1.13.Usingthemasterchaintomakeworkchainsandshardchains tightlycoupled.Oncethehashofablo ckofashardchainisincorp orated intoablo ckofthemasterchain,thatshardchainblo ckandallitsancestors areconsideredcanonical,meaningthattheycanb ereferencedfromthesub- sequentblo cksofallshardchainsassomethingxedandimmutable.Infact, eachnewshardchainblo ckcontainsahashofthemostrecentmasterchain blo ck,andallshardchainblo cksreferencedfromthatmasterchainblo ckare consideredimmutablebythenewblo ck. Essentially,thismeansthatatransactionoramessagecommittedina shardchainblo ckmayb esafelyusedintheverynextblo cksoftheother shardchains,withoutneedingtowaitfor,say,twentyconrmations(i.e., twentyblo cksgeneratedaftertheoriginalblo ckinthesameblo ckchain)b e- foreforwardingamessageortakingotheractionsbasedonaprevioustrans- action,asiscommoninmostprop osedlo osely-coupledsystems(cf.2.8.14), suchasEOS.Thisabilitytousetransactionsandmessagesinothershard- chainsamerevesecondsafterb eingcommittedisoneofthereasonswe b elieveourtightly-coupledsystem,therstofitskind,willb eableto deliverunprecedentedp erformance(cf.2.8.12and2.8.14). 9 2.1.TONBlockchainasaCollectionof2-Blockchains 2.1.14.Masterchainblo ckhashasaglobalstate.Accordingto2.1.13, thehashofthelastmasterchainblo ckcompletelydeterminestheoverallstate ofthesystemfromthep ersp ectiveofanexternalobserver.Onedo esnotneed tomonitorthestateofallshardchainsseparately. 2.1.15.Generationofnewblo cksbyvalidators;cf.2.6.TheTON Blo ckchainusesaPro of-of-Stake(PoS)approachforgeneratingnewblo cksin theshardchainsandthemasterchain.Thismeansthatthereisasetof,say, uptoafewhundredvalidatorssp ecialno desthathavedep ositedstakes (largeamountsofTONcoins)byasp ecialmasterchaintransactiontob e eligiblefornewblo ckgenerationandvalidation. Thenasmallersubsetofvalidatorsisassignedtoeachshard(w,s)ina deterministicpseudorandomway,changingapproximatelyevery1024blo cks. Thissubsetofvalidatorssuggestsandreachesconsensusonwhatthenext shardchainblo ckwouldb e,bycollectingsuitableprop osedtransactionsfrom theclientsintonewvalidblo ckcandidates.Foreachblo ck,thereisapseudo- randomlychosenorderonthevalidatorstodeterminewhoseblo ckcandidate hasthehighestprioritytob ecommittedateachturn. Validatorsandotherno descheckthevalidityoftheprop osedblo ckcandi- dates;ifavalidatorsignsaninvalidblo ckcandidate,itmayb eautomatically punishedbylosingpartorallofitsstake,orbyb eingsusp endedfromthe setofvalidatorsforsometime.Afterthat,thevalidatorsshouldreachcon- sensusonthechoiceofthenextblo ck,essentiallybyanecientvariantof theBFT(ByzantineFaultTolerant;cf.2.8.4)consensusproto col,similarto PBFT\[4\]orHoneyBadgerBFT\[11\].Ifconsensusisreached,anewblo ck iscreated,andvalidatorsdivideb etweenthemselvesthetransactionfeesfor thetransactionsincluded,plussomenewly-created(minted)coins. Eachvalidatorcanb eelectedtoparticipateinseveralvalidatorsubsets; inthiscase,itisexp ectedtorunallvalidationandconsensusalgorithmsin parallel. Afterallnewshardchainblo cksaregeneratedoratimeoutispassed,a newmasterchainblo ckisgenerated,includingthehashesofthelatestblo cks ofallshardchains.ThisisdonebyBFTconsensusofal lvalidators. 2 MoredetailontheTONPoSapproachanditseconomicalmo delispro- videdinsection2.6. 2 Actually,two-thirdsbystakeisenoughtoachieveconsensus,butaneortismadeto collectasmanysignaturesasp ossible. 10 2.1.TONBlockchainasaCollectionof2-Blockchains 2.1.16.Forksofthemasterchain.Acomplicationthatarisesfromour tightly-coupledapproachisthatswitchingtoadierentforkinthemaster- chainwillalmostnecessarilyrequireswitchingtoanotherforkinatleast someoftheshardchains.Ontheotherhand,aslongastherearenoforks inthemasterchain,noforksintheshardchainareevenp ossible,b ecauseno blo cksinthealternativeforksoftheshardchainscanb ecomecanonicalby havingtheirhashesincorp oratedintoamasterchainblo ck. ThegeneralruleisthatifmasterchainblockB ′ isapredecessorofB, B ′ includeshashHash(B ′ w,s )of(w,s)-shardchainblockB ′ w,s ,andBincludes hashHash(B w,s ),thenB ′ w,s mustbeapredecessorofB w,s ;otherwise,the masterchainblockBisinvalid. Weexp ectmasterchainforkstob erare,nexttonon-existent,b ecause intheBFTparadigmadoptedbytheTONBlo ckchaintheycanhapp en onlyinthecaseofincorrectb ehaviorbyamajorityofvalidators(cf.2.6.1 and2.6.15),whichwouldimplysignicantstakelossesbytheoenders. Therefore,notrueforksintheshardchainsshouldb eexp ected.Instead, ifaninvalidshardchainblo ckisdetected,itwillb ecorrectedbymeansof theverticalblo ckchainmechanismofthe2-blo ckchain(cf.2.1.17),which canachievethisgoalwithoutforkingthehorizontalblo ckchain(i.e.,the shardchain).Thesamemechanismcanb eusedtoxnon-fatalmistakesin themasterchainblo cksaswell. 2.1.17.Correctinginvalidshardchainblo cks.Normally,onlyvalid shardchainblo ckswillb ecommitted,b ecausevalidatorsassignedtothe shardchainmustreachatwo-thirdsByzantineconsensusb eforeanewblo ck canb ecommitted.However,thesystemmustallowfordetectionofprevi- ouslycommittedinvalidblo cksandtheircorrection. Ofcourse,onceaninvalidshardchainblo ckisfoundeitherbyavalidator (notnecessarilyassignedtothisshardchain)orbyasherman(anyno de ofthesystemthatmadeacertaindep osittob eabletoraisequestionsab out blo ckvalidity;cf.2.6.4)theinvalidityclaimanditspro ofarecommitted intothemasterchain,andthevalidatorsthathavesignedtheinvalidblo ckare punishedbylosingpartoftheirstakeand/orb eingtemp orarilysusp ended fromthesetofvalidators(thelattermeasureisimp ortantforthecaseofan attackerstealingtheprivatesigningkeysofanotherwiseb enignvalidator). However,thisisnotsucient,b ecausetheoverallstateofthesystem (TONBlo ckchain)turnsouttob einvalidb ecauseoftheinvalidshardchain blo ckpreviouslycommitted.Thisinvalidblo ckmustb ereplacedbyanewer 11 2.1.TONBlockchainasaCollectionof2-Blockchains validversion. Mostsystemswouldachievethisbyrollingbacktothelastblo ckb efore theinvalidoneinthisshardchainandthelastblo cksunaectedbymessages propagatedfromtheinvalidblo ckineachoftheothershardchains,and creatinganewforkfromtheseblo cks.Thisapproachhasthedisadvantage thatalargenumb erofotherwisecorrectandcommittedtransactionsare suddenlyrolledback,anditisunclearwhethertheywillb eincludedlaterat all. TheTONBlo ckchainsolvesthisproblembymakingeachblo ckof eachshardchainandofthemasterchain(horizontalblo ckchains)asmall blo ckchain(verticalblo ckchain)byitself,containingdierentversionsof thisblo ck,ortheirdierences.Normally,theverticalblo ckchainconsists ofexactlyoneblo ck,andtheshardchainlo okslikeaclassicalblo ckchain. However,oncetheinvalidityofablo ckisconrmedandcommittedintoa masterchainblo ck,theverticalblo ckchainoftheinvalidblo ckisallowedto growbyanewblo ckintheverticaldirection,replacingoreditingtheinvalid blo ck.Thenewblo ckisgeneratedbythecurrentvalidatorsubsetforthe shardchaininquestion. Therulesforanewverticalblo cktob evalidarequitestrict.Inpar- ticular,ifavirtualaccount-chainblo ck(cf.2.1.2)containedintheinvalid blo ckisvalidbyitself,itmustb eleftunchangedbythenewverticalblo ck. Onceanewverticalblo ckiscommittedontopoftheinvalidblo ck,its hashispublishedinanewmasterchainblo ck(orratherinanewvertical blo ck,lyingab ovetheoriginalmasterchainblo ckwherethehashoftheinvalid shardchainblo ckwasoriginallypublished),andthechangesarepropagated furthertoanyshardchainblo cksreferringtothepreviousversionofthisblo ck (e.g.,thosehavingreceivedmessagesfromtheincorrectblo ck).Thisisxed bycommittingnewverticalblo cksinverticalblo ckchainsforallblo cks previouslyreferringtotheincorrectblo ck;newverticalblo ckswillrefer tothemostrecent(corrected)versionsinstead.Again,strictrulesforbid changingaccount-chainsthatarenotreallyaected(i.e.,thatreceivethe samemessagesasinthepreviousversion).Inthisway,xinganincorrect blo ckgeneratesripplesthatareultimatelypropagatedtowardsthemost recentblo cksofallaectedshardchains;thesechangesarereectedinnew verticalmasterchainblo cksaswell. Oncethehistoryrewritingripplesreachthemostrecentblo cks,thenew shardchainblo cksaregeneratedinoneversiononly,b eingsuccessorsofthe newestblo ckversionsonly.Thismeansthattheywillcontainreferencesto 12 2.1.TONBlockchainasaCollectionof2-Blockchains thecorrect(mostrecent)verticalblo cksfromtheveryb eginning. Themasterchainstateimplicitlydenesamaptransformingthehashof therstblo ckofeachverticalblo ckchainintothehashofitslatestversion. Thisenablesaclienttoidentifyandlo cateanyverticalblo ckchainbythe hashofitsveryrst(andusuallytheonly)blo ck. 2.1.18.TONcoinsandmulti-currencyworkchains.TheTONBlo ck- chainsupp ortsupto2 32 dierentcrypto currencies,coins,ortokens, distinguishedbya32-bitcurrency\_id.Newcrypto currenciescanb eadded bysp ecialtransactionsinthemasterchain.Eachworkchainhasabasiccryp- to currency,andcanhaveseveraladditionalcrypto currencies. Thereisonesp ecialcrypto currencywithcurrency\_id= 0,namely,the TONcoin(cf.App endixA).Itisthebasiccrypto currencyofWorkchain Zero.Itisalsousedfortransactionfeesandvalidatorstakes. Inprinciple,otherworkchainsmaycollecttransactionfeesinotherto- kens.Inthiscase,somesmartcontractforautomatedconversionofthese transactionfeesintoTONcoinsshouldb eprovided. 2.1.19.Messagingandvaluetransfer.Shardchainsb elongingtothe sameordierentworkchainsmaysendmessagestoeachother.Whilethe exactformofthemessagesalloweddep endsonthereceivingworkchainand receivingaccount(smartcontract),therearesomecommoneldsmaking inter-workchainmessagingp ossible.Inparticular,eachmessagemayhave somevalueattached,intheformofacertainamountofTONcoinsand/or otherregisteredcrypto currencies,providedtheyaredeclaredasacceptable crypto currenciesbythereceivingworkchain. Thesimplestformofsuchmessagingisavaluetransferfromone(usually notasmart-contract)accounttoanother. 2.1.20.TONVirtualMachine.TheTONVirtualMachine,alsoab- breviatedasTONVMorTVM,isthevirtualmachineusedtoexecute smart-contractco deinthemasterchainandinthebasicworkchain.Other workchainsmayuseothervirtualmachinesalongsideorinsteadoftheTVM. Herewelistsomeofitsfeatures.Theyarediscussedfurtherin2.3.12, 2.3.14andelsewhere. ˆTVMrepresentsalldataasacollectionof(TVM)cel ls(cf.2.3.14). Eachcellcontainsupto128databytesandupto4referencestoother cells.Asaconsequenceoftheeverythingisabagofcellsphilosophy 13 2.1.TONBlockchainasaCollectionof2-Blockchains (cf.2.5.14),thisenablesTVMtoworkwithalldatarelatedtotheTON Blo ckchain,includingblo cksandblo ckchainglobalstateifnecessary. ˆTVMcanworkwithvaluesofarbitraryalgebraicdatatyp es(cf.2.3.12), representedastreesordirectedacyclicgraphsofTVMcells.However, itisagnostictowardstheexistenceofalgebraicdatatyp es;itjustworks withcells. ˆTVMhasbuilt-insupp ortforhashmaps(cf.2.3.7). ˆTVMisastackmachine.Itsstackkeepseither64-bitintegersorcell references. ˆ64-bit,128-bitand256-bitarithmeticissupp orted.Alln-bitarithmetic op erationscomeinthreeavors:forunsignedintegers,forsignedinte- gersandforintegersmo dulo2 n (noautomaticoverowchecksinthe lattercase). ˆTVMhasunsignedandsignedintegerconversionfromn-bittom-bit, forall0≤m,n≤256,withoverowchecks. ˆAllarithmeticop erationsp erformoverowchecksbydefault,greatly simplifyingthedevelopmentofsmartcontracts. ˆTVMhasmultiply-then-shiftandshift-then-dividearithmeticop er- ationswithintermediatevaluescomputedinalargerintegertyp e;this simpliesimplementingxed-p ointarithmetic. ˆTVMoerssupp ortforbitstringsandbytestrings. ˆSupp ortfor256-bitEllipticCurveCryptography(ECC)forsomepre- denedcurves,includingCurve25519,ispresent. ˆSupp ortforWeilpairingsonsomeellipticcurves,usefulforfastimple- mentationofzk-SNARKs,isalsopresent. ˆSupp ortforp opularhashfunctions,includingsha256,ispresent. ˆTVMcanworkwithMerklepro ofs(cf.5.1.9). ˆTVMoerssupp ortforlargeorglobalsmartcontracts.Suchsmart contractsmustb eawareofsharding(cf.2.3.18and2.3.16).Usual (lo cal)smartcontractscanb esharding-agnostic. 14 2.2.GeneralitiesonBlockchains ˆTVMsupp ortsclosures. ˆAspinelesstaglessG-machine\[13\]canb eeasilyimplementedinside TVM. Severalhigh-levellanguagescanb edesignedforTVM,inadditiontothe TVMassembly.Alltheselanguageswillhavestatictyp esandwillsupp ort algebraicdatatyp es.Weenvisionthefollowingp ossibilities: ˆAJava-likeimp erativelanguage,witheachsmartcontractresembling aseparateclass. ˆAlazyfunctionallanguage(thinkofHaskell). ˆAneagerfunctionallanguage(thinkofML). 2.1.21.Congurableparameters.Animp ortantfeatureoftheTON Blo ckchainisthatmanyofitsparametersarecongurable.Thismeansthat theyarepartofthemasterchainstate,andcanb echangedbycertainsp ecial prop osal/vote/resulttransactionsinthemasterchain,withoutanyneedfor hardforks.Changingsuchparameterswillrequirecollectingtwo-thirdsof validatorvotesandmorethanhalfofthevotesofallotherparticipantswho wouldcaretotakepartinthevotingpro cessinfavoroftheprop osal. 2.2GeneralitiesonBlo ckchains 2.2.1.Generalblo ckchaindenition.Ingeneral,any(true)blockchain isasequenceofblocks,eachblo ckBcontainingareferenceblk-prev(B)to thepreviousblo ck(usuallybyincludingthehashofthepreviousblo ckinto theheaderofthecurrentblo ck),andalistoftransactions.Eachtransaction describ essometransformationoftheglobalblockchainstate;thetransactions listedinablo ckareappliedsequentiallytocomputethenewstatestarting fromtheoldstate,whichistheresultingstateaftertheevaluationofthe previousblo ck. 2.2.2.RelevancefortheTONBlo ckchain.RecallthattheTONBlock- chainisnotatrueblo ckchain,butacollectionof2-blo ckchains(i.e.,of blo ckchainsofblo ckchains;cf.2.1.1),sotheab oveisnotdirectlyapplicable toit.However,westartwiththesegeneralitiesontrueblo ckchainstouse themasbuildingblo cksforourmoresophisticatedconstructions. 15 2.2.GeneralitiesonBlockchains 2.2.3.Blo ckchaininstanceandblo ckchaintyp e.Oneoftenusesthe wordblockchaintodenoteb othageneralblockchaintypeanditssp ecic blockchaininstances,denedassequencesofblo ckssatisfyingcertaincondi- tions.Forexample,2.2.1referstoblo ckchaininstances. Inthisway,ablo ckchaintyp eisusuallyasubtyp eofthetyp eBlock ∗ of lists(i.e.,nitesequences)ofblo cks,consistingofthosesequencesofblo cks thatsatisfycertaincompatibilityandvalidityconditions: Blockchain⊂Block ∗ (1) Ab etterwaytodeneBlockchainwouldb etosaythatBlockchainisa dependentcoupletype,consistingofcouples(B,v),withrstcomp onentB: Block ∗ b eingoftyp eBlock ∗ (i.e.,alistofblo cks),andthesecondcomp onent v:isValidBc(B)b eingapro oforawitnessofthevalidityofB.Inthisway, Blockchain≡Σ (B:Block ∗ ) isValidBc(B)(2) Weuseherethenotationfordep endentsumsoftyp esb orrowedfrom\[16\]. 2.2.4.Dep endenttyp etheory,Co qandTL.Notethatweareusing (Martin-Löf )dep endenttyp etheoryhere,similartothatusedintheCo q 3 pro ofassistant.Asimpliedversionofdep endenttyp etheoryisalsousedin TL(TypeLanguage), 4 whichwillb eusedintheformalsp ecicationofthe TONBlo ckchaintodescrib etheserializationofalldatastructuresandthe layoutsofblo cks,transactions,andthelike. Infact,dep endenttyp etheorygivesausefulformalizationofwhatapro of is,andsuchformalpro ofs(ortheirserializations)mightb ecomehandywhen oneneedstoprovidepro ofofinvalidityforsomeblo ck,forexample. 2.2.5.TL,ortheTyp eLanguage.SinceTL(Typ eLanguage)willb e usedintheformalsp ecicationsofTONblo cks,transactions,andnetwork datagrams,itwarrantsabriefdiscussion. TLisalanguagesuitablefordescriptionofdep endentalgebraictypes, whichareallowedtohavenumeric(natural)andtyp eparameters.Each typ eisdescrib edbymeansofseveralconstructors.Eachconstructorhasa (human-readable)identierandaname,whichisabitstring(32-bitinteger bydefault).Apartfromthat,thedenitionofaconstructorcontainsalist ofeldsalongwiththeirtyp es. 3 https://coq.inria.fr 4 https://core.telegram.org/mtproto/TL 16 2.2.GeneralitiesonBlockchains Acollectionofconstructorandtyp edenitionsiscalledaTL-scheme.It isusuallykeptinoneorseveralleswiththesux.tl. Animp ortantfeatureofTL-schemesisthattheydetermineanunambigu- ouswayofserializinganddeserializingvalues(orob jects)ofalgebraictyp es dened.Namely,whenavalueneedstob eserializedintoastreamofbytes, rstthenameoftheconstructorusedforthisvalueisserialized.Recursively computedserializationsofeacheldfollow. ThedescriptionofapreviousversionofTL,suitableforserializingarbi- traryob jectsintosequencesof32-bitintegers,isavailableathttps://core. telegram.org/mtproto/TL.AnewversionofTL,calledTL-B,isb eingde- velop edforthepurp oseofdescribingtheserializationofob jectsusedbythe TONPro ject.Thisnewversioncanserializeob jectsintostreamsofbytes andevenbits(notjust32-bitintegers),andoerssupp ortforserialization intoatreeofTVMcells(cf.2.3.14).AdescriptionofTL-Bwillb eapart oftheformalsp ecicationoftheTONBlo ckchain. 2.2.6.Blo cksandtransactionsasstatetransformationop erators. Normally,anyblo ckchain(typ e)Blockchainhasanasso ciatedglobalstate (typ e)State,andatransaction(typ e)Transaction.Thesemanticsofa blo ckchainaretoalargeextentdeterminedbythetransactionapplication function: ev\_trans ′ :Transaction×State→State ? (3) HereX ? denotesMaybeX,theresultofapplyingtheMaybemonadto typ eX.ThisissimilartoouruseofX ∗ forListX.Essentially,avalue oftyp eX ? iseitheravalueoftyp eXorasp ecialvalue⊥indicatingthe absenceofanactualvalue(thinkab outanullp ointer).Inourcase,weuse State ? insteadofStateastheresulttyp eb ecauseatransactionmayb einvalid ifinvokedfromcertainoriginalstates(thinkab outattemptingtowithdraw fromanaccountmoremoneythanitisactuallythere). Wemightpreferacurriedversionofev\_trans ′ : ev\_trans:Transaction→State→State ? (4) Becauseablo ckisessentiallyalistoftransactions,theblo ckevaluation function ev\_block:Block→State→State ? (5) canb ederivedfromev\_trans.Ittakesablo ckB:Blockandtheprevious blo ckchainstates:State(whichmightincludethehashoftheprevious 17 2.2.GeneralitiesonBlockchains blo ck)andcomputesthenextblo ckchainstates ′ =ev\_block(B)(s) :State, whichiseitheratruestateorasp ecialvalue⊥indicatingthatthenext statecannotb ecomputed(i.e.,thattheblo ckisinvalidifevaluatedfromthe startingstategivenforexample,theblo ckincludesatransactiontryingto debitanemptyaccount.) 2.2.7.Blo cksequencenumb ers.Eachblo ckBintheblo ckchaincanb e referredtobyitssequencenumberblk-seqno(B),startingfromzeroforthe veryrstblo ck,andincrementedbyonewheneverpassingtothenextblo ck. Moreformally, blk-seqno(B) =blk-seqno ( blk-prev(B) ) + 1(6) Noticethatthesequencenumb erdo esnotidentifyablo ckuniquelyinthe presenceofforks. 2.2.8.Blo ckhashes.Anotherwayofreferringtoablo ckBisbyitshash blk-hash(B),whichisactuallythehashoftheheaderofblo ckB(however, theheaderoftheblo ckusuallycontainshashesthatdep endonallcontentof blo ckB).Assumingthattherearenocollisionsforthehashfunctionused (oratleastthattheyareveryimprobable),ablo ckisuniquelyidentiedby itshash. 2.2.9.Hashassumption.Duringformalanalysisofblo ckchainalgorithms, weassumethattherearenocollisionsforthek-bithashfunctionHash: Bytes ∗ →2 k used: Hash(s) =Hash(s ′ )⇒s=s ′ foranys,s ′ ∈Bytes ∗ (7) HereBytes={0...255}=2 8 isthetyp eofbytes,orthesetofallbyte values,andBytes ∗ isthetyp eorsetofarbitrary(nite)listsofbytes;while 2={0,1}isthebittyp e,and2 k istheset(oractuallythetyp e)ofallk-bit sequences(i.e.,ofk-bitnumb ers). Ofcourse,(7)isimp ossiblemathematically,b ecauseamapfromanin- nitesettoanitesetcannotb einjective.Amorerigorousassumptionwould b e ∀s,s ′ :s6=s ′ ,P ( Hash(s) =Hash(s ′ ) ) = 2 −k (8) However,thisisnotsoconvenientforthepro ofs.If(8)isusedatmostN timesinapro ofwith2 −k N < forsomesmall(say,= 10 −18 ),wecan 18 2.3.BlockchainState,AccountsandHashmaps reasonasif(7)weretrue,providedweacceptafailureprobability(i.e.,the nalconclusionswillb etruewithprobabilityatleast1−). Finalremark:inordertomaketheprobabilitystatementof(8)really rigorous,onemustintro duceaprobabilitydistributiononthesetBytes ∗ of allbytesequences.Awayofdoingthisisbyassumingallbytesequences ofthesamelengthlequiprobable,andsettingtheprobabilityofobservinga sequenceoflengthlequaltop l −p l+1 forsomep→1−.Then(8)shouldb e understo o dasalimitofconditionalprobabilityP ( Hash(s) =Hash(s ′ )|s6= s ′ ) whenptendstoonefromb elow. 2.2.10.HashusedfortheTONBlo ckchain.Weareusingthe256-bit sha256hashfortheTONBlo ckchainforthetimeb eing.Ifitturnsoutto b eweakerthanexp ected,itcanb ereplacedbyanotherhashfunctioninthe future.Thechoiceofthehashfunctionisacongurableparameterofthe proto col,soitcanb echangedwithouthardforksasexplainedin2.1.21. 2.3Blo ckchainState,AccountsandHashmaps Wehavenotedab ovethatanyblo ckchaindenesacertainglobalstate,and eachblo ckandeachtransactiondenesatransformationofthisglobalstate. Herewedescrib etheglobalstateusedbyTONblo ckchains. 2.3.1.AccountIDs.ThebasicaccountIDsusedbyTONblo ckchains oratleastbyitsmasterchainandWorkchainZeroare256-bitintegers, assumedtob epublickeysfor256-bitEllipticCurveCryptography(ECC) forasp ecicellipticcurve.Inthisway, account\_id:Account=uint 256 =2 256 (9) HereAccountistheaccounttype,whileaccount\_id:Accountisasp ecic variableoftyp eAccount. OtherworkchainscanuseotheraccountIDformats,256-bitorotherwise. Forexample,onecanuseBitcoin-styleaccountIDs,equaltosha256ofan ECCpublickey. However,thebitlengthlofanaccountIDmustb exedduringthe creationoftheworkchain(inthemasterchain),anditmustb eatleast64, b ecausetherst64bitsofaccount\_idareusedforshardingandmessage routing. 19 2.3.BlockchainState,AccountsandHashmaps 2.3.2.Maincomp onent:Hashmaps.Theprincipalcomp onentofthe TONblo ckchainstateisahashmap.Insomecasesweconsider(partially dened)mapsh:2 n 99K2 m .Moregenerally,wemightb einterestedin hashmapsh:2 n 99KXforacomp ositetyp eX.However,thesource(or index)typ eisalmostalways2 n . Sometimes,wehaveadefaultvalueempty:X,andthehashmaph: 2 n →Xisinitializedbyitsdefaultvaluei7→empty. 2.3.3.Example:TONaccountbalances.Animp ortantexampleisgiven byTONaccountbalances.Itisahashmap balance:Account→uint 128 (10) mappingAccount=2 256 intoaTONcoinbalanceoftyp euint 128 =2 128 . Thishashmaphasadefaultvalueofzero,meaningthatinitially(b eforethe rstblo ckispro cessed)thebalanceofallaccountsiszero. 2.3.4.Example:smart-contractp ersistentstorage.Anotherexample isgivenbysmart-contractp ersistentstorage,whichcanb e(veryapproxi- mately)representedasahashmap storage:2 256 99K2 256 (11) Thishashmapalsohasadefaultvalueofzero,meaningthatuninitialized cellsofp ersistentstorageareassumedtob ezero. 2.3.5.Example:p ersistentstorageofallsmartcontracts.Because wehavemorethanonesmartcontract,distinguishedbyaccount\_id,each havingitsseparatep ersistentstorage,wemustactuallyhaveahashmap Storage:Account99K(2 256 99K2 256 )(12) mappingaccount\_idofasmartcontractintoitsp ersistentstorage. 2.3.6.Hashmaptyp e.Thehashmapisnotjustanabstract(partially dened)function2 n 99KX;ithasasp ecicrepresentation.Therefore,we supp osethatwehaveasp ecialhashmaptyp e Hashmap(n,X) :Type(13) corresp ondingtoadatastructureenco dinga(partial)map2 n 99KX.We canalsowrite Hashmap(n:nat)(X:Type) :Type(14) 20 2.3.BlockchainState,AccountsandHashmaps or Hashmap:nat→Type→Type(15) Wecanalwaystransformh:Hashmap(n,X)intoamaphget(h) :2 n →X ? . Henceforth,weusuallywriteh\[i\]insteadofhget(h)(i): h\[i\] :≡hget(h)(i) :X ? foranyi:2 n ,h:Hashmap(n,X)(16) 2.3.7.Denitionofhashmaptyp easaPatriciatree.Logically,one mightdeneHashmap(n,X)asan(incomplete)binarytreeofdepthnwith edgelab els0and1andwithvaluesoftyp eXintheleaves.Anotherwayto describ ethesamestructurewouldb easa(bitwise)trieforbinarystringsof lengthequalton. Inpractice,weprefertouseacompactrepresentationofthistrie,by compressingeachvertexhavingonlyonechildwithitsparent.Theresult- ingrepresentationisknownasaPatriciatreeorabinaryradixtree.Each intermediatevertexnowhasexactlytwochildren,lab eledbytwonon-empty binarystrings,b eginningwithzerofortheleftchildandwithoneforthe rightchild. Inotherwords,therearetwotyp esof(non-ro ot)no desinaPatriciatree: ˆLeaf(x),containingvaluexoftyp eX. ˆNode(l,s l ,r,s r ),wherelisthe(referencetothe)leftchildorsubtree, s l isthebitstringlab elingtheedgeconnectingthisvertextoitsleft child(alwaysb eginningwith0),ristherightsubtree,ands r isthe bitstringlab elingtheedgetotherightchild(alwaysb eginningwith1). Athirdtyp eofno de,tob eusedonlyonceatthero otofthePatriciatree, isalsonecessary: ˆRoot(n,s 0 ,t),wherenisthecommonlengthofindexbitstringsof Hashmap(n,X),s 0 isthecommonprexofallindexbitstrings,andt isareferencetoaLeaforaNode. IfwewanttoallowthePatriciatreetob eempty,afourthtyp eof(ro ot) no dewouldb eused: ˆEmptyRoot(n),wherenisthecommonlengthofallindexbitstrings. 21 2.3.BlockchainState,AccountsandHashmaps WedenetheheightofaPatriciatreeby height(Leaf(x)) = 0(17) height ( Node(l,s l ,r,s r ) ) =height(l) +len(s l ) =height(r) +len(s r ) (18) height ( Root(n,s 0 ,t) ) =len(s 0 ) +height(t) =n(19) Thelasttwoexpressionsineachofthelasttwoformulasmustb eequal.We usePatriciatreesofheightntorepresentvaluesoftyp eHashmap(n,X). IfthereareNleavesinthetree(i.e.,ourhashmapcontainsNvalues), thenthereareexactlyN−1intermediatevertices.Insertinganewvalue alwaysinvolvessplittinganexistingedgebyinsertinganewvertexinthe middleandaddinganewleafastheotherchildofthisnewvertex.Deleting avaluefromahashmapdo estheopp osite:aleafanditsparentaredeleted, andtheparent'sparentanditsotherchildb ecomedirectlylinked. 2.3.8.Merkle-Patriciatrees.Whenworkingwithblo ckchains,wewant tob eabletocomparePatriciatrees(i.e.,hashmaps)andtheirsubtrees, byreducingthemtoasinglehashvalue.Theclassicalwayofachieving thisisgivenbytheMerkletree.Essentially,wewanttodescrib eawayof hashingob jectshoftyp eHashmap(n,X)withtheaidofahashfunction Hashdenedforbinarystrings,providedweknowhowtocomputehashes Hash(x)ofob jectsx:X(e.g.,byapplyingthehashfunctionHashtoa binaryserializationofob jectx). OnemightdeneHash(h)recursivelyasfollows: Hash ( Leaf(x) ) :=Hash(x)(20) Hash ( Node(l,s l ,r,s r ) ) :=Hash ( Hash(l).Hash(r).code(s l ).code(s r ) ) (21) Hash ( Root(n,s 0 ,t) ) :=Hash ( code(n).code(s 0 ).Hash(t) ) (22) Heres.tdenotestheconcatenationof(bit)stringssandt,andcode(s)is aprexco deforallbitstringss.Forexample,onemightenco de0by10,1 by11,andtheendofthestringby0. 5 5 Onecanshowthatthisenco dingisoptimalforapproximatelyhalfofalledgelab els ofaPatriciatreewithrandomorconsecutiveindices.Remainingedgelab elsarelikelyto b elong(i.e.,almost256bitslong).Therefore,anearlyoptimalenco dingforedgelab els istousetheab oveco dewithprex0forshortbitstrings,andenco de1,thenninebits containinglengthl=|s|ofbitstrings,andthenthelbitsofsforlongbitstrings(with l≥10). 22 2.3.BlockchainState,AccountsandHashmaps Wewillseelater(cf.2.3.12and2.3.14)thatthisisa(slightlytweaked) versionofrecursivelydenedhashesforvaluesofarbitrary(dep endent)al- gebraictyp es. 2.3.9.RecomputingMerkletreehashes.Thiswayofrecursivelyden- ingHash(h),calledaMerkletreehash,hastheadvantagethat,ifoneexplic- itlystoresHash(h ′ )alongwitheachno deh ′ (resultinginastructurecalleda Merkletree,or,inourcase,aMerklePatriciatree),oneneedstorecompute onlyatmostnhasheswhenanelementisaddedto,deletedfromorchanged inthehashmap. Inthisway,ifonerepresentstheglobalblo ckchainstatebyasuitable Merkletreehash,itiseasytorecomputethisstatehashaftereachtransac- tion. 2.3.10.Merklepro ofs.Undertheassumption(7)ofinjectivityofthe chosenhashfunctionHash,onecanconstructapro ofthat,foragivenvalue zofHash(h),h:Hashmap(n,X),onehashget(h)(i) =xforsomei:2 n andx:X.Suchapro ofwillconsistofthepathintheMerklePatriciatree fromtheleafcorresp ondingtoitothero ot,augmentedbythehashesofall siblingsofallno deso ccurringonthispath. Inthisway,alightno de 6 knowingonlythevalueofHash(h)forsome hashmaph(e.g.,smart-contractp ersistentstorageorglobalblo ckchainstate) mightrequestfromafullno de 7 notonlythevaluex=h\[i\] =hget(h)(i),but suchavaluealongwithaMerklepro ofstartingfromthealreadyknownvalue Hash(h).Then,underassumption(7),thelightno decancheckforitself thatxisindeedthecorrectvalueofh\[i\]. Insomecases,theclientmaywanttoobtainthevaluey=Hash(x) = Hash(h\[i\])insteadforexample,ifxitselfisverylarge(e.g.,ahashmap itself ).ThenaMerklepro offor(i,y)canb eprovidedinstead.Ifxisa hashmapaswell,thenasecondMerklepro ofstartingfromy=Hash(x) mayb eobtainedfromafullno de,toprovideavaluex\[j\] =h\[i\]\[j\]orjustits hash. 6 Alightnodeisano dethatdo esnotkeeptrackofthefullstateofashardchain; instead,itkeepsminimalinformationsuchasthehashesoftheseveralmostrecentblo cks, andreliesoninformationobtainedfromfullno deswhenitb ecomesnecessarytoinsp ect somepartsofthefullstate. 7 Aful lnodeisano dekeepingtrackofthecompleteup-to-datestateoftheshardchain inquestion. 23 2.3.BlockchainState,AccountsandHashmaps 2.3.11.Imp ortanceofMerklepro ofsforamulti-chainsystemsuch asTON.Noticethatano denormallycannotb eafullno deforallshard- chainsexistingintheTONenvironment.Itusuallyisafullno deonlyfor someshardchainsforinstance,thosecontainingitsownaccount,asmart contractitisinterestedin,orthosethatthisno dehasb eenassignedtob e avalidatorof.Forothershardchains,itmustb ealightno deotherwise thestorage,computingandnetworkbandwidthrequirementswouldb epro- hibitive.Thismeansthatsuchano decannotdirectlycheckassertionsab out thestateofothershardchains;itmustrelyonMerklepro ofsobtainedfrom fullno desforthoseshardchains,whichisassafeascheckingbyitselfunless (7)fails(i.e.,ahashcollisionisfound). 2.3.12.PeculiaritiesofTONVM.TheTONVMorTVM(TONVirtual Machine),usedtorunsmartcontractsinthemasterchainandWorkchain Zero,isconsiderablydierentfromcustomarydesignsinspiredbytheEVM (EthereumVirtualMachine):itworksnotjustwith256-bitintegers,butac- tuallywith(almost)arbitraryrecords,structures,orsum-pro ducttyp es, makingitmoresuitabletoexecuteco dewritteninhigh-level(esp eciallyfunc- tional)languages.Essentially,TVMusestaggeddatatyp es,notunlikethose usedinimplementationsofPrologorErlang. OnemightimaginerstthatthestateofaTVMsmartcontractisnot justahashmap2 256 →2 256 ,orHashmap(256,2 256 ),but(asarststep) Hashmap(256,X),whereXisatyp ewithseveralconstructors,enablingit tostore,apartfrom256-bitintegers,otherdatastructures,includingother hashmapsHashmap(256,X)inparticular.Thiswouldmeanthatacellof TVM(p ersistentortemp orary)storageoravariableoranelementofan arrayinaTVMsmart-contractco demaycontainnotonlyaninteger,but awholenewhashmap.Ofcourse,thiswouldmeanthatacellcontainsnot just256bits,butalso,say,an8-bittag,describinghowthese256bitsshould b einterpreted. Infact,valuesdonotneedtob eprecisely256-bit.Thevalueformat usedbyTVMconsistsofasequenceofrawbytesandreferencestoother structures,mixedinarbitraryorder,withsomedescriptorbytesinserted insuitablelo cationstob eabletodistinguishp ointersfromrawdata(e.g., stringsorintegers);cf.2.3.14. Thisrawvalueformatmayb eusedtoimplementarbitrarysum-pro duct algebraictyp es.Inthiscase,thevaluewouldcontainarawbyterst,de- scribingtheconstructorb eingused(fromthep ersp ectiveofahigh-level 24 2.3.BlockchainState,AccountsandHashmaps language),andthenothereldsorconstructorarguments,consistingof rawbytesandreferencestootherstructuresdep endingontheconstructor chosen(cf.2.2.5).However,TVMdo esnotknowanythingab outthecorre- sp ondenceb etweenconstructorsandtheirarguments;themixtureofbytes andreferencesisexplicitlydescrib edbycertaindescriptorbytes. 8 TheMerkletreehashingisextendedtoarbitrarysuchstructures:to computethehashofsuchastructure,allreferencesarerecursivelyreplaced byhashesofob jectsreferredto,andthenthehashoftheresultingbytestring (descriptorbytesincluded)iscomputed. Inthisway,theMerkletreehashingforhashmaps,describ edin2.3.8,is justasp ecialcaseofhashingforarbitrary(dep endent)algebraicdatatyp es, appliedtotyp eHashmap(n,X)withtwoconstructors. 9 2.3.13.PersistentstorageofTONsmartcontracts.Persistentstorage ofaTONsmartcontractessentiallyconsistsofitsglobalvariables,pre- servedb etweencallstothesmartcontract.Assuch,itisjustapro duct, tuple,orrecordtyp e,consistingofeldsofthecorrecttyp es,corresp ond- ingtooneglobalvariableeach.Ifthereareto omanyglobalvariables,they cannottintooneTONcellb ecauseoftheglobalrestrictiononTONcell size.Insuchacase,theyaresplitintoseveralrecordsandorganizedintoa tree,essentiallyb ecomingapro ductofpro ductsorpro ductofpro ductsof pro ductstyp einsteadofjustapro ducttyp e. 2.3.14.TVMCells.Ultimately,theTONVMkeepsalldatainacollection of(TVM)cel ls.Eachcellcontainstwodescriptorbytesrst,indicatinghow manybytesofrawdataarepresentinthiscell(upto128)andhowmany referencestoothercellsarepresent(uptofour).Thentheserawdatabytes andreferencesfollow.Eachcellisreferencedexactlyonce,sowemighthave includedineachcellareferencetoitsparent(theonlycellreferencingthis one).However,thisreferenceneednotb eexplicit. Inthisway,thep ersistentdatastoragecellsofaTONsmartcontract areorganizedintoatree, 10 withareferencetothero otofthistreekeptin 8 Thesetwodescriptorbytes,presentinanyTVMcell,describ eonlythetotalnumb er ofreferencesandthetotalnumb erofrawbytes;referencesarekepttogethereitherb efore orafterallrawbytes. 9 Actually,LeafandNodeareconstructorsofanauxiliarytyp e,HashmapAux(n, X). Typ eHashmap(n, X)hasconstructorsRootandEmptyRoot,withRootcontaininga valueoftyp eHashmapAux(n, X). 10 Logically;thebagofcellsrepresentationdescrib edin2.5.5identiesallduplicate 25 2.3.BlockchainState,AccountsandHashmaps thesmart-contractdescription.Ifnecessary,aMerkletreehashofthisentire p ersistentstorageisrecursivelycomputed,startingfromtheleavesandthen simplyreplacingallreferencesinacellwiththerecursivelycomputedhashes ofthereferencedcells,andsubsequentlycomputingthehashofthebyte stringthusobtained. 2.3.15.GeneralizedMerklepro ofsforvaluesofarbitraryalgebraic typ es.BecausetheTONVMrepresentsavalueofarbitraryalgebraictyp e bymeansofatreeconsistingof(TVM)cells,andeachcellhasawell-dened (recursivelycomputed)Merklehash,dep endinginfactonthewholesubtree ro otedinthiscell,wecanprovidegeneralizedMerklepro ofsfor(partsof ) valuesofarbitraryalgebraictyp es,intendedtoprovethatacertainsubtree ofatreewithaknownMerklehashtakesasp ecicvalueoravaluewitha sp ecichash.Thisgeneralizestheapproachof2.3.10,whereonlyMerkle pro ofsforx\[i\] =yhaveb eenconsidered. 2.3.16.Supp ortforshardinginTONVMdatastructures.Wehave justoutlinedhowtheTONVM,withoutb eingoverlycomplicated,sup- p ortsarbitrary(dep endent)algebraicdatatyp esinhigh-levelsmart-contract languages.However,shardingoflarge(orglobal)smartcontractsrequires sp ecialsupp ortonthelevelofTONVM.Tothisend,asp ecialversion ofthehashmaptyp ehasb eenaddedtothesystem,amountingtoamap Account99KX.ThismapmightseemequivalenttoHashmap(m,X),where Account=2 m .However,whenashardissplitintwo,ortwoshardsare merged,suchhashmapsareautomaticallysplitintwo,ormergedback,soas tokeeponlythosekeysthatb elongtothecorresp ondingshard. 2.3.17.Paymentforp ersistentstorage.Anoteworthyfeatureofthe TONBlo ckchainisthepaymentexactedfromsmartcontractsforstoring theirp ersistentdata(i.e.,forenlargingthetotalstateoftheblo ckchain).It worksasfollows: Eachblo ckdeclarestworates,nominatedintheprincipalcurrencyof theblo ckchain(usuallytheTONcoin):thepriceforkeepingonecellinthe p ersistentstorage,andthepriceforkeepingonerawbyteinsomecellofthe p ersistentstorage.Statisticsonthetotalnumb ersofcellsandbytesusedby eachaccountarestoredaspartofitsstate,sobymultiplyingthesenumb ers bythetworatesdeclaredintheblo ckheader,wecancomputethepayment cells,transformingthistreeintoadirectedacyclicgraph(dag)whenserialized. 26 2.3.BlockchainState,AccountsandHashmaps tob edeductedfromtheaccountbalanceforkeepingitsdatab etweenthe previousblo ckandthecurrentone. However,paymentforp ersistentstorageusageisnotexactedforevery accountandsmartcontractineachblo ck;instead,thesequencenumb erof theblo ckwherethispaymentwaslastexactedisstoredintheaccountdata, andwhenanyactionisdonewiththeaccount(e.g.,avaluetransferora messageisreceivedandpro cessedbyasmartcontract),thestorageusage paymentforallblo ckssincetheprevioussuchpaymentisdeductedfrom theaccountbalanceb eforep erforminganyfurtheractions.Iftheaccount's balancewouldb ecomenegativeafterthis,theaccountisdestroyed. Aworkchainmaydeclaresomenumb erofrawdatabytesp eraccount tob efree(i.e.,notparticipatinginthep ersistentstoragepayments)in ordertomakesimpleaccounts,whichkeeponlytheirbalanceinoneortwo crypto currencies,exemptfromtheseconstantpayments. Noticethat,ifnob o dysendsanymessagestoanaccount,itsp ersistent storagepaymentsarenotcollected,anditcanexistindenitely.However, anyb o dycansend,forinstance,anemptymessagetodestroysuchanaccount. Asmallincentive,collectedfrompartoftheoriginalbalanceoftheaccount tob edestroyed,canb egiventothesenderofsuchamessage.Weexp ect, however,thatthevalidatorswoulddestroysuchinsolventaccountsforfree, simplytodecreasetheglobalblo ckchainstatesizeandtoavoidkeepinglarge amountsofdatawithoutcomp ensation. Paymentscollectedforkeepingp ersistentdataaredistributedamongthe validatorsoftheshardchainorthemasterchain(prop ortionallytotheirstakes inthelattercase). 2.3.18.Lo calandglobalsmartcontracts;smart-contractinstances. Asmartcontractnormallyresidesjustinoneshard,selectedaccordingtothe smartcontract'saccount\_id,similarlytoanordinaryaccount.Thisisusu- allysucientformostapplications.However,somehigh-loadsmartcon- tractsmaywanttohaveaninstanceineachshardchainofsomeworkchain. Toachievethis,theymustpropagatetheircreatingtransactionintoallshard- chains,forinstance,bycommittingthistransactionintothero otshardchain (w,∅) 11 oftheworkchainwandpayingalargecommission. 12 11 Amoreexp ensivealternativeistopublishsuchaglobalsmartcontractinthemas- terchain. 12 Thisisasortofbroadcastfeatureforallshards,andassuch,itmustb equite exp ensive. 27 2.3.BlockchainState,AccountsandHashmaps Thisactioneectivelycreatesinstancesofthesmartcontractineach shard,withseparatebalances.Originally,thebalancetransferredinthe creatingtransactionisdistributedsimplybygivingtheinstanceinshard (w,s)the2 −|s| partofthetotalbalance.Whenashardsplitsintotwochild shards,balancesofallinstancesofglobalsmartcontractsaresplitinhalf; whentwoshardsmerge,balancesareaddedtogether. Insomecases,splitting/merginginstancesofglobalsmartcontractsmay involve(delayed)executionofsp ecialmetho dsofthesesmartcontracts.By default,thebalancesaresplitandmergedasdescrib edab ove,andsome sp ecialaccount-indexedhashmapsarealsoautomaticallysplitandmerged (cf.2.3.16). 2.3.19.Limitingsplittingofsmartcontracts.Aglobalsmartcontract maylimititssplittingdepthdup onitscreation,inordertomakep ersistent storageexp ensesmorepredictable.Thismeansthat,ifshardchain(w,s)with |s|≥dsplitsintwo,onlyoneoftwonewshardchainsinheritsaninstanceof thesmartcontract.Thisshardchainischosendeterministically:eachglobal smartcontracthassomeaccount\_id,whichisessentiallythehashofits creatingtransaction,anditsinstanceshavethesameaccount\_idwiththe rst≤dbitsreplacedbysuitablevaluesneededtofallintothecorrectshard. Thisaccount\_idselectswhichshardwillinheritthesmart-contractinstance aftersplitting. 2.3.20.Account/Smart-contractstate.Wecansummarizeallofthe ab ovetoconcludethatanaccountorsmart-contractstateconsistsofthe following: ˆAbalanceintheprincipalcurrencyoftheblo ckchain ˆAbalanceinothercurrenciesoftheblo ckchain ˆSmart-contractco de(oritshash) ˆSmart-contractp ersistentdata(oritsMerklehash) ˆStatisticsonthenumb erofp ersistentstoragecellsandrawbytesused ˆThelasttime(actually,themasterchainblo cknumb er)whenpayment forsmart-contractp ersistentstoragewascollected 28 2.4.MessagesBetweenShardchains ˆThepublickeyneededtotransfercurrencyandsendmessagesfromthis account(optional;bydefaultequaltoaccount\_iditself ).Insomecases, moresophisticatedsignaturecheckingco demayb elo catedhere,similar towhatisdoneforBitcointransactionoutputs;thentheaccount\_id willb eequaltothehashofthisco de. Wealsoneedtokeepsomewhere,eitherintheaccountstateorinsomeother account-indexedhashmap,thefollowingdata: ˆTheoutputmessagequeueoftheaccount(cf.2.4.17) ˆThecollectionof(hashesof )recentlydeliveredmessages(cf.2.4.23) Notallofthesearereallyrequiredforeveryaccount;forexample,smart- contractco deisneededonlyforsmartcontracts,butnotforsimpleac- counts.Furthermore,whileanyaccountmusthaveanon-zerobalanceinthe principalcurrency(e.g.,TONcoinsforthemasterchainandshardchainsof thebasicworkchain),itmayhavebalancesofzeroinothercurrencies.In ordertoavoidkeepingunuseddata,asum-pro ducttyp e(dep endingonthe workchain)isdened(duringtheworkchain'screation),whichusesdierent tagbytes(e.g.,TLconstructors;cf.2.2.5)todistinguishb etweendierent constructorsused.Ultimately,theaccountstateisitselfkeptasacollection ofcellsoftheTVMp ersistentstorage. 2.4MessagesBetweenShardchains Animp ortantcomp onentoftheTONBlo ckchainisthemessagingsystem b etweenblo ckchains.Theseblo ckchainsmayb eshardchainsofthesame workchain,orofdierentworkchains. 2.4.1.Messages,accountsandtransactions:abird'seyeviewofthe system.Messagesaresentfromoneaccounttoanother.Eachtransaction consistsofanaccountreceivingonemessage,changingitsstateaccordingto certainrules,andgeneratingseveral(mayb eoneorzero)newmessagesto otheraccounts.Eachmessageisgeneratedandreceived(delivered)exactly once. Thismeansthatmessagesplayafundamentalroleinthesystem,com- parabletothatofaccounts(smartcontracts).Fromthep ersp ectiveofthe InniteShardingParadigm(cf.2.1.2),eachaccountresidesinitsseparate account-chain,andtheonlywayitcanaectthestateofsomeotheraccount isbysendingamessage. 29 2.4.MessagesBetweenShardchains 2.4.2.Accountsaspro cessesoractors;Actormo del.Onemightthink ab outaccounts(andsmartcontracts)aspro cesses,oractors,thatare abletopro cessincomingmessages,changetheirinternalstateandgenerate someoutb oundmessagesasaresult.Thisiscloselyrelatedtotheso-called Actormodel,usedinlanguagessuchasErlang(however,actorsinErlangare usuallycalledpro cesses).Sincenewactors(i.e.,smartcontracts)arealso allowedtob ecreatedbyexistingactorsasaresultofpro cessinganinb ound message,thecorresp ondencewiththeActormo delisessentiallycomplete. 2.4.3.Messagerecipient.Anymessagehasitsrecipient,characterizedby thetargetworkchainidentierw(assumedbydefaulttob ethesameasthat oftheoriginatingshardchain),andtherecipientaccountaccount\_id.The exactformat(i.e.,numb erofbits)ofaccount\_iddep endsonw;however,the shardisalwaysdeterminedbyitsrst(mostsignicant)64bits. 2.4.4.Messagesender.Inmostcases,amessagehasasender,charac- terizedagainbya(w ′ ,account\_id ′ )pair.Ifpresent,itislo catedafterthe messagerecipientandmessagevalue.Sometimes,thesenderisunimp ortant oritissomeb o dyoutsidetheblo ckchain(i.e.,notasmartcontract),inwhich casethiseldisabsent. NoticethattheActormo deldo esnotrequirethemessagestohavean implicitsender.Instead,messagesmaycontainareferencetotheActorto whichananswertotherequestshouldb esent;usuallyitcoincideswiththe sender.However,itisusefultohaveanexplicitunforgeablesendereldina messageinacrypto currency(Byzantine)environment. 2.4.5.Messagevalue.Anotherimp ortantcharacteristicofamessageis itsattachedvalue,inoneorseveralcrypto currenciessupp ortedb othbythe sourceandbythetargetworkchain.Thevalueofthemessageisindicatedat itsveryb eginningimmediatelyafterthemessagerecipient;itisessentiallya listof(currency\_id,value)pairs. Noticethatsimplevaluetransfersb etweensimpleaccountsarejust empty(no-op)messageswithsomevalueattachedtothem.Ontheother hand,aslightlymorecomplicatedmessageb o dymightcontainasimpletext orbinarycomment(e.g.,ab outthepurp oseofthepayment). 2.4.6.Externalmessages,ormessagesfromnowhere.Somemes- sagesarriveintothesystemfromnowherethatis,theyarenotgenerated byanaccount(smartcontractornot)residingintheblo ckchain.Themost 30 2.4.MessagesBetweenShardchains typicalexampleariseswhenauserwantstotransfersomefundsfroman accountcontrolledbyhertosomeotheraccount.Inthiscase,theusersends amessagefromnowheretoherownaccount,requestingittogeneratea messagetothereceivingaccount,carryingthesp eciedvalue.Ifthismes- sageiscorrectlysigned,heraccountreceivesitandgeneratestherequired outb oundmessages. Infact,onemightconsiderasimpleaccountasasp ecialcaseofasmart contractwithpredenedco de.Thissmartcontractreceivesonlyonetyp eof message.Suchaninb oundmessagemustcontainalistofoutb oundmessages tob egeneratedasaresultofdelivering(pro cessing)theinb oundmessage, alongwithasignature.Thesmartcontractchecksthesignature,and,ifitis correct,generatestherequiredmessages. Ofcourse,thereisadierenceb etweenmessagesfromnowhereand normalmessages,b ecausethemessagesfromnowherecannotb earvalue, sotheycannotpayfortheirgas(i.e.,theirpro cessing)themselves.Instead, theyaretentativelyexecutedwithasmallgaslimitb eforeevenb eingsug- gestedforinclusioninanewshardchainblo ck;iftheexecutionfails(the signatureisincorrect),themessagefromnowhereisdeemedincorrectand isdiscarded.Iftheexecutiondo esnotfailwithinthesmallgaslimit,themes- sagemayb eincludedinanewshardchainblo ckandpro cessedcompletely, withthepaymentforthegas(pro cessingcapacity)consumedexactedfrom thereceiver'saccount.Messagesfromnowherecanalsodenesometrans- actionfeewhichisdeductedfromthereceiver'saccountontopofthegas paymentforredistributiontothevalidators. Inthissense,messagesfromnowhereorexternalmessagestakethe roleoftransactioncandidatesusedinotherblo ckchainsystems(e.g.,Bitcoin andEthereum). 2.4.7.Logmessages,ormessagestonowhere.Similarly,sometimesa sp ecialmessagecanb egeneratedandroutedtoasp ecicshardchainnotto b edeliveredtoitsrecipient,buttob eloggedinordertob eeasilyobservable byanyb o dyreceivingup datesab outtheshardinquestion.Theselogged messagesmayb eoutputinauser'sconsole,ortriggeranexecutionofsome scriptonano-chainserver.Inthissense,theyrepresenttheexternalout- putoftheblo ckchainsup ercomputer,justasthemessagesfromnowhere representtheexternalinputoftheblo ckchainsup ercomputer. 2.4.8.Interactionwitho-chainservicesandexternalblo ckchains. Theseexternalinputandoutputmessagescanb eusedforinteractingwith 31 2.4.MessagesBetweenShardchains o-chainservicesandother(external)blo ckchains,suchasBitcoinorEthe- reum.Onemightcreatetokensorcrypto currenciesinsidetheTONBlo ck- chainp eggedtoBitcoins,EthersoranyERC-20tokensdenedintheEthe- reumblo ckchain,andusemessagesfromnowhereandmessagestonowhere, generatedandpro cessedbyscriptsresidingonsomethird-partyo-chain servers,toimplementthenecessaryinteractionb etweentheTONBlo ckchain andtheseexternalblo ckchains. 2.4.9.Messageb o dy.Themessagebodyissimplyasequenceofbytes, themeaningofwhichisdeterminedonlybythereceivingworkchainand/or smartcontract.Forblo ckchainsusingTONVM,thiscouldb etheserial- izationofanyTVMcell,generatedautomaticallyviatheSend()op eration. Suchaserializationisobtainedsimplybyrecursivelyreplacingallreferences inaTONVMcellwiththecellsreferredto.Ultimately,astringofrawbytes app ears,whichisusuallyprep endedbya4-bytemessagetyp eormessage constructor,usedtoselectthecorrectmetho dofthereceivingsmartcon- tract. Anotheroptionwouldb etouseTL-serializedob jects(cf.2.2.5)asmes- sageb o dies.Thismightb eesp eciallyusefulforcommunicationb etween dierentworkchains,oneorb othofwhicharenotnecessarilyusingtheTON VM. 2.4.10.Gaslimitandotherworkchain/VM-sp ecicparameters. Sometimesamessageneedstocarryinformationab outthegaslimit,the gasprice,transactionfeesandsimilarvaluesthatdep endonthereceiving workchainandarerelevantonlyforthereceivingworkchain,butnotnecessar- ilyfortheoriginatingworkchain.Suchparametersareincludedinorb efore themessageb o dy,sometimes(dep endingontheworkchain)withsp ecial4- byteprexesindicatingtheirpresence(whichcanb edenedbyaTL-scheme; cf.2.2.5). 2.4.11.Creatingmessages:smartcontractsandtransactions.There aretwosourcesofnewmessages.Mostmessagesarecreatedduringsmart- contractexecution(viatheSend()op erationinTONVM),whensomesmart contractisinvokedtopro cessanincomingmessage.Alternatively,mes- sagesmaycomefromtheoutsideasexternalmessagesormessagesfrom nowhere(cf.2.4.6). 13 13 Theab oveneedstob eliterallytrueonlyforthebasicworkchainanditsshardchains; otherworkchainsmayprovideotherwaysofcreatingmessages. 32 2.4.MessagesBetweenShardchains 2.4.12.Deliveringmessages.Whenamessagereachestheshardchaincon- tainingitsdestinationaccount, 14 itisdeliveredtoitsdestinationaccount. Whathapp ensnextdep endsontheworkchain;fromanoutsidep ersp ective, itisimp ortantthatsuchamessagecanneverb eforwardedfurtherfromthis shardchain. Forshardchainsofthebasicworkchain,deliveryconsistsinaddingthe messagevalue(minusanygaspayments)tothebalanceofthereceivingac- count,andp ossiblyininvokingamessage-dep endentmetho dofthereceiving smartcontractafterwards,ifthereceivingaccountisasmartcontract.In fact,asmartcontracthasonlyoneentryp ointforpro cessingallincoming messages,anditmustdistinguishb etweendierenttyp esofmessagesby lo okingattheirrstfewbytes(e.g.,therstfourbytescontainingaTL constructor;cf.2.2.5). 2.4.13.Deliveryofamessageisatransaction.Becausethedeliveryof amessagechangesthestateofanaccountorsmartcontract,itisasp ecial transactioninthereceivingshardchain,andisexplicitlyregisteredassuch. Essentially,al lTONBlo ckchaintransactionsconsistinthedeliveryofone inb oundmessagetoitsreceivingaccount(smartcontract),neglectingsome minortechnicaldetails. 2.4.14.Messagesb etweeninstancesofthesamesmartcontract. Recallthatasmartcontractmayb elocal(i.e.,residinginoneshardchainas anyordinaryaccountdo es)orglobal(i.e.,havinginstancesinallshards,or atleastinallshardsuptosomeknowndepthd;cf.2.3.18).Instancesofa globalsmartcontractmayexchangesp ecialmessagestotransferinformation andvalueb etweeneachotherifrequired.Inthiscase,the(unforgeable) senderaccount\_idb ecomesimp ortant(cf.2.4.4). 2.4.15.Messagestoanyinstanceofasmartcontract;wildcardad- dresses.Sometimesamessage(e.g.,aclientrequest)needsb edeliveredto anyinstanceofaglobalsmartcontract,usuallytheclosestone(ifthereisone residinginthesameshardchainasthesender,itistheobviouscandidate). Onewayofdoingthisisbyusingawildcardrecipientaddress,withthe rstdbitsofthedestinationaccount\_idallowedtotakearbitraryvalues.In practice,onewillusuallysetthesedbitstothesamevaluesasinthesender's account\_id. 14 Asadegeneratecase,thisshardchainmaycoincidewiththeoriginatingshardchain forexample,ifweareworkinginsideaworkchainwhichhasnotyetb eensplit. 33 2.4.MessagesBetweenShardchains 2.4.16.Inputqueueisabsent.Allmessagesreceivedbyablo ckchain (usuallyashardchain;sometimesthemasterchain)or,essentially,byan account-chainresidinginsidesomeshardchainareimmediatelydelivered (i.e.,pro cessedbythereceivingaccount).Therefore,thereisnoinputqueue assuch.Instead,ifnotallmessagesdestinedforasp ecicshardchaincan b epro cessedb ecauseoflimitationsonthetotalsizeofblo cksandgasusage, somemessagesaresimplylefttoaccumulateintheoutputqueuesofthe originatingshardchains. 2.4.17.Outputqueues.Fromthep ersp ectiveoftheInniteSharding Paradigm(cf.2.1.2),eachaccount-chain(i.e.,eachaccount)hasitsownout- putqueue,consistingofallmessagesithasgenerated,butnotyetdelivered totheirrecipients.Ofcourse,account-chainshaveonlyavirtualexistence; theyaregroup edintoshardchains,andashardchainhasanoutputqueue, consistingoftheunionoftheoutputqueuesofallaccountsb elongingtothe shardchain. Thisshardchainoutputqueueimp osesonlypartialorderonitsmemb er messages.Namely,amessagegeneratedinaprecedingblo ckmustb edeliv- eredb eforeanymessagegeneratedinasubsequentblo ck,andanymessages generatedbythesameaccountandhavingthesamedestinationmustb e deliveredintheorderoftheirgeneration. 2.4.18.Reliableandfastinter-chainmessaging.Itisofparamount imp ortanceforascalablemulti-blo ckchainpro jectsuchasTONtob eableto forwardanddelivermessagesb etweendierentshardchains(cf.2.1.3),even iftherearemillionsoftheminthesystem.Themessagesshouldb edelivered reliably(i.e.,messagesshouldnotb elostordeliveredmorethanonce)and quickly.TheTONBlo ckchainachievesthisgoalbyusingacombinationof twomessageroutingmechanisms. 2.4.19.Hyp ercub erouting:slowpathformessageswithassured delivery.TheTONBlo ckchainuseshyp ercub eroutingasaslow,but safeandreliablewayofdeliveringmessagesfromoneshardchaintoanother, usingseveralintermediateshardchainsfortransitifnecessary.Otherwise,the validatorsofanygivenshardchainwouldneedtokeeptrackofthestateof (theoutputqueuesof )allothershardchains,whichwouldrequireprohibitive amountsofcomputingp owerandnetworkbandwidthasthetotalquantity ofshardchainsgrows,thuslimitingthescalabilityofthesystem.Therefore, itisnotp ossibletodelivermessagesdirectlyfromanyshardtoeveryother. 34 2.4.MessagesBetweenShardchains Instead,eachshardisconnectedonlytoshardsdieringinexactlyone hexadecimaldigitoftheir(w,s)shardidentiers(cf.2.1.8).Inthisway,all shardchainsconstituteahyp ercub egraph,andmessagestravelalongthe edgesofthishyp ercub e. Ifamessageissenttoasharddierentfromthecurrentone,oneofthe hexadecimaldigits(chosendeterministically)ofthecurrentshardidentier isreplacedbythecorresp ondingdigitofthetargetshard,andtheresulting identierisusedastheproximatetargettoforwardthemessageto. 15 Themainadvantageofhyp ercub eroutingisthattheblo ckvaliditycon- ditionsimplythatvalidatorscreatingblo cksofashardchainmustcollectand pro cessmessagesfromtheoutputqueuesofneighb oringshardchains,on painoflosingtheirstakes.Inthisway,anymessagecanb eexp ectedtoreach itsnaldestinationso onerorlater;amessagecannotb elostintransitor deliveredtwice. Noticethathyp ercub eroutingintro ducessomeadditionaldelaysandex- p enses,b ecauseofthenecessitytoforwardmessagesthroughseveralinterme- diateshardchains.However,thenumb eroftheseintermediateshardchains growsveryslowly,asthelogarithmlogN(moreprecisely,dlog 16 Ne−1)of thetotalnumb erofshardchainsN.Forexample,ifN≈250,therewill b eatmostoneintermediatehop;andforN≈4000shardchains,atmost two.Withfourintermediatehops,wecansupp ortuptoonemillionshard- chains.Wethinkthisisaverysmallpricetopayfortheessentiallyunlimited scalabilityofthesystem.Infact,itisnotnecessarytopayeventhisprice: 2.4.20.InstantHyp ercub eRouting:fastpathformessages.A novelfeatureoftheTONBlo ckchainisthatitintro ducesafastpathfor forwardingmessagesfromoneshardchaintoanyother,allowinginmostcases tobypasstheslowhyp ercub eroutingof2.4.19altogetheranddeliverthe messageintotheverynextblo ckofthenaldestinationshardchain. Theideaisasfollows.Duringtheslowhyp ercub erouting,themessage travels(inthenetwork)alongtheedgesofthehyp ercub e,butitisdelayed (forapproximatelyveseconds)ateachintermediatevertextob ecommitted intothecorresp ondingshardchainb eforecontinuingitsvoyage. Toavoidunnecessarydelays,onemightinsteadrelaythemessagealong withasuitableMerklepro ofalongtheedgesofthehyp ercub e,withoutwait- 15 Thisisnotnecessarilythenalversionofthealgorithmusedtocomputethenexthop forhyp ercub erouting.Inparticular,hexadecimaldigitsmayb ereplacedbyr-bitgroups, withracongurableparameter,notnecessarilyequaltofour. 35 2.4.MessagesBetweenShardchains ingtocommititintotheintermediateshardchains.Infact,thenetworkmes- sageshouldb eforwardedfromthevalidatorsofthetaskgroup(cf.2.6.8) oftheoriginalshardtothedesignatedblo ckpro ducer(cf.2.6.9)ofthetask groupofthedestinationshard;thismightb edonedirectlywithoutgoing alongtheedgesofthehyp ercub e.WhenthismessagewiththeMerklepro of reachesthevalidators(moreprecisely,thecollators;cf.2.6.5)ofthedestina- tionshardchain,theycancommititintoanewblo ckimmediately,without waitingforthemessagetocompleteitstravelalongtheslowpath.Thena conrmationofdeliveryalongwithasuitableMerklepro ofissentbackalong thehyp ercub eedges,anditmayb eusedtostopthetravelofthemessage alongtheslowpath,bycommittingasp ecialtransaction. Notethatthisinstantdeliverymechanismdo esnotreplacetheslow butfailpro ofmechanismdescrib edin2.4.19.Theslowpathisstillneeded b ecausethevalidatorscannotb epunishedforlosingorsimplydecidingnot tocommitthefastpathmessagesintonewblo cksoftheirblo ckchains. 16 Therefore,b othmessageforwardingmetho dsareruninparallel,andthe slowmechanismisab ortedonlyifapro ofofsuccessofthefastmechanism iscommittedintoanintermediateshardchain. 17 2.4.21.Collectinginputmessagesfromoutputqueuesofneighb or- ingshardchains.Whenanewblo ckforashardchainisprop osed,some oftheoutputmessagesoftheneighb oring(inthesenseoftheroutinghy- p ercub eof2.4.19)shardchainsareincludedinthenewblo ckasinput messagesandimmediatelydelivered(i.e.,pro cessed).Therearecertainrules astotheorderinwhichtheseneighb ors'outputmessagesmustb epro cessed. Essentially,anoldermessage(comingfromashardchainblo ckreferringto anoldermasterchainblo ck)mustb edeliveredb eforeanynewermessage; andformessagescomingfromthesameneighb oringshardchain,thepartial orderoftheoutputqueuedescrib edin2.4.17mustb eobserved. 2.4.22.Deletingmessagesfromoutputqueues.Onceanoutputqueue messageisobservedashavingb eendeliveredbyaneighb oringshardchain, itisexplicitlydeletedfromtheoutputqueuebyasp ecialtransaction. 16 However,thevalidatorshavesomeincentivetodosoasso onasp ossible,b ecausethey willb eabletocollectallforwardingfeesasso ciatedwiththemessagethathavenotyet b eenconsumedalongtheslowpath. 17 Infact,onemighttemp orarilyorp ermanentlydisabletheinstantdeliverymecha- nismaltogether,andthesystemwouldcontinueworking,alb eitmoreslowly. 36 2.4.MessagesBetweenShardchains 2.4.23.Preventingdoubledeliveryofmessages.Topreventdouble deliveryofmessagestakenfromtheoutputqueuesoftheneighb oringshard- chains,eachshardchain(moreprecisely,eachaccount-chaininsideit)keeps thecollectionofrecentlydeliveredmessages(orjusttheirhashes)aspartof itsstate.Whenadeliveredmessageisobservedtob edeletedfromtheout- putqueuebyitsoriginatingneighb oringshardchain(cf.2.4.22),itisdeleted fromthecollectionofrecentlydeliveredmessagesaswell. 2.4.24.Forwardingmessagesintendedforothershardchains.Hy- p ercub erouting(cf.2.4.19)meansthatsometimesoutb oundmessagesare deliverednottotheshardchaincontainingtheintendedrecipient,buttoa neighb oringshardchainlyingonthehyp ercub epathtothedestination.In thiscase,deliveryconsistsinmovingtheinb oundmessagetotheoutb ound queue.Thisisreectedexplicitlyintheblo ckasasp ecialforwardingtrans- action,containingthemessageitself.Essentially,thislo oksasifthemessage hadb eenreceivedbysomeb o dyinsidetheshardchain,andoneidenticalmes- sagehadb eengeneratedasresult. 2.4.25.Paymentforforwardingandkeepingamessage.Thefor- wardingtransactionactuallysp endssomegas(dep endingonthesizeofthe messageb eingforwarded),soagaspaymentisdeductedfromthevalueof themessageb eingforwardedonb ehalfofthevalidatorsofthisshardchain. Thisforwardingpaymentisnormallyconsiderablysmallerthanthegaspay- mentexactedwhenthemessageisnallydeliveredtoitsrecipient,evenif themessagehasb eenforwardedseveraltimesb ecauseofhyp ercub erouting. Furthermore,aslongasamessageiskeptintheoutputqueueofsomeshard- chain,itispartoftheshardchain'sglobalstate,soapaymentforkeeping globaldataforalongtimemayb ealsocollectedbysp ecialtransactions. 2.4.26.Messagestoandfromthemasterchain.Messagescanb esent directlyfromanyshardchaintothemasterchain,andviceversa.However, gaspricesforsendingmessagestoandforpro cessingmessagesinthemaster- chainarequitehigh,sothisabilitywillb eusedonlywhentrulynecessary forexample,bythevalidatorstodep osittheirstakes.Insomecases,a minimaldep osit(attachedvalue)formessagessenttothemasterchainmay b edened,whichisreturnedonlyifthemessageisdeemedvalidbythe receivingparty. Messagescannotb eautomaticallyroutedthroughthemasterchain.A messagewithworkchain\_id6=−1(−1b eingthesp ecialworkchain\_idindi- 37 2.5.GlobalShardchainState.BagofCellsPhilosophy. catingthemasterchain)cannotb edeliveredtothemasterchain. Inprinciple,onecancreateamessage-forwardingsmartcontractinside themasterchain,butthepriceofusingitwouldb eprohibitive. 2.4.27.Messagesb etweenaccountsinthesameshardchain.Insome cases,amessageisgeneratedbyanaccountb elongingtosomeshardchain, destinedtoanotheraccountinthesameshardchain.Forexample,thishap- p ensinanewworkchainwhichhasnotyetsplitintoseveralshardchains b ecausetheloadismanageable. Suchmessagesmightb eaccumulatedintheoutputqueueoftheshard- chainandthenpro cessedasincomingmessagesinsubsequentblo cks(any shardisconsideredaneighb orofitselfforthispurp ose).However,inmost casesitisp ossibletodeliverthesemessageswithintheoriginatingblo ck itself. Inordertoachievethis,apartialorderisimp osedonalltransactions includedinashardchainblo ck,andthetransactions(eachconsistinginthe deliveryofamessagetosomeaccount)arepro cessedresp ectingthispartial order.Inparticular,atransactionisallowedtopro cesssomeoutputmessage ofaprecedingtransactionwithresp ecttothispartialorder. Inthiscase,themessageb o dyisnotcopiedtwice.Instead,theoriginating andthepro cessingtransactionsrefertoasharedcopyofthemessage. 2.5Global Shardchain State.Bag of CellsPhilosophy. Nowwearereadytodescrib etheglobalstateofaTONblo ckchain,orat leastofashardchainofthebasicworkchain. Westartwithahigh-levelorlogicaldescription,whichconsistsin sayingthattheglobalstateisavalueofalgebraictyp eShardchainState. 2.5.1.Shardchainstateasacollectionofaccount-chainstates.Ac- cordingtotheInniteShardingParadigm(cf.2.1.2),anyshardchainisjust a(temp orary)collectionofvirtualaccount-chains,containingexactlyone accounteach.Thismeansthat,essentially,theglobalshardchainstatemust b eahashmap ShardchainState:= (Account99KAccountState)(23) whereallaccount\_idapp earingasindicesofthishashmapmustb eginwith prexs,ifwearediscussingthestateofshard(w,s)(cf.2.1.8). 38 2.5.GlobalShardchainState.BagofCellsPhilosophy. Inpractice,wemightwanttosplitAccountStateintoseveralparts(e.g., keeptheaccountoutputmessagequeueseparatetosimplifyitsexamination bytheneighb oringshardchains),andhaveseveralhashmaps(Account99K AccountStatePart i )insidetheShardchainState.Wemightalsoaddasmall numb erofglobalorintegralparameterstotheShardchainState,(e.g.,the totalbalanceofallaccountsb elongingtothisshard,orthetotalnumb erof messagesinalloutputqueues). However,(23)isago o drstapproximationofwhattheshardchainglobal statelo okslike,atleastfromalogical(high-level)p ersp ective.Theformal descriptionofalgebraictyp esAccountStateandShardchainStatecanb edone withtheaidofaTL-scheme(cf.2.2.5),tob eprovidedelsewhere. 2.5.2.Splittingandmergingshardchainstates.NoticethattheInnite ShardingParadigmdescriptionoftheshardchainstate(23)showshowthis stateshouldb epro cessedwhenshardsaresplitormerged.Infact,these statetransformationsturnouttob everysimpleop erationswithhashmaps. 2.5.3.Account-chainstate.The(virtual)account-chainstateisjustthe stateofoneaccount,describ edbytyp eAccountState.Usuallyithasallor someoftheeldslistedin2.3.20,dep endingonthesp ecicconstructorused. 2.5.4.Globalworkchainstate.Similarlyto(23),wemaydenetheglobal workchainstatebythesameformula,butwithaccount\_id'sallowedtotake anyvalues,notjustthoseb elongingtooneshard.Remarkssimilartothose madein2.5.1applyinthiscaseaswell:wemightwanttosplitthishashmap intoseveralhashmaps,andwemightwanttoaddsomeintegralparameters suchasthetotalbalance. Essentially,theglobalworkchainstatemustb egivenbythesametyp e ShardchainStateastheshardchainstate,b ecauseitistheshardchainstate wewouldobtainifallexistingshardchainsofthisworkchainsuddenlymerged intoone. 2.5.5.Low-levelp ersp ective:bagofcells.Thereisalow-levelde- scriptionoftheaccount-chainorshardchainstateaswell,complementary tothehigh-leveldescriptiongivenab ove.Thisdescriptionisquiteimp or- tant,b ecauseitturnsouttob eprettyuniversal,providingacommonbasis forrepresenting,storing,serializingandtransferringbynetworkalmostall datausedbytheTONBlo ckchain(blo cks,shardchainstates,smart-contract storage,Merklepro ofs,etc.).Atthesametime,suchauniversallow-level 39 2.5.GlobalShardchainState.BagofCellsPhilosophy. description,onceundersto o dandimplemented,allowsustoconcentrateour attentiononthehigh-levelconsiderationsonly. RecallthattheTVMrepresentsvaluesofarbitraryalgebraictyp es(in- cluding,forinstance,ShardchainStateof(23))bymeansofatreeofTVM cel ls,orcel lsforshort(cf.2.3.14and2.2.5). Anysuchcellconsistsoftwodescriptorbytes,deningcertainagsand values0≤b≤128,thequantityofrawbytes,and0≤c≤4,thequantity ofreferencestoothercells.Thenbrawbytesandccellreferencesfollow. 18 Theexactformatofcellreferencesdep endsontheimplementationandon whetherthecellislo catedinRAM,ondisk,inanetworkpacket,inablo ck, andsoon.Ausefulabstractmo delconsistsinimaginingthatallcellsare keptincontent-addressablememory,withtheaddressofacellequaltoits (sha256)hash.Recallthatthe(Merkle)hashofacelliscomputedexactly byreplacingthereferencestoitschildcellsbytheir(recursivelycomputed) hashesandhashingtheresultingbytestring. Inthisway,ifweusecellhashestoreferencecells(e.g.,insidedescriptions ofothercells),thesystemsimpliessomewhat,andthehashofacellstarts tocoincidewiththehashofthebytestringrepresentingit. NowweseethatanyobjectrepresentablebyTVM,theglobalshardchain stateincluded,canberepresentedasabagofcel lsi.e.,acol lectionofcel ls alongwitharootreferencetooneofthem(e.g.,byhash).Noticethat duplicatecellsareremovedfromthisdescription(thebagofcellsisaset ofcells,notamultisetofcells),sotheabstracttreerepresentationmight actuallyb ecomeadirectedacyclicgraph(dag)representation. OnemightevenkeepthisstateondiskinaB-orB+-tree,containingall cellsinquestion(mayb ewithsomeadditionaldata,suchassubtreeheightor referencecounter),indexedbycellhash.However,anaiveimplementation ofthisideawouldresultinthestateofonesmartcontractb eingscattered amongdistantpartsofthediskle,somethingwewouldratheravoid. 19 18 Onecanshowthat,ifMerklepro ofsforalldatastoredinatreeofcellsareneeded equallyoften,oneshouldusecellswithb+ch≈2(h+r)tominimizeaverageMerklepro of size,whereh= 32isthehashsizeinbytes,andr≈4isthebytesizeofacellreference. Inotherwords,acellshouldcontaineithertworeferencesandafewrawbytes,orone referenceandab out36rawbytes,ornoreferencesatallwith72rawbytes. 19 Ab etterimplementationwouldb etokeepthestateofthesmartcontractasaserialized string,ifitissmall,orinaseparateB-tree,ifitislarge;thenthetop-levelstructure representingthestateofablo ckchainwouldb eaB-tree,whoseleavesareallowedto containreferencestootherB-trees. 40 2.5.GlobalShardchainState.BagofCellsPhilosophy. Nowwearegoingtoexplaininsomedetailhowalmostallob jectsusedby theTONBlo ckchaincanb erepresentedasbagsofcells,thusdemonstrating theuniversalityofthisapproach. 2.5.6.Shardchainblo ckasabagofcells.Ashardchainblo ckitself canb ealsodescrib edbyanalgebraictyp e,andstoredasabagofcells. Thenanaivebinaryrepresentationoftheblo ckmayb eobtainedsimplyby concatenatingthebytestringsrepresentingeachofthecellsinthebagof cells,inarbitraryorder.Thisrepresentationmightb eimprovedandopti- mized,forinstance,byprovidingalistofosetsofallcellsattheb eginning oftheblo ck,andreplacinghashreferencestoothercellswith32-bitindices inthislistwheneverp ossible.However,oneshouldimaginethatablo ck isessentiallyabagofcells,andallothertechnicaldetailsarejustminor optimizationandimplementationissues. 2.5.7.Up datetoanob jectasabagofcells.Imaginethatwehavean oldversionofsomeob jectrepresentedasabagofcells,andthatwewant torepresentanewversionofthesameob ject,supp osedlynotto odierent fromthepreviousone.Onemightsimplyrepresentthenewstateasanother bagofcellswithitsownro ot,andremovefromital lcel lsoccurringin theoldversion.Theremainingbagofcellsisessentiallyanupdatetothe ob ject.Everyb o dywhohastheoldversionofthisob jectandtheup date cancomputethenewversion,simplybyunitingthetwobagsofcells,and removingtheoldro ot(decreasingitsreferencecounterandde-allo catingthe cellifthereferencecounterb ecomeszero). 2.5.8.Up datestothestateofanaccount.Inparticular,up datestothe stateofanaccount,ortotheglobalstateofashardchain,ortoanyhashmap canb erepresentedusingtheideadescrib edin2.5.7.Thismeansthatwhen wereceiveanewshardchainblo ck(whichisabagofcells),weinterpret thisbagofcellsnotjustbyitself,butbyunitingitrstwiththebagof cellsrepresentingthepreviousstateoftheshardchain.Inthissenseeach blo ckmaycontainthewholestateoftheblo ckchain. 2.5.9.Up datestoablo ck.Recallthatablo ckitselfisabagofcells, so,ifitb ecomesnecessarytoeditablo ck,onecansimilarlydeneablo ck up dateasabagofcells,interpretedinthepresenceofthebagofcells whichisthepreviousversionofthisblo ck.Thisisroughlytheideab ehind theverticalblo cksdiscussedin2.1.17. 41 2.5.GlobalShardchainState.BagofCellsPhilosophy. 2.5.10.Merklepro ofasabagofcells.Noticethata(generalized) Merklepro offorexample,oneassertingthatx\[i\] =ystartingfromaknown valueofHash(x) =h(cf.2.3.10and2.3.15)mayalsob erepresented asabagofcells.Namely,onesimplyneedstoprovideasubsetofcells corresp ondingtoapathfromthero otofx:Hashmap(n,X)toitsdesired leafwithindexi:2 n andvaluey:X.Referencestochildrenofthesecellsnot lyingonthispathwillb eleftunresolvedinthispro of,representedbycell hashes.OnecanalsoprovideasimultaneousMerklepro ofof,say,x\[i\] =y andx\[i ′ \] =y ′ ,byincludinginthebagofcellsthecellslyingontheunionof thetwopathsfromthero otofxtoleavescorresp ondingtoindicesiandi ′ . 2.5.11.Merklepro ofsasqueryresp onsesfromfullno des.Inessence, afullno dewithacompletecopyofashardchain(oraccount-chain)state canprovideaMerklepro ofwhenrequestedbyalightno de(e.g.,anetwork no derunningalightversionoftheTONBlo ckchainclient),enablingthe receivertop erformsomesimplequerieswithoutexternalhelp,usingonly thecellsprovidedinthisMerklepro of.Thelightno decansenditsqueries inaserializedformattothefullno de,andreceivethecorrectanswerswith Merklepro ofsorjusttheMerklepro ofs,b ecausetherequestershouldb e abletocomputetheanswersusingonlythecellsincludedintheMerklepro of. ThisMerklepro ofwouldconsistsimplyofabagofcells,containingonly thosecellsb elongingtotheshardchain'sstatethathaveb eenaccessedby thefullno dewhileexecutingthelightno de'squery.Thisapproachcanb e usedinparticularforexecutinggetqueriesofsmartcontracts(cf.4.3.12). 2.5.12.Augmentedup date,orstateup datewithMerklepro ofof validity.Recall(cf.2.5.7)thatwecandescrib ethechangesinanob ject statefromanoldvaluex:Xtoanewvaluex ′ :Xbymeansofanup date, whichissimplyabagofcells,containingthosecellsthatlieinthesubtree representingnewvaluex ′ ,butnotinthesubtreerepresentingoldvaluex, b ecausethereceiverisassumedtohaveacopyoftheoldvaluexandallits cells. However,ifthereceiverdo esnothaveafullcopyofx,butknowsonly its(Merkle)hashh=Hash(x),itwillnotb eabletocheckthevalidityof theup date(i.e.,thatalldanglingcellreferencesintheup datedoreferto cellspresentinthetreeofx).Onewouldliketohaveveriableup dates, augmentedbyMerklepro ofsofexistenceofallreferredcellsintheoldstate. Thenanyb o dyknowingonlyh=Hash(x)wouldb eabletocheckthevalidity oftheup dateandcomputethenewh ′ =Hash(x ′ )byitself. 42 2.5.GlobalShardchainState.BagofCellsPhilosophy. BecauseourMerklepro ofsarebagsofcellsthemselves(cf.2.5.10),one canconstructsuchanaugmentedupdateasabagofcells,containingthe oldro otofx,someofitsdescendantsalongwithpathsfromthero otofxto them,andthenewro otofx ′ andallitsdescendantsthatarenotpartofx. 2.5.13.Accountstateup datesinashardchainblo ck.Inparticular, accountstateup datesinashardchainblo ckshouldb eaugmentedasdis- cussedin2.5.12.Otherwise,someb o dymightcommitablo ckcontaining aninvalidstateup date,referringtoacellabsentintheoldstate;proving theinvalidityofsuchablo ckwouldb eproblematic(howisthechallengerto provethatacellisnotpartofthepreviousstate?). Now,ifallstateup datesincludedinablo ckareaugmented,theirvalidity iseasilychecked,andtheirinvalidityisalsoeasilyshownasaviolationof therecursivedeningprop ertyof(generalized)Merklehashes. 2.5.14.Everythingisabagofcellsphilosophy.Previousconsidera- tionsshowthateverythingweneedtostoreortransfer,eitherintheTON Blo ckchainorinthenetwork,isrepresentableasabagofcells.Thisis animp ortantpartoftheTONBlo ckchaindesignphilosophy.Oncethebag ofcellsapproachisexplainedandsomelow-levelserializationsofbagsof cellsaredened,onecansimplydeneeverything(blo ckformat,shardchain andaccountstate,etc.)onthehighlevelofabstract(dep endent)algebraic datatyp es. Theunifyingeectoftheeverythingisabagofcellsphilosophyconsid- erablysimpliestheimplementationofseeminglyunrelatedservices;cf.5.1.9 foranexampleinvolvingpaymentchannels. 2.5.15.Blo ckheadersforTONblo ckchains.Usually,ablo ckina blo ckchainb eginswithasmallheader,containingthehashoftheprevious blo ck,itscreationtime,theMerklehashofthetreeofalltransactionscon- tainedintheblo ck,andsoon.Thentheblo ckhashisdenedtob ethehash ofthissmallblo ckheader.Becausetheblo ckheaderultimatelydep endson alldataincludedintheblo ck,onecannotaltertheblo ckwithoutchanging itshash. Inthebagofcellsapproachusedbytheblo cksofTONblo ckchains, thereisnodesignatedblo ckheader.Instead,theblo ckhashisdenedasthe (Merkle)hashofthero otcelloftheblo ck.Therefore,thetop(ro ot)cellof theblo ckmightb econsideredasmallheaderofthisblo ck. 43 2.6.CreatingandValidatingNewBlocks However,thero otcellmightnotcontainallthedatausuallyexp ected fromsuchaheader.Essentially,onewantstheheadertocontainsomeofthe eldsdenedintheBlockdatatyp e.Normally,theseeldswillb econtained inseveralcells,includingthero ot.Thesearethecellsthattogetherconstitute aMerklepro of forthevaluesoftheeldsinquestion.Onemightinsist thatablo ckcontaintheseheadercellsintheveryb eginning,b eforeany othercells.Thenonewouldneedtodownloadonlytherstseveralbytesof ablo ckserializationinordertoobtainalloftheheadercells,andtolearn alloftheexp ectedelds. 2.6CreatingandValidatingNewBlo cks TheTONBlo ckchainultimatelyconsistsofshardchainandmasterchain blo cks.Theseblo cksmustb ecreated,validatedandpropagatedthrough thenetworktoallpartiesconcerned,inorderforthesystemtofunction smo othlyandcorrectly. 2.6.1.Validators.Newblo cksarecreatedandvalidatedbysp ecialdesig- natedno des,calledvalidators.Essentially,anyno dewishingtob ecomea validatormayb ecomeone,provideditcandep ositasucientlylargestake (inTONcoins,i.e.,TONcoins;cf.App endixA)intothemasterchain.Val- idatorsobtainsomerewardsforgo o dwork,namely,thetransaction,storage andgasfeesfromalltransactions(messages)committedintonewlygener- atedblo cks,andsomenewlymintedcoins,reectingthegratitudeofthe wholecommunitytothevalidatorsforkeepingtheTONBlo ckchainworking. Thisincomeisdistributedamongallparticipatingvalidatorsprop ortionally totheirstakes. However,b eingavalidatorisahighresp onsibility.Ifavalidatorsigns aninvalidblo ck,itcanb epunishedbylosingpartorallofitsstake,and byb eingtemp orarilyorp ermanentlyexcludedfromthesetofvalidators.If avalidatordo esnotparticipateincreatingablo ck,itdo esnotreceiveits shareoftherewardasso ciatedwiththatblo ck.Ifavalidatorabstainsfrom creatingnewblo cksforalongtime,itmaylosepartofitsstakeandb e susp endedorp ermanentlyexcludedfromthesetofvalidators. Allthismeansthatthevalidatordo esnotgetitsmoneyfornothing. Indeed,itmustkeeptrackofthestatesofallorsomeshardchains(each validatorisresp onsibleforvalidatingandcreatingnewblo cksinacertain subsetofshardchains),p erformallcomputationsrequestedbysmartcon- 44 2.6.CreatingandValidatingNewBlocks tractsintheseshardchains,receiveup datesab outothershardchainsandso on.Thisactivityrequiresconsiderablediskspace,computingp owerand networkbandwidth. 2.6.2.Validatorsinsteadofminers.RecallthattheTONBlo ckchainuses thePro of-of-Stakeapproach,insteadofthePro of-of-Workapproachadopted byBitcoin,thecurrentversionofEthereum,andmostothercrypto currencies. Thismeansthatonecannotmineanewblo ckbypresentingsomepro of-of- work(computingalotofotherwiseuselesshashes)andobtainsomenewcoins asaresult.Instead,onemustb ecomeavalidatorandsp endone'scomputing resourcestostoreandpro cessTONBlo ckchainrequestsanddata.Inshort, onemustbeavalidatortominenewcoins.Inthisresp ect,validatorsarethe newminers. However,therearesomeotherwaystoearncoinsapartfromb einga validator. 2.6.3.Nominatorsandminingp o ols.Tob ecomeavalidator,one wouldnormallyneedtobuyandinstallseveralhigh-p erformanceserversand acquireago o dInternetconnectionforthem.Thisisnotsoexp ensiveasthe ASICequipmentcurrentlyrequiredtomineBitcoins.However,onedenitely cannotminenewTONcoinsonahomecomputer,letaloneasmartphone. IntheBitcoin,EthereumandotherPro of-of-Workcrypto currencymining communitiesthereisanotionofminingpools,wherealotofno des,having insucientcomputingp owertominenewblo cksbythemselves,combine theireortsandsharetherewardafterwards. Acorresp ondingnotioninthePro of-of-Stakeworldisthatofanominator. Essentially,thisisano delendingitsmoneytohelpavalidatorincreaseits stake;thevalidatorthendistributesthecorresp ondingshareofitsreward (orsomepreviouslyagreedfractionofitsay,50%)tothenominator. Inthisway,anominatorcanalsotakepartintheminingandobtain somerewardprop ortionaltotheamountofmoneyitiswillingtodep ositfor thispurp ose.Itreceivesonlyafractionofthecorresp ondingshareofthe validator'sreward,b ecauseitprovidesonlythecapital,butdo esnotneed tobuycomputingp ower,storageandnetworkbandwidth. However,ifthevalidatorlosesitsstakeb ecauseofinvalidb ehavior,the nominatorlosesitsshareofthestakeaswell.Inthissensethenominator sharestherisk.Itmustcho oseitsnominatedvalidatorwisely,otherwiseit canlosemoney.Inthissense,nominatorsmakeaweighteddecisionand voteforcertainvalidatorswiththeirfunds. 45 2.6.CreatingandValidatingNewBlocks Ontheotherhand,thisnominatingorlendingsystemenablesoneto b ecomeavalidatorwithoutinvestingalargeamountofmoneyintoTON coinsrst.Inotherwords,itpreventsthosekeepinglargeamountsofTON coinsfrommonop olizingthesupplyofvalidators. 2.6.4.Fishermen:obtainingmoneybyp ointingoutothers'mis- takes.Anotherwaytoobtainsomerewardswithoutb eingavalidatoris byb ecomingasherman.Essentially,anyno decanb ecomeashermanby makingasmalldep ositinthemasterchain.Thenitcanusesp ecialmas- terchaintransactionstopublish(Merkle)invaliditypro ofsofsome(usually shardchain)blo ckspreviouslysignedandpublishedbyvalidators.Ifother validatorsagreewiththisinvaliditypro of,theoendingvalidatorsarepun- ished(bylosingpartoftheirstake),andtheshermanobtainssomereward (afractionofcoinsconscatedfromtheoendingvalidators).Afterwards, theinvalid(shardchain)blo ckmustb ecorrectedasoutlinedin2.1.17.Cor- rectinginvalidmasterchainblo cksmayinvolvecreatingverticalblo ckson topofpreviouslycommittedmasterchainblo cks(cf.2.1.17);thereisnoneed tocreateaforkofthemasterchain. Normally,ashermanwouldneedtob ecomeafullno deforatleastsome shardchains,andsp endsomecomputingresourcesbyrunningtheco deof atleastsomesmartcontracts.Whileashermando esnotneedtohaveas muchcomputingp owerasavalidator,wethinkthatanaturalcandidate tob ecomeashermanisawould-b evalidatorthatisreadytopro cessnew blo cks,buthasnotyetb eenelectedasavalidator(e.g.,b ecauseofafailure todep ositasucientlylargestake). 2.6.5.Collators:obtainingmoneybysuggestingnewblo ckstoval- idators.Yetanotherwaytoobtainsomerewardswithoutb eingavalidator isbyb ecomingacol lator.Thisisano dethatpreparesandsuggeststo avalidatornewshardchainblo ckcandidates,complemented(collated)with datatakenfromthestateofthisshardchainandfromother(usuallyneigh- b oring)shardchains,alongwithsuitableMerklepro ofs.(Thisisnecessary, forexample,whensomemessagesneedtob eforwardedfromneighb oring shardchains.)Thenavalidatorcaneasilychecktheprop osedblo ckcandi- dateforvalidity,withouthavingtodownloadthecompletestateofthisor othershardchains. Becauseavalidatorneedstosubmitnew(collated)blo ckcandidatesto obtainsome(mining)rewards,itmakessensetopaysomepartofthe rewardtoacollatorwillingtoprovidesuitableblo ckcandidates.Inthisway, 46 2.6.CreatingandValidatingNewBlocks avalidatormayfreeitselffromthenecessityofwatchingthestateofthe neighb oringshardchains,byoutsourcingittoacollator. However,weexp ectthatduringthesystem'sinitialdeploymentphase therewillb enoseparatedesignatedcollators,b ecauseallvalidatorswillb e abletoactascollatorsforthemselves. 2.6.6.Collatorsorvalidators:obtainingmoneyforincludinguser transactions.Userscanop enmicropaymentchannelstosomecollatorsor validatorsandpaysmallamountsofcoinsinexchangefortheinclusionof theirtransactionsintheshardchain. 2.6.7.Globalvalidatorsetelection.Theglobalsetofvalidatorsis electedonceeachmonth(actually,every2 19 masterchainblo cks).Thissetis determinedanduniversallyknownonemonthinadvance. Inordertob ecomeavalidator,ano demusttransfersomeTONcoins intothemasterchain,andthensendthemtoasp ecialsmartcontractasits suggestedstakes.Anotherparameter,sentalongwiththestake,isl≥1, themaximumvalidatingloadthisno deiswillingtoacceptrelativetothe minimalp ossible.Thereisalsoaglobalupp erb ound(anothercongurable parameter)Lonl,equalto,say,10. Thentheglobalsetofvalidatorsiselectedbythissmartcontract,simply byselectinguptoTcandidateswithmaximalsuggestedstakesandpublishing theiridentities.Originally,thetotalnumb erofvalidatorsisT= 100;we exp ectittogrowto1000astheloadincreases.Itisacongurableparameter (cf.2.1.21). Theactualstakeofeachvalidatoriscomputedasfollows:IfthetopT prop osedstakesares 1 ≥s 2 ≥ ··· ≥s T ,theactualstakeofi-thvalidatoris settos ′ i := min(s i ,l i ·s T ).Inthisway,s ′ i /s ′ T ≤l i ,sothei-thvalidatordo es notobtainmorethanl i ≤Ltimestheloadoftheweakestvalidator(b ecause theloadisultimatelyprop ortionaltothestake). Thenelectedvalidatorsmaywithdrawtheunusedpartoftheirstake, s i −s ′ i .Unsuccessfulvalidatorcandidatesmaywithdrawalloftheirprop osed stake. Eachvalidatorpublishesitspublicsigningkey,notnecessarilyequalto thepublickeyoftheaccountthestakecamefrom. 20 Thestakesofthevalidatorsarefrozenuntiltheendofthep erio dfor whichtheyhaveb eenelected,andonemonthmore,incasenewdisputes 20 Itmakessensetogenerateanduseanewkeypairforeveryvalidatorelection. 47 2.6.CreatingandValidatingNewBlocks arise(i.e.,aninvalidblo cksignedbyoneofthesevalidatorsisfound).After that,thestakeisreturned,alongwiththevalidator'sshareofcoinsminted andfeesfromtransactionspro cessedduringthistime. 2.6.8.Electionofvalidatortaskgroups.Thewholeglobalsetofval- idators(whereeachvalidatorisconsideredpresentwithmultiplicityequalto itsstakeotherwiseavalidatormightb etemptedtoassumeseveralidenti- tiesandsplititsstakeamongthem)isusedonlytovalidatenewmasterchain blo cks.Theshardchainblo cksarevalidatedonlybysp eciallyselectedsub- setsofvalidators,takenfromtheglobalsetofvalidatorschosenasdescrib ed in2.6.7. Thesevalidatorsubsetsortaskgroups,denedforeveryshard,are rotatedeachhour(actually,every2 10 masterchainblo cks),andtheyare knownonehourinadvance,sothateveryvalidatorknowswhichshardsit willneedtovalidate,andcanprepareforthat(e.g.,bydownloadingmissing shardchaindata). Thealgorithmusedtoselectvalidatortaskgroupsforeachshard(w,s) isdeterministicpseudorandom.Itusespseudorandomnumb ersemb edded byvalidatorsintoeachmasterchainblo ck(generatedbyaconsensususing thresholdsignatures)tocreatearandomseed,andthencomputesforex- ampleHash(code(w).code(s).validator\_id.rand\_seed)foreachvalidator. Thenvalidatorsaresortedbythevalueofthishash,andtherstseveralare selected,soastohaveatleast20/Tofthetotalvalidatorstakesandconsist ofatleast5validators. Thisselectioncouldb edonebyasp ecialsmartcontract.Inthatcase, theselectionalgorithmwouldeasilyb eupgradablewithouthardforksbythe votingmechanismmentionedin2.1.21.Allotherconstantsmentionedso far(suchas2 19 ,2 10 ,T,20,and5)arealsocongurableparameters. 2.6.9.Rotatingpriorityorderoneachtaskgroup.Thereisacertain priorityorderimp osedonthememb ersofashardtaskgroup,dep endingon thehashofthepreviousmasterchainblo ckand(shardchain)blo cksequence numb er.Thisorderisdeterminedbygeneratingandsortingsomehashesas describ edab ove. Whenanewshardchainblo ckneedstob egenerated,theshardtaskgroup validatorselectedtocreatethisblo ckisnormallytherstonewithresp ect tothisrotatingpriorityorder.Ifitfailstocreatetheblo ck,thesecondor thirdvalidatormaydoit.Essentially,allofthemmaysuggesttheirblo ck candidates,butthecandidatesuggestedbythevalidatorhavingthehighest 48 2.6.CreatingandValidatingNewBlocks priorityshouldwinastheresultofByzantineFaultTolerant(BFT)consensus proto col. 2.6.10.Propagationofshardchainblo ckcandidates.Becauseshard- chaintaskgroupmemb ershipisknownonehourinadvance,theirmemb ers canusethattimetobuildadedicatedshardvalidatorsmulticastoverlaynet- work,usingthegeneralmechanismsoftheTONNetwork(cf.3.3).When anewshardchainblo ckneedstob egeneratednormallyoneortwoseconds afterthemostrecentmasterchainblo ckhasb eenpropagatedeveryb o dy knowswhohasthehighestprioritytogeneratethenextblo ck(cf.2.6.9). Thisvalidatorwillcreateanewcollatedblo ckcandidate,eitherbyitselfor withtheaidofacollator(cf.2.6.5).Thevalidatormustcheck(validate)this blo ckcandidate(esp eciallyifithasb eenpreparedbysomecollator)andsign itwithits(validator)privatekey.Thentheblo ckcandidateispropagated totheremainderofthetaskgroupusingtheprearrangedmulticastoverlay network(thetaskgroupcreatesitsownprivateoverlaynetworkasexplained in3.3,andthenusesaversionofthestreamingmulticastproto coldescrib ed in3.3.15topropagateblo ckcandidates). AtrulyBFTwayofdoingthiswouldb etouseaByzantinemulticast proto col,suchastheoneusedinHoneyBadgerBFT\[11\]:enco detheblo ck candidatebyan(N,2N/3)-erasureco de,send1/Noftheresultingdata directlytoeachmemb erofthegroup,andexp ectthemtomulticastdirectly theirpartofthedatatoallothermemb ersofthegroup. However,afasterandmorestraightforwardwayofdoingthis(cf.also 3.3.15)istosplittheblo ckcandidateintoasequenceofsignedone-kilobyte blo cks(chunks),augmenttheirsequencebyaReedSolomonorafountain co de(suchastheRaptorQco de\[9\]\[14\]),andstarttransmittingchunkstothe neighb orsinthemulticastmesh(i.e.,theoverlaynetwork),exp ectingthem topropagatethesechunksfurther.Onceavalidatorobtainsenoughchunks toreconstructtheblo ckcandidatefromthem,itsignsaconrmationreceipt andpropagatesitthroughitsneighb orstothewholeofthegroup.Then itsneighb orsstopsendingnewchunkstoit,butmaycontinuetosendthe (original)signaturesofthesechunks,b elievingthatthisno decangeneratethe subsequentchunksbyapplyingtheReedSolomonorfountainco debyitself (havingalldatanecessary),combinethemwithsignatures,andpropagateto itsneighb orsthatarenotyetready. Ifthemulticastmesh(overlaynetwork)remainsconnectedafterremov- ingallbadno des(recallthatuptoone-thirdofno desareallowedtob e 49 2.6.CreatingandValidatingNewBlocks badinaByzantineway,i.e.,b ehaveinarbitrarymaliciousfashion),this algorithmwillpropagatetheblo ckcandidateasquicklyasp ossible. Notonlythedesignatedhigh-priorityblo ckcreatormaymulticastits blo ckcandidatetothewholeofthegroup.Thesecondandthirdvalidator byprioritymaystartmulticastingtheirblo ckcandidates,eitherimmediately orafterfailingtoreceiveablo ckcandidatefromthetoppriorityvalidator. However,normallyonlytheblo ckcandidatewithmaximalprioritywillb e signedbyall(actually,byatleasttwo-thirdsofthetaskgroup)validators andcommittedasanewshardchainblo ck. 2.6.11.Validationofblo ckcandidates.Onceablo ckcandidateisre- ceivedbyavalidatorandthesignatureofitsoriginatingvalidatorischecked, thereceivingvalidatorchecksthevalidityofthisblo ckcandidate,byp er- formingalltransactionsinitandcheckingthattheirresultcoincideswith theoneclaimed.Allmessagesimp ortedfromotherblo ckchainsmustb esup- p ortedbysuitableMerklepro ofsinthecollateddata,otherwisetheblo ck candidateisdeemedinvalid(and,ifapro ofofthisiscommittedtothemas- terchain,thevalidatorshavingalreadysignedthisblo ckcandidatemayb e punished).Ontheotherhand,iftheblo ckcandidateisfoundtob evalid,the receivingvalidatorsignsitandpropagatesitssignaturetoothervalidatorsin thegroup,eitherthroughthemeshmulticastnetwork,orbydirectnetwork messages. Wewouldliketoemphasizethatavalidatordoesnotneedaccesstothe statesofthisorneighboringshardchainsinordertocheckthevalidityof a(col lated)blockcandidate. 21 Thisallowsthevalidationtopro ceedvery quickly(withoutdiskaccesses),andlightensthecomputationalandstorage burdenonthevalidators(esp eciallyiftheyarewillingtoaccepttheservices ofoutsidecollatorsforcreatingblo ckcandidates). 2.6.12.Electionofthenextblo ckcandidate.Onceablo ckcandidate collectsatleasttwo-thirds(bystake)ofthevaliditysignaturesofvalidators inthetaskgroup,itiseligibletob ecommittedasthenextshardchainblo ck. ABFTproto colisruntoachieveconsensusontheblo ckcandidatechosen (theremayb emorethanoneprop osed),withallgo o dvalidatorspreferring theblo ckcandidatewiththehighestpriorityforthisround.Asaresultof 21 Ap ossibleexceptionisthestateofoutputqueuesoftheneighb oringshardchains, neededtoguaranteethemessageorderingrequirementsdescrib edin2.4.21,b ecausethe sizeofMerklepro ofsmightb ecomeprohibitiveinthiscase. 50 2.6.CreatingandValidatingNewBlocks runningthisproto col,theblo ckisaugmentedbysignaturesofatleasttwo- thirdsofthevalidators(bystake).Thesesignaturestestifynotonlytothe validityoftheblo ckinquestion,butalsotoitsb eingelectedbytheBFT proto col.Afterthat,theblo ck(withoutcollateddata)iscombinedwith thesesignatures,serializedinadeterministicway,andpropagatedthrough thenetworktoallpartiesconcerned. 2.6.13.Validatorsmustkeeptheblo ckstheyhavesigned.During theirmemb ershipinthetaskgroupandforatleastonehour(orrather 2 10 blo cks)afterward,thevalidatorsareexp ectedtokeeptheblo cksthey havesignedandcommitted.Thefailuretoprovideasignedblo cktoother validatorsmayb epunished. 2.6.14.Propagatingtheheadersandsignaturesofnewshardchain blo ckstoallvalidators.Validatorspropagatetheheadersandsignatures ofnewly-generatedshardchainblo ckstotheglobalsetofvalidators,usinga multicastmeshnetworksimilartotheonecreatedforeachtaskgroup. 2.6.15.Generationofnewmasterchainblo cks.Afterall(oralmostall) newshardchainblo ckshaveb eengenerated,anewmasterchainblo ckmay b egenerated.Thepro cedureisessentiallythesameasforshardchainblo cks (cf.2.6.12),withthedierencethatal lvalidators(oratleasttwo-thirdsof them)mustparticipateinthispro cess.Becausetheheadersandsignaturesof newshardchainblo cksarepropagatedtoallvalidators,hashesofthenewest blo cksineachshardchaincanandmustb eincludedinthenewmasterchain blo ck.Oncethesehashesarecommittedintothemasterchainblo ck,outside observersandothershardchainsmayconsiderthenewshardchainblo cks committedandimmutable(cf.2.1.13). 2.6.16.Validatorsmustkeepthestateofmasterchain.Anoteworthy dierenceb etweenthemasterchainandtheshardchainsisthatallvalidators areexp ectedtokeeptrackofthemasterchainstate,withoutrelyingoncol- lateddata.Thisisimp ortantb ecausetheknowledgeofvalidatortaskgroups isderivedfromthemasterchainstate. 2.6.17.Shardchainblo cksaregeneratedandpropagatedinparallel. Normally,eachvalidatorisamemb erofseveralshardchaintaskgroups;their quantity(hencetheloadonthevalidator)isapproximatelyprop ortionalto thevalidator'sstake.Thismeansthatthevalidatorrunsseveralinstancesof newshardchainblo ckgenerationproto colinparallel. 51 2.6.CreatingandValidatingNewBlocks 2.6.18.Mitigationofblo ckretentionattacks.Becausethetotalsetof validatorsinsertsanewshardchainblo ck'shashintothemasterchainafter havingseenonlyitsheaderandsignatures,thereisasmallprobabilitythat thevalidatorsthathavegeneratedthisblo ckwillconspireandtrytoavoid publishingthenewblo ckinitsentirety.Thiswouldresultintheinability ofvalidatorsofneighb oringshardchainstocreatenewblo cks,b ecausethey mustknowatleasttheoutputmessagequeueofthenewblo ck,onceitshash hasb eencommittedintothemasterchain. Inordertomitigatethis,thenewblo ckmustcollectsignaturesfromsome othervalidators(e.g.,two-thirdsoftheunionoftaskgroupsofneighb oring shardchains)testifyingthatthesevalidatorsdohavecopiesofthisblo ckand arewillingtosendthemtoanyothervalidatorsifrequired.Onlyafter thesesignaturesarepresentedmaythenewblo ck'shashb eincludedinthe masterchain. 2.6.19.Masterchainblo cksaregeneratedlaterthanshardchain blo cks.Masterchainblo cksaregeneratedapproximatelyonceeveryve seconds,asareshardchainblo cks.However,whilethegenerationofnew blo cksinallshardchainsrunsessentiallyatthesametime(normallytrig- geredbythereleaseofanewmasterchainblo ck),thegenerationofnew masterchainblo cksisdelib eratelydelayed,toallowtheinclusionofhashes ofnewly-generatedshardchainblo cksinthemasterchain. 2.6.20.Slowvalidatorsmayreceivelowerrewards.Ifavalidator isslow,itmayfailtovalidatenewblo ckcandidates,andtwo-thirdsof thesignaturesrequiredtocommitthenewblo ckmayb egatheredwithout itsparticipation.Inthiscase,itwillreceivealowershareofthereward asso ciatedwiththisblo ck. Thisprovidesanincentiveforthevalidatorstooptimizetheirhardware, software,andnetworkconnectioninordertopro cessusertransactionsasfast asp ossible. However,ifavalidatorfailstosignablo ckb eforeitiscommitted,its signaturemayb eincludedinoneofthenextblo cks,andthenapartofthe reward(exp onentiallydecreasingdep endingonhowmanyblo ckshaveb een generatedsincee.g.,0.9 k ifthevalidatoriskblo ckslate)willb estillgiven tothisvalidator. 2.6.21.Depthofvalidatorsignatures.Normally,whenavalidator signsablo ck,thesignaturetestiesonlytotherelativevalidityofablo ck: 52 2.6.CreatingandValidatingNewBlocks thisblo ckisvalidprovidedallpreviousblo cksinthisandothershardchains arevalid.Thevalidatorcannotb epunishedfortakingforgrantedinvalid datacommittedintopreviousblo cks. However,thevalidatorsignatureofablo ckhasanintegerparameter calleddepth.Ifitisnon-zero,itmeansthatthevalidatorassertsthe (relative)validityofthesp eciednumb erofpreviousblo cksaswell.Thisis awayforslowortemp orarilyoinevalidatorstocatchupandsignsome oftheblo cksthathaveb eencommittedwithouttheirsignatures.Thensome partoftheblo ckrewardwillstillb egiventothem(cf.2.6.20). 2.6.22.Validatorsareresp onsibleforrelativevalidityofsigned shardchainblo cks;absolutevalidityfollows.Wewouldliketoempha- sizeonceagainthatavalidator'ssignatureonashardchainblo ckBtesties toonlytherelativevalidityofthatblo ck(ormayb eofdpreviousblo cks aswell,ifthesignaturehasdepthd,cf.2.6.21;butthisdo esnotaect thefollowingdiscussionmuch).Inotherwords,thevalidatorassertsthat thenextstates ′ oftheshardchainisobtainedfromthepreviousstatesby applyingtheblo ckevaluationfunctionev\_blockdescrib edin2.2.6: s ′ =ev\_block(B)(s)(24) Inthisway,thevalidatorthatsignedblo ckBcannotb epunishedifthe originalstatesturnsouttob eincorrect(e.g.,b ecauseoftheinvalidityof oneofthepreviousblo cks).Asherman(cf.2.6.4)shouldcomplainonlyifit ndsablo ckthatisrelativelyinvalid.ThePoSsystemasawholeendeavors tomakeeveryblo ckrelativelyvalid,notrecursively(orabsolutely)valid. Notice,however,thatifal lblocksinablockchainarerelativelyvalid,thenal l ofthemandtheblockchainasawholeareabsolutelyvalid;thisstatementis easilyshownusingmathematicalinductiononthelengthoftheblo ckchain. Inthisway,easilyveriableassertionsofrelativevalidityofblo ckstogether demonstratethemuchstrongerabsolutevalidityofthewholeblo ckchain. Notethatbysigningablo ckBthevalidatorassertsthattheblo ckis validgiventheoriginalstates(i.e.,thattheresultof(24)isnotthevalue⊥ indicatingthatthenextstatecannotb ecomputed).Inthisway,thevalidator mustp erformminimalformalchecksofthecellsoftheoriginalstatethatare accessedduringtheevaluationof(24). Forexample,imaginethatthecellexp ectedtocontaintheoriginalbal- anceofanaccountaccessedfromatransactioncommittedintoablo ckturns outtohavezerorawbytesinsteadoftheexp ected8or16.Thentheoriginal 53 2.6.CreatingandValidatingNewBlocks balancesimplycannotb eretrievedfromthecell,andanunhandledexcep- tionhapp enswhiletryingtopro cesstheblo ck.Inthiscase,thevalidator shouldnotsignsuchablo ckonpainofb eingpunished. 2.6.23.Signingmasterchainblo cks.Thesituationwiththemasterchain blo cksissomewhatdierent:bysigningamasterchainblo ck,thevalida- torassertsnotonlyitsrelativevalidity,butalsotherelativevalidityofall precedingblo cksuptotheveryrstblo ckwhenthisvalidatorassumedits resp onsibility(butnotfurtherback). 2.6.24.Thetotalnumb erofvalidators.Theupp erlimitTforthetotal numb erofvalidatorstob eelected(cf.2.6.7)cannotb ecome,inthesystem describ edsofar,morethan,say,severalhundredorathousand,b ecauseall validatorsareexp ectedtoparticipateinaBFTconsensusproto coltocre- ateeachnewmasterchainblo ck,anditisnotclearwhethersuchproto cols canscaletothousandsofparticipants.Evenmoreimp ortantly,masterchain blo cksmustcollectthesignaturesofatleasttwo-thirdsofallthevalidators (bystake),andthesesignaturesmustb eincludedinthenewblo ck(other- wiseallotherno desinthesystemwouldhavenoreasontotrustthenew blo ckwithoutvalidatingitbythemselves).Ifmorethan,say,onethousand validatorsignatureswouldhavetob eincludedineachmasterchainblo ck, thiswouldimplymoredataineachmasterchainblo ck,tob estoredbyall fullno desandpropagatedthroughthenetwork,andmorepro cessingp ower sp enttocheckthesesignatures(inaPoSsystem,fullno desdonotneedto validateblo cksbythemselves,buttheyneedtocheckthevalidators'signa- turesinstead). WhilelimitingTtoathousandvalidatorsseemsmorethansucientfor therstphaseofthedeploymentoftheTONBlo ckchain,aprovisionmust b emadeforfuturegrowth,whenthetotalnumb erofshardchainsb ecomes solargethatseveralhundredvalidatorswillnotsucetopro cessallof them.Tothisend,weintro duceanadditionalcongurableparameterT ′ ≤T (originallyequaltoT),andonlythetopT ′ electedvalidators(bystake)are exp ectedtocreateandsignnewmasterchainblo cks. 2.6.25.Decentralizationofthesystem.Onemightsusp ectthataPro of- of-StakesystemsuchastheTONBlo ckchain,relyingonT≈1000validators tocreateallshardchainandmasterchainblo cks,isb oundtob ecometo o centralized,asopp osedtoconventionalPro of-of-Workblo ckchainslikeBit- coinorEthereum,whereeveryb o dy(inprinciple)mightmineanewblo ck, 54 2.6.CreatingandValidatingNewBlocks withoutanexplicitupp erlimitonthetotalnumb erofminers. However,p opularPro of-of-Workblo ckchains,suchasBitcoinandEther- eum,currentlyrequirevastamountsofcomputingp ower(highhashrates) tominenewblo ckswithnon-negligibleprobabilityofsuccess.Thus,the miningofnewblo ckstendstob econcentratedinthehandsofseverallarge players,whoinvesthugeamountsmoneyintodatacenterslledwithcustom- designedhardwareoptimizedformining;andinthehandsofseverallarge miningp o ols,whichconcentrateandco ordinatetheeortsoflargergroups ofp eoplewhoarenotabletoprovideasucienthashratebythemselves. Therefore,asof2017,morethan75%ofnewEthereumorBitcoinblo cks arepro ducedbylessthantenminers.Infact,thetwolargestEthereum miningp o olspro ducetogethermorethanhalfofallnewblo cks!Clearly, suchasystemismuchmorecentralizedthanonerelyingonT≈1000no des topro ducenewblo cks. Onemightalsonotethattheinvestmentrequiredtob ecomeaTON Blo ckchainvalidatori.e.,tobuythehardware(say,severalhigh-p erformance servers)andthestake(whichcanb eeasilycollectedthroughap o olofnom- inatorsifnecessary;cf.2.6.3)ismuchlowerthanthatrequiredtob ecome asuccessfulstand-aloneBitcoinorEthereumminer.Infact,theparame- terLof2.6.7willforcenominatorsnottojointhelargestminingp o ol (i.e.,thevalidatorthathasamassedthelargeststake),butrathertolo ok forsmallervalidatorscurrentlyacceptingfundsfromnominators,orevento createnewvalidators,b ecausethiswouldallowahigherprop ortions ′ i /s i of thevalidator'sandbyextensionalsothenominator'sstaketob eused, henceyieldinglargerrewardsfrommining.Inthisway,theTONPro of-of- Stakesystemactuallyencouragesdecentralization(creatingandusingmore validators)andpunishescentralization. 2.6.26.Relativereliabilityofablo ck.The(relative)reliabilityofablo ck issimplythetotalstakeofallvalidatorsthathavesignedthisblo ck.Inother words,thisistheamountofmoneycertainactorswouldloseifthisblo ck turnsouttob einvalid.Ifoneisconcernedwithtransactionstransferring valuelowerthanthereliabilityoftheblo ck,onecanconsiderthemtob esafe enough.Inthissense,therelativereliabilityisameasureoftrustanoutside observercanhaveinaparticularblo ck. Notethatwesp eakoftherelativereliabilityofablo ck,b ecauseitisa guaranteethattheblo ckisvalidprovidedthepreviousblockandal lother shardchains'blocksreferredtoarevalid(cf.2.6.22). 55 2.6.CreatingandValidatingNewBlocks Therelativereliabilityofablo ckcangrowafteritiscommittedfor example,whenb elatedvalidators'signaturesareadded(cf.2.6.21).Onthe otherhand,ifoneofthesevalidatorslosespartorallofitsstakeb ecause ofitsmisb ehaviorrelatedtosomeotherblo cks,therelativereliabilityofa blo ckmaydecrease. 2.6.27.Strengtheningtheblo ckchain.Itisimp ortanttoprovidein- centivesforvalidatorstoincreasetherelativereliabilityofblo cksasmuchas p ossible.Onewayofdoingthisisbyallo catingasmallrewardtovalidators foraddingsignaturestoblo cksofothershardchains.Evenwould-b evalida- tors,whohavedep ositedastakeinsucienttogetintothetopTvalidators bystakeandtob eincludedintheglobalsetofvalidators(cf.2.6.7),might participateinthisactivity(iftheyagreetokeeptheirstakefrozeninstead ofwithdrawingitafterhavinglosttheelection).Suchwould-b evalidators mightdoubleasshermen(cf.2.6.4):iftheyhavetocheckthevalidityof certainblo cksanyway,theymightaswellopttorep ortinvalidblo cksand collecttheasso ciatedrewards. 2.6.28.Recursivereliabilityofablo ck.Onecanalsodenetherecursive reliabilityofablo cktob etheminimumofitsrelativereliabilityandthe recursivereliabilitiesofallblo cksitrefersto(i.e.,themasterchainblo ck,the previousshardchainblo ck,andsomeblo cksofneighb oringshardchains).In otherwords,iftheblo ckturnsouttob einvalid,eitherb ecauseitisinvalidby itselforb ecauseoneoftheblo cksitdep endsonisinvalid,thenatleastthis amountofmoneywouldb elostbysomeone.Ifoneistrulyunsurewhether totrustasp ecictransactioninablo ck,oneshouldcomputetherecursive reliabilityofthisblo ck,notjusttherelativeone. Itdo esnotmakesensetogoto ofarbackwhencomputingrecursive reliability,b ecause,ifwelo okto ofarback,wewillseeblo ckssignedby validatorswhosestakeshavealreadyb eenunfrozenandwithdrawn.Inany case,wedonotallowthevalidatorstoautomaticallyreconsiderblo cksthat arethatold(i.e.,createdmorethantwomonthsago,ifcurrentvaluesof congurableparametersareused),andcreateforksstartingfromthemor correctthemwiththeaidofverticalblo ckchains(cf.2.1.17),evenifthey turnouttob einvalid.Weassumethatap erio doftwomonthsprovides ampleopp ortunitiesfordetectingandrep ortinganyinvalidblo cks,sothat ifablo ckisnotchallengedduringthisp erio d,itisunlikelytob echallenged atall. 56 2.7.SplittingandMergingShardchains 2.6.29.ConsequenceofPro of-of-Stakeforlightno des.Animp ortant consequenceofthePro of-of-StakeapproachusedbytheTONBlo ckchainis thatalightno de(runninglightclientsoftware)fortheTONBlo ckchaindo es notneedtodownloadtheheadersofallshardchainorevenmasterchain blo cksinordertob eabletocheckbyitselfthevalidityofMerklepro ofs providedtoitbyfullno desasanswerstoitsqueries. Indeed,b ecausethemostrecentshardchainblo ckhashesareincludedin themasterchainblo cks,afullno decaneasilyprovideaMerklepro ofthata givenshardchainblo ckisvalidstartingfromaknownhashofamasterchain blo ck.Next,thelightno deneedstoknowonlytheveryrstblo ckofthe masterchain(wheretheveryrstsetofvalidatorsisannounced),which(or atleastthehashofwhich)mightb ebuilt-inintotheclientsoftware,and onlyonemasterchainblo ckapproximatelyeverymonthafterwards,where newly-electedvalidatorsetsareannounced,b ecausethisblo ckwillhaveb een signedbytheprevioussetofvalidators.Startingfromthat,itcanobtainthe severalmostrecentmasterchainblo cks,oratleasttheirheadersandvalidator signatures,andusethemasabaseforcheckingMerklepro ofsprovidedby fullno des. 2.7SplittingandMergingShardchains OneofthemostcharacteristicanduniquefeaturesoftheTONBlo ckchainis itsabilitytoautomaticallysplitashardchainintwowhentheloadb ecomes to ohigh,andmergethembackiftheloadsubsides(cf.2.1.10).Wemust discussitinsomedetailb ecauseofitsuniquenessanditsimp ortancetothe scalabilityofthewholepro ject. 2.7.1.Shardconguration.Recallthat,atanygivenmomentoftime, eachworkchainwissplitintooneorseveralshardchains(w,s)(cf.2.1.8). Theseshardchainsmayb erepresentedbyleavesofabinarytree,withro ot (w,∅),andeachnon-leafno de(w,s)havingchildren(w,s.0)and(w,s.1). Inthisway,everyaccountb elongingtoworkchainwisassignedtoexactly oneshard,andeveryb o dywhoknowsthecurrentshardchainconguration candeterminetheshard(w,s)containingaccountaccount\_id:itistheonly shardwithbinarystringsb eingaprexofaccount\_id. Theshardcongurationi.e.,thisshardbinarytree,orthecollection ofallactive(w,s)foragivenw(corresp ondingtotheleavesoftheshard binarytree)ispartofthemasterchainstateandisavailabletoeveryb o dy 57 2.7.SplittingandMergingShardchains whokeepstrackofthemasterchain. 22 2.7.2.Mostrecentshardcongurationandstate.Recallthathashes ofthemostrecentshardchainblo cksareincludedineachmasterchainblo ck. Thesehashesareorganizedinashardbinarytree(actually,acollectionof trees,oneforeachworkchain).Inthisway,eachmasterchainblo ckcontains themostrecentshardconguration. 2.7.3.Announcingandp erformingchangesintheshardcongura- tion.Theshardcongurationmayb echangedintwoways:eitherashard (w,s)canb esplitintotwoshards(w,s.0)and(w,s.1),ortwosiblingshards (w,s.0)and(w,s.1)canb emergedintooneshard(w,s). Thesesplit/mergeop erationsareannouncedseveral(e.g.,2 6 ;thisisa congurableparameter)blo cksinadvance,rstintheheadersofthecor- resp ondingshardchainblo cks,andtheninthemasterchainblo ckthatrefers totheseshardchainblo cks.Thisadvanceannouncementisneededforall partiesconcernedtopreparefortheplannedchange(e.g.,buildanoverlay multicastnetworktodistributenewblo cksofthenewly-createdshardchains, asdiscussedin3.3).Thenthechangeiscommitted,rstintothe(headerof the)shardchainblo ck(incaseofasplit;foramerge,blo cksofb othshard- chainsshouldcommitthechange),andthenpropagatedtothemasterchain blo ck.Inthisway,themasterchainblo ckdenesnotonlythemostrecent shardcongurationbeforeitscreation,butalsothenextimmediateshard conguration. 2.7.4.Validatortaskgroupsfornewshardchains.Recallthateach shard,i.e.,eachshardchain,normallyisassignedasubsetofvalidators(a validatortaskgroup)dedicatedtocreatingandvalidatingnewblo cksinthe corresp ondingshardchain(cf.2.6.8).Thesetaskgroupsareelectedforsome p erio doftime(approximatelyonehour)andareknownsometimeinadvance (alsoapproximatelyonehour),andareimmutableduringthisp erio d. 23 However,theactualshardcongurationmaychangeduringthisp erio d b ecauseofsplit/mergeop erations.Onemustassigntaskgroupstonewly createdshards.Thisisdoneasfollows: 22 Actually,theshardcongurationiscompletelydeterminedbythelastmasterchain blo ck;thissimpliesgettingaccesstotheshardconguration. 23 Unlesssomevalidatorsaretemp orarilyorp ermanentlybannedb ecauseofsigning invalidblo cksthentheyareautomaticallyexcludedfromalltaskgroups. 58 2.7.SplittingandMergingShardchains Noticethatanyactiveshard(w,s)willeitherb eadescendantofsome uniquelydeterminedoriginalshard(w,s ′ ),meaningthats ′ isaprexofs, oritwillb ethero otofasubtreeoforiginalshards(w,s ′ ),whereswillb e aprexofeverys ′ .Intherstcase,wesimplytakethetaskgroupofthe originalshard(w,s ′ )todoubleasthetaskgroupofthenewshard(w,s).In thelattercase,thetaskgroupofthenewshard(w,s)willb etheunionof taskgroupsofalloriginalshards(w,s ′ )thataredescendantsof(w,s)inthe shardtree. Inthisway,everyactiveshard(w,s)getsassignedawell-denedsubset ofvalidators(taskgroup).Whenashardissplit,b othchildreninheritthe wholeofthetaskgroupfromtheoriginalshard.Whentwoshardsaremerged, theirtaskgroupsarealsomerged. Anyonewhokeepstrackofthemasterchainstatecancomputevalidator taskgroupsforeachoftheactiveshards. 2.7.5.Limitonsplit/mergeop erationsduringthep erio dofresp on- sibilityoforiginaltaskgroups.Ultimately,thenewshardconguration willb etakenintoaccount,andnewdedicatedvalidatorsubsets(taskgroups) willautomaticallyb eassignedtoeachshard.Beforethathapp ens,onemust imp oseacertainlimitonsplit/mergeop erations;otherwise,anoriginaltask groupmayendupvalidating2 k shardchainsforalargekatthesametime, iftheoriginalshardquicklysplitsinto2 k newshards. Thisisachievedbyimp osinglimitsonhowfartheactiveshardcongu- rationmayb eremovedfromtheoriginalshardconguration(theoneused toselectvalidatortaskgroupscurrentlyincharge).Forexample,onemight requirethatthedistanceintheshardtreefromanactiveshard(w,s)toan originalshard(w,s ′ )mustnotexceed3,ifs ′ isapredecessorofs(i.e.,s ′ isa prexofbinarystrings),andmustnotexceed2,ifs ′ isasuccessorofs(i.e., sisaprexofs ′ ).Otherwise,thesplitormergeop erationisnotp ermitted. Roughlysp eaking,oneisimp osingalimitonthenumb eroftimesa shardcanb esplit(e.g.,three)ormerged(e.g.,two)duringthep erio dof resp onsibilityofagivencollectionofvalidatortaskgroups.Apartfrom that,afterashardhasb eencreatedbymergingorsplitting,itcannotb e reconguredforsomep erio doftime(somenumb erofblo cks). 2.7.6.Determiningthenecessityofsplitop erations.Thesplitop er- ationforashardchainistriggeredbycertainformalconditions(e.g.,iffor 64consecutiveblo ckstheshardchainblo cksareatleast90%full).These conditionsaremonitoredbytheshardchaintaskgroup.Iftheyaremet, 59 2.7.SplittingandMergingShardchains rstasplitpreparationagisincludedintheheaderofanewshardchain blo ck(andpropagatedtothemasterchainblo ckreferringtothisshardchain blo ck).Then,severalblo cksafterwards,thesplitcommitagisincludedin theheaderoftheshardchainblo ck(andpropagatedtothenextmasterchain blo ck). 2.7.7.Performingsplitop erations.Afterthesplitcommitagisin- cludedinablo ckBofshardchain(w,s),therecannotb easubsequentblo ck B ′ inthatshardchain.Instead,twoblo cksB ′ 0 andB ′ 1 ofshardchains(w,s.0) and(w,s.1),resp ectively,willb ecreated,b othreferringtoblo ckBastheir previousblo ck(andb othofthemwillindicatebyaagintheheaderthatthe shardhasb eenjustsplit).Thenextmasterchainblo ckwillcontainhashes ofblo cksB ′ 0 andB ′ 1 ofthenewshardchains;itisnotallowedtocontainthe hashofanewblo ckB ′ ofshardchain(w,s),b ecauseasplitcommitevent hasalreadyb eencommittedintothepreviousmasterchainblo ck. Noticethatb othnewshardchainswillb evalidatedbythesamevalidator taskgroupastheoldone,sotheywillautomaticallyhaveacopyoftheir state.Thestatesplittingop erationitselfisquitesimplefromthep ersp ective oftheInniteShardingParadigm(cf.2.5.2). 2.7.8.Determiningthenecessityofmergeop erations.Thenecessity ofshardmergeop erationsisalsodetectedbycertainformalconditions(e.g., iffor64consecutiveblo cksthesumofthesizesofthetwoblo cksofsibling shardchainsdo esnotexceed60%ofmaximalblo cksize).Theseformalcon- ditionsshouldalsotakeintoaccountthetotalgassp entbytheseblo cksand compareittothecurrentblo ckgaslimit,otherwisetheblo cksmayhapp en tob esmallb ecausetherearesomecomputation-intensivetransactionsthat preventtheinclusionofmoretransactions. Theseconditionsaremonitoredbyvalidatortaskgroupsofb othsibling shards(w,s.0)and(w,s.1).Noticethatsiblingsarenecessarilyneighb ors withresp ecttohyp ercub erouting(cf.2.4.19),sovalidatorsfromthetask groupofanyshardwillb emonitoringthesiblingshardtosomeextentany- ways. Whentheseconditionsaremet,eitheroneofthevalidatorsubgroupscan suggesttotheotherthattheymergebysendingasp ecialmessage.Then theycombineintoaprovisionalmergedtaskgroup,withcombinedmem- b ership,capableofrunningBFTconsensusalgorithmsandofpropagating blo ckup datesandblo ckcandidatesifnecessary. 60 2.8.ClassificationofBlockchainProjects Iftheyreachconsensusonthenecessityandreadinessofmerging,merge prepareagsarecommittedintotheheadersofsomeblo cksofeachshard- chain,alongwiththesignaturesofatleasttwo-thirdsofthevalidatorsof thesibling'staskgroup(andarepropagatedtothenextmasterchainblo cks, sothateveryb o dycangetreadyfortheimminentreconguration).How- ever,theycontinuetocreateseparateshardchainblo cksforsomepredened numb erofblo cks. 2.7.9.Performingmergeop erations.Afterthat,whenthevalidators fromtheunionofthetwooriginaltaskgroupsarereadytob ecomevalidators forthemergedshardchain(thismightinvolveastatetransferfromthesibling shardchainandastatemergeop eration),theycommitamergecommit agintheheadersofblo cksoftheirshardchain(thiseventispropagated tothenextmasterchainblo cks),andstopcreatingnewblo cksinseparate shardchains(oncethemergecommitagapp ears,creatingblo cksinseparate shardchainsisforbidden).Instead,amergedshardchainblo ckiscreated(by theunionofthetwooriginaltaskgroups),referringtob othofitspreceding blo cksinitsheader.Thisisreectedinthenextmasterchainblo ck,which willcontainthehashofthenewlycreatedblo ckofthemergedshardchain. Afterthat,themergedtaskgroupcontinuescreatingblo cksinthemerged shardchain. 2.8ClassicationofBlo ckchainPro jects WewillconcludeourbriefdiscussionoftheTONBlo ckchainbycomparingit withexistingandprop osedblo ckchainpro jects.Beforedoingthis,however, wemustintro duceasucientlygeneralclassicationofblo ckchainpro jects. Thecomparisonofparticularblo ckchainpro jects,basedonthisclassication, isp ostp oneduntil2.9. 2.8.1.Classicationofblo ckchainpro jects.Asarststep,wesuggest someclassicationcriteriaforblo ckchains(i.e.,forblo ckchainpro jects).Any suchclassicationissomewhatincompleteandsup ercial,b ecauseitmust ignoresomeofthemostsp ecicanduniquefeaturesofthepro jectsunder consideration.However,wefeelthatthisisanecessaryrststepinprovid- ingatleastaveryroughandapproximatemapoftheblo ckchainpro jects territory. Thelistofcriteriaweconsideristhefollowing: 61 2.8.ClassificationofBlockchainProjects ˆSingle-blo ckchainvs.multi-blo ckchainarchitecture(cf.2.8.2) ˆConsensusalgorithm:Pro of-of-Stakevs.Pro of-of-Work(cf.2.8.3) ˆForPro of-of-Stakesystems,theexactblo ckgeneration,validationand consensusalgorithmused(thetwoprincipaloptionsareDPOSvs.BFT; cf.2.8.4) ˆSupp ortforarbitrary(Turing-complete)smartcontracts(cf.2.8.6) Multi-blo ckchainsystemshaveadditionalclassicationcriteria(cf.2.8.7): ˆTyp eandrulesofmemb erblo ckchains:homogeneous,heterogeneous (cf.2.8.8),mixed(cf.2.8.9).Confederations(cf.2.8.10). ˆAbsenceorpresenceofamasterchain,internalorexternal(cf.2.8.11) ˆNativesupp ortforsharding(cf.2.8.12).Staticordynamicsharding (cf.2.8.13). ˆInteractionb etweenmemb erblo ckchains:lo osely-coupledandtightly- coupledsystems(cf.2.8.14) 2.8.2.Single-blo ckchainvs.multi-blo ckchainpro jects.Therstclas- sicationcriterionisthequantityofblo ckchainsinthesystem.Theoldest andsimplestpro jectsconsistofasingleblockchain(singlechainpro jects forshort);moresophisticatedpro jectsuse(or,rather,plantouse)multiple blockchains(multichainpro jects). Singlechainpro jectsaregenerallysimplerandb ettertested;theyhave withsto o dthetestoftime.Theirmaindrawbackislowp erformance,orat leasttransactionthroughput,whichisontheleveloften(Bitcoin)toless thanonehundred 24 (Ethereum)transactionsp ersecondforgeneral-purp ose systems.Somesp ecializedsystems(suchasBitshares)arecapableofpro cess- ingtensofthousandsofsp ecializedtransactionsp ersecond,attheexp ense ofrequiringtheblo ckchainstatetotintomemory,andlimitingthepro- cessingtoapredenedsp ecialsetoftransactions,whicharethenexecuted byhighly-optimizedco dewritteninlanguageslikeC++(noVMshere). Multichainpro jectspromisethescalabilityeveryb o dycraves.Theymay supp ortlargertotalstatesandmoretransactionsp ersecond,attheexp ense 24 Morelike15,forthetimeb eing.However,someupgradesareb eingplannedtomake Ethereumtransactionthroughputseveraltimeslarger. 62 2.8.ClassificationofBlockchainProjects ofmakingthepro jectmuchmorecomplex,anditsimplementationmorechal- lenging.Asaresult,therearefewmultichainpro jectsalreadyrunning,but mostprop osedpro jectsaremultichain.Web elievethatthefutureb elongs tomultichainpro jects. 2.8.3.Creatingandvalidatingblo cks:Pro of-of-Workvs.Pro of-of- Stake.Anotherimp ortantdistinctionisthealgorithmandproto colused tocreateandpropagatenewblo cks,checktheirvalidity,andselectoneof severalforksiftheyapp ear. ThetwomostcommonparadigmsareProof-of-Work(PoW)andProof-of- Stake(PoS).ThePro of-of-Workapproachusuallyallowsanyno detocreate (mine)anewblo ck(andobtainsomerewardasso ciatedwithmininga blo ck)ifitisluckyenoughtosolveanotherwiseuselesscomputationalprob- lem(usuallyinvolvingthecomputationofalargeamountofhashes)b efore othercomp etitorsmanagetodothis.Inthecaseofforks(forexample,iftwo no despublishtwootherwisevalidbutdierentblo ckstofollowtheprevious one)thelongestforkwins.Inthisway,theguaranteeofimmutabilityofthe blo ckchainisbasedontheamountofwork(computationalresources)sp ent togeneratetheblo ckchain:anyb o dywhowouldliketocreateaforkofthis blo ckchainwouldneedtore-dothisworktocreatealternativeversionsofthe alreadycommittedblo cks.Forthis,onewouldneedtocontrolmorethan 50%ofthetotalcomputingp owersp entcreatingnewblo cks,otherwisethe alternativeforkwillhaveexp onentiallylowchancesofb ecomingthelongest. ThePro of-of-Stakeapproachisbasedonlargestakes(nominatedincryp- to currency)madebysomesp ecialno des(validators)toassertthattheyhave checked(validated)someblo cksandhavefoundthemcorrect.Validators signblo cks,andreceivesomesmallrewardsforthis;however,ifavalidator isevercaughtsigninganincorrectblo ck,andapro ofofthisispresented, partorallofitsstakeisforfeit.Inthisway,theguaranteeofvalidityand immutabilityoftheblo ckchainisgivenbythetotalvolumeofstakesputby validatorsonthevalidityoftheblo ckchain. ThePro of-of-Stakeapproachismorenaturalintheresp ectthatitincen- tivizesthevalidators(whichreplacePoWminers)top erformusefulcompu- tation(neededtocheckorcreatenewblo cks,inparticular,byp erformingall transactionslistedinablo ck)insteadofcomputingotherwiseuselesshashes. Inthisway,validatorswouldpurchasehardwarethatisb etteradaptedto pro cessingusertransactions,inordertoreceiverewardsasso ciatedwiththese transactions,whichseemsquiteausefulinvestmentfromthep ersp ectiveof 63 2.8.ClassificationofBlockchainProjects thesystemasawhole. However,Pro of-of-Stakesystemsaresomewhatmorechallengingtoim- plement,b ecauseonemustprovideformanyrarebutp ossibleconditions. Forexample,somemaliciousvalidatorsmightconspiretodisruptthesystem toextractsomeprot(e.g.,byalteringtheirowncrypto currencybalances). Thisleadstosomenon-trivialgame-theoreticproblems. Inshort,Pro of-of-Stakeismorenaturalandmorepromising,esp ecially formultichainpro jects(b ecausePro of-of-Workwouldrequireprohibitive amountsofcomputationalresourcesiftherearemanyblo ckchains),butmust b emorecarefullythoughtoutandimplemented.Mostcurrentlyrunning blo ckchainpro jects,esp eciallytheoldestones(suchasBitcoinandatleast theoriginalEthereum),usePro of-of-Work. 2.8.4.VariantsofPro of-of-Stake.DPOSvs.BFT.WhilePro of-of- Workalgorithmsareverysimilartoeachotheranddiermostlyinthehash functionsthatmustb ecomputedforminingnewblo cks,therearemore p ossibilitiesforPro of-of-Stakealgorithms.Theymeritasub-classicationof theirown. Essentially,onemustanswerthefollowingquestionsab outaPro of-of- Stakealgorithm: ˆWhocanpro duce(mine)anewblo ckanyfullno de,oronlyamem- b erofa(relatively)smallsubsetofvalidators?(MostPoSsystems requirenewblo ckstob egeneratedandsignedbyoneofseveraldesig- natedvalidators.) ˆDovalidatorsguaranteethevalidityoftheblo cksbytheirsignatures,or areallfullno desexp ectedtovalidateallblo cksbythemselves?(Scal- ablePoSsystemsmustrelyonvalidatorsignaturesinsteadofrequiring allno destovalidateallblo cksofallblo ckchains.) ˆIsthereadesignatedpro ducerforthenextblo ckchainblo ck,knownin advance,suchthatnob o dyelsecanpro ducethatblo ckinstead? ˆIsanewly-createdblo ckoriginallysignedbyonlyonevalidator(its pro ducer),ormustitcollectama jorityofvalidatorsignaturesfrom theveryb eginning? Whilethereseemtob e2 4 p ossibleclassesofPoSalgorithmsdep endingon theanswerstothesequestions,thedistinctioninpracticeb oilsdowntotwo 64 2.8.ClassificationofBlockchainProjects ma jorapproachestoPoS.Infact,mostmo dernPoSalgorithms,designedto b eusedinscalablemulti-chainsystems,answerthersttwoquestionsinthe samefashion:onlyvalidatorscanpro ducenewblo cks,andtheyguarantee blo ckvaliditywithoutrequiringallfullno destocheckthevalidityofall blo cksbythemselves. Astothetwolastquestions,theiranswersturnouttob ehighlycorre- lated,leavingessentiallyonlytwobasicoptions: ˆDelegatedProof-of-Stake(DPOS):Thereisauniversallyknowndesig- natedpro ducerforeveryblo ck;nooneelsecanpro ducethatblo ck;the newblo ckisoriginallysignedonlybyitspro ducingvalidator. ˆByzantineFaultTolerant(BFT)PoSalgorithms:Thereisaknown subsetofvalidators,anyofwhichcansuggestanewblo ck;thechoice oftheactualnextblo ckamongseveralsuggestedcandidates,which mustb evalidatedandsignedbyama jorityofvalidatorsb eforeb eing releasedtotheotherno des,isachievedbyaversionofByzantineFault Tolerantconsensusproto col. 2.8.5.ComparisonofDPOSandBFTPoS.TheBFTapproachhas theadvantagethatanewly-pro ducedblo ckhasfromtheverybeginningthe signaturesofama jorityofvalidatorstestifyingtoitsvalidity.Anotheradvan- tageisthat,ifama jorityofvalidatorsexecutestheBFTconsensusproto col correctly,noforkscanapp earatall.Ontheotherhand,BFTalgorithms tendtob equiteconvolutedandrequiremoretimeforthesubsetofvalida- torstoreachconsensus.Therefore,blo ckscannotb egeneratedto ooften. Thisiswhyweexp ecttheTONBlo ckchain(whichisaBFTpro jectfrom thep ersp ectiveofthisclassication)topro duceablo ckonlyonceeveryve seconds.Inpractice,thisintervalmightb edecreasedto23seconds(though wedonotpromisethis),butnotfurther,ifvalidatorsarespreadacrossthe glob e. TheDPOSalgorithmhastheadvantageofb eingquitesimpleandstraight- forward.Itcangeneratenewblo cksquiteoftensay,onceeverytwoseconds, ormayb eevenonceeverysecond, 25 b ecauseofitsrelianceondesignatedblo ck pro ducersknowninadvance. However,DPOSrequiresallno desoratleastallvalidatorstovalidate allblo cksreceived,b ecauseavalidatorpro ducingandsigninganewblo ck 25 Somep eopleevenclaimDPOSblo ckgenerationtimesofhalfasecond,whichdo es notseemrealisticifvalidatorsarescatteredacrossseveralcontinents. 65 2.8.ClassificationofBlockchainProjects conrmsnotonlytherelativevalidityofthisblo ck,butalsothevalidityof thepreviousblo ckitrefersto,andalltheblo cksfurtherbackinthechain (mayb euptotheb eginningofthep erio dofresp onsibilityofthecurrent subsetofvalidators).Thereisapredeterminedorderonthecurrentsubset ofvalidators,sothatforeachblo ckthereisadesignatedpro ducer(i.e., validatorexp ectedtogeneratethatblo ck);thesedesignatedpro ducersare rotatedinaround-robinfashion.Inthisway,ablo ckisatrstsignedonlyby itspro ducingvalidator;then,whenthenextblo ckismined,anditspro ducer cho osestorefertothisblo ckandnottooneofitspredecessors(otherwise itsblo ckwouldlieinashorterchain,whichmightlosethelongestfork comp etitioninthefuture),thesignatureofthenextblo ckisessentiallyan additionalsignatureonthepreviousblo ckaswell.Inthisway,anewblo ck graduallycollectsthesignaturesofmorevalidatorssay,twentysignatures inthetimeneededtogeneratethenexttwentyblo cks.Afullno dewill eitherneedtowaitforthesetwentysignatures,orvalidatetheblo ckby itself,startingfromasucientlyconrmedblo ck(say,twentyblo cksback), whichmightb enotsoeasy. TheobviousdisadvantageoftheDPOSalgorithmisthatanewblo ck (andtransactionscommittedintoit)achievesthesameleveloftrust(re- cursivereliabilityasdiscussedin2.6.28)onlyaftertwentymoreblo cksare mined,comparedtotheBFTalgorithms,whichdeliverthisleveloftrust (say,twentysignatures)immediately.AnotherdisadvantageisthatDPOS usesthelongestforkwinsapproachforswitchingtootherforks;thismakes forksquiteprobableifatleastsomepro ducersfailtopro ducesubsequent blo cksaftertheoneweareinterestedin(orwefailtoobservetheseblo cks b ecauseofanetworkpartitionorasophisticatedattack). Web elievethattheBFTapproach,whilemoresophisticatedtoimple- mentandrequiringlongertimeintervalsb etweenblo cksthanDPOS,isb et- teradaptedtotightly-coupled(cf.2.8.14)multichainsystems,b ecause otherblo ckchainscanstartactingalmostimmediatelyafterseeingacom- mittedtransaction(e.g.,generatingamessageintendedforthem)inanew blo ck,withoutwaitingfortwentyconrmationsofvalidity(i.e.,thenext twentyblo cks),orwaitingforthenextsixblo ckstob esurethatnoforks app earandverifyingthenewblo ckbythemselves(verifyingblo cksofother blo ckchainsmayb ecomeprohibitiveinascalablemulti-chainsystem).Thus theycanachievescalabilitywhilepreservinghighreliabilityandavailability (cf.2.8.12). Ontheotherhand,DPOSmightb eago o dchoiceforalo osely-coupled 66 2.8.ClassificationofBlockchainProjects multi-chainsystem,wherefastinteractionb etweenblo ckchainsisnotre- quirede.g.,ifeachblo ckchain(workchain)representsaseparatedis- tributedexchange,andinter-blo ckchaininteractionislimitedtoraretransfers oftokensfromoneworkchainintoanother(or,rather,tradingonealtcoin residinginoneworkchainforanotheratarateapproaching1 : 1).This iswhatisactuallydoneintheBitSharespro ject,whichusesDPOSquite successfully. Tosummarize,whileDPOScangeneratenewblo cksandincludetrans- actionsintothemfaster(withsmallerintervalsb etweenblo cks),thesetrans- actionsreachtheleveloftrustrequiredtousetheminotherblo ckchainsand o-chainapplicationsascommittedandimmutablemuchmoreslow ly thanintheBFTsystemssay,inthirtyseconds 26 insteadofve.Faster transactioninclusiondo esnotmeanfastertransactioncommitment.This couldb ecomeahugeproblemiffastinter-blo ckchaininteractionisrequired. Inthatcase,onemustabandonDPOSandoptforBFTPoSinstead. 2.8.6.Supp ortforTuring-completeco deintransactions,i.e.,es- sentiallyarbitrarysmartcontracts.Blo ckchainpro jectsnormallycol- lectsometransactionsintheirblo cks,whichaltertheblo ckchainstatein awaydeemeduseful(e.g.,transfersomeamountofcrypto currencyfrom oneaccounttoanother).Someblo ckchainpro jectsmightallowonlysome sp ecicpredenedtyp esoftransactions(suchasvaluetransfersfromoneac- counttoanother,providedcorrectsignaturesarepresented).Othersmight supp ortsomelimitedformofscriptinginthetransactions.Finally,some blo ckchainssupp orttheexecutionofarbitrarilycomplexco deintransactions, enablingthesystem(atleastinprinciple)tosupp ortarbitraryapplications, providedthep erformanceofthesystemp ermits.Thisisusuallyasso ciated withTuring-completevirtualmachinesandscriptinglanguages(meaning thatanyprogramthatcanb ewritteninanyothercomputinglanguagemay b ere-writtentob ep erformedinsidetheblo ckchain),andsmartcontracts (whichareprogramsresidingintheblo ckchain). Ofcourse,supp ortforarbitrarysmartcontractsmakesthesystemtruly exible.Ontheotherhand,thisexibilitycomesatacost:theco deofthese smartcontractsmustb eexecutedonsomevirtualmachine,andthismust b edoneeverytimeforeachtransactionintheblo ckwhensomeb o dywants 26 Forinstance,EOS,oneoftheb estDPOSpro jectsprop oseduptothisdate,promises a45-secondconrmationandinter-blo ckchaininteractiondelay(cf.\[5\],TransactionCon- rmationandLatencyofInterchainCommunicationsections). 67 2.8.ClassificationofBlockchainProjects tocreateorvalidateablo ck.Thisslowsdownthep erformanceofthesystem comparedtothecaseofapredenedandimmutablesetoftyp esofsimple transactions,whichcanb eoptimizedbyimplementingtheirpro cessingina languagesuchasC++(insteadofsomevirtualmachine). Ultimately,supp ortforTuring-completesmartcontractsseemstob ede- sirableinanygeneral-purp oseblo ckchainpro ject;otherwise,thedesigners oftheblo ckchainpro jectmustdecideinadvancewhichapplicationstheir blo ckchainwillb eusedfor.Infact,thelackofsupp ortforsmartcontracts intheBitcoinblo ckchainwastheprincipalreasonwhyanewblo ckchain pro ject,Ethereum,hadtob ecreated. Ina(heterogeneous;cf.2.8.8)multi-chainsystem,onemighthavethe b estofb othworldsbysupp ortingTuring-completesmartcontractsinsome blo ckchains(i.e.,workchains),andasmallpredenedsetofhighly-optimized transactionsinothers. 2.8.7.Classicationofmultichainsystems.Sofar,theclassication wasvalidb othforsingle-chainandmulti-chainsystems.However,multi- chainsystemsadmitseveralmoreclassicationcriteria,reectingtherela- tionshipb etweenthedierentblo ckchainsinthesystem.Wenowdiscuss thesecriteria. 2.8.8.Blo ckchaintyp es:homogeneousandheterogeneoussystems. Inamulti-chainsystem,allblo ckchainsmayb eessentiallyofthesametyp e andhavethesamerules(i.e.,usethesameformatoftransactions,thesame virtualmachineforexecutingsmart-contractco de,sharethesamecrypto cur- rency,andsoon),andthissimilarityisexplicitlyexploited,butwithdierent dataineachblo ckchain.Inthiscase,wesaythatthesystemishomogeneous. Otherwise,dierentblo ckchains(whichwillusuallyb ecalledworkchainsin thiscase)canhavedierentrules.Thenwesaythatthesystemishetero- geneous. 2.8.9.Mixedheterogeneous-homogeneoussystems.Sometimeswe haveamixedsystem,wherethereareseveralsetsoftyp esorrulesfor blo ckchains,butmanyblo ckchainswiththesamerulesarepresent,andthis factisexplicitlyexploited.Thenitisamixedheterogeneous-homogeneous system.Toourknowledge,theTONBlo ckchainistheonlyexampleofsuch asystem. 2.8.10.Heterogeneoussystemswithseveralworkchainshavingthe samerules,orconfederations.Insomecases,severalblo ckchains(work- 68 2.8.ClassificationofBlockchainProjects chains)withthesamerulescanb epresentinaheterogeneoussystem,butthe interactionb etweenthemisthesameasb etweenblo ckchainswithdierent rules(i.e.,theirsimilarityisnotexploitedexplicitly).Eveniftheyapp ear tousethesamecrypto currency,theyinfactusedierentaltcoins(inde- p endentincarnationsofthecrypto currency).Sometimesonecanevenhave certainmechanismstoconvertthesealtcoinsataratenearto1 : 1.How- ever,thisdo esnotmakethesystemhomogeneousinourview;itremains heterogeneous.Wesaythatsuchaheterogeneouscollectionofworkchains withthesamerulesisaconfederation. Whilemakingaheterogeneoussystemthatallowsonetocreateseveral workchainswiththesamerules(i.e.,aconfederation)mayseemacheapway ofbuildingascalablesystem,thisapproachhasalotofdrawbacks,to o. Essentially,ifsomeonehostsalargepro jectinmanyworkchainswiththe samerules,shedo esnotobtainalargepro ject,butratheralotofsmall instancesofthispro ject.Thisislikehavingachatapplication(oragame) thatallowshavingatmost50memb ersinanychat(orgame)ro om,but scalesbycreatingnewro omstoaccommo datemoreuserswhennecessary. Asaresult,alotofuserscanparticipateinthechatsorinthegame,but canwesaythatsuchasystemistrulyscalable? 2.8.11.Presenceofamasterchain,externalorinternal.Sometimes, amulti-chainpro jecthasadistinguishedmasterchain(sometimescalled controlblo ckchain),whichisused,forexample,tostoretheoverallcong- urationofthesystem(thesetofallactiveblo ckchains,orratherworkchains), thecurrentsetofvalidators(foraPro of-of-Stakesystem),andsoon.Some- timesotherblo ckchainsareb oundtothemasterchain,forexamplebycom- mittingthehashesoftheirlatestblo cksintoit(thisissomethingtheTON Blo ckchaindo es,to o). Insomecases,themasterchainisexternal,meaningthatitisnotapart ofthepro ject,butsomeotherpre-existingblo ckchain,originallycompletely unrelatedtoitsusebythenewpro jectandagnosticofit.Forexample,one cantrytousetheEthereumblo ckchainasamasterchainforanexternal pro ject,andpublishsp ecialsmartcontractsintotheEthereumblo ckchain forthispurp ose(e.g.,forelectingandpunishingvalidators). 2.8.12.Shardingsupp ort.Someblo ckchainpro jects(orsystems)have nativesupp ortforsharding,meaningthatseveral(necessarilyhomogeneous; cf.2.8.8)blo ckchainsarethoughtofasshardsofasingle(fromahigh- levelp ersp ective)virtualblo ckchain.Forexample,onecancreate256shard 69 2.8.ClassificationofBlockchainProjects blo ckchains(shardchains)withthesamerules,andkeepthestateofan accountinexactlyoneshardselecteddep endingontherstbyteofits account\_id. Shardingisanaturalapproachtoscalingblo ckchainsystems,b ecause, ifitisprop erlyimplemented,usersandsmartcontractsinthesystemneed notb eawareoftheexistenceofshardingatall.Infact,oneoftenwantsto addshardingtoanexistingsingle-chainpro ject(suchasEthereum)when theloadb ecomesto ohigh. Analternativeapproachtoscalingwouldb etouseaconfederationof heterogeneousworkchainsasdescrib edin2.8.10,allowingeachusertokeep heraccountinoneorseveralworkchainsofherchoice,andtransferfunds fromheraccountinoneworkchaintoanotherworkchainwhennecessary, essentiallyp erforminga1 : 1altcoinexchangeop eration.Thedrawbacksof thisapproachhavealreadyb eendiscussedin2.8.10. However,shardingisnotsoeasytoimplementinafastandreliablefash- ion,b ecauseitimpliesalotofmessagesb etweendierentshardchains.For example,ifaccountsareevenlydistributedb etweenNshards,andtheonly transactionsaresimplefundtransfersfromoneaccounttoanother,thenonly asmallfraction(1/N)ofalltransactionswillb ep erformedwithinasingle blo ckchain;almostall(1−1/N)transactionswillinvolvetwoblo ckchains, requiringinter-blo ckchaincommunication.Ifwewantthesetransactionsto b efast,weneedafastsystemfortransferringmessagesb etweenshardchains. Inotherwords,theblo ckchainpro jectneedstob etightly-coupledinthe sensedescrib edin2.8.14. 2.8.13.Dynamicandstaticsharding.Shardingmightb edynamic(if additionalshardsareautomaticallycreatedwhennecessary)orstatic(when thereisapredenednumb erofshards,whichischangeableonlythrougha hardforkatb est).Mostshardingprop osalsarestatic;theTONBlo ckchain usesdynamicsharding(cf.2.7). 2.8.14.Interactionb etweenblo ckchains:lo osely-coupledandtightly- coupledsystems.Multi-blo ckchainpro jectscanb eclassiedaccordingto thesupp ortedlevelofinteractionb etweentheconstituentblo ckchains. Theleastlevelofsupp ortistheabsenceofanyinteractionb etweendif- ferentblo ckchainswhatso ever.Wedonotconsiderthiscasehere,b ecause wewouldrathersaythattheseblo ckchainsarenotpartsofoneblo ckchain system,butjustseparateinstancesofthesameblo ckchainproto col. 70 2.8.ClassificationofBlockchainProjects Thenextlevelofsupp ortistheabsenceofanysp ecicsupp ortfor messagingb etweenblo ckchains,makinginteractionp ossibleinprinciple, butawkward.Wecallsuchsystemslo osely-coupled;inthemonemust sendmessagesandtransfervalueb etweenblo ckchainsasiftheyhadb een blo ckchainsb elongingtocompletelyseparateblo ckchainpro jects(e.g.,Bit- coinandEthereum;imaginetwopartieswanttoexchangesomeBitcoins, keptintheBitcoinblo ckchain,intoEthers,keptintheEthereumblo ckchain). Inotherwords,onemustincludetheoutb oundmessage(oritsgenerating transaction)inablo ckofthesourceblo ckchain.Thenshe(orsomeother party)mustwaitforenoughconrmations(e.g.,agivennumb erofsubse- quentblo cks)toconsidertheoriginatingtransactiontob ecommittedand immutable,soastob eabletop erformexternalactionsbasedonitsex- istence.Onlythenmayatransactionrelayingthemessageintothetarget blo ckchain(p erhapsalongwithareferenceandaMerklepro ofofexistence fortheoriginatingtransaction)b ecommitted. Ifonedo esnotwaitlongenoughb eforetransferringthemessage,orif aforkhapp ensanywayforsomeotherreason,thejoinedstateofthetwo blo ckchainsturnsouttob einconsistent:amessageisdeliveredintothe secondblo ckchainthathasneverb eengeneratedin(theultimatelychosen forkof )therstblo ckchain. Sometimespartialsupp ortformessagingisadded,bystandardizingthe formatofmessagesandthelo cationofinputandoutputmessagequeuesin theblo cksofallworkchains(thisisesp eciallyusefulinheterogeneoussys- tems).Whilethisfacilitatesmessagingtoacertainextent,itisconceptually notto odierentfromthepreviouscase,sosuchsystemsarestilllo osely- coupled. Bycontrast,tightly-coupledsystemsincludesp ecialmechanismstopro- videfastmessagingb etweenallblo ckchains.Thedesiredb ehavioristob e abletodeliveramessageintoanotherworkchainimmediatelyafterithas b eengeneratedinablo ckoftheoriginatingblo ckchain.Ontheotherhand, tightly-coupledsystemsarealsoexp ectedtomaintainoverallconsistency inthecaseofforks.Whilethesetworequirementsapp eartob econtradictory atrstglance,web elievethatthemechanismsusedbytheTONBlo ckchain (theinclusionofshardchainblo ckhashesintomasterchainblo cks;theuse ofverticalblo ckchainsforxinginvalidblo cks,cf.2.1.17;hyp ercub erout- ing,cf.2.4.19;InstantHyp ercub eRouting,cf.2.4.20)enableittob ea tightly-coupledsystem,p erhapstheonlyonesofar. Ofcourse,buildingalo osely-coupledsystemismuchsimpler;however, 71 2.8.ClassificationofBlockchainProjects fastandecientsharding(cf.2.8.12)requiresthesystemtob etightly- coupled. 2.8.15.Simpliedclassication.Generationsofblo ckchainpro jects. Theclassicationwehavesuggestedsofarsplitsallblo ckchainpro jectsinto alargenumb erofclasses.However,theclassicationcriteriaweusehapp en tob equitecorrelatedinpractice.Thisenablesustosuggestasimplied generationalapproachtotheclassicationofblo ckchainpro jects,asavery roughapproximationofreality,withsomeexamples.Pro jectsthathavenot b eenimplementedanddeployedyetareshowninitalics;themostimp ortant characteristicsofagenerationareshowninb old. ˆFirstgeneration:Single-chain,PoW,nosupp ortforsmartcontracts. Examples:Bitcoin(2009)andalotofotherwiseuninterestingimitators (Litecoin,Monero,. . . ). ˆSecondgeneration:Single-chain,PoW,smart-contractsupp ort.Ex- ample:Ethereum(2013;deployedin2015),atleastinitsoriginalform. ˆThirdgeneration:Single-chain,PoS,smart-contractsupp ort.Exam- ple:futureEthereum(2018orlater). ˆAlternativethird(3 ′ )generation:Multi-chain,PoS,nosupp ortfor smartcontracts,lo osely-coupled.Example:Bitshares(20132014;uses DPOS). ˆFourthgeneration:Multi-chain,PoS,smart-contractsupp ort, lo osely-coupled.Examples:EOS(2017;usesDPOS),PolkaDot(2016; usesBFT). ˆFifthgeneration:Multi-chain,PoSwithBFT,smart-contractsupp ort, tightly-coupled,withsharding.Examples:TON(2017). Whilenotallblo ckchainpro jectsfallpreciselyintooneofthesecategories, mostofthemdo. 2.8.16.Complicationsofchangingthegenomeofablo ckchain pro ject.Theab oveclassicationdenesthegenomeofablo ckchain pro ject.Thisgenomeisquiterigid:itisalmostimp ossibletochangeit oncethepro jectisdeployedandisusedbyalotofp eople.Onewouldneeda seriesofhardforks(whichwouldrequiretheapprovalofthema jorityofthe 72 2.9.ComparisontoOtherBlockchainProjects community),andeventhenthechangeswouldneedtob everyconservative inordertopreservebackwardcompatibility(e.g.,changingthesemantics ofthevirtualmachinemightbreakexistingsmartcontracts).Analterna- tivewouldb etocreatenewsidechainswiththeirdierentrules,andbind themsomehowtotheblo ckchain(ortheblo ckchains)oftheoriginalpro ject. Onemightusetheblo ckchainoftheexistingsingle-blo ckchainpro jectasan externalmasterchainforanessentiallynewandseparatepro ject. 27 Ourconclusionisthatthegenomeofapro jectisveryhardtochange onceithasb eendeployed.EvenstartingwithPoWandplanningtoreplace itwithPoSinthefutureisquitecomplicated. 28 Addingshardstoapro ject originallydesignedwithoutsupp ortforthemseemsalmostimp ossible. 29 In fact,addingsupp ortforsmartcontractsintoapro ject(namely,Bitcoin) originallydesignedwithoutsupp ortforsuchfeatureshasb eendeemedim- p ossible(oratleastundesirablebythema jorityoftheBitcoincommunity) andeventuallyledtothecreationofanewblo ckchainpro ject,Ethereum. 2.8.17.GenomeoftheTONBlo ckchain.Therefore,ifonewantsto buildascalableblo ckchainsystem,onemustcho oseitsgenomecarefully fromtheveryb eginning.Ifthesystemismeanttosupp ortsomeadditional sp ecicfunctionalityinthefuturenotknownatthetimeofitsdeployment, itshouldsupp ortheterogeneousworkchains(havingp otentiallydierent rules)fromthestart.Forthesystemtob etrulyscalable,itmustsupp ort shardingfromtheveryb eginning;shardingmakessenseonlyifthesystem istightly-coupled(cf.2.8.14),sothisinturnimpliestheexistenceofa masterchain,afastsystemofinter-blo ckchainmessaging,usageofBFTPoS, andsoon. Whenonetakesintoaccountalltheseimplications,mostofthedesign choicesmadefortheTONBlo ckchainpro jectapp earnatural,andalmost theonlyonesp ossible. 27 Forexample,thePlasmapro jectplanstousetheEthereumblo ckchainasits(external) masterchain;itdo esnotinteractmuchwithEthereumotherwise,anditcouldhaveb een suggestedandimplementedbyateamunrelatedtotheEthereumpro ject. 28 Asof2017,EthereumisstillstrugglingtotransitionfromPoWtoacombined PoW+PoSsystem;wehop eitwillb ecomeatrulyPoSsystemsomeday. 29 Thereareshardingprop osalsforEthereumdatingbackto2015;itisunclearhow theymightb eimplementedanddeployedwithoutdisruptingEthereumorcreatingan essentiallyindep endentparallelpro ject. 73 2.9.ComparisontoOtherBlockchainProjects Pro jectYearG.Cons.Sm.Ch.R.Sh.Int. Bitcoin20091PoWno1 Ethereum2013,20152PoWyes1 NXT20142+PoSno1 Tezos2017,?2+PoSyes1 Casp er2015,(2017)3PoW/PoSyes1 BitShares2013,20143 ′ DPoSnomht.noL EOS2016,(2018)4DPoSyesmht.noL PolkaDot2016,(2019)4PoSBFTyesmht.noL Cosmos2017,?4PoSBFTyesmht.noL TON2017,(2018)5PoSBFTyesmmixdyn.T Table1:Asummaryofsomenotableblo ckchainpro jects.Thecolumnsare:Projectpro jectname; Yearyearannouncedandyeardeployed;G.generation(cf.2.8.15);Cons.consensusalgorithm (cf.2.8.3and2.8.4);Sm.supp ortforarbitraryco de(smartcontracts;cf.2.8.6);Ch.single/multiple blo ckchainsystem(cf.2.8.2);R.heterogeneous/homogeneousmultichainsystems(cf.2.8.8);Sh. shardingsupp ort(cf.2.8.12);Int.interactionb etweenblo ckchains,(L)o oseor(T)ight(cf.2.8.14). 2.9ComparisontoOtherBlo ckchainPro jects WeconcludeourbriefdiscussionoftheTONBlo ckchainanditsmostimp or- tantanduniquefeaturesbytryingtondaplaceforitonamapcontaining existingandprop osedblo ckchainpro jects.Weusetheclassicationcriteria describ edin2.8todiscussdierentblo ckchainpro jectsinauniformway andconstructsuchamapofblo ckchainpro jects.Werepresentthismapas Table1,andthenbrieydiscussafewpro jectsseparatelytop ointouttheir p eculiaritiesthatmaynottintothegeneralscheme. 2.9.1.Bitcoin\[12\];https://bitcoin.org/.Bitcoin(2009)istherstand themostfamousblo ckchainpro ject.Itisatypicalrst-generationblo ckchain pro ject:itissingle-chain,itusesPro of-of-Workwithalongest-fork-wins forkselectionalgorithm,anditdo esnothaveaTuring-completescripting language(however,simplescriptswithoutlo opsaresupp orted).TheBit- coinblo ckchainhasnonotionofanaccount;itusestheUTXO(Unsp ent TransactionOutput)mo delinstead. 2.9.2.Ethereum\[2\];https://ethereum.org/.Ethereum(2015)isthe rstblo ckchainwithsupp ortforTuring-completesmartcontracts.Assuch, itisatypicalsecond-generationpro ject,andthemostp opularamongthem. ItusesPro of-of-Workonasingleblo ckchain,buthassmartcontractsand accounts. 74 2.9.ComparisontoOtherBlockchainProjects 2.9.3.NXT;https://nxtplatform.org/.NXT(2014)istherstPoS- basedblo ckchainandcurrency.Itisstillsingle-chain,andhasnosmart contractsupp ort. 2.9.4.Tezos;https://www.tezos.com/.Tezos(2018orlater)isapro- p osedPoS-basedsingle-blo ckchainpro ject.Wementionithereb ecauseof itsuniquefeature:itsblo ckinterpretationfunctionev\_block(cf.2.2.6)is notxed,butisdeterminedbyanOCamlmo dule,whichcanb eupgraded bycommittinganewversionintotheblo ckchain(andcollectingsomevotes fortheprop osedchange).Inthisway,onewillb eabletocreatecustom single-chainpro jectsbyrstdeployingavanillaTezosblo ckchain,andthen graduallychangingtheblo ckinterpretationfunctioninthedesireddirection, withoutanyneedforhardforks. Thisidea,whileintriguing,hastheobviousdrawbackthatitforbidsany optimizedimplementationsinotherlanguageslikeC++,soaTezos-based blo ckchainisdestinedtohavelowerp erformance.Wethinkthatasimilar resultmighthaveb eenobtainedbypublishingaformalspecicationofthe prop osedblo ckinterpretationfunctionev\_trans,withoutxingaparticular implementation. 2.9.5.Casp er. 30 Casperisanup comingPoSalgorithmforEthereum;its gradualdeploymentin2017(or2018),ifsuccessful,willchangeEthereuminto asingle-chainPoSormixedPoW+PoSsystemwithsmartcontractsupp ort, transformingEthereumintoathird-generationpro ject. 2.9.6.BitShares\[8\];https://bitshares.org.BitShares(2014)isaplat- formfordistributedblo ckchain-basedexchanges.Itisaheterogeneousmulti- blo ckchainDPoSsystemwithoutsmartcontracts;itachievesitshighp er- formancebyallowingonlyasmallsetofpredenedsp ecializedtransaction typ es,whichcanb eecientlyimplementedinC++,assumingtheblo ckchain statetsintomemory.Itisalsotherstblo ckchainpro jecttouseDelegated Pro of-of-Stake(DPoS),demonstratingitsviabilityatleastforsomesp ecial- izedpurp oses. 2.9.7.EOS\[5\];https://eos.io.EOS(2018orlater)isaprop osedhet- erogeneousmulti-blo ckchainDPoSsystemwithsmartcontractsupp ortand withsomeminimalsupp ortformessaging(stilllo osely-coupledinthesense describ edin2.8.14).Itisanattemptbythesameteamthathaspreviously 30 https://blog.ethereum.org/2015/08/01/introducing- casper- friendly- ghost/ 75 2.9.ComparisontoOtherBlockchainProjects successfullycreatedtheBitSharesandSteemItpro jects,demonstratingthe strongp ointsoftheDPoSconsensusalgorithm.Scalabilitywillb eachieved bycreatingsp ecializedworkchainsforpro jectsthatneedit(e.g.,adistributed exchangemightuseaworkchainsupp ortingasp ecialsetofoptimizedtrans- actions,similarlytowhatBitSharesdid)andbycreatingmultipleworkchains withthesamerules(confederationsinthesensedescrib edin2.8.10).The drawbacksandlimitationsofthisapproachtoscalabilityhaveb eendiscussed inloc.cit.Cf.also2.8.5,2.8.12,and2.8.14foramoredetaileddiscussion ofDPoS,sharding,interactionb etweenworkchainsandtheirimplicationsfor thescalabilityofablo ckchainsystem. Atthesametime,evenifonewillnotb eabletocreateaFaceb o ok insideablo ckchain(cf.2.9.13),EOSorotherwise,wethinkthatEOSmight b ecomeaconvenientplatformforsomehighly-sp ecializedweaklyinteracting distributedapplications,similartoBitShares(decentralizedexchange)and SteemIt(decentralizedblogplatform). 2.9.8.PolkaDot\[17\];https://polkadot.io/.PolkaDot(2019orlater) isoneoftheb estthought-outandmostdetailedprop osedmultichainPro of- of-Stakepro jects;itsdevelopmentisledbyoneoftheEthereumco-founders. Thispro jectisoneoftheclosestpro jectstotheTONBlo ckchainonourmap. (Infact,weareindebtedforourterminologyforshermenandnominators tothePolkaDotpro ject.) PolkaDotisaheterogeneouslo osely-coupledmultichainPro of-of-Stake pro ject,withByzantineFaultTolerant(BFT)consensusforgenerationof newblo cksandamasterchain(whichmightb eexternale.g.,theEthereum blo ckchain).Italsouseshyp ercub erouting,somewhatlike(theslowversion of )TON'sasdescrib edin2.4.19. Itsuniquefeatureisitsabilitytocreatenotonlypublic,butalsoprivate blo ckchains.Theseprivateblo ckchainswouldalsob eabletointeractwith otherpublicblo ckchains,PolkaDotorotherwise. Assuch,PolkaDotmightb ecomeaplatformforlarge-scaleprivateblo ck- chains,whichmightb eused,forexample,bybankconsortiumstoquickly transferfundstoeachother,orforanyotherusesalargecorp orationmight haveforprivateblo ckchaintechnology. However,PolkaDothasnoshardingsupp ortandisnottightly-coupled. Thissomewhathamp ersitsscalability,whichissimilartothatofEOS.(Per- hapsabitb etter,b ecausePolkaDotusesBFTPoSinsteadofDPoS.) 2.9.9.Universa;https://universa.io.Theonlyreasonwementionthis 76 2.9.ComparisontoOtherBlockchainProjects unusualblo ckchainpro jecthereisb ecauseitistheonlypro jectsofarto makeinpassinganexplicitreferencetosomethingsimilartoourInnite ShardingParadigm(cf.2.1.2).Itsotherp eculiarityisthatitbypassesall complicationsrelatedtoByzantineFaultTolerancebypromisingthatonly trustedandlicensedpartnersofthepro jectwillb eadmittedasvalidators, hencetheywillnevercommitinvalidblo cks.Thisisaninterestingdecision; however,itessentiallymakesablo ckchainpro jectdelib eratelycentralized, somethingblo ckchainpro jectsusuallywanttoavoid(whydo esoneneeda blo ckchainatalltoworkinatrustedcentralizedenvironment?). 2.9.10.Plasma;https://plasma.io).Plasma(2019?)isanunconven- tionalblo ckchainpro jectfromanotherco-founderofEthereum.Itissup- p osedtomitigatesomelimitationsofEthereumwithoutintro ducingshard- ing.Inessence,itisaseparatepro jectfromEthereum,intro ducingahier- archyof(heterogeneous)workchains,b oundtotheEthereumblo ckchain(to b eusedasanexternalmasterchain)atthetoplevel.Fundscanb etrans- ferredfromanyblo ckchainupinthehierarchy(startingfromtheEthereum blo ckchainasthero ot),alongwithadescriptionofajobtob edone.Then thenecessarycomputationsaredoneinthechildworkchain(p ossiblyre- quiringforwardingofpartsoftheoriginaljobfurtherdownthetree),their resultsarepassedup,andarewardiscollected.Theproblemofachieving consistencyandvalidatingtheseworkchainsiscircumventedbya(payment channel-inspired)mechanismallowinguserstounilaterallywithdrawtheir fundsfromamisb ehavingworkchaintoitsparentworkchain(alb eitslowly), andre-allo catetheirfundsandtheirjobstoanotherworkchain. Inthisway,Plasmamightb ecomeaplatformfordistributedcompu- tationsb oundtotheEthereumblo ckchain,somethinglikeamathematical co-pro cessor.However,thisdo esnotseemlikeawaytoachievetruegeneral- purp osescalability. 2.9.11.Sp ecializedblo ckchainpro jects.Therearealsosomesp ecialized blo ckchainpro jects,suchasFileCoin(asystemthatincentivizesuserstooer theirdiskspaceforstoringthelesofotheruserswhoarewillingtopayfor it),Golem(ablo ckchain-basedplatformforrentingandlendingcomputing p owerforsp ecializedapplicationssuchas3D-rendering)orSONM(another similarcomputingp ower-lendingpro ject).Suchpro jectsdonotintro duce anythingconceptuallynewonthelevelofblo ckchainorganization;rather, theyareparticularblo ckchainapplications,whichcouldb eimplementedby smartcontractsrunninginageneral-purp oseblo ckchain,provideditcan 77 2.9.ComparisontoOtherBlockchainProjects delivertherequiredp erformance.Assuch,pro jectsofthiskindarelikely touseoneoftheexistingorplannedblo ckchainpro jectsastheirbase,such asEOS,PolkaDotorTON.Ifapro jectneedstruescalability(basedon sharding),itwouldb etteruseTON;ifitiscontenttoworkinaconfederated contextbydeningafamilyofworkchainsofitsown,explicitlyoptimized foritspurp ose,itmightoptforEOSorPolkaDot. 2.9.12.TheTONBlo ckchain.TheTON(TheOp enNetwork)Blo ck- chain(planned2018)isthepro jectwearedescribinginthisdo cument.Itis designedtob etherstfth-generationblo ckchainpro jectthatis,aBFT PoS-multichainpro ject,mixedhomogeneous/heterogeneous,withsupp ort for(shardable)customworkchains,withnativeshardingsupp ort,andtightly- coupled(inparticular,capableofforwardingmessagesb etweenshardsalmost instantlywhilepreservingaconsistentstateofallshardchains).Assuch, itwillb eatrulyscalablegeneral-purp oseblo ckchainpro ject,capableof accommo datingessentiallyanyapplicationsthatcanb eimplementedina blo ckchainatall.Whenaugmentedbytheothercomp onentsoftheTON Pro ject(cf.1),itsp ossibilitiesexpandevenfurther. 2.9.13.Isitp ossibletouploadFaceb o okintoablo ckchain?Some- timesp eopleclaimthatitwillb ep ossibletoimplementaso cialnetworkon thescaleofFaceb o okasadistributedapplicationresidinginablo ckchain. Usuallyafavoriteblo ckchainpro jectiscitedasap ossiblehostforsuchan application. Wecannotsaythatthisisatechnicalimp ossibility.Ofcourse,oneneeds atightly-coupledblo ckchainpro jectwithtruesharding(i.e.,TON)inorder forsuchalargeapplicationnottoworkto oslowly(e.g.,delivermessages andup datesfromusersresidinginoneshardchaintotheirfriendsresidingin anothershardchainwithreasonabledelays).However,wethinkthatthisis notneededandwillneverb edone,b ecausethepricewouldb eprohibitive. LetusconsideruploadingFaceb o okintoablo ckchainasathoughtex- p eriment;anyotherpro jectofsimilarscalemightserveasanexampleaswell. OnceFaceb o okisuploadedintoablo ckchain,allop erationscurrentlydone byFaceb o ok'sserverswillb eserializedastransactionsincertainblo ckchains (e.g.,TON'sshardchains),andwillb ep erformedbyallvalidatorsofthese blo ckchains.Eachop erationwillhavetob ep erformed,say,atleasttwenty times,ifweexp ecteveryblo cktocollectatleasttwentyvalidatorsignatures (immediatelyoreventually,asinDPOSsystems).Similarly,alldatakeptby 78 2.9.ComparisontoOtherBlockchainProjects Faceb o ok'sserversontheirdiskswillb ekeptonthedisksofallvalidators forthecorresp ondingshardchain(i.e.,inatleasttwentycopies). Becausethevalidatorsareessentiallythesameservers(orp erhapsclus- tersofservers,butthisdo esnotaectthevalidityofthisargument)asthose currentlyusedbyFaceb o ok,weseethatthetotalhardwareexp ensesasso ci- atedwithrunningFaceb o okinablo ckchainareatleasttwentytimeshigher thanifitwereimplementedintheconventionalway. Infact,theexp enseswouldb emuchhigherstill,b ecausetheblo ckchain's virtualmachineisslowerthanthebareCPUrunningoptimizedcompiled co de,anditsstorageisnotoptimizedforFaceb o ok-sp ecicproblems.One mightpartiallymitigatethisproblembycraftingasp ecicworkchainwith somesp ecialtransactionsadaptedforFaceb o ok;thisistheapproachof BitSharesandEOStoachievinghighp erformance,availableintheTON Blo ckchainaswell.However,thegeneralblo ckchaindesignwouldstillim- p osesomeadditionalrestrictionsbyitself,suchasthenecessitytoregister allop erationsastransactionsinablo ck,toorganizethesetransactionsina Merkletree,tocomputeandchecktheirMerklehashes,topropagatethis blo ckfurther,andsoon. Therefore,aconservativeestimateisthatonewouldneed100timesmore serversofthesamep erformanceasthoseusedbyFaceb o oknowinorderto validateablo ckchainpro jecthostingaso cialnetworkofthatscale.Some- b o dywillhavetopayfortheseservers,eitherthecompanyowningthedis- tributedapplication(imagineseeing700adsoneachFaceb o okpageinstead of7)oritsusers.Eitherway,thisdo esnotseemeconomicallyviable. Web elievethatitisnottruethateverythingshouldbeuploadedintothe blockchain.Forexample,itisnotnecessarytokeepuserphotographsinthe blo ckchain;registeringthehashesofthesephotographsintheblo ckchainand keepingthephotographsinadistributedo-chainstorage(suchasFileCoin orTONStorage)wouldb eab etteridea.ThisisthereasonwhyTONisnot justablo ckchainpro ject,butacollectionofseveralcomp onents(TONP2P Network,TONStorage,TONServices)centeredaroundtheTONBlo ckchain asoutlinedinChapters1and4. 79 3.1.AbstractDatagramNetworkLayer 3TONNetworking Anyblo ckchainpro jectrequiresnotonlyasp ecicationofblo ckformatand blo ckchainvalidationrules,butalsoanetworkproto colusedtopropagate newblo cks,sendandcollecttransactioncandidatesandsoon.Inother words,asp ecializedp eer-to-p eernetworkmustb esetupbyeveryblo ckchain pro ject.Thisnetworkmustb ep eer-to-p eer,b ecauseblo ckchainpro jectsare normallyexp ectedtob edecentralized,soonecannotrelyonacentralized groupofserversanduseconventionalclient-serverarchitecture,as,forin- stance,classicalonlinebankingapplicationsdo.Evenlightclients(e.g.,light crypto currencywalletsmartphoneapplications),whichmustconnecttofull no desinaclient-serverlikefashion,areactuallyfreetoconnecttoanother fullno deiftheirpreviousp eergo esdown,providedtheproto colusedto connecttofullno desisstandardizedenough. Whilethenetworkingdemandsofsingle-blo ckchainpro jects,suchasBit- coinorEthereum,canb emetquiteeasily(oneessentiallyneedstoconstruct arandomp eer-to-p eeroverlaynetwork,andpropagateallnewblo cksand transactioncandidatesbyagossipproto col),multi-blo ckchainpro jects,such astheTONBlo ckchain,aremuchmoredemanding(e.g.,onemustb eableto subscrib etoup datesofonlysomeshardchains,notnecessarilyallofthem). Therefore,thenetworkingpartoftheTONBlo ckchainandtheTONPro ject asawholemeritsatleastabriefdiscussion. Ontheotherhand,oncethemoresophisticatednetworkproto colsneeded tosupp orttheTONBlo ckchainareinplace,itturnsoutthattheycaneasily b eusedforpurp osesnotnecessarilyrelatedtotheimmediatedemandsofthe TONBlo ckchain,thusprovidingmorep ossibilitiesandexibilityforcreating newservicesintheTONecosystem. 3.1AbstractDatagramNetworkLayer ThecornerstoneinbuildingtheTONnetworkingproto colsisthe(TON) Abstract(Datagram)NetworkLayer.Itenablesallno destoassumecertain networkidentities,representedby256-bitabstractnetworkaddresses,and communicate(senddatagramstoeachother,asarststep)usingonlythese 256-bitnetworkaddressestoidentifythesenderandthereceiver.Inpartic- ular,onedo esnotneedtoworryab outIPv4orIPv6addresses,UDPp ort numb ers,andthelike;theyarehiddenbytheAbstractNetworkLayer. 80 3.1.AbstractDatagramNetworkLayer 3.1.1.Abstractnetworkaddresses.Anabstractnetworkaddress,oran abstractaddress,orjustaddressforshort,isa256-bitinteger,essentially equaltoa256-bitECCpublickey.Thispublickeycanb egeneratedarbi- trarily,thuscreatingasmanydierentnetworkidentitiesastheno delikes. However,onemustknowthecorresp ondingprivatekeyinordertoreceive (anddecrypt)messagesintendedforsuchanaddress. Infact,theaddressisnotthepublickeyitself;instead,itisa256-bit hash(Hash=sha256)ofaserializedTL-ob ject(cf.2.2.5)thatcandescrib e severaltyp esofpublickeysandaddressesdep endingonitsconstructor(rst fourbytes).Inthesimplestcase,thisserializedTL-ob jectconsistsjustofa 4-bytemagicnumb eranda256-bitellipticcurvecryptography(ECC)public key;inthiscase,theaddresswillequalthehashofthis36-bytestructure. Onemightuse,however,2048-bitRSAkeys,oranyotherschemeofpublic- keycryptographyinstead. Whenano delearnsanotherno de'sabstractaddress,itmustalsoreceive itspreimage(i.e.,theserializedTL-ob ject,thehashofwhichequalsthat abstractaddress)orelseitwillnotb eabletoencryptandsenddatagrams tothataddress. 3.1.2.Lower-levelnetworks.UDPimplementation.Fromthep er- sp ectiveofalmostallTONNetworkingcomp onents,theonlythingthat existsisanetwork(theAbstractDatagramNetworkingLayer)ableto(un- reliably)senddatagramsfromoneabstractaddresstoanother.Inprinciple, theAbstractDatagramNetworkingLayer(ADNL)canb eimplementedover dierentexistingnetworktechnologies.However,wearegoingtoimplement itoverUDPinIPv4/IPv6networks(suchastheInternetorintranets),with anoptionalTCPfallbackifUDPisnotavailable. 3.1.3.SimplestcaseofADNLoverUDP.Thesimplestcaseofsending adatagramfromasender'sabstractaddresstoanyotherabstractaddress (withknownpreimage)canb eimplementedasfollows. Supp osethatthesendersomehowknowstheIP-addressandtheUDP p ortofthereceiverwhoownsthedestinationabstractaddress,andthat b oththereceiverandthesenderuseabstractaddressesderivedfrom256-bit ECCpublickeys. Inthiscase,thesendersimplyaugmentsthedatagramtob esentbyits ECCsignature(donewithitsprivatekey)anditssourceaddress(orthe preimageofthesourceaddress,ifthereceiverisnotknowntoknowthat 81 3.1.AbstractDatagramNetworkLayer preimageyet).Theresultisencryptedwiththerecipient'spublickey,em- b eddedintoaUDPdatagramandsenttotheknownIPandp ortofthe recipient.Becausetherst256bitsoftheUDPdatagramcontaintherecip- ient'sabstractaddress,therecipientcanidentifywhichprivatekeyshould b eusedtodecrypttheremainderofthedatagram.Onlyafterthatisthe sender'sidentityrevealed. 3.1.4.Lesssecureway,withthesender'saddressinplaintext.Some- timesalesssecureschemeissucient,whentherecipient'sandthesender's addressesarekeptinplaintextintheUDPdatagram;thesender'sprivate keyandtherecipient'spublickeyarecombinedtogetherusingECDH(Ellip- ticCurveDieHellman)togeneratea256-bitsharedsecret,whichisused afterwards,alongwitharandom256-bitnoncealsoincludedintheunen- cryptedpart,toderiveAESkeysusedforencryption.Theintegritymayb e provided,forinstance,byconcatenatingthehashoftheoriginalplaintext datatotheplaintextb eforeencryption. Thisapproachhastheadvantagethat,ifmorethanonedatagramis exp ectedtob eexchangedb etweenthetwoaddresses,thesharedsecretcan b ecomputedonlyonceandthencached;thenslowerellipticcurveop erations willnolongerb erequiredforencryptingordecryptingthenextdatagrams. 3.1.5.Channelsandchannelidentiers.Inthesimplestcase,therst 256bitsofaUDPdatagramcarryinganemb eddedTONADNLdatagram willb eequaltotherecipient'saddress.However,ingeneraltheyconstitute achannelidentier.Therearedierenttyp esofchannels.Someofthem arep oint-to-p oint;theyarecreatedbytwopartieswhowishtoexchangea lotofdatainthefutureandgenerateasharedsecretbyexchangingseveral packetsencryptedasdescrib edin3.1.3or3.1.4,byrunningclassicalor ellipticcurveDieHellman(ifextrasecurityisrequired),orsimplybyone partygeneratingarandomsharedsecretandsendingittotheotherparty. Afterthat,achannelidentierisderivedfromthesharedsecretcombined withsomeadditionaldata(suchasthesender'sandrecipient'saddresses), forinstancebyhashing,andthatidentierisusedastherst256bitsof UDPdatagramscarryingdataencryptedwiththeaidofthatsharedsecret. 3.1.6.Channelasatunnelidentier.Ingeneral,achannel,orchan- nelidentiersimplyselectsawayofpro cessinganinb oundUDPdatagram, knowntothereceiver.Ifthechannelisthereceiver'sabstractaddress,the pro cessingisdoneasoutlinedin3.1.3or3.1.4;ifthechannelisanestab- 82 3.1.AbstractDatagramNetworkLayer lishedp oint-to-p ointchanneldiscussedin3.1.5,thepro cessingconsistsin decryptingthedatagramwiththeaidofthesharedsecretasexplainedin loc.cit.,andsoon. Inparticular,achannelidentiercanactuallyselectatunnel,when theimmediaterecipientsimplyforwardsthereceivedmessagetosomeb o dy elsetheactualrecipientoranotherproxy.Someencryptionordecryption steps(reminiscentofonionrouting\[6\]orevengarlicrouting 31 )mightb e donealongtheway,andanotherchannelidentiermightb eusedforre- encryptedforwardedpackets(forexample,ap eer-to-p eerchannelcouldb e employedtoforwardthepackettothenextrecipientonthepath). Inthisway,somesupp ortfortunnelingandproxyingsomewhatsim- ilartothatprovidedbytheTORorI 2 Ppro jectscanb eaddedonthelevel oftheTONAbstractDatagramNetworkLayer,withoutaectingthefunc- tionalityofallhigher-levelTONnetworkproto cols,whichwouldb eagnostic ofsuchanaddition.Thisopp ortunityisexploitedbytheTONProxyservice (cf.4.1.10). 3.1.7.Zerochannelandtheb o otstrapproblem.Normally,aTON ADNLno dewillhavesomeneighb ortable,containinginformationab out otherknownno des,suchastheirabstractaddressesandtheirpreimages(i.e., publickeys)andtheirIPaddressesandUDPp orts.Thenitwillgradually extendthistablebyusinginformationlearnedfromtheseknownno desas answerstosp ecialqueries,andsometimespruneobsoleterecords. However,whenaTONADNLno dejuststartsup,itmayhapp enthatit do esnotknowanyotherno de,andcanlearnonlytheIPaddressandUDP p ortofano de,butnotitsabstractaddress.Thishapp ens,forexample,if alightclientisnotabletoaccessanyofthepreviouslycachedno desand anyno deshardco dedintothesoftware,andmustasktheusertoenteranIP addressoraDNSdomainofano de,tob eresolvedthroughDNS. Inthiscase,theno dewillsendpacketstoasp ecialzerochannelofthe no deinquestion.Thisdo esnotrequireknowledgeoftherecipient'spublic key(butthemessageshouldstillcontainthesender'sidentityandsignature), sothemessageistransferredwithoutencryption.Itshouldb enormallyused onlytoobtainanidentity(mayb eaone-timeidentitycreatedesp eciallyfor thispurp ose)ofthereceiver,andthentostartcommunicatinginasaferway. Onceatleastoneno deisknown,itiseasytop opulatetheneighb or tableandroutingtablebymoreentries,learningthemfromanswersto 31 https://geti2p.net/en/docs/how/garlic- routing 83 3.2.TONDHT:Kademlia-likeDistributedHashTable sp ecialqueriessenttothealreadyknownno des. Notallno desarerequiredtopro cessdatagramssenttothezerochannel, butthoseusedtob o otstraplightclientsshouldsupp ortthisfeature. 3.1.8.TCP-likestreamproto coloverADNL.TheADNL,b einganun- reliable(small-size)datagramproto colbasedon256-bitabstractaddresses, canb eusedasabaseformoresophisticatednetworkproto cols.Onecan build,forexample,aTCP-likestreamproto col,usingADNLasanabstract replacementforIP.However,mostcomp onentsoftheTONPro jectdonot needsuchastreamproto col. 3.1.9.RLDP,orReliableLargeDatagramProto coloverADNL.A reliablearbitrary-sizedatagramproto colbuiltup ontheADNL,calledRLDP, isusedinsteadofaTCP-likeproto col.Thisreliabledatagramproto colcan b eemployed,forinstance,tosendRPCqueriestoremotehostsandreceive answersfromthem(cf.4.1.5). 3.2TONDHT:Kademlia-likeDistributedHashTable TheTONDistributedHashTable(DHT)playsacrucialroleinthenet- workingpartoftheTONPro ject,b eingusedtolo cateotherno desinthe network.Forexample,aclientwantingtocommitatransactionintoashard- chainmightwanttondavalidatororacollatorofthatshardchain,orat leastsomeno dethatmightrelaytheclient'stransactiontoacollator.This canb edonebylo okingupasp ecialkeyintheTONDHT.Anotherimp or- tantapplicationoftheTONDHTisthatitcanb eusedtoquicklyp opulate anewno de'sneighb ortable(cf.3.1.7),simplybylo okinguparandomkey, orthenewno de'saddress.Ifano deusesproxyingandtunnelingforitsin- b ounddatagrams,itpublishesthetunnelidentieranditsentryp oint(e.g., IPaddressandUDPp ort)intheTONDHT;thenallno deswishingtosend datagramstothatno dewillobtainthiscontactinformationfromtheDHT rst. TheTONDHTisamemb erofthefamilyofKademlia-likedistributed hashtables\[10\]. 3.2.1.KeysoftheTONDHT.ThekeysoftheTONDHTaresimply256- bitintegers.Inmostcases,theyarecomputedassha256ofaTL-serialized ob ject(cf.2.2.5),calledpreimageofthekey,orkeydescription.Insome cases,theabstractaddressesoftheTONNetworkno des(cf.3.1.1)canalso 84 3.2.TONDHT:Kademlia-likeDistributedHashTable b eusedaskeysoftheTONDHT,b ecausetheyarealso256-bit,andtheyare alsohashesofTL-serializedob jects.Forexample,ifano deisnotafraidof publishingitsIPaddress,itcanb efoundbyanyb o dywhoknowsitsabstract addressbysimplylo okingupthataddressasakeyintheDHT. 3.2.2.ValuesoftheDHT.Thevaluesassignedtothese256-bitkeysare essentiallyarbitrarybytestringsoflimitedlength.Theinterpretationof suchbytestringsisdeterminedbythepreimageofthecorresp ondingkey;it isusuallyknownb othbytheno dethatlo oksupthekey,andbytheno de thatstoresthekey. 3.2.3.No desoftheDHT.Semi-p ermanentnetworkidentities.The key-valuemappingoftheTONDHTiskeptonthenodesoftheDHT essentially,allmemb ersoftheTONNetwork.Tothisend,anyno deofthe TONNetwork(p erhapswiththeexceptionofsomeverylightno des),apart fromanynumb erofephemeralandp ermanentabstractaddressesdescrib ed in3.1.1,hasatleastonesemi-p ermanentaddress,whichidentiesitasa memb eroftheTONDHT.Thissemi-permanentorDHTaddressshouldnot tob echangedto ooften,otherwiseotherno deswouldb eunabletolo catethe keystheyarelo okingfor.Ifano dedo esnotwanttorevealitstrueidentity, itgeneratesaseparateabstractaddresstob eusedonlyforthepurp oseof participatingintheDHT.However,thisabstractaddressmustb epublic, b ecauseitwillb easso ciatedwiththeno de'sIPaddressandp ort. 3.2.4.Kademliadistance.Nowwehaveb oth256-bitkeysand256-bit (semi-p ermanent)no deaddresses.Weintro ducetheso-calledXORdistance orKademliadistanced K onthesetof256-bitsequences,givenby d K (x,y) := (x⊕y)interpretedasanunsigned256-bitinteger(25) Herex⊕ydenotesthebitwiseeXclusiveOR(XOR)oftwobitsequencesof thesamelength. TheKademliadistanceintro ducesametricontheset2 256 ofall256-bit sequences.Inparticular,wehaved K (x,y) = 0ifandonlyifx=y,d K (x,y) = d K (y,x),andd K (x,z)≤d K (x,y) +d K (y,z).Anotherimp ortantprop ertyis thatthereisonlyonepointatanygivendistancefromx:d K (x,y) =d K (x,y ′ ) impliesy=y ′ . 3.2.5.Kademlia-likeDHTsandtheTONDHT.Wesaythatadis- tributedhashtable(DHT)with256-bitkeysand256-bitno deaddressesisa 85 3.2.TONDHT:Kademlia-likeDistributedHashTable Kademlia-likeDHTifitisexp ectedtokeepthevalueofkeyKonsKademlia- nearestno destoK(i.e.,thesno deswithsmallestKademliadistancefrom theiraddressestoK.) Heresisasmallparameter,say,s= 7,neededtoimprovereliabilityof theDHT(ifwewouldkeepthekeyonlyononeno de,thenearestonetoK, thevalueofthatkeywouldb elostifthatonlyno dego esoine). TheTONDHTisaKademlia-likeDHT,accordingtothisdenition.It isimplementedovertheADNLproto coldescrib edin3.1. 3.2.6.Kademliaroutingtable.Anyno departicipatinginaKademlia- likeDHTusuallymaintainsaKademliaroutingtable.InthecaseofTON DHT,itconsistsofn= 256buckets,numb eredfrom0ton−1.Thei-th bucketwillcontaininformationab outsomeknownno des(axednumb ert ofb estno des,andmayb esomeextracandidates)thatlieataKademlia distancefrom2 i to2 i+1 −1fromtheno de'saddressa. 32 Thisinformation includestheir(semi-p ermanent)addresses,IPaddressesandUDPp orts,and someavailabilityinformationsuchasthetimeandthedelayofthelastping. WhenaKademliano delearnsab outanyotherKademliano deasaresult ofsomequery,itincludesitintoasuitablebucketofitsroutingtable,rst asacandidate.Then,ifsomeoftheb estno desinthatbucketfail(e.g.,do notresp ondtopingqueriesforalongtime),theycanb ereplacedbysome ofthecandidates.InthiswaytheKademliaroutingtablestaysp opulated. Newno desfromtheKademliaroutingtablearealsoincludedinthe ADNLneighb ortabledescrib edin3.1.7.Ifab estno defromabucketof theKademliaroutingtableisusedoften,achannelinthesensedescrib ed in3.1.5canb eestablishedtofacilitatetheencryptionofdatagrams. Asp ecialfeatureoftheTONDHTisthatittriestoselectno deswiththe smallestround-tripdelaysastheb estno desforthebucketsoftheKademlia routingtable. 3.2.7.(Kademlianetworkqueries.)AKademliano deusuallysupp ortsthe followingnetworkqueries: ˆPingChecksno deavailability. 32 Iftherearesucientlymanyno desinabucket,itcanb esub dividedfurtherinto,say, eightsub-bucketsdep endingonthetopfourbitsoftheKademliadistance.Thiswould sp eedupDHTlo okups. 86 3.2.TONDHT:Kademlia-likeDistributedHashTable ˆStore(key,value)Askstheno detokeepvalueasavalueforkey key.ForTONDHT,theStorequeriesareslightlymorecomplicated (cf.3.2.9). ˆFind\_Node(key,l)Askstheno detoreturnlKademlia-nearest knownno des(fromitsKademliaroutingtable)tokey. ˆFind\_Value(key,l)Thesameasab ove,butiftheno deknowsthe valuecorresp ondingtokeykey,itjustreturnsthatvalue. Whenanyno dewantstolo okupthevalueofakeyK,itrstcreates asetSofs ′ no des(forsomesmallvalueofs ′ ,say,s ′ = 5),nearesttoK withresp ecttotheKademliadistanceamongallknownno des(i.e.,theyare takenfromtheKademliaroutingtable).ThenaFind\_Valuequeryissent toeachofthem,andno desmentionedintheiranswersareincludedinS. Thenthes ′ no desfromS,nearesttoK,arealsosentaFind\_Valuequery ifthishasn'tb eendoneb efore,andthepro cesscontinuesuntilthevalueis foundorthesetSstopsgrowing.Thisisasortofb eamsearchoftheno de nearesttoKwithresp ecttoKademliadistance. IfthevalueofsomekeyKistob eset,thesamepro cedureisrunfor s ′ ≥s,withFind\_NodequeriesinsteadofFind\_Value,tondsnearest no destoK.Afterwards,Storequeriesaresenttoallofthem. Therearesomelessimp ortantdetailsintheimplementationofaKademlia- likeDHT(forexample,anyno deshouldlo okupsnearestno destoitself,say, onceeveryhour,andre-publishallstoredkeystothembymeansofStore queries).Wewillignorethemforthetimeb eing. 3.2.8.Bo otingaKademliano de.WhenaKademliano dego esonline, itrstp opulatesitsKademliaroutingtablebylo okingupitsownaddress. Duringthispro cess,itidentiesthesnearestno destoitself.Itcandownload fromthemall(key,value)pairsknowntothemtop opulateitspartofthe DHT. 3.2.9.StoringvaluesinTONDHT.StoringvaluesinTONDHTis slightlydierentfromageneralKademlia-likeDHT.Whensomeonewishes tostoreavalue,shemustprovidenotonlythekeyKitselftotheStore query,butalsoitspreimagei.e.,aTL-serializedstring(withoneofseveral predenedTL-constructorsattheb eginning)containingadescriptionof thekey.Thiskeydescriptionislaterkeptbytheno de,alongwiththekey andthevalue. 87 3.2.TONDHT:Kademlia-likeDistributedHashTable Thekeydescriptiondescrib esthetyp eoftheob jectb eingstored,its owner,anditsup daterulesincaseoffutureup dates.Theowneris usuallyidentiedbyapublickeyincludedinthekeydescription.Ifitis included,normallyonlyup datessignedbythecorresp ondingprivatekeywill b eaccepted.Thetyp eofthestoredob jectisnormallyjustabytestring. However,insomecasesitcanb emoresophisticatedforexample,aninput tunneldescription(cf.3.1.6),oracollectionofno deaddresses. Theup daterulescanalsob edierent.Insomecases,theysimply p ermitreplacingtheoldvaluewiththenewvalue,providedthenewvalue issignedbytheowner(thesignaturemustb ekeptaspartofthevalue,to b echeckedlaterbyanyotherno desaftertheyobtainthevalueofthiskey). Inothercases,theoldvaluesomehowaectsthenewvalue.Forexample,it cancontainasequencenumb er,andtheoldvalueisoverwrittenonlyifthe newsequencenumb erislarger(topreventreplayattacks). 3.2.10.Distributedtorrenttrackersandnetworkinterestgroups inTONDHT.Yetanotherinterestingcaseiswhenthevaluecontainsa listofno desp erhapswiththeirIPaddressesandp orts,orjustwiththeir abstractaddressesandtheup dateruleconsistsinincludingtherequester inthislist,providedshecanconrmheridentity. Thismechanismmightb eusedtocreateadistributedtorrenttracker, whereallno desinterestedinacertaintorrent(i.e.,acertainle)cannd otherno desthatareinterestedinthesametorrent,oralreadyhaveacopy. TONStorage(cf.4.1.7)usesthistechnologytondtheno desthathave acopyofarequiredle(e.g.,asnapshotofthestateofashardchain,oran oldblo ck).However,itsmoreimp ortantuseistocreateoverlaymulticast subnetworksandnetworkinterestgroups(cf.3.3).Theideaisthatonly someno desareinterestedintheup datesofasp ecicshardchain.Ifthe numb erofshardchainsb ecomesverylarge,ndingevenoneno deinterestedin thesameshardmayb ecomecomplicated.Thisdistributedtorrenttracker providesaconvenientwaytondsomeoftheseno des.Anotheroption wouldb etorequestthemfromavalidator,butthiswouldnotb eascalable approach,andvalidatorsmightcho osenottoresp ondtosuchqueriescoming fromarbitraryunknownno des. 3.2.11.Fall-backkeys.Mostofthekeytyp esdescrib edsofarhavean extra32-bitintegereldintheirTLdescription,normallyequaltozero. However,ifthekeyobtainedbyhashingthatdescriptioncannotb eretrieved fromorup datedintheTONDHT,thevalueinthiseldisincreased,and 88 3.2.TONDHT:Kademlia-likeDistributedHashTable anewattemptismade.Inthisway,onecannotcaptureandcensor akey(i.e.,p erformakeyretentionattack)bycreatingalotofabstract addresseslyingnearthekeyunderattackandcontrollingthecorresp onding DHTno des. 3.2.12.Lo catingservices.Someservices,lo catedintheTONNetwork andavailablethroughthe(higher-levelproto colsbuiltup onthe)TONADNL describ edin3.1,maywanttopublishtheirabstractaddressessomewhere, sothattheirclientswouldknowwheretondthem. However,publishingtheservice'sabstractaddressintheTONBlo ckchain maynotb etheb estapproach,b ecausetheabstractaddressmightneedto b echangedquiteoften,andb ecauseitcouldmakesensetoprovideseveral addresses,forreliabilityorloadbalancingpurp oses. AnalternativeistopublishapublickeyintotheTONBlo ckchain,and useasp ecialDHTkeyindicatingthatpublickeyasitsownerintheTL descriptionstring(cf.2.2.5)topublishanup-to-datelistoftheservice's abstractaddresses.ThisisoneoftheapproachesexploitedbyTONServices. 3.2.13.Lo catingownersofTONblo ckchainaccounts.Inmostcases, ownersofTONblo ckchainaccountswouldnotliketob easso ciatedwith abstractnetworkaddresses,andesp eciallyIPaddresses,b ecausethiscan violatetheirprivacy.Insomecases,however,theownerofaTONblo ckchain accountmaywanttopublishoneorseveralabstractaddresseswhereshe couldb econtacted. Atypicalcaseisthatofano deintheTONPaymentslightningnetwork (cf.5.2),theplatformforinstantcrypto currencytransfers.ApublicTON Paymentsno demaywantnotonlytoestablishpaymentchannelswithother p eers,butalsotopublishanabstractnetworkaddressthatcouldb eused tocontactitatalatertimefortransferringpaymentsalongthealready- establishedchannels. Oneoptionwouldb etoincludeanabstractnetworkaddressinthesmart contractcreatingthepaymentchannel.Amoreexibleoptionistoincludea publickeyinthesmartcontract,andthenuseDHTasexplainedin3.2.12. Themostnaturalwaywouldb etousethesameprivatekeythatcon- trolstheaccountintheTONBlo ckchaintosignandpublishup datesinthe TONDHTab outtheabstractaddressesasso ciatedwiththataccount.This isdonealmostinthesamewayasdescrib edin3.2.12;however,theDHT keyemployedwouldrequireasp ecialkeydescription,containingonlythe 89 3.3.OverlayNetworksandMulticastingMessages account\_iditself,equaltosha256oftheaccountdescription,whichcon- tainsthepublickeyoftheaccount.Thesignature,includedinthevalueof thisDHTkey,wouldcontaintheaccountdescriptionaswell. Inthisway,amechanismforlo catingabstractnetworkaddressesofsome ownersoftheTONBlo ckchainaccountsb ecomesavailable. 3.2.14.Lo catingabstractaddresses.NoticethattheTONDHT,while b eingimplementedoverTONADNL,isitselfusedbytheTONADNLfor severalpurp oses. Themostimp ortantofthemistolo cateano deoritscontactdatastarting fromits256-bitabstractaddress.Thisisnecessaryb ecausetheTONADNL shouldb eabletosenddatagramstoarbitrary256-bitabstractaddresses, evenifnoadditionalinformationisprovided. Tothisend,the256-bitabstractaddressissimplylo okedupasakeyin theDHT.Eitherano dewiththisaddress(i.e.,usingthisaddressasapublic semi-p ersistentDHTaddress)isfound,inwhichcaseitsIPaddressandp ort canb elearned;or,aninputtunneldescriptionmayb eretrievedasthevalue ofthekeyinquestion,signedbythecorrectprivatekey,inwhichcasethis tunneldescriptionwouldb eusedtosendADNLdatagramstotheintended recipient. Noticethatinordertomakeanabstractaddresspublic(reachablefrom anyno desinthenetwork),itsownermusteitheruseitasasemi-p ermanent DHTaddress,orpublish(intheDHTkeyequaltotheabstractaddress underconsideration)aninputtunneldescriptionwithanotherofitspublic abstractaddresses(e.g.,thesemi-p ermanentaddress)asthetunnel'sentry p oint.Anotheroptionwouldb etosimplypublishitsIPaddressandUDP p ort. 3.3OverlayNetworksandMulticastingMessages Inamulti-blo ckchainsystemliketheTONBlo ckchain,evenfullno deswould normallyb einterestedinobtainingup dates(i.e.,newblo cks)onlyab out someshardchains.Tothisend,asp ecialoverlay(sub)networkmustb ebuilt insidetheTONNetwork,ontopoftheADNLproto coldiscussedin3.1,one foreachshardchain. Therefore,theneedtobuildarbitraryoverlaysubnetworks,op entoany no deswillingtoparticipate,arises.Sp ecialgossipproto cols,builtup on ADNL,willb erunintheseoverlaynetworks.Inparticular,thesegossip 90 3.3.OverlayNetworksandMulticastingMessages proto colsmayb eusedtopropagate(broadcast)arbitrarydatainsidesucha subnetwork. 3.3.1.Overlaynetworks.Anoverlay(sub)networkissimplya(virtual) networkimplementedinsidesomelargernetwork.Usuallyonlysomeno des ofthelargernetworkparticipateintheoverlaysubnetwork,andonlysome linksb etweentheseno des,physicalorvirtual,arepartoftheoverlaysub- network. Inthisway,iftheencompassingnetworkisrepresentedasagraph(p er- hapsafullgraphinthecaseofadatagramnetworksuchasADNL,where anyno decaneasilycommunicatetoanyother),theoverlaysubnetworkisa subgraphofthisgraph. Inmostcases,theoverlaynetworkisimplementedusingsomeproto col builtup onthenetworkproto colofthelargernetwork.Itmayusethesame addressesasthelargernetwork,orusecustomaddresses. 3.3.2.OverlaynetworksinTON.OverlaynetworksinTONarebuilt up ontheADNLproto coldiscussedin3.1;theyuse256-bitADNLabstract addressesasaddressesintheoverlaynetworksaswell.Eachno deusually selectsoneofitsabstractaddressestodoubleasitsaddressintheoverlay network. IncontrasttoADNL,theTONoverlaynetworksusuallydonotsupp ort sendingdatagramstoarbitraryotherno des.Instead,somesemip ermanent linksareestablishedb etweensomeno des(calledneighb orswithresp ectto theoverlaynetworkunderconsideration),andmessagesareusuallyforwarded alongtheselinks(i.e.,fromano detooneofitsneighb ors).Inthisway,a TONoverlaynetworkisa(usuallynotfull)subgraphinsidethe(full)graph oftheADNLnetwork. Linkstoneighb orsinTONoverlaynetworkscanb eimplementedusing dedicatedp eer-to-p eerADNLchannels(cf.3.1.5). Eachno deofanoverlaynetworkmaintainsalistofneighb ors(withre- sp ecttotheoverlaynetwork),containingtheirabstractaddresses(which theyusetoidentifythemintheoverlaynetwork)andsomelinkdata(e.g., theADNLchannelusedtocommunicatewiththem). 3.3.3.Privateandpublicoverlaynetworks.Someoverlaynetworks arepublic,meaningthatanyno decanjointhematwill.Otherareprivate, meaningthatonlycertainno descanb eadmitted(e.g.,thosethatcanprove 91 3.3.OverlayNetworksandMulticastingMessages theiridentitiesasvalidators.)Someprivateoverlaynetworkscanevenb eun- knowntothegeneralpublic.Theinformationab outsuchoverlaynetworks ismadeavailableonlytocertaintrustedno des;forexample,itcanb een- cryptedwithapublickey,andonlyno deshavingacopyofthecorresp onding privatekeywillb eabletodecryptthisinformation. 3.3.4.Centrallycontrolledoverlaynetworks.Someoverlaynetworks arecentral lycontrol led,byoneorseveralno des,orbytheownerofsome widely-knownpublickey.Othersaredecentralized,meaningthatthereare nosp ecicno desresp onsibleforthem. 3.3.5.Joininganoverlaynetwork.Whenano dewantstojoinanover- laynetwork,itrstmustlearnits256-bitnetworkidentier,usuallyequal tosha256ofthedescriptionoftheoverlaynetworkaTL-serializedob ject (cf.2.2.5)whichmaycontain,forinstance,thecentralauthorityoftheover- laynetwork(i.e.,itspublickeyandp erhapsitsabstractaddress, 33 )astring withthenameoftheoverlaynetwork,aTONBlo ckchainshardidentierif thisisanoverlaynetworkrelatedtothatshard,andsoon. Sometimesitisp ossibletorecovertheoverlaynetworkdescriptionstart- ingfromthenetworkidentier,simplybylo okingitupintheTONDHT.In othercases(e.g.,forprivateoverlaynetworks),onemustobtainthenetwork descriptionalongwiththenetworkidentier. 3.3.6.Lo catingonememb eroftheoverlaynetwork.Afterano de learnsthenetworkidentierandthenetworkdescriptionoftheoverlaynet- workitwantstojoin,itmustlo cateatleastoneno deb elongingtothat network. Thisisalsoneededforno desthatdonotwanttojointheoverlaynetwork, butwantjusttocommunicatewithit;forexample,theremightb eanoverlay networkdedicatedtocollectingandpropagatingtransactioncandidatesfor asp ecicshardchain,andaclientmightwanttoconnecttoanyno deofthis networktosuggestatransaction. Themetho dusedforlo catingmemb ersofanoverlaynetworkisdenedin thedescriptionofthatnetwork.Sometimes(esp eciallyforprivatenetworks) onemustalreadyknowamemb erno detob eabletojoin.Inothercases,the abstractaddressesofsomeno desarecontainedinthenetworkdescription. Amoreexibleapproachistoindicateinthenetworkdescriptiononlythe 33 Alternatively,theabstractaddressmightb estoredintheDHTasexplainedin3.2.12. 92 3.3.OverlayNetworksandMulticastingMessages centralauthorityresp onsibleforthenetwork,andthentheabstractaddresses willb eavailablethroughvaluesofcertainDHTkeys,signedbythatcentral authority. Finally,trulydecentralizedpublicoverlaynetworkscanusethedis- tributedtorrent-trackermechanismdescrib edin3.2.10,alsoimplemented withtheaidoftheTONDHT. 3.3.7.Lo catingmorememb ersoftheoverlaynetwork.Creating links.Onceoneno deoftheoverlaynetworkisfound,asp ecialquerymayb e senttothatno derequestingalistofothermemb ers,forinstance,neighb ors oftheno deb eingqueried,orarandomselectionthereof. Thisenablesthejoiningmemb ertop opulateheradjacencyorneighb or listwithresp ecttotheoverlaynetwork,byselectingsomenewly-learned networkno desandestablishinglinkstothem(i.e.,dedicatedADNLp oint- to-p ointchannels,asoutlinedin3.3.2).Afterthat,sp ecialmessagesare senttoallneighb orsindicatingthatthenewmemb erisreadytoworkinthe overlaynetwork.Theneighb orsincludetheirlinkstothenewmemb erin theirneighb orlists. 3.3.8.Maintainingtheneighb orlist.Anoverlaynetworkno demust up dateitsneighb orlistfromtimetotime.Someneighb ors,oratleastlinks (channels)tothem,maystopresp onding;inthiscase,theselinksmustb e markedassusp ended,someattemptstoreconnecttosuchneighb orsmust b emade,and,iftheseattemptsfail,thelinksmustb edestroyed. Ontheotherhand,everyno desometimesrequestsfromarandomlycho- senneighb oritslistofneighb ors(orsomerandomselectionthereof ),anduses ittopartiallyup dateitsownneighb orlist,byaddingsomenewly-discovered no destoit,andremovingsomeoftheoldones,eitherrandomlyordep ending ontheirresp onsetimesanddatagramlossstatistics. 3.3.9.Theoverlaynetworkisarandomsubgraph.Inthisway,the overlaynetworkb ecomesarandomsubgraphinsidetheADNLnetwork.If thedegreeofeachvertexisatleastthree(i.e.,ifeachno deisconnectedto atleastthreeneighb ors),thisrandomgraphisknowntob econnectedwitha probabilityalmostequaltoone.Moreprecisely,theprobabilityofarandom graphwithnverticesb eingdisconnectedisexp onentiallysmall,andthis probabilitycanb ecompletelyneglectedif,say,n≥20.(Ofcourse,thisdo es notapplyinthecaseofaglobalnetworkpartition,whenno desondierent sidesofthepartitionhavenochancetolearnab outeachother.)Onthe 93 3.3.OverlayNetworksandMulticastingMessages otherhand,ifnissmallerthan20,itwouldsucetorequireeachvertexto have,say,atleasttenneighb ors. 3.3.10.TONoverlaynetworksareoptimizedforlowerlatency.TON overlaynetworksoptimizetherandomnetworkgraphgeneratedbythepre- viousmetho dasfollows.Everyno detriestoretainatleastthreeneighb ors withtheminimalround-triptime,changingthislistoffastneighb orsvery rarely.Atthesametime,italsohasatleastthreeotherslowneighb orsthat arechosencompletelyrandomly,sothattheoverlaynetworkgraphwouldal- wayscontainarandomsubgraph.Thisisrequiredtomaintainconnectivity andpreventsplittingoftheoverlaynetworkintoseveralunconnectedregional subnetworks.Atleastthreeintermediateneighb ors,whichhaveintermedi- ateround-triptimes,b oundedbyacertainconstant(actually,afunctionof theround-triptimesofthefastandtheslowneighb ors),arealsochosenand retained. Inthisway,thegraphofanoverlaynetworkstillmaintainsenoughran- domnesstob econnected,butisoptimizedforlowerlatencyandhigher throughput. 3.3.11.Gossipproto colsinanoverlaynetwork.Anoverlaynetwork isoftenusedtorunoneoftheso-calledgossipprotocols,whichachievesome globalgoalwhilelettingeveryno deinteractonlywithitsneighb ors.For example,therearegossipproto colstoconstructanapproximatelistofall memb ersofa(notto olarge)overlaynetwork,ortocomputeanestimateof thenumb erofmemb ersofan(arbitrarilylarge)overlaynetwork,usingonly ab oundedamountofmemoryateachno de(cf.\[15,4.4.3\]or\[1\]fordetails). 3.3.12.Overlaynetworkasabroadcastdomain.Themostimp or- tantgossipproto colrunninginanoverlaynetworkisthebroadcastprotocol, intendedtopropagatebroadcastmessagesgeneratedbyanyno deofthenet- work,orp erhapsbyoneofthedesignatedsenderno des,toallotherno des. Thereareinfactseveralbroadcastproto cols,optimizedfordierentuse cases.Thesimplestofthemreceivesnewbroadcastmessagesandrelaysthem toallneighb orsthathavenotyetsentacopyofthatmessagethemselves. 3.3.13.Moresophisticatedbroadcastproto cols.Someapplications maywarrantmoresophisticatedbroadcastproto cols.Forinstance,forbroad- castingmessagesofsubstantialsize,itmakessensetosendtotheneighb ors notthenewly-receivedmessageitself,butitshash(oracollectionofhashes 94 3.3.OverlayNetworksandMulticastingMessages ofnewmessages).Theneighb ormayrequestthemessageitselfafterlearning apreviouslyunseenmessagehash,tob etransferred,say,usingthereliable largedatagramproto col(RLDP)discussedin3.1.9.Inthisway,thenew messagewillb edownloadedfromoneneighb oronly. 3.3.14.Checkingtheconnectivityofanoverlaynetwork.Thecon- nectivityofanoverlaynetworkcanb echeckedifthereisaknownno de(e.g., theownerorthecreatoroftheoverlaynetwork)thatmustb einthis overlaynetwork.Thentheno deinquestionsimplybroadcastsfromtime totimeshortmessagescontainingthecurrenttime,asequencenumb erand itssignature.Anyotherno decanb esurethatitisstillconnectedtothe overlaynetworkifithasreceivedsuchabroadcastnotto olongago.This proto colcanb eextendedtothecaseofseveralwell-knownno des;forexam- ple,theyallwillsendsuchbroadcasts,andallotherno deswillexp ectto receivebroadcastsfrommorethanhalfofthewell-knownno des. Inthecaseofanoverlaynetworkusedforpropagatingnewblo cks(or justnewblo ckheaders)ofasp ecicshardchain,ago o dwayforano deto checkconnectivityistokeeptrackofthemostrecentblo ckreceivedsofar. Becauseablo ckisnormallygeneratedeveryveseconds,ifnonewblo ck isreceivedformorethan,say,thirtyseconds,theno deprobablyhasb een disconnectedfromtheoverlaynetwork. 3.3.15.Streamingbroadcastproto col.Finally,thereisastreaming broadcastprotocolforTONoverlaynetworks,used,forexample,topropa- gateblo ckcandidatesamongvalidatorsofsomeshardchain(shardchaintask group),who,ofcourse,createaprivateoverlaynetworkforthatpurp ose. Thesameproto colcanb eusedtopropagatenewshardchainblo ckstoall fullno desforthatshardchain. Thisproto colhasalreadyb eenoutlinedin2.6.10:thenew(large)broad- castmessageissplitinto,say,None-kilobytechunks;thesequenceofthese chunksisaugmentedtoM≥Nchunksbymeansofanerasureco desuchas theReedSolomonorafountainco de(e.g.,theRaptorQco de\[9\]\[14\]),and theseMchunksarestreamedtoallneighb orsinascendingchunknumb er order.Theparticipatingno descollectthesechunksuntiltheycanrecover theoriginallargemessage(onewouldhavetosuccessfullyreceiveatleastN ofthechunksforthis),andtheninstructtheirneighb orstostopsendingnew chunksofthestream,b ecausenowtheseno descangeneratethesubsequent chunksontheirown,havingacopyoftheoriginalmessage.Suchno des continuetogeneratethesubsequentchunksofthestreamandsendthemto 95 3.3.OverlayNetworksandMulticastingMessages theirneighb ors,unlesstheneighb orsinturnindicatethatthisisnolonger necessary. Inthisway,ano dedo esnotneedtodownloadalargemessageinits entiretyb eforepropagatingitfurther.Thisminimizesbroadcastlatency, esp eciallywhencombinedwiththeoptimizationsdescrib edin3.3.10. 3.3.16.Constructingnewoverlaynetworksbasedonexistingones. Sometimesonedo esnotwanttoconstructanoverlaynetworkfromscratch. Instead,oneorseveralpreviouslyexistingoverlaynetworksareknown,and thememb ershipofthenewoverlaynetworkisexp ectedtooverlapsigni- cantlywiththecombinedmemb ershipoftheseoverlaynetworks. Animp ortantexampleariseswhenaTONshardchainissplitintwo,or twosiblingshardchainsaremergedintoone(cf.2.7).Intherstcase,the overlaynetworksusedforpropagatingnewblo ckstofullno desmustb econ- structedforeachofthenewshardchains;however,eachofthesenewoverlay networkscanb eexp ectedtob econtainedintheblo ckpropagationnetwork oftheoriginalshardchain(andcompriseapproximatelyhalfitsmemb ers). Inthesecondcase,theoverlaynetworkforpropagatingnewblo cksofthe mergedshardchainwillconsistapproximatelyoftheunionofmemb ersofthe twooverlaynetworksrelatedtothetwosiblingshardchainsb eingmerged. Insuchcases,thedescriptionofthenewoverlaynetworkmaycontainan explicitorimplicitreferencetoalistofrelatedexistingoverlaynetworks.A no dewishingtojointhenewoverlaynetworkmaycheckwhetheritisalready amemb erofoneoftheseexistingnetworks,andqueryitsneighb orsinthese networkswhethertheyareinterestedinthenewnetworkaswell.Incase ofap ositiveanswer,newp oint-to-p ointchannelscanb eestablishedtosuch neighb ors,andtheycanb eincludedintheneighb orlistforthenewoverlay network. Thismechanismdo esnottotallysupplantthegeneralmechanismde- scrib edin3.3.6and3.3.7;rather,b othareruninparallelandareusedto p opulatetheneighb orlist.Thisisneededtopreventinadvertentsplittingof thenewoverlaynetworkintoseveralunconnectedsubnetworks. 3.3.17.Overlaynetworkswithinoverlaynetworks.Anotherinterest- ingcasearisesintheimplementationofTONPayments(alightningnet- workforinstanto-chainvaluetransfers;cf.5.2).Inthiscase,rstan overlaynetworkcontainingalltransitno desofthelightningnetworkiscon- structed.However,someoftheseno deshaveestablishedpaymentchannels intheblo ckchain;theymustalwaysb eneighb orsinthisoverlaynetwork,in 96 3.3.OverlayNetworksandMulticastingMessages additiontoanyrandomneighb orsselectedbythegeneraloverlaynetwork algorithmsdescrib edin3.3.6,3.3.7and3.3.8.Thesep ermanentlinks totheneighb orswithestablishedpaymentchannelsareusedtorunsp ecic lightningnetworkproto cols,thuseectivelycreatinganoverlaysubnetwork (notnecessarilyconnected,ifthingsgoawry)insidetheencompassing(al- mostalwaysconnected)overlaynetwork. 97 4.1.TONServiceImplementationStrategies 4TONServicesandApplications WehavediscussedtheTONBlo ckchainandTONNetworkingtechnologies atsomelength.Nowweexplainsomewaysinwhichtheycanb ecombined tocreateawiderangeofservicesandapplications,anddiscusssomeofthe servicesthatwillb eprovidedbytheTONPro jectitself,eitherfromthevery b eginningoratalatertime. 4.1TONServiceImplementationStrategies Westartwithadiscussionofhowdierentblo ckchainandnetwork-related applicationsandservicesmayb eimplementedinsidetheTONecosystem. Firstofall,asimpleclassicationisinorder: 4.1.1.Applicationsandservices.Wewillusethewordsapplication andserviceinterchangeably.However,thereisasubtleandsomewhat vaguedistinction:anapplicationusuallyprovidessomeservicesdirectlyto humanusers,whileaserviceisusuallyexploitedbyotherapplicationsand services.Forexample,TONStorageisaservice,b ecauseitisdesignedto keeplesonb ehalfofotherapplicationsandservices,eventhoughahuman usermightuseitdirectlyaswell.Ahyp otheticalFaceb o okinablo ckchain (cf.2.9.13),ifmadeavailablethroughtheTONNetwork(i.e.,implemented asaton-service),wouldratherb eanapplication,eventhoughsomeb ots mightaccessitautomaticallywithouthumanintervention. 4.1.2.Lo cationoftheapplication:on-chain,o-chainormixed.A serviceoranapplicationdesignedfortheTONecosystemneedstokeepits dataandpro cessthatdatasomewhere.Thisleadstothefollowingclassi- cationofapplications(andservices): ˆOn-chainapplications(cf.4.1.4):Alldataandpro cessingareinthe TONBlo ckchain. ˆO-chainapplications(cf.4.1.5):Alldataandpro cessingareoutside theTONBlo ckchain,onserversavailablethroughtheTONNetwork. ˆMixedapplications(cf.4.1.6):Some,butnotall,dataandpro cessing areintheTONBlo ckchain;therestareono-chainserversavailable throughtheTONNetwork. 98 4.1.TONServiceImplementationStrategies 4.1.3.Centralization:centralizedanddecentralized,ordistributed, applications.Anotherclassicationcriterioniswhethertheapplication (orservice)reliesonacentralizedservercluster,orisreallydistributed (cf.4.1.8).Allon-chainapplicationsareautomaticallydecentralizedand distributed.O-chainandmixedapplicationsmayexhibitdierentdegrees ofcentralization. Nowletusconsidertheab ovep ossibilitiesinmoredetail. 4.1.4.Pureon-chainapplications:distributedapplications,or dapps,residingintheblo ckchain.Oneofthep ossibleapproaches, mentionedin4.1.2,istodeployadistributedapplication(commonlyab- breviatedasdapp)completelyintheTONBlo ckchain,asonesmartcon- tractoracollectionofsmartcontracts.Alldatawillb ekeptaspartofthe p ermanentstateofthesesmartcontracts,andallinteractionwiththepro ject willb edonebymeansof(TONBlo ckchain)messagessenttoorreceivedfrom thesesmartcontracts. Wehavealreadydiscussedin2.9.13thatthisapproachhasitsdrawbacks andlimitations.Ithasitsadvantages,to o:suchadistributedapplication needsnoserverstorunonortostoreitsdata(itrunsintheblo ckchain i.e.,onthevalidators'hardware),andenjoystheblo ckchain'sextremelyhigh (Byzantine)reliabilityandaccessibility.Thedevelop erofsuchadistributed applicationdo esnotneedtobuyorrentanyhardware;allsheneedstodois developsomesoftware(i.e.,theco deforthesmartcontracts).Afterthat,she willeectivelyrentthecomputingp owerfromthevalidators,andwillpay foritinTONcoins,eitherherselforbyputtingthisburdenontheshoulders ofherusers. 4.1.5.Purenetworkservices:ton-sitesandton-services.Another extremeoptionistodeploytheserviceonsomeserversandmakeitavailable totheusersthroughtheADNLproto coldescrib edin3.1,andmayb esome higherlevelproto colsuchastheRLDPdiscussedin3.1.9,whichcanb eused tosendRPCqueriestotheserviceinanycustomformatandobtainanswers tothesequeries.Inthisway,theservicewillb etotallyo-chain,andwill resideintheTONNetwork,almostwithoutusingtheTONBlo ckchain. TheTONBlo ckchainmightb eusedonlytolo catetheabstractaddress oraddressesoftheservice,asoutlinedin3.2.12,p erhapswiththeaidofa servicesuchastheTONDNS(cf.4.3.1)tofacilitatetranslationofdomain- likehuman-readablestringsintoabstractaddresses. 99 4.1.TONServiceImplementationStrategies TotheextenttheADNLnetwork(i.e.,theTONNetwork)issimilarto theInvisibleInternetPro ject(I 2 P),such(almost)purelynetworkservices areanalogoustotheso-calledeep-services(i.e.,servicesthathaveanI 2 P- addressastheirentryp oint,andareavailabletoclientsthroughtheI 2 P network).WewillsaythatsuchpurelynetworkservicesresidingintheTON Networkareton-services. Aneep-servicemayimplementHTTPasitsclient-serverproto col;in theTONNetworkcontext,aton-servicemightsimplyuseRLDP(cf.3.1.9) datagramstotransferHTTPqueriesandresp onsestothem.Ifitusesthe TONDNStoallowitsabstractaddresstob elo okedupbyahuman-readable domainname,theanalogytoawebsiteb ecomesalmostp erfect.Onemight evenwriteasp ecializedbrowser,orasp ecialproxy(ton-proxy)thatisrun lo callyonauser'smachine,acceptsarbitraryHTTPqueriesfromanordinary webbrowsertheuseremploys(oncethelo calIPaddressandtheTCPp ortof theproxyareenteredintothebrowser'sconguration),andforwardsthese queriesthroughtheTONNetworktotheabstractaddressoftheservice. Thentheuserwouldhaveabrowsingexp eriencesimilartothatoftheWorld WideWeb(WWW). IntheI 2 Pecosystem,sucheep-servicesarecalledeep-sites.Onecan easilycreateton-sitesintheTONecosystemaswell.Thisisfacilitated somewhatbytheexistenceofservicessuchastheTONDNS,whichexploit theTONBlo ckchainandtheTONDHTtotranslate(TON)domainnames intoabstractaddresses. 4.1.6.Mixedservices:partlyo-chain,partlyon-chain.Someser- vicesmightuseamixedapproach:domostofthepro cessingo-chain,but alsohavesomeon-chainpart(forexample,toregistertheirobligationsto- wardstheirusers,andviceversa).Inthisway,partofthestatewouldstill b ekeptintheTONBlo ckchain(i.e.,animmutablepublicledger),andany misb ehavioroftheserviceorofitsuserscouldb epunishedbysmartcon- tracts. 4.1.7.Example:keepingleso-chain;TONStorage.Anexample ofsuchaserviceisgivenbyTONStorage.Initssimplestform,itallows userstostoreleso-chain,bykeepingon-chainonlyahashoftheletob e stored,andp ossiblyasmartcontractwheresomeotherpartiesagreetokeep theleinquestionforagivenp erio doftimeforapre-negotiatedfee.Infact, thelemayb esub dividedintochunksofsomesmallsize(e.g.,1kilobyte), augmentedbyanerasureco desuchasaReedSolomonorafountainco de,a 100 4.1.TONServiceImplementationStrategies Merkletreehashmayb econstructedfortheaugmentedsequenceofchunks, andthisMerkletreehashmightb epublishedinthesmartcontractinstead oforalongwiththeusualhashofthele.Thisissomewhatreminiscentof thewaylesarestoredinatorrent. Anevensimplerformofstoringlesiscompletelyo-chain:onemightes- sentiallycreateatorrentforanewle,anduseTONDHTasadistributed torrenttrackerforthistorrent(cf.3.2.10).Thismightactuallyworkpretty wellforp opularles.However,onedo esnotgetanyavailabilityguarantees. Forexample,ahyp otheticalblo ckchainFaceb o ok(cf.2.9.13),whichwould opttokeeptheprolephotographsofitsuserscompletelyo-chaininsuch torrents,mightrisklosingphotographsofordinary(notesp eciallyp opular) users,oratleastriskb eingunabletopresentthesephotographsforprolonged p erio ds.TheTONStoragetechnology,whichismostlyo-chain,butuses anon-chainsmartcontracttoenforceavailabilityofthestoredles,might b eab ettermatchforthistask. 4.1.8.Decentralizedmixedservices,orfogservices.Sofar,wehave discussedcentralizedmixedservicesandapplications.Whiletheiron-chain comp onentispro cessedinadecentralizedanddistributedfashion,b eing lo catedintheblo ckchain,theiro-chaincomp onentreliesonsomeservers controlledbytheserviceproviderintheusualcentralizedfashion.Instead ofusingsomededicatedservers,computingp owermightb erentedfroma cloudcomputingserviceoeredbyoneofthelargecompanies.However,this wouldnotleadtodecentralizationoftheo-chaincomp onentoftheservice. Adecentralizedapproachtoimplementingtheo-chaincomp onentofa serviceconsistsincreatingamarket,whereanyb o dyp ossessingtherequired hardwareandwillingtorenttheircomputingp owerordiskspacewouldoer theirservicestothoseneedingthem. Forexample,theremightexistaregistry(whichmightalsob ecalleda marketoranexchange)whereallno desinterestedinkeepinglesofother userspublishtheircontactinformation,alongwiththeiravailablestorage capacity,availabilityp olicy,andprices.Thoseneedingtheseservicesmight lo okthemupthere,and,iftheotherpartyagrees,createsmartcontractsin theblo ckchainanduploadlesforo-chainstorage.Inthiswayaservice likeTONStorageb ecomestrulydecentralized,b ecauseitdo esnotneedto relyonanycentralizedclusterofserversforstoringles. 4.1.9.Example:fogcomputingplatformsasdecentralizedmixed services.Anotherexampleofsuchadecentralizedmixedapplicationarises 101 4.2.ConnectingUsersandServiceProviders whenonewantstop erformsomesp eciccomputations(e.g.,3Drenderingor trainingneuralnetworks),oftenrequiringsp ecicandexp ensivehardware. Thenthosehavingsuchequipmentmightoertheirservicesthroughasimilar exchange,andthoseneedingsuchserviceswouldrentthem,withtheobli- gationsofthesidesregisteredbymeansofsmartcontracts.Thisissimilarto whatfogcomputingplatforms,suchasGolem(https://golem.network/) orSONM(https://sonm.io/),promisetodeliver. 4.1.10.Example:TONProxyisafogservice.TONProxyprovidesyet anotherexampleofafogservice,whereno deswishingtooertheirservices (withorwithoutcomp ensation)astunnelsforADNLnetworktracmight register,andthoseneedingthemmightcho oseoneoftheseno desdep ending ontheprice,latencyandbandwidthoered.Afterwards,onemightuse paymentchannelsprovidedbyTONPaymentsforpro cessingmicropayments fortheservicesofthoseproxies,withpaymentscollected,forinstance,for every128KiBtransferred. 4.1.11.Example:TONPaymentsisafogservice.TheTONPayments platform(cf.5)isalsoanexampleofsuchadecentralizedmixedapplication. 4.2ConnectingUsersandServiceProviders Wehaveseenin4.1.8thatfogservices(i.e.,mixeddecentralizedservices) willusuallyneedsomemarkets,exchangesorregistries,wherethoseneeding sp ecicservicesmightmeetthoseprovidingthem. Suchmarketsarelikelytob eimplementedason-chain,o-chainormixed servicesthemselves,centralizedordistributed. 4.2.1.Example:connectingtoTONPayments.Forexample,ifone wantstouseTONPayments(cf.5),therststepwouldb etondatleast someexistingtransitno desofthelightningnetwork(cf.5.2),andestablish paymentchannelswiththem,iftheyarewilling.Someno descanb efound withtheaidoftheencompassingoverlaynetwork,whichissupp osedto containalltransitlightningnetworkno des(cf.3.3.17).However,itisnot clearwhethertheseno deswillb ewillingtocreatenewpaymentchannels. Therefore,aregistryisneededwhereno desreadytocreatenewlinkscan publishtheircontactinformation(e.g.,theirabstractaddresses). 4.2.2.Example:uploadingaleintoTONStorage.Similarly,ifone wantstouploadaleintotheTONStorage,shemustlo catesomeno des 102 4.3.AccessingTONServices willingtosignasmartcontractbindingthemtokeepacopyofthatle(or ofanyleb elowacertainsizelimit,forthatmatter).Therefore,aregistry ofno desoeringtheirservicesforstoringlesisneeded. 4.2.3.On-chain,mixedando-chainregistries.Sucharegistryof serviceprovidersmightb eimplementedcompletelyon-chain,withtheaid ofasmartcontractwhichwouldkeeptheregistryinitsp ermanentstorage. However,thiswouldb equiteslowandexp ensive.Amixedapproachis moreecient,wheretherelativelysmallandrarelychangedon-chainregistry isusedonlytop ointoutsomeno des(bytheirabstractaddresses,orby theirpublickeys,whichcanb eusedtolo cateactualabstractaddressesas describ edin3.2.12),whichprovideo-chain(centralized)registryservices. Finally,adecentralized,purelyo-chainapproachmightconsistofa publicoverlaynetwork(cf.3.3),wherethosewillingtooertheirservices, orthoselo okingtobuysomeb o dy'sservices,simplybroadcasttheiroers, signedbytheirprivatekeys.Iftheservicetob eprovidedisverysimple,even broadcastingtheoersmightb enotnecessary:theapproximatememb ership oftheoverlaynetworkitselfmightb eusedasaregistryofthosewillingto provideaparticularservice.Thenaclientrequiringthisservicemightlo- cate(cf.3.3.7)andquerysomeno desofthisoverlaynetwork,andthenquery theirneighb ors,iftheno desalreadyknownarenotreadytosatisfyitsneeds. 4.2.4.Registryorexchangeinaside-chain.Anotherapproachtoim- plementingdecentralizedmixedregistriesconsistsincreatinganindep en- dentsp ecializedblo ckchain(side-chain),maintainedbyitsownsetofself- pro claimedvalidators,whopublishtheiridentitiesinanon-chainsmartcon- tractandprovidenetworkaccesstoallinterestedpartiestothissp ecialized blo ckchain,collectingtransactioncandidatesandbroadcastingblo ckup dates throughdedicatedoverlaynetworks(cf.3.3).Thenanyfullno deforthis sidechaincanmaintainitsowncopyofthesharedregistry(essentiallyequal totheglobalstateofthisside-chain),andpro cessarbitraryqueriesrelated tothisregistry. 4.2.5.Registryorexchangeinaworkchain.Anotheroptionisto createadedicatedworkchaininsidetheTONBlo ckchain,sp ecializedfor creatingregistries,marketsandexchanges.Thismightb emoreecientand lessexp ensivethanusingsmartcontractsresidinginthebasicworkchain (cf.2.1.11).However,thiswouldstillb emoreexp ensivethanmaintaining registriesinside-chains(cf.4.2.4). 103 4.3.AccessingTONServices 4.3AccessingTONServices Wehavediscussedin4.1thedierentapproachesonemightemployfor creatingnewservicesandapplicationsresidingintheTONecosystem.Now wediscusshowtheseservicesmightb eaccessed,andsomeofthehelp er servicesthatwillb eprovidedbyTON,includingTONDNSandTON Storage. 4.3.1.TONDNS:amostlyon-chainhierarchicaldomainnameser- vice.TheTONDNSisapredenedservice,whichusesacollectionofsmart contractstokeepamapfromhuman-readabledomainnamesto(256-bit)ad- dressesofADNLnetworkno desandTONBlo ckchainaccountsandsmart contracts. Whileanyb o dymightinprincipleimplementsuchaserviceusingthe TONBlo ckchain,itisusefultohavesuchapredenedservicewithawell- knowninterface,tob eusedbydefaultwheneveranapplicationoraservice wantstotranslatehuman-readableidentiersintoaddresses. 4.3.2.TONDNSusecases.Forexample,auserlo okingtotransfersome crypto currencytoanotheruserortoamerchantmayprefertorememb era TONDNSdomainnameoftheaccountofthatuserormerchant,insteadof keepingtheir256-bitaccountidentiersathandandcopy-pastingtheminto therecipienteldintheirlightwalletclient. Similarly,TONDNSmayb eusedtolo cateaccountidentiersofsmart contractsorentryp ointsofton-servicesandton-sites(cf.4.1.5),enabling asp ecializedclient(ton-browser),orausualinternetbrowsercombined withasp ecializedton-proxyextensionorstand-aloneapplication,todeliver aWWW-likebrowsingexp eriencetotheuser. 4.3.3.TONDNSsmartcontracts.TheTONDNSisimplementedby meansofatreeofsp ecial(DNS)smartcontracts.EachDNSsmartcontract isresp onsibleforregisteringsub domainsofsomexeddomain.Thero ot DNSsmartcontract,wherelevelonedomainsoftheTONDNSsystemwillb e kept,islo catedinthemasterchain.Itsaccountidentiermustb ehardco ded intoallsoftwarethatwishestoaccesstheTONDNSdatabasedirectly. AnyDNSsmartcontractcontainsahashmap,mappingvariable-length null-terminatedUTF-8stringsintotheirvalues.Thishashmapisimple- mentedasabinaryPatriciatree,similartothatdescrib edin2.3.7but supp ortingvariable-lengthbitstringsaskeys. 104 4.3.AccessingTONServices 4.3.4.ValuesoftheDNShashmap,orTONDNSrecords.Astothe values,theyareTONDNSrecordsdescrib edbyaTL-scheme(cf.2.2.5). Theyconsistofamagicnumb er,selectingoneoftheoptionssupp orted, andtheneitheranaccountidentier,orasmart-contractidentier,oran abstractnetworkaddress(cf.3.1),orapublickeyusedtolo cateabstract addressesofaservice(cf.3.2.12),oradescriptionofanoverlaynetwork, andsoon.Animp ortantcaseisthatofanotherDNSsmartcontract:insuch acase,thatsmartcontractisusedtoresolvesub domainsofitsdomain.In thisway,onecancreateseparateregistriesfordierentdomains,controlled bytheownersofthosedomains. Theserecordsmayalsocontainanexpirationtime,acachingtime(usu- allyverylarge,b ecauseup datingvaluesinablo ckchainto ooftenisexp en- sive),andinmostcasesareferencetotheownerofthesub domaininquestion. Theownerhastherighttochangethisrecord(inparticular,theownereld, thustransferringthedomaintosomeb o dyelse'scontrol),andtoprolongit. 4.3.5.Registeringnewsub domainsofexistingdomains.Inorderto registeranewsub domainofanexistingdomain,onesimplysendsamessage tothesmartcontract,whichistheregistrarofthatdomain,containingthe sub domain(i.e.,thekey)tob eregistered,thevalueinoneofseveralprede- nedformats,anidentityoftheowner,anexpirationdate,andsomeamount ofcrypto currencyasdeterminedbythedomain'sowner. Sub domainsareregisteredonarst-come,rst-servedbasis. 4.3.6.RetrievingdatafromaDNSsmartcontract.Inprinciple, anyfullno deforthemasterchainorshardchaincontainingaDNSsmart contractmightb eabletolo okupanysub domaininthedatabaseofthat smartcontract,ifthestructureandthelo cationofthehashmapinsidethe p ersistentstorageofthesmartcontractareknown. However,thisapproachwouldworkonlyforcertainDNSsmartcontracts. Itwouldfailmiserablyifanon-standardDNSsmartcontractwereused. Instead,anapproachbasedongeneralsmartcontractinterfacesandget methods(cf.4.3.11)isused.AnyDNSsmartcontractmustdeneaget metho dwithaknownsignature,whichisinvokedtolo okupakey.Since thisapproachmakessenseforothersmartcontractsaswell,esp eciallythose providingon-chainandmixedservices,weexplainitinsomedetailin4.3.11. 4.3.7.TranslatingaTONDNSdomain.Onceanyfullno de,actingby itselforonb ehalfofsomelightclient,canlo okupentriesinthedatabase 105 4.3.AccessingTONServices ofanyDNSsmartcontract,arbitraryTONDNSdomainnamescanb ere- cursivelytranslated,startingfromthewell-knownandxedro otDNSsmart contract(account)identier. Forexample,ifonewantstotranslateA.B.C,onelo oksupkeys.C,.B.C, andA.B.Cinthero otdomaindatabase.Iftherstofthemisnotfound,but thesecondis,anditsvalueisareferencetoanotherDNSsmartcontract, thenAislo okedupinthedatabaseofthatsmartcontractandthenalvalue isretrieved. 4.3.8.TranslatingTONDNSdomainsforlightno des.Inthisway, afullno deforthemasterchainandalsoforallshardchainsinvolvedinthe domainlo ok-uppro cessmighttranslateanydomainnameintoitscurrent valuewithoutexternalhelp.Alightno demightrequestafullno detodothis onitsb ehalfandreturnthevalue,alongwithaMerklepro of(cf.2.5.11). ThisMerklepro ofwouldenablethelightno detoverifythattheansweris correct,sosuchTONDNSresp onsescannotb esp o ofedbyamalicious interceptor,incontrasttotheusualDNSproto col. Becausenono decanb eexp ectedtob eafullno dewithresp ecttoall shardchains,actualTONDNSdomaintranslationwouldinvolveacombina- tionofthesetwostrategies. 4.3.9.DedicatedTONDNSservers.Onemightprovideasimple TONDNSserver,whichwouldreceiveRPCDNSqueries(e.g.,viathe ADNLorRLDPproto colsdescrib edin3.1),requestingthattheservertrans- lateagivendomain,pro cessthesequeriesbyforwardingsomesub queriesto other(full)no desifnecessary,andreturnanswerstotheoriginalqueries, augmentedbyMerklepro ofsifrequired. SuchDNSserversmightoertheirservices(forfreeornot)toanyother no desandesp eciallylightclients,usingoneofthemetho dsdescrib edin4.2. Noticethattheseservers,ifconsideredpartoftheTONDNSservice,would eectivelytransformitfromadistributedon-chainserviceintoadistributed mixedservice(i.e.,afogservice). ThisconcludesourbriefoverviewoftheTONDNSservice,ascalable on-chainregistryforhuman-readabledomainnamesofTONBlo ckchainand TONNetworkentities. 4.3.10.Accessingdatakeptinsmartcontracts.Wehavealreadyseen thatitissometimesnecessarytoaccessdatastoredinasmartcontract withoutchangingitsstate. 106 4.3.AccessingTONServices Ifoneknowsthedetailsofthesmart-contractimplementation,onecan extractalltheneededinformationfromthesmartcontract'sp ersistentstor- age,availabletoallfullno desoftheshardchainthesmartcontractresides in.However,thisisquiteaninelegantwayofdoingthings,dep endingvery muchonthesmart-contractimplementation. 4.3.11.Getmetho dsofsmartcontracts.Ab etterwaywouldb eto denesomegetmethodsinthesmartcontract,thatis,sometyp esofinb ound messagesthatdonotaectthestateofthesmartcontractwhendelivered, butgenerateoneormoreoutputmessagescontainingtheresultoftheget metho d.Inthisway,onecanobtaindatafromasmartcontract,knowing onlythatitimplementsagetmetho dwithaknownsignature(i.e.,aknown formatoftheinb oundmessagetob esentandoutb oundmessagestob e receivedasaresult). Thiswayismuchmoreelegantandinlinewithob jectorientedprogram- ming(OOP).However,ithasanobviousdefectsofar:onemustactually commitatransactionintotheblo ckchain(sendingthegetmessagetothe smartcontract),waituntilitiscommittedandpro cessedbythevalidators, extracttheanswerfromanewblo ck,andpayforgas(i.e.,forexecutingthe getmetho donthevalidators'hardware).Thisisawasteofresources:get metho dsdonotchangethestateofthesmartcontractanyways,sotheyneed notb eexecutedintheblo ckchain. 4.3.12.Tentativeexecutionofgetmetho dsofsmartcontracts.We havealreadyremarked(cf.2.4.6)thatanyfullno decantentativelyexe- cuteanymetho dofanysmartcontract(i.e.,deliveranymessagetoasmart contract),startingfromagivenstateofthesmartcontract,withoutactually committingthecorresp ondingtransaction.Thefullno decansimplyloadthe co deofthesmartcontractunderconsiderationintotheTONVM,initialize itsp ersistentstoragefromtheglobalstateoftheshardchain(knowntoall fullno desoftheshardchain),andexecutethesmart-contractco dewiththe inb oundmessageasitsinputparameter.Theoutputmessagescreatedwill yieldtheresultofthiscomputation. Inthisway,anyfullno decanevaluatearbitrarygetmetho dsofarbitrary smartcontracts,providedtheirsignature(i.e.,theformatofinb oundand outb oundmessages)isknown.Theno demaykeeptrackofthecellsofthe shardchainstateaccessedduringthisevaluation,andcreateaMerklepro of ofthevalidityofthecomputationp erformed,fortheb enetofalightno de thatmighthaveaskedthefullno detodoso(cf.2.5.11). 107 4.3.AccessingTONServices 4.3.13.Smart-contractinterfacesinTL-schemes.Recallthatthe metho dsimplementedbyasmartcontract(i.e.,theinputmessagesaccepted byit)areessentiallysomeTL-serializedob jects,whichcanb edescrib edby aTL-scheme(cf.2.2.5).Theresultingoutputmessagescanb edescrib edby thesameTL-schemeaswell.Inthisway,theinterfaceprovidedbyasmart contracttootheraccountsandsmartcontractsmayb eformalizedbymeans ofaTL-scheme. Inparticular,(asubsetof )getmetho dssupp ortedbyasmartcontract canb edescrib edbysuchaformalizedsmart-contractinterface. 4.3.14.Publicinterfacesofasmartcontract.Noticethataformalized smart-contractinterface,eitherinformofaTL-scheme(representedasaTL sourcele;cf.2.2.5)orinserializedform, 34 canb epublishedforexample, inasp ecialeldinthesmart-contractaccountdescription,storedinthe blo ckchain,orseparately,ifthisinterfacewillb ereferredtomanytimes.In thelattercaseahashofthesupp ortedpublicinterfacemayb eincorp orated intothesmart-contractdescriptioninsteadoftheinterfacedescriptionitself. AnexampleofsuchapublicinterfaceisthatofaDNSsmartcontract, whichissupp osedtoimplementatleastonestandardgetmetho dforlo oking upsub domains(cf.4.3.6).Astandardmetho dforregisteringnewsub do- mainscanb ealsoincludedinthestandardpublicinterfaceofDNSsmart contracts. 4.3.15.Userinterfaceofasmartcontract.Theexistenceofapublic interfaceforasmartcontracthasotherb enets,to o.Forexample,awallet clientapplicationmaydownloadsuchaninterfacewhileexaminingasmart contractontherequestofauser,anddisplayalistofpublicmetho ds(i.e., ofavailableactions)supp ortedbythesmartcontract,p erhapswithsome human-readablecommentsifanyareprovidedintheformalinterface.After theuserselectsoneofthesemetho ds,aformmayb eautomaticallygenerated accordingtotheTL-scheme,wheretheuserwillb epromptedforallelds requiredbythechosenmetho dandforthedesiredamountofcrypto currency (e.g.,TONcoins)tob eattachedtothisrequest.Submittingthisformwill createanewblo ckchaintransactioncontainingthemessagejustcomp osed, sentfromtheuser'sblo ckchainaccount. Inthisway,theuserwillb eabletointeractwitharbitrarysmartcontracts 34 TL-schemescanb eTL-serializedthemselves;cf.https://core.telegram.org/ mtproto/TL- tl. 108 4.3.AccessingTONServices fromthewalletclientapplicationinauser-friendlywaybyllingandsub- mittingcertainforms,providedthesesmartcontractshavepublishedtheir interfaces. 4.3.16.Userinterfaceofaton-service.Itturnsoutthatton-services (i.e.,servicesresidingintheTONNetworkandacceptingqueriesthrough theADNLandRLDPproto colsof3;cf.4.1.5)mayalsoprotfromhaving publicinterfaces,describ edbyTL-schemes(cf.2.2.5).Aclientapplication, suchasalightwalletoraton-browser,mightprompttheusertoselectone ofthemetho dsandtollinaformwithparametersdenedbytheinterface, similarlytowhathasjustb eendiscussedin4.3.15.Theonlydierenceis thattheresultingTL-serializedmessageisnotsubmittedasatransactionin theblo ckchain;instead,itissentasanRPCquerytotheabstractaddress oftheton-serviceinquestion,andtheresp onsetothisqueryisparsedand displayedaccordingtotheformalinterface(i.e.,aTL-scheme). 4.3.17.Lo catinguserinterfacesviaTONDNS.TheTONDNSrecord containinganabstractaddressofaton-serviceorasmart-contractaccount identiermightalsocontainanoptionalelddescribingthepublic(user) interfaceofthatentity,orseveralsupp ortedinterfaces.Thentheclient application(b eitawallet,aton-browseroraton-proxy)willb eableto downloadtheinterfaceandinteractwiththeentityinquestion(b eitasmart contractoraton-service)inauniformway. 4.3.18.Blurringthedistinctionb etweenon-chainando-chainser- vices.Inthisway,thedistinctionb etweenon-chain,o-chainandmixed services(cf.4.1.2)isblurredfortheenduser:shesimplyentersthedomain nameofthedesiredserviceintotheaddresslineofherton-browserorwallet, andtherestishandledseamlesslybytheclientapplication. 4.3.19.ton-sitesaston-servicessupp ortinganHTTPinterface. Aton-siteissimplyaton-servicethatsupp ortsanHTTPinterface,p erhaps alongwithsomeotherinterfaces.Thissupp ortmayb eannouncedinthe corresp ondingTONDNSrecord. 4.3.20.Hyp erlinks.NoticethattheHTMLpagesreturnedbyton-sites maycontainton-hyperlinksthatis,referencestootherton-sites,smartcon- tractsandaccountsbymeansofsp eciallycraftedURIschemes(cf.4.3.21) containingeitherabstractnetworkaddresses,accountidentiers,orhuman- readableTONDNSdomains.Thenaton-browsermightfollowsucha 109 4.3.AccessingTONServices hyp erlinkwhentheuserselectsit,detecttheinterfacetob eused,anddis- playauserinterfaceformasoutlinedin4.3.15and4.3.16. 4.3.21.Hyp erlinkURLsmaysp ecifysomeparameters.Thehyp erlink URLsmaycontainnotonlya(TON)DNSdomainoranabstractaddressof theserviceinquestion,butalsothenameofthemetho dtob einvokedand someorallofitsparameters.Ap ossibleURIschemeforthismightlo okas follows: ton:///?<eld1>=&<eld2>=. . . Whentheuserselectssuchalinkinaton-browser,eithertheactionisp er- formedimmediately(esp eciallyifitisagetmetho dofasmartcontract, invokedanonymously),orapartiallylledformisdisplayed,tob eexplic- itlyconrmedandsubmittedbytheuser(thismayb erequiredforpayment forms). 4.3.22.POSTactions.Aton-sitemayemb edintotheHTMLpagesit returnssomeusual-lo okingPOSTforms,withPOSTactionsreferringei- thertoton-sites,ton-servicesorsmartcontractsbymeansofsuitable(TON) URLs.Inthatcase,oncetheuserllsandsubmitsthatcustomform,the corresp ondingactionistaken,eitherimmediatelyorafteranexplicitconr- mation. 4.3.23.TONWWW.Alloftheab ovewillleadtothecreationofawhole webofcross-referencingentities,residingintheTONNetwork,whichwould b eaccessibletotheenduserthroughaton-browser,providingtheuserwith aWWW-likebrowsingexp erience.Forendusers,thiswillnallymake blo ckchainapplicationsfundamentallysimilartothewebsitestheyareal- readyaccustomedto. 4.3.24.AdvantagesofTONWWW.ThisTONWWWofon-chain ando-chainserviceshassomeadvantagesoveritsconventionalcounterpart. Forexample,paymentsareinherentlyintegratedinthesystem.Useridentity canb ealwayspresentedtotheservices(bymeansofautomaticallygenerated signaturesonthetransactionsandRPCrequestsgenerated),orhiddenat will.Serviceswouldnotneedtocheckandre-checkusercredentials;these credentialscanb epublishedintheblo ckchainonceandforall.Usernetwork anonymitycanb eeasilypreservedbymeansofTONProxy,andallservices willb eeectivelyunblo ckable.Micropaymentsarealsop ossibleandeasy, b ecauseton-browserscanb eintegratedwiththeTONPaymentssystem. 110 5.1.PaymentChannels 5TONPayments Thelastcomp onentoftheTONPro jectwewillbrieydiscussinthistext isTONPayments,theplatformfor(micro)paymentchannelsandlightning networkvaluetransfers.Itwouldenableinstantpayments,withoutthe needtocommitalltransactionsintotheblo ckchain,paytheasso ciatedtrans- actionfees(e.g.,forthegasconsumed),andwaitvesecondsuntiltheblo ck containingthetransactionsinquestionisconrmed. Theoveralloverheadofsuchinstantpaymentsissosmallthatonecan usethemformicropayments.Forexample,aTONle-storingservicemight chargetheuserforevery128KiBofdownloadeddata,orapaidTONProxy mightrequiresometinymicropaymentforevery128KiBoftracrelayed. WhileTONPaymentsislikelytob ereleasedlaterthanthecorecomp o- nentsoftheTONPro ject,someconsiderationsneedtob emadeatthevery b eginning.Forexample,theTONVirtualMachine(TONVM;cf.2.1.20), usedtoexecutetheco deofTONBlo ckchainsmartcontracts,mustsupp ort somesp ecialop erationswithMerklepro ofs.Ifsuchsupp ortisnotpresent intheoriginaldesign,addingitatalaterstagemightb ecomeproblematic (cf.2.8.16).Wewillsee,however,thattheTONVMcomeswithnatural supp ortforsmartpaymentchannels(cf.5.1.9)outoftheb ox. 5.1PaymentChannels Westartwithadiscussionofp oint-to-p ointpaymentchannels,andhowthey canb eimplementedintheTONBlo ckchain. 5.1.1.Theideaofapaymentchannel.Supp osetwoparties,AandB, knowthattheywillneedtomakealotofpaymentstoeachotherinthefuture. Insteadofcommittingeachpaymentasatransactionintheblo ckchain,they createasharedmoneyp o ol(orp erhapsasmallprivatebankwithexactly twoaccounts),andcontributesomefundstoit:Acontributesacoins,and Bcontributesbcoins.Thisisachievedbycreatingasp ecialsmartcontract intheblo ckchain,andsendingthemoneytoit. Beforecreatingthemoneyp o ol,thetwosidesagreetoacertainproto col. Theywillkeeptrackofthestateofthep o olthatis,oftheirbalancesin thesharedp o ol.Originally,thestateis(a,b),meaningthatacoinsactually b elongtoA,andbcoinsb elongtoB.Then,ifAwantstopaydcoins toB,theycansimplyagreethatthenewstateis(a ′ ,b ′ ) = (a−d,b+d). 111 5.1.PaymentChannels Afterwards,if,say,Bwantstopayd ′ coinstoA,thestatewillb ecome (a ′′ ,b ′′ ) = (a ′ +d ′ ,b ′ −d ′ ),andsoon. Allthisup datingofbalancesinsidethep o olisdonecompletelyo-chain. Whenthetwopartiesdecidetowithdrawtheirduefundsfromthep o ol,they dosoaccordingtothenalstateofthep o ol.Thisisachievedbysendinga sp ecialmessagetothesmartcontract,containingtheagreed-up onnalstate (a ∗ ,b ∗ )alongwiththesignaturesofb othAandB.Thenthesmartcontract sendsa ∗ coinstoA,b ∗ coinstoBandself-destructs. Thissmartcontract,alongwiththenetworkproto colusedbyAandBto up datethestateofthep o ol,isasimplepaymentchannelbetweenAandB. Accordingtotheclassicationdescrib edin4.1.2,itisamixedservice:partof itsstateresidesintheblo ckchain(thesmartcontract),butmostofitsstate up datesarep erformedo-chain(bythenetworkproto col).Ifeverything go eswell,thetwopartieswillb eabletop erformasmanypaymentstoeach otherastheywant(withtheonlyrestrictionb eingthatthecapacityof thechannelisnotoverruni.e.,theirbalancesinthepaymentchannelb oth remainnon-negative),committingonlytwotransactionsintotheblo ckchain: onetoop en(create)thepaymentchannel(smartcontract),andanotherto close(destroy)it. 5.1.2.Trustlesspaymentchannels.Thepreviousexamplewassomewhat unrealistic,b ecauseitassumesthatb othpartiesarewillingtoco op erateand willnevercheattogainsomeadvantage.Imagine,forexample,thatAwill cho osenottosignthenalbalance(a ′ ,b ′ )witha ′ < a.ThiswouldputBin adicultsituation. Toprotectagainstsuchscenarios,oneusuallytriestodeveloptrustless paymentchannelproto cols,whichdonotrequirethepartiestotrusteach other,andmakeprovisionsforpunishinganypartywhowouldattemptto cheat. Thisisusuallyachievedwiththeaidofsignatures.Thepaymentchannel smartcontractknowsthepublickeysofAandB,anditcanchecktheir signaturesifneeded.Thepaymentchannelproto colrequiresthepartiesto signtheintermediatestatesandsendthesignaturestoeachother.Then, ifoneofthepartiescheatsforinstance,pretendsthatsomestateofthe paymentchannelneverexisteditsmisb ehaviorcanb eprovedbyshowing itssignatureonthatstate.Thepaymentchannelsmartcontractactsas anon-chainarbiter,abletopro cesscomplaintsofthetwopartiesab out eachother,andpunishtheguiltypartybyconscatingallofitsmoneyand 112 5.1.PaymentChannels awardingittotheotherparty. 5.1.3.Simplebidirectionalsynchronoustrustlesspaymentchannel. Considerthefollowing,morerealisticexample:Letthestateofthepayment channelb edescrib edbytriple(δ i ,i,o i ),whereiisthesequencenumb erofthe state(itisoriginallyzero,andthenitisincreasedbyonewhenasubsequent stateapp ears),δ i isthechannelimbalance(meaningthatAandBowna+δ i andb−δ i coins,resp ectively),ando i isthepartyallowedtogeneratethe nextstate(eitherAorB).Eachstatemustb esignedb othbyAandB b eforeanyfurtherprogresscanb emade. Now,ifAwantstotransferdcoinstoBinsidethepaymentchannel,and thecurrentstateisS i = (δ i ,i,o i )witho i =A,thenitsimplycreatesanew stateS i+1 = (δ i −d,i+ 1,o i+1 ),signsit,andsendsittoBalongwithits signature.ThenBconrmsitbysigningandsendingacopyofitssignature toA.Afterthat,b othpartieshaveacopyofthenewstatewithb othoftheir signatures,andanewtransfermayo ccur. IfAwantstotransfercoinstoBinastateS i witho i =B,thenitrst asksBtocommitasubsequentstateS i+1 withthesameimbalanceδ i+1 =δ i , butwitho i+1 =A.Afterthat,Awillb eabletomakeitstransfer. Whenthetwopartiesagreetoclosethepaymentchannel,theyb othput theirsp ecialnalsignaturesonthestateS k theyb elievetob enal,and invokethecleanortwo-sidednalizationmethodofthepaymentchannel smartcontractbysendingitthenalstatealongwithb othnalsignatures. Iftheotherpartydo esnotagreetoprovideitsnalsignature,orsimplyif itstopsresp onding,itisp ossibletoclosethechannelunilaterally.Forthis, thepartywishingtodosowillinvoketheunilateralnalizationmetho d, sendingtothesmartcontractitsversionofthenalstate,itsnalsignature, andthemostrecentstatehavingasignatureoftheotherparty.Afterthat, thesmartcontractdo esnotimmediatelyactonthenalstatereceived. Instead,itwaitsforacertainp erio doftime(e.g.,oneday)fortheotherparty topresentitsversionofthenalstate.Whentheotherpartysubmitsits versionanditturnsouttob ecompatiblewiththealreadysubmittedversion, thetruenalstateiscomputedbythesmartcontractandusedtodistribute themoneyaccordingly.Iftheotherpartyfailstopresentitsversionofthe nalstatetothesmartcontract,thenthemoneyisredistributedaccording totheonlycopyofthenalstatepresented. Ifoneofthetwopartiescheatsforexample,bysigningtwodierent statesasnal,orbysigningtwodierentnextstatesS i+1 andS ′ i+1 ,orby 113 5.1.PaymentChannels signinganinvalidnewstateS i+1 (e.g.,withimbalanceδ i+1 <−aor> b) thentheotherpartymaysubmitpro ofofthismisb ehaviortoathirdmetho d ofthesmartcontract.Theguiltypartyispunishedimmediatelybylosing itsshareinthepaymentchannelcompletely. Thissimplepaymentchannelproto colisfairinthesensethatanyparty canalwaysgetitsdue,withorwithouttheco op erationoftheotherparty, andislikelytoloseallofitsfundscommittedtothepaymentchannelifit triestocheat. 5.1.4.Synchronouspaymentchannelasasimplevirtualblo ckchain withtwovalidators.Theab oveexampleofasimplesynchronouspayment channelcanb erecastasfollows.ImaginethatthesequenceofstatesS 0 , S 1 ,. . . ,S n isactuallythesequenceofblo cksofaverysimpleblo ckchain. Eachblo ckofthisblo ckchaincontainsessentiallyonlythecurrentstateof theblo ckchain,andmayb eareferencetothepreviousblo ck(i.e.,itshash). BothpartiesAandBactasvalidatorsforthisblo ckchain,soeveryblo ck mustcollectb othoftheirsignatures.ThestateS i oftheblo ckchaindenes thedesignatedpro ducero i forthenextblo ck,sothereisnoraceb etweenA andBforpro ducingthenextblo ck.Pro ducerAisallowedtocreateblo cks thattransferfundsfromAtoB(i.e.,decreasetheimbalance:δ i+1 ≤δ i ),and BcanonlytransferfundsfromBtoA(i.e.,increaseδ). Ifthetwovalidatorsagreeonthenalblo ck(andthenalstate)ofthe blo ckchain,itisnalizedbycollectingsp ecialnalsignaturesofthetwo parties,andsubmittingthemalongwiththenalblo cktothechannelsmart contractforpro cessingandre-distributingthemoneyaccordingly. Ifavalidatorsignsaninvalidblo ck,orcreatesafork,orsignstwodierent nalblo cks,itcanb epunishedbypresentingapro ofofitsmisb ehaviorto thesmartcontract,whichactsasanon-chainarbiterforthetwovalidators; thentheoendingpartywillloseallitsmoneykeptinthepaymentchannel, whichisanalogoustoavalidatorlosingitsstake. 5.1.5.Asynchronouspaymentchannelasavirtualblo ckchainwith twoworkchains.Thesynchronouspaymentchanneldiscussedin5.1.3 hasacertaindisadvantage:onecannotb eginthenexttransaction(money transferinsidethepaymentchannel)b eforethepreviousoneisconrmedby theotherparty.Thiscanb exedbyreplacingthesinglevirtualblo ckchain discussedin5.1.4byasystemoftwointeractingvirtualworkchains(orrather shardchains). 114 5.1.PaymentChannels TherstoftheseworkchainscontainsonlytransactionsbyA,andits blo ckscanb egeneratedonlybyA;itsstatesareS i = (i,φ i ,j,ψ j ),where iistheblo cksequencenumb er(i.e.,thecountoftransactions,ormoney transfers,p erformedbyAsofar),φ i isthetotalamounttransferredfromA toBsofar,jisthesequencenumb erofthemostrecentvalidblo ckinB's blo ckchainthatAisawareof,andψ j istheamountofmoneytransferred fromBtoAinitsjtransactions.AsignatureofBputontoitsj-thblo ck shouldalsob eapartofthisstate.Hashesofthepreviousblo ckofthis workchainandofthej-thblo ckoftheotherworkchainmayb ealsoincluded. ValidityconditionsforS i includeφ i ≥0,φ i ≥φ i−1 ifi >0,ψ j ≥0,and −a≤ψ j −φ i ≤b. Similarly,thesecondworkchaincontainsonlytransactionsbyB,andits blo cksaregeneratedonlybyB;itsstatesareT j = (j,ψ j ,i,φ i ),withsimilar validityconditions. Now,ifAwantstotransfersomemoneytoB,itsimplycreatesanew blo ckinitsworkchain,signsit,andsendstoB,withoutwaitingforconr- mation. ThepaymentchannelisnalizedbyAsigning(itsversionof )thenal stateofitsblo ckchain(withitssp ecialnalsignature),Bsigningthe- nalstateofitsblo ckchain,andpresentingthesetwonalstatestotheclean nalizationmetho dofthepaymentchannelsmartcontract.Unilateralnal- izationisalsop ossible,butinthatcasethesmartcontractwillhavetowait fortheotherpartytopresentitsversionofthenalstate,atleastforsome gracep erio d. 5.1.6.Unidirectionalpaymentchannels.IfonlyAneedstomakepay- mentstoB(e.g.,Bisaserviceprovider,andAitsclient),thenaunilateral paymentchannelcanb ecreated.Essentially,itisjusttherstworkchain describ edin5.1.5withoutthesecondone.Conversely,onecansaythat theasynchronouspaymentchanneldescrib edin5.1.5consistsoftwounidi- rectionalpaymentchannels,orhalf-channels,managedbythesamesmart contract. 5.1.7.Moresophisticatedpaymentchannels.Promises.Wewillsee laterin5.2.4thatthelightningnetwork(cf.5.2),whichenablesinstant moneytransfersthroughchainsofseveralpaymentchannels,requireshigher degreesofsophisticationfromthepaymentchannelsinvolved. Inparticular,wewanttob eabletocommitpromises,orconditional moneytransfers:AagreestosendccoinstoB,butBwillgetthemoney 115 5.1.PaymentChannels onlyifacertainconditionisfullled,forinstance,ifBcanpresentsome stringuwithHash(u) =vforaknownvalueofv.Otherwise,Acangetthe moneybackafteracertainp erio doftime. Suchapromisecouldeasilyb eimplementedon-chainbyasimplesmart contract.However,wewantpromisesandotherkindsofconditionalmoney transferstob ep ossibleo-chain,inthepaymentchannel,b ecausetheycon- siderablysimplifymoneytransfersalongachainofpaymentchannelsexisting inthelightningnetwork(cf.5.2.4). Thepaymentchannelasasimpleblo ckchainpictureoutlinedin5.1.4 and5.1.5b ecomesconvenienthere.Nowweconsideramorecomplicatedvir- tualblo ckchain,thestateofwhichcontainsasetofsuchunfullledpromises, andtheamountoffundslo ckedinsuchpromises.Thisblo ckchainorthe twoworkchainsintheasynchronouscasewillhavetoreferexplicitlyto thepreviousblo cksbytheirhashes.Nevertheless,thegeneralmechanism remainsthesame. 5.1.8.Challengesforthesophisticatedpaymentchannelsmartcon- tracts.Noticethat,whilethenalstateofasophisticatedpaymentchannel isstillsmall,andthecleannalizationissimple(ifthetwosideshave agreedontheiramountsdue,andb othhavesignedtheiragreement,nothing elseremainstob edone),theunilateralnalizationmetho dandthemetho d forpunishingfraudulentb ehaviorneedtob emorecomplex.Indeed,they mustb eabletoacceptMerklepro ofsofmisb ehavior,andtocheckwhether themoresophisticatedtransactionsofthepaymentchannelblo ckchainhave b eenpro cessedcorrectly. Inotherwords,thepaymentchannelsmartcontractmustb eableto workwithMerklepro ofs,tochecktheirhashvalidity,andmustcontain animplementationofev\_transandev\_blockfunctions(cf.2.2.6)forthe paymentchannel(virtual)blo ckchain. 5.1.9.TONVMsupp ortforsmartpaymentchannels.TheTON VM,usedtoruntheco deofTONBlo ckchainsmartcontracts,isuptothe challengeofexecutingthesmartcontractsrequiredforsmart,orsophisti- cated,paymentchannels(cf.5.1.8). Atthisp ointtheeverythingisabagofcellsparadigm(cf.2.5.14)b e- comesextremelyconvenient.Sinceallblo cks(includingtheblo cksofthe ephemeralpaymentchannelblo ckchain)arerepresentedasbagsofcells(and describ edbysomealgebraicdatatyp es),andthesameholdsformessages andMerklepro ofsaswell,aMerklepro ofcaneasilyb eemb eddedintoan 116 5.1.PaymentChannels inb oundmessagesenttothepaymentchannelsmartcontract.Thehash conditionoftheMerklepro ofwillb echeckedautomatically,andwhenthe smartcontractaccessestheMerklepro of presented,itwillworkwithit asifitwereavalueofthecorresp ondingalgebraicdatatyp ealb eitincom- plete,withsomesubtreesofthetreereplacedbysp ecialno descontainingthe Merklehashoftheomittedsubtree.Thenthesmartcontractwillworkwith thatvalue,whichmightrepresent,forinstance,ablo ckofthepaymentchan- nel(virtual)blo ckchainalongwithitsstate,andwillevaluatetheev\_block function(cf.2.2.6)ofthatblo ckchainonthisblo ckandthepreviousstate. Theneitherthecomputationnishes,andthenalstatecanb ecompared withthatassertedintheblo ck,oranabsentno deexceptionisthrownwhile attemptingtoaccessanabsentsubtree,indicatingthattheMerklepro ofis invalid. Inthisway,theimplementationofthevericationco deforsmartpay- mentchannelblo ckchainsturnsouttob equitestraightforwardusingTON Blo ckchainsmartcontracts.OnemightsaythattheTONVirtualMa- chinecomeswithbuilt-insupportforcheckingthevalidityofothersimple blockchains.TheonlylimitingfactoristhesizeoftheMerklepro oftob e incorp oratedintotheinb oundmessagetothesmartcontract(i.e.,intothe transaction). 5.1.10.Simplepaymentchannelwithinasmartpaymentchannel. Wewouldliketodiscussthep ossibilityofcreatingasimple(synchronousor asynchronous)paymentchannelinsideanexistingpaymentchannel. Whilethismayseemsomewhatconvoluted,itisnotmuchhardertoun- derstandandimplementthanthepromisesdiscussedin5.1.7.Essentially, insteadofpromisingtopayccoinstotheotherpartyifasolutiontosome hashproblemispresented,ApromisestopayuptoccoinstoBaccording tothenalsettlementofsomeother(virtual)paymentchannelblo ckchain. Generallysp eaking,thisotherpaymentchannelblo ckchainneednotevenb e b etweenAandB;itmightinvolvesomeotherparties,say,CandD,will- ingtocommitcanddcoinsintotheirsimplepaymentchannel,resp ectively. (Thisp ossibilityisexploitedlaterin5.2.5.) Iftheencompassingpaymentchannelisasymmetric,twopromisesneed tob ecommittedintothetwoworkchains:Awillpromisetopay−δcoins toBifthenalsettlementoftheinternalsimplepaymentchannelyields anegativenalimbalanceδwith0≤ −δ≤c;andBwillhavetopromise topayδtoAifδisp ositive.Ontheotherhand,iftheencompassing 117 5.2.PaymentChannelNetwork,orLightningNetwork paymentchannelissymmetric,thiscanb edonebycommittingasingle simplepaymentchannelcreationtransactionwithparameters(c,d)into thesinglepaymentchannelblo ckchainbyA(whichwouldfreezeccoins b elongingtoA),andthencommittingasp ecialconrmationtransaction byB(whichwouldfreezedcoinsofB). Weexp ecttheinternalpaymentchanneltob eextremelysimple(e.g.,the simplesynchronouspaymentchanneldiscussedin5.1.3),tominimizethe sizeofMerklepro ofstob esubmitted.Theexternalpaymentchannelwill havetob esmartinthesensedescrib edin5.1.7. 5.2PaymentChannelNetwork,orLightningNetwork NowwearereadytodiscussthelightningnetworkofTONPaymentsthat enablesinstantmoneytransfersb etweenanytwoparticipatingno des. 5.2.1.Limitationsofpaymentchannels.Apaymentchannelisusefulfor partieswhoexp ectalotofmoneytransfersb etweenthem.However,ifone needstotransfermoneyonlyonceortwicetoaparticularrecipient,creating apaymentchannelwithherwouldb eimpractical.Amongotherthings,this wouldimplyfreezingasignicantamountofmoneyinthepaymentchannel, andwouldrequireatleasttwoblo ckchaintransactionsanyway. 5.2.2.Paymentchannelnetworks,orlightningnetworks.Payment channelnetworksovercomethelimitationsofpaymentchannelsbyenabling moneytransfersalongchainsofpaymentchannels.IfAwantstotransfer moneytoE,shedo esnotneedtoestablishapaymentchannelwithE.It wouldb esucienttohaveachainofpaymentchannelslinkingAwithE throughseveralintermediateno dessay,fourpaymentchannels:fromAto B,fromBtoC,fromCtoDandfromDtoE. 5.2.3.Overviewofpaymentchannelnetworks.Recallthatapayment channelnetwork,knownalsoasalightningnetwork,consistsofacollection ofparticipatingno des,someofwhichhaveestablishedlong-livedpayment channelsb etweenthem.Wewillseeinamomentthatthesepaymentchannels willhavetob esmartinthesenseof5.1.7.Whenaparticipatingno deA wantstotransfermoneytoanyotherparticipatingno deE,shetriestond apathlinkingAtoEinsidethepaymentchannelnetwork.Whensucha pathisfound,shep erformsachainmoneytransferalongthispath. 118 5.2.PaymentChannelNetwork,orLightningNetwork 5.2.4.Chainmoneytransfers.Supp osethatthereisachainofpayment channelsfromAtoB,fromBtoC,fromCtoD,andfromDtoE.Supp ose, further,thatAwantstotransferxcoinstoE. Asimplisticapproachwouldb etotransferxcoinstoBalongtheexisting paymentchannel,andaskhimtoforwardthemoneyfurthertoC.However, itisnotevidentwhyBwouldnotsimplytakethemoneyforhimself.There- fore,onemustemployamoresophisticatedapproach,notrequiringallparties involvedtotrusteachother. Thiscanb eachievedasfollows.Ageneratesalargerandomnumb eru andcomputesitshashv=Hash(u).Thenshecreatesapromisetopay xcoinstoBifanumb eruwithhashvispresented(cf.5.1.7),insideher paymentchannelwithB.Thispromisecontainsv,butnotu,whichisstill keptsecret. Afterthat,BcreatesasimilarpromisetoCintheirpaymentchannel.He isnotafraidtogivesuchapromise,b ecauseheisawareoftheexistenceofa similarpromisegiventohimbyA.IfCeverpresentsasolutionofthehash problemtocollectxcoinspromisedbyB,thenBwillimmediatelysubmit thissolutiontoAtocollectxcoinsfromA. ThensimilarpromisesofCtoDandofDtoEarecreated.When thepromisesareallinplace,Atriggersthetransferbycommunicatingthe solutionutoallpartiesinvolvedorjusttoE. Someminordetailsareomittedinthisdescription.Forexample,these promisesmusthavedierentexpirationtimes,andtheamountpromised mightslightlydieralongthechain(Bmightpromiseonlyx−coinsto C,whereisasmallpre-agreedtransitfee).Weignoresuchdetailsforthe timeb eing,b ecausetheyarenotto orelevantforunderstandinghowpayment channelsworkandhowtheycanb eimplementedinTON. 5.2.5.Virtualpaymentchannelsinsideachainofpaymentchannels. Nowsupp osethatAandEexp ecttomakealotofpaymentstoeachother. Theymightcreateanewpaymentchannelb etweenthemintheblo ckchain, butthiswouldstillb equiteexp ensive,b ecausesomefundswouldb elo ckedin thispaymentchannel.Anotheroptionwouldb etousechainmoneytransfers describ edin5.2.4foreachpayment.However,thiswouldinvolvealotof networkactivityandalotoftransactionsinthevirtualblo ckchainsofall paymentchannelsinvolved. Analternativeistocreateavirtualpaymentchannelinsidethechain linkingAtoEinthepaymentchannelnetwork.Forthis,AandEcreate 119 5.2.PaymentChannelNetwork,orLightningNetwork a(virtual)blo ckchainfortheirpayments,asiftheyweregoingtocreatea paymentchannelintheblo ckchain.However,insteadofcreatingapayment channelsmartcontractintheblo ckchain,theyaskallintermediatepayment channelsthoselinkingAtoB,BtoC,etc.tocreatesimplepayment channelsinsidethem,b oundtothevirtualblo ckchaincreatedbyAandE (cf.5.1.10).Inotherwords,nowapromisetotransfermoneyaccording tothenalsettlementb etweenAandEexistsinsideeveryintermediate paymentchannel. Ifthevirtualpaymentchannelisunidirectional,suchpromisescanb e implementedquiteeasily,b ecausethenalimbalanceδisgoingtob enon- p ositive,sosimplepaymentchannelscanb ecreatedinsideintermediatepay- mentchannelsinthesameorderasdescrib edin5.2.4.Theirexpiration timescanalsob esetinthesameway. Ifthevirtualpaymentchannelisbidirectional,thesituationisslightly morecomplicated.Inthatcase,oneshouldsplitthepromisetotransferδ coinsaccordingtothenalsettlementintotwohalf-promises,asexplained in5.1.10:totransferδ − = max(0,−δ)coinsintheforwarddirection,andto transferδ + = max(0,δ)inthebackwarddirection.Thesehalf-promisescan b ecreatedintheintermediatepaymentchannelsindep endently,onechain ofhalf-promisesinthedirectionfromAtoE,andtheotherchaininthe opp ositedirection. 5.2.6.Findingpathsinthelightningnetwork.Onep ointremains undiscussedsofar:howwillAandEndapathconnectingtheminthe paymentnetwork?Ifthepaymentnetworkisnotto olarge,anOSPF-like proto colcanb eused:allno desofthepaymentnetworkcreateanoverlay network(cf.3.3.17),andtheneveryno depropagatesallavailablelink(i.e., participatingpaymentchannel)informationtoitsneighb orsbyagossippro- to col.Ultimately,allno deswillhaveacompletelistofallpaymentchannels participatinginthepaymentnetwork,andwillb eabletondtheshortest pathsbythemselvesforexample,byapplyingaversionofDijkstra'salgo- rithmmo diedtotakeintoaccountthecapacitiesofthepaymentchannels involved(i.e.,themaximalamountsthatcanb etransferredalongthem). Onceacandidatepathisfound,itcanb eprob edbyasp ecialADNLdata- gramcontainingthefullpath,andaskingeachintermediateno detoconrm theexistenceofthepaymentchannelinquestion,andtoforwardthisdata- gramfurtheraccordingtothepath.Afterthat,achaincanb econstructed, andaproto colforchaintransfers(cf.5.2.4),orforcreatingavirtualpayment 120 5.2.PaymentChannelNetwork,orLightningNetwork channelinsideachainofpaymentchannels(cf.5.2.5),canb erun. 5.2.7.Optimizations.Someoptimizationsmightb edonehere.Forexam- ple,onlytransitno desofthelightningnetworkneedtoparticipateinthe OSPF-likeproto coldiscussedin5.2.6.Twoleaf no deswishingtoconnect throughthelightningnetworkwouldcommunicatetoeachotherthelistsof transitno destheyareconnectedto(i.e.,withwhichtheyhaveestablished paymentchannelsparticipatinginthepaymentnetwork).Thenpathscon- nectingtransitno desfromonelisttotransitno desfromtheotherlistcan b einsp ectedasoutlinedab ovein5.2.6. 5.2.8.Conclusion.Wehaveoutlinedhowtheblo ckchainandnetwork technologiesoftheTONpro jectareadequatetothetaskofcreatingTON Payments,aplatformforo-chaininstantmoneytransfersandmicropay- ments.Thisplatformcanb eextremelyusefulforservicesresidinginthe TONecosystem,allowingthemtoeasilycollectmicropaymentswhenand whererequired. 121 Conclusion Conclusion Wehaveprop osedascalablemulti-blo ckchainarchitecturecapableofsup- p ortingamassivelyp opularcrypto currencyanddecentralizedapplications withuser-friendlyinterfaces. Toachievethenecessaryscalability,weprop osedtheTONBlockchain, atightly-coupledmulti-blo ckchainsystem(cf.2.8.14)withb ottom-upap- proachtosharding(cf.2.8.12and2.1.2).Tofurtherincreasep otentialp er- formance,weintro ducedthe2-blo ckchainmechanismforreplacinginvalid blo cks(cf.2.1.17)andInstantHyp ercub eRoutingforfastercommunication b etweenshards(cf.2.4.20).AbriefcomparisonoftheTONBlo ckchainto existingandprop osedblo ckchainpro jects(cf.2.8and2.9)highlightsthe b enetsofthisapproachforsystemsthatseektohandlemillionsoftransac- tionsp ersecond. TheTONNetwork,describ edinChapter3,coversthenetworkingde- mandsoftheprop osedmulti-blo ckchaininfrastructure.Thisnetworkcom- p onentmayalsob eusedincombinationwiththeblo ckchaintocreateawide sp ectrumofapplicationsandservices,imp ossibleusingtheblo ckchainalone (cf.2.9.13).Theseservices,discussedinChapter4,includeTONDNS,a servicefortranslatinghuman-readableob jectidentiersintotheiraddresses; TONStorage,adistributedplatformforstoringarbitraryles;TONProxy, aserviceforanonymizingnetworkaccessandaccessingTON-p oweredser- vices;andTONPayments(cf.Chapter5),aplatformforinstanto-chain moneytransfersacrosstheTONecosystemthatapplicationsmayusefor micropayments. TheTONinfrastructureallowsforsp ecializedlightclientwalletandton- browserdesktopandsmartphoneapplicationsthatenableabrowser-like exp eriencefortheenduser(cf.4.3.23),makingcrypto currencypayments andinteractionwithsmartcontractsandotherservicesontheTONPlatform accessibletothemassuser. 122 References References \[1\]K.Birman,ReliableDistributedSystems:Technologies,WebServices andApplications,Springer,2005. \[2\]V.Buterin,Ethereum:Anext-generationsmartcontractandde- centralizedapplicationplatform,https://github.com/ethereum/wiki/ wiki/White- Paper,2013. \[3\]M.Ben-Or,B.Kelmer,T.Rabin,Asynchronoussecurecomputa- tionswithoptimalresilience,inProceedingsofthethirteenthannualACM symposiumonPrinciplesofdistributedcomputing,p.183192.ACM, 1994. \[4\]M.Castro,B.Liskov,etal.,Practicalbyzantinefaulttolerance, ProceedingsoftheThirdSymposiumonOperatingSystemsDesignand Implementation(1999),p.173186,availableathttp://pmg.csail.mit. edu/papers/osdi99.pdf. \[5\]EOS.IO,EOS.IOtechnicalwhitepap er,https://github.com/EOSIO/ Documentation/blob/master/TechnicalWhitePaper.md,2017. \[6\]D.Goldschlag,M.Reed,P.Syverson,OnionRoutingforAnony- mousandPrivateInternetConnections,CommunicationsoftheACM, 42,num.2(1999),http://www.onion- router.net/Publications/ CACM- 1999.pdf. \[7\]L.Lamport,R.Shostak,M.Pease,Thebyzantinegeneralsproblem, ACMTransactionsonProgrammingLanguagesandSystems,4/3(1982), p.382401. \[8\]S.Larimer,ThehistoryofBitShares,https://docs.bitshares.org/ bitshares/history.html,2013. \[9\]M.Luby,A.Shokrollahi,etal.,RaptorQforwarderrorcorrection schemeforob jectdelivery,IETFRFC6330,https://tools.ietf.org/ html/rfc6330,2011. \[10\]P.Maymounkov,D.Mazières,Kademlia:Ap eer-to-p eerinfor- mationsystembasedontheXORmetric,inIPTPS'01revisedpa- persfromtheFirstInternationalWorkshoponPeer-to-PeerSystems, 123 References p.5365,availableathttp://pdos.csail.mit.edu/~petar/papers/ maymounkov- kademlia- lncs.pdf,2002. \[11\]A.Miller,YuXia,etal.,ThehoneybadgerofBFTproto cols, Cryptologye-printarchive2016/99,https://eprint.iacr.org/2016/ 199.pdf,2016. \[12\]S.Nakamoto,Bitcoin:Ap eer-to-p eerelectroniccashsystem,https: //bitcoin.org/bitcoin.pdf,2008. \[13\]S.PeytonJones,Implementinglazyfunctionallanguagesonsto ck hardware:theSpinelessTaglessG-machine,JournalofFunctionalPro- gramming2(2),p.127202,1992. \[14\]A.Shokrollahi,M.Luby,RaptorCo des,IEEETransactionson InformationTheory6,no.34(2006),p.212322. \[15\]M.vanSteen,A.Tanenbaum,DistributedSystems,3rded.,2017. \[16\]TheUnivalentFoundationsProgram,HomotopyTyp eTheory: UnivalentFoundationsofMathematics,InstituteforAdvancedStudy, 2013,availableathttps://homotopytypetheory.org/book. \[17\]G.Wood,PolkaDot:visionforaheterogeneousmulti-chainframe- work,draft1,https://github.com/w3f/polkadot- white- paper/raw/ master/PolkaDotPaper.pdf,2016. 124 AppendixA.TheTONCoin ATheTONCoin Theprincipalcrypto currencyoftheTONBlo ckchain,andinparticularof itsmasterchainandbasicworkchain,istheTONCoin.Itisusedtomake dep ositsrequiredtob ecomeavalidator;transactionfees,gaspayments(i.e., smart-contractmessagepro cessingfees)andp ersistentstoragepaymentsare alsousuallycollectedinTONcoins. A.1.Sub divisionandterminology.ATONcoinissub dividedintoone billion(10 9 )smallerunits,callednanotons,ntonsorsimplynanos.Alltrans- fersandaccountbalancesareexpressedasnon-negativeintegermultiplesof nanos.Otherunitsinclude: ˆAnano,ntonornanotonisthesmallestunit,equalto10 −9 TONcoins. ˆAmicroormicrotonequalsonethousand(10 3 )nanos. ˆAmil liisonemillion(10 6 )nanos,oronethousandthpart(10 −3 )ofa TONcoin. ˆATONcoinequalsonebillion(10 9 )nanos. ˆAkiloton,orkTon,equalsonethousand(10 3 )TONcoins. ˆAmegaton,orMTon,equalsonemillion(10 6 )TONcoins,or10 15 nanos. ˆFinally,agigaton,orGTon,equalsonebillion(10 9 )TONcoins,or10 18 nanos. Therewillb enoneedforlargerunits,b ecausetheinitialsupplyofTON coinswillb elimitedtovebillion(5·10 9 )TONcoins(i.e.,5Gigatons). A.2.Smallerunitsforexpressinggasprices.Ifthenecessityforsmaller unitsarises,sp ecksequalto2 −16 nanotonswillb eused.Forexample,gas pricesmayb eindicatedinsp ecks.However,theactualfeetob epaid,com- putedasthepro ductofthegaspriceandtheamountofgasconsumed,will b ealwaysroundeddowntothenearestmultipleof2 16 sp ecksandexpressed asanintegernumb erofnanos. 125 AppendixA.TheTONCoin A.3.Originalsupply,miningrewardsandination.Thetotalsupply ofTONcoinsisoriginallylimitedto5Gigatons(i.e.,vebillionTONcoins or5·10 18 nanos). Thissupplywillincreaseveryslowly,asrewardstovalidatorsformining newmasterchainandshardchainblo cksaccumulate.Theserewardswould amounttoapproximately20%(theexactnumb ermayb eadjustedinfuture) ofthevalidator'sstakep eryear,providedthevalidatordiligentlyp erforms itsduties,signsallblo cks,nevergo esoineandneversignsinvalidblo cks.In thisway,thevalidatorswillhaveenoughprottoinvestintob etterandfaster hardwareneededtopro cesstheevergrowingquantityofusers'transactions. Weexp ectthatatmost10% 35 ofthetotalsupplyofTONcoins,on average,willb eb oundinvalidatorstakesatanygivenmoment.Thiswill pro duceaninationrateof2%p eryear,andasaresult,willdoublethe totalsupplyofTONcoins(totenGigatons)in35years.Essentially,this inationrepresentsapaymentmadebyallmemb ersofthecommunitytothe validatorsforkeepingthesystemupandrunning. Ontheotherhand,ifavalidatoriscaughtmisb ehaving,apartorallof itsstakewillb etakenawayasapunishment,andalargerp ortionofitwill subsequentlyb eburned,decreasingthetotalsupplyofTONcoins.This wouldleadtodeation.Asmallerp ortionofthenemayb eredistributed tothevalidatorortheshermanwhocommittedapro ofoftheguilty validator'smisb ehavior. 35 Themaximumtotalamountofvalidatorstakesisacongurableparameterofthe blo ckchain,sothisrestrictioncanb eenforcedbytheproto colifnecessary. 126 --- # Unknown Telegram Open Network Virtual Machine Nikolai Durov March 23, 2020 Abstract The aim of this text is to provide a description of the Telegram Open Network Virtual Machine (TON VM or TVM), used to execute smart contracts in the TON Blockchain. Introduction The primary purpose of the Telegram Open Network Virtual Machine (TON VM or TVM) is to execute smart-contract code in the TON Blockchain. TVM must support all operations required to parse incoming messages and persistent data, and to create new messages and modify persistent data. Additionally, TVM must meet the following requirements: •It must provide for possible future extensions and improvements while retaining backward compatibility and interoperability, because the code of a smart contract, once committed into the blockchain, must continue working in a predictable manner regardless of any future modifications to the VM. •It must strive to attain high “(virtual) machine code” density, so that the code of a typical smart contract occupies as little persistent block- chain storage as possible. •It must be completely deterministic. In other words, each run of the same code with the same input data must produce the same result, 1 Introduction regardless of specific software and hardware used. 1 The design of TVM is guided by these requirements. While this document describes a preliminary and experimental version of TVM, 2 the backward compatibility mechanisms built into the system allow us to be relatively unconcerned with the efficiency of the operation encoding used for TVM code in this preliminary version. TVM is not intended to be implemented in hardware (e.g., in a specialized microprocessor chip); rather, it should be implemented in software running on conventional hardware. This consideration lets us incorporate some high- level concepts and operations in TVM that would require convoluted mi- crocode in a hardware implementation but pose no significant problems for a software implementation. Such operations are useful for achieving high code density and minimizing the byte (or storage cell) profile of smart-contract code when deployed in the TON Blockchain. 1 For example, there are no floating-point arithmetic operations (which could be effi- ciently implemented using hardware-supporteddoubletype on most modern CPUs) present in TVM, because the result of performing such operations is dependent on the specific un- derlying hardware implementation and rounding mode settings. Instead, TVM supports special integer arithmetic operations, which can be used to simulate fixed-point arithmetic if needed. 2 The production version will likely require some tweaks and modifications prior to launch, which will become apparent only after using the experimental version in the test environment for some time. 2 Introduction Contents 1 Overview5 1.0 Notation for bitstrings . . . . . . . . . . . . . . . . . . . . . . 5 1.1 TVM is a stack machine . . . . . . . . . . . . . . . . . . . . . 6 1.2 Categories of TVM instructions . . . . . . . . . . . . . . . . . 9 1.3 Control registers . . . . . . . . . . . . . . . . . . . . . . . . . 10 1.4 Total state of TVM (SCCCG) . . . . . . . . . . . . . . . . . . 12 1.5 Integer arithmetic . . . . . . . . . . . . . . . . . . . . . . . . . 13 2 The stack16 2.1 Stack calling conventions . . . . . . . . . . . . . . . . . . . . . 16 2.2 Stack manipulation primitives . . . . . . . . . . . . . . . . . . 21 2.3 Efficiency of stack manipulation primitives . . . . . . . . . . . 25 3 Cells, memory, and persistent storage28 3.1 Generalities on cells . . . . . . . . . . . . . . . . . . . . . . . . 28 3.2 Data manipulation instructions and cells . . . . . . . . . . . . 32 3.3 Hashmaps, or dictionaries . . . . . . . . . . . . . . . . . . . . 37 3.4 Hashmaps with variable-length keys . . . . . . . . . . . . . . . 47 4 Control flow, continuations, and exceptions49 4.1 Continuations and subroutines . . . . . . . . . . . . . . . . . . 49 4.2 Control flow primitives: conditional and iterated execution . . 53 4.3 Operations with continuations . . . . . . . . . . . . . . . . . . 55 4.4 Continuations as objects . . . . . . . . . . . . . . . . . . . . . 57 4.5 Exception handling . . . . . . . . . . . . . . . . . . . . . . . . 58 4.6 Functions, recursion, and dictionaries . . . . . . . . . . . . . . 61 5 Codepages and instruction encoding67 5.1 Codepages and interoperability of different TVM versions . . . 67 5.2 Instruction encoding . . . . . . . . . . . . . . . . . . . . . . . 70 5.3 Instruction encoding in codepage zero . . . . . . . . . . . . . . 73 A Instructions and opcodes77 A.1 Gas prices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 A.2 Stack manipulation primitives . . . . . . . . . . . . . . . . . . 78 A.3 Tuple, List, and Null primitives . . . . . . . . . . . . . . . . . 81 A.4 Constant, or literal primitives . . . . . . . . . . . . . . . . . . 86 3 Introduction A.5 Arithmetic primitives . . . . . . . . . . . . . . . . . . . . . . . 88 A.6 Comparison primitives . . . . . . . . . . . . . . . . . . . . . . 92 A.7 Cell primitives . . . . . . . . . . . . . . . . . . . . . . . . . . . 95 A.8 Continuation and control flow primitives . . . . . . . . . . . . 105 A.9 Exception generating and handling primitives . . . . . . . . . 114 A.10 Dictionary manipulation primitives . . . . . . . . . . . . . . . 115 A.11 Application-specific primitives . . . . . . . . . . . . . . . . . . 128 A.12 Debug primitives . . . . . . . . . . . . . . . . . . . . . . . . . 138 A.13 Codepage primitives . . . . . . . . . . . . . . . . . . . . . . . 140 B Formal properties and specifications of TVM142 B.1 Serialization of the TVM state . . . . . . . . . . . . . . . . . . 142 B.2 Step function of TVM . . . . . . . . . . . . . . . . . . . . . . 144 C Code density of stack and register machines147 C.1 Sample leaf function . . . . . . . . . . . . . . . . . . . . . . . 147 C.2 Comparison of machine code for sample leaf function . . . . . 154 C.3 Sample non-leaf function . . . . . . . . . . . . . . . . . . . . . 160 C.4 Comparison of machine code for sample non-leaf function . . . 170 4 1.0. Notation for bitstrings 1 Overview This chapter provides an overview of the main features and design principles of TVM. More detail on each topic is provided in subsequent chapters. 1.0 Notation for bitstrings The following notation is used for bit strings (orbitstrings)—i.e., finite strings consisting of binary digits (bits),0and1—throughout this document. 1.0.1. Hexadecimal notation for bitstrings.When the length of a bit- string is a multiple of four, we subdivide it into groups of four bits and represent each group by one of sixteen hexadecimal digits0–9,A–Fin the usual manner:0 16 ↔0000,1 16 ↔0001, . . . ,F 16 ↔1111. The resulting hexadecimal string is our equivalent representation for the original binary string. 1.0.2. Bitstrings of lengths not divisible by four.If the length of a binary string is not divisible by four, we augment it by one1and several (maybe zero)0s at the end, so that its length becomes divisible by four, and then transform it into a string of hexadecimal digits as described above. To indicate that such a transformation has taken place, a special “completion tag”\_is added to the end of the hexadecimal string. The reverse transforma- tion (applied if the completion tag is present) consists in first replacing each hexadecimal digit by four corresponding bits, and then removing all trailing zeroes (if any) and the last1immediately preceding them (if the resulting bitstring is non-empty at this point). Notice that there are several admissible hexadecimal representations for the same bitstring. Among them, the shortest one is “canonical”. It can be deterministically obtained by the above procedure. For example,8Acorresponds to binary string10001010, while8A\_and 8A0\_both correspond to100010. An empty bitstring may be represented by either ‘’, ‘8\_’, ‘0\_’, ‘\_’, or ‘00\_’. 1.0.3. Emphasizing that a string is a hexadecimal representation of a bitstring.Sometimes we need to emphasize that a string of hexadecimal digits (with or without a\_at the end) is the hexadecimal representation of a bitstring. In such cases, we either prependxto the resulting string (e.g., x8A), or prependx{and append}(e.g.,x{2D9\_}, which is00101101100). 5 1.1. TVM is a stack machine This should not be confused with hexadecimal numbers, usually prepended by0x(e.g.,0x2D9or0x2d9, which is the integer 729). 1.0.4. Serializing a bitstring into a sequence of octets.When a bit- string needs to be represented as a sequence of 8-bit bytes (octets), which take values in integers0...255, this is achieved essentially in the same fash- ion as above: we split the bitstring into groups of eight bits and interpret each group as the binary representation of an integer0...255. If the length of the bitstring is not a multiple of eight, the bitstring is augmented by a binary1and up to seven binary0s before being split into groups. The fact that such a completion has been applied is usually reflected by a “completion tag” bit. For instance,00101101100corresponds to the sequence of two octets (0x2d,0x90)(hexadecimal), or(45,144)(decimal), along with a completion tag bit equal to1(meaning that the completion has been applied), which must be stored separately. In some cases, it is more convenient to assume the completion is enabled by default rather than store an additional completion tag bit separately. Under such conventions,8n-bit strings are represented byn+ 1octets, with the last octet always equal to0x80= 128. 1.1 TVM is a stack machine First of all,TVM is a stack machine.This means that, instead of keeping values in some “variables” or “general-purpose registers”, they are kept in a (LIFO)stack, at least from the “low-level” (TVM) perspective. 3 Most operations and user-defined functions take their arguments from the top of the stack, and replace them with their result. For example, the inte- ger addition primitive (built-in operation)ADDdoes not take any arguments describing which registers or immediate values should be added together and where the result should be stored. Instead, the two top values are taken from the stack, they are added together, and their sum is pushed into the stack in their place. 3 A high-level smart-contract language might create a visibility of variables for the ease of programming; however, the high-level source code working with variables will be translated into TVM machine code keeping all the values of these variables in the TVM stack. 6 1.1. TVM is a stack machine 1.1.1. TVM values.The entities that can be stored in the TVM stack will be calledTVM values, or simplyvaluesfor brevity. They belong to one of several predefinedvalue types. Each value belongs to exactly one value type. The values are always kept on the stack along with tags uniquely determining their types, and all built-in TVM operations (orprimitives) only accept values of predefined types. For example, the integer addition primitiveADDaccepts only two integer values, and returns one integer value as a result. One cannot supplyADDwith two strings instead of two integers expecting it to concatenate these strings or to implicitly transform the strings into their decimal integer values; any attempt to do so will result in a run-time type-checking exception. 1.1.2. Static typing, dynamic typing, and run-time type checking. In some respects TVM performs a kind of dynamic typing using run-time type checking. However, this does not make the TVM code a “dynamically typed language” like PHP or Javascript, because all primitives accept values and return results of predefined (value) types, each value belongs to strictly one type, and values are never implicitly converted from one type to another. If, on the other hand, one compares the TVM code to the conventional microprocessor machine code, one sees that the TVM mechanism of value tagging prevents, for example, using the address of a string as a number— or, potentially even more disastrously, using a number as the address of a string—thus eliminating the possibility of all sorts of bugs and security vulnerabilities related to invalid memory accesses, usually leading to memory corruption and segmentation faults. This property is highly desirable for a VM used to execute smart contracts in a blockchain. In this respect, TVM’s insistence on tagging all values with their appropriate types, instead of reinterpreting the bit sequence in a register depending on the needs of the operation it is used in, is just an additional run-time type-safety mechanism. An alternative would be to somehow analyze the smart-contract code for type correctness and type safety before allowing its execution in the VM, or even before allowing it to be uploaded into the blockchain as the code of a smart contract. Such a static analysis of code for a Turing-complete machine appears to be a time-consuming and non-trivial problem (likely to be equivalent to the stopping problem for Turing machines), something we would rather avoid in a blockchain smart-contract context. One should bear in mind that one always can implement compilers from statically typed high-level smart-contract languages into the TVM code (and 7 1.1. TVM is a stack machine we do expect that most smart contracts for TON will be written in such lan- guages), just as one can compile statically typed languages into conventional machine code (e.g., x86 architecture). If the compiler works correctly, the resulting machine code will never generate any run-time type-checking ex- ceptions. All type tags attached to values processed by TVM will always have expected values and may be safely ignored during the analysis of the resulting TVM code, apart from the fact that the run-time generation and verification of these type tags by TVM will slightly slow down the execution of the TVM code. 1.1.3. Preliminary list of value types.A preliminary list of value types supported by TVM is as follows: •Integer— Signed 257-bit integers, representing integer numbers in the range−2 256 ...2 256 −1, as well as a special “not-a-number” valueNaN. •Cell— ATVM cellconsists of at most 1023 bits of data, and of at most four references to other cells. All persistent data (including TVM code) in the TON Blockchain is represented as a collection of TVM cells (cf. \[1, 2.5.14\]). •Tuple— An ordered collection of up to 255 components, having ar- bitrary value types, possibly distinct. May be used to represent non- persistent values of arbitrary algebraic data types. •Null— A type with exactly one value⊥, used for representing empty lists, empty branches of binary trees, absence of return value in some situations, and so on. •Slice— ATVM cell slice, orslicefor short, is a contiguous “sub-cell” of an existing cell, containing some of its bits of data and some of its references. Essentially, a slice is a read-only view for a subcell of a cell. Slices are used for unpacking data previously stored (or serialized) in a cell or a tree of cells. •Builder— ATVM cell builder, orbuilderfor short, is an “incomplete” cell that supports fast operations of appending bitstrings and cell ref- erences at its end. Builders are used for packing (or serializing) data from the top of the stack into new cells (e.g., before transferring them to persistent storage). 8 1.2. Categories of TVM instructions •Continuation— Represents an “execution token” for TVM, which may be invoked (executed) later. As such, it generalizes function addresses (i.e., function pointers and references), subroutine return addresses, instruction pointer addresses, exception handler addresses, closures, partial applications, anonymous functions, and so on. This list of value types is incomplete and may be extended in future revisions of TVM without breaking the old TVM code, due mostly to the fact that all originally defined primitives accept only values of types known to them and will fail (generate a type-checking exception) if invoked on values of new types. Furthermore, existing value types themselves can also be extended in the future: for example, 257-bitIntegermight become 513-bitLongInteger, with originally defined arithmetic primitives failing if either of the arguments or the result does not fit into the original subtypeInteger. Backward com- patibility with respect to the introduction of new value types and extension of existing value types will be discussed in more detail later (cf.5.1.4). 1.2 Categories of TVM instructions TVMinstructions, also calledprimitivesand sometimes(built-in) operations, are the smallest operations atomically performed by TVM that can be present in the TVM code. They fall into several categories, depending on the types of values (cf.1.1.3) they work on. The most important of these categories are: •Stack (manipulation) primitives— Rearrange data in the TVM stack, so that the other primitives and user-defined functions can later be called with correct arguments. Unlike most other primitives, they are polymorphic, i.e., work with values of arbitrary types. •Tuple (manipulation) primitives— Construct, modify, and decompose Tuples. Similarly to the stack primitives, they are polymorphic. •Constantorliteral primitives— Push into the stack some “constant” or “literal” values embedded into the TVM code itself, thus providing arguments to the other primitives. They are somewhat similar to stack primitives, but are less generic because they work with values of specific types. 9 1.3. Control registers •Arithmetic primitives— Perform the usual integer arithmetic opera- tions on values of typeInteger. •Cell (manipulation) primitives— Create new cells and store data in them (cell creation primitives) or read data from previously created cells (cell parsing primitives). Because all memory and persistent stor- age of TVM consists of cells, these cell manipulation primitives actually correspond to “memory access instructions” of other architectures. Cell creation primitives usually work with values of typeBuilder, while cell parsing primitives work withSlices. •Continuationandcontrol flow primitives— Create and modifyCon- tinuations, as well as execute existingContinuations in different ways, including conditional and repeated execution. •Customorapplication-specific primitives— Efficiently perform spe- cific high-level actions required by the application (in our case, the TON Blockchain), such as computing hash functions, performing ellip- tic curve cryptography, sending new blockchain messages, creating new smart contracts, and so on. These primitives correspond to standard library functions rather than microprocessor instructions. 1.3 Control registers While TVM is a stack machine, some rarely changed values needed in almost all functions are better passed in certain special registers, and not near the top of the stack. Otherwise, a prohibitive number of stack reordering operations would be required to manage all these values. To this end, the TVM model includes, apart from the stack, up to 16 specialcontrol registers, denoted byc0toc15, orc(0)toc(15). The original version of TVM makes use of only some of these registers; the rest may be supported later. 1.3.1. Values kept in control registers.The values kept in control regis- ters are of the same types as those kept on the stack. However, some control registers accept only values of specific types, and any attempt to load a value of a different type will lead to an exception. 1.3.2. List of control registers.The original version of TVM defines and uses the following control registers: 10 1.4. Total state of TVM (SCCCG) •c0— Contains thenext continuationorreturn continuation(similar to the subroutine return address in conventional designs). This value must be aContinuation. •c1— Contains thealternative (return) continuation; this value must be aContinuation. It is used in some (experimental) control flow primitives, allowing TVM to define and call “subroutines with two exit points”. •c2— Contains theexception handler. This value is aContinuation, invoked whenever an exception is triggered. •c3— Contains thecurrent dictionary, essentially a hashmap containing the code of all functions used in the program. For reasons explained later in4.6, this value is also aContinuation, not aCellas one might expect. •c4— Contains theroot of persistent data, or simply thedata. This value is aCell. When the code of a smart contract is invoked,c4 points to the root cell of its persistent data kept in the blockchain state. If the smart contract needs to modify this data, it changesc4 before returning. •c5— Contains theoutput actions. It is also aCellinitialized by a reference to an empty cell, but its final value is considered one of the smart contract outputs. For instance, theSENDMSGprimitive, specific for the TON Blockchain, simply inserts the message into a list stored in the output actions. •c7— Contains theroot of temporary data. It is aTuple, initialized by a reference to an emptyTuplebefore invoking the smart contract and discarded after its termination. 4 More control registers may be defined in the future for specific TON Block- chain or high-level programming language purposes, if necessary. 4 In the TON Blockchain context,c7is initialized with a singletonTuple, the only component of which is aTuplecontaining blockchain-specific data. The smart contract is free to modifyc7to store its temporary data provided the first component of thisTuple remains intact. 11 1.5. Integer arithmetic 1.4 Total state of TVM (SCCCG) The total state of TVM consists of the following components: •Stack(cf.1.1) — Contains zero or morevalues(cf.1.1.1), each be- longing to one ofvalue typeslisted in1.1.3. •Control registersc0–c15— Contain some specific values as described in1.3.2. (Only seven control registers are used in the current version.) •Current continuationcc— Contains the current continuation (i.e., the code that would be normally executed after the current primitive is completed). This component is similar to the instruction pointer reg- ister (ip) in other architectures. •Current codepagecp— A special signed 16-bit integer value that selects the way the next TVM opcode will be decoded. For example, future versions of TVM might use different codepages to add new opcodes while preserving backward compatibility. •Gas limitsgas— Contains four signed 64-bit integers: the current gas limitg l , the maximal gas limitg m , the remaining gasg r , and the gas creditg c . Always0≤g l ≤g m ,g c ≥0, andg r ≤g l +g c ;g c is usually initialized by zero,g r is initialized byg l +g c and gradually decreases as the TVM runs. Wheng r becomes negative or if the final value ofg r is less thang c , anout of gasexception is triggered. Notice that there is no “return stack” containing the return addresses of all previously called but unfinished functions. Instead, only control registerc0 is used. The reason for this will be explained later in4.1.9. Also notice that there are no general-purpose registers, because TVM is a stack machine (cf.1.1). So the above list, which can be summarized as “stack, control, continuation, codepage, and gas” (SCCCG), similarly to the classical SECD machine state (“stack, environment, control, dump”), is indeed thetotalstate of TVM. 5 5 Strictly speaking, there is also the currentlibrary context, which consists of a dictionary with 256-bit keys and cell values, used to load library reference cells of3.1.7. 12 1.5. Integer arithmetic 1.5 Integer arithmetic All arithmetic primitives of TVM operate on several arguments of typeIn- teger, taken from the top of the stack, and return their results, of the same type, into the stack. Recall thatIntegerrepresents all integer values in the range−2 256 ≤x <2 256 , and additionally contains a special valueNaN(“not- a-number”). If one of the results does not fit into the supported range of integers— or if one of the arguments is aNaN—then this result or all of the results are replaced by aNaN, and (by default) an integer overflow exception is generated. However, special “quiet” versions of arithmetic operations will simply produceNaNs and keep going. If theseNaNs end up being used in a “non-quiet” arithmetic operation, or in a non-arithmetic operation, an integer overflow exception will occur. 1.5.1. Absence of automatic conversion of integers.Notice that TVM Integers are “mathematical” integers, and not 257-bit strings interpreted dif- ferently depending on the primitive used, as is common for other machine code designs. For example, TVM has only one multiplication primitiveMUL, rather than two (MULfor unsigned multiplication andIMULfor signed multi- plication) as occurs, for example, in the popular x86 architecture. 1.5.2. Automatic overflow checks.Notice that all TVM arithmetic prim- itives perform overflow checks of the results. If a result does not fit into the Integertype, it is replaced by aNaN, and (usually) an exception occurs. In particular, the result isnotautomatically reduced modulo2 256 or2 257 , as is common for most hardware machine code architectures. 1.5.3. Custom overflow checks.In addition to automatic overflow checks, TVM includes custom overflow checks, performed by primitivesFITSnand UFITSn, where1≤n≤256. These primitives check whether the value on (the top of) the stack is an integerxin the range−2 n−1 ≤x <2 n−1 or 0≤x <2 n , respectively, and replace the value with aNaNand (optionally) generate an integer overflow exception if this is not the case. This greatly simplifies the implementation of arbitraryn-bit integer types, signed or un- signed: the programmer or the compiler must insert appropriateFITSor UFITSprimitives either after each arithmetic operation (which is more rea- sonable, but requires more checks) or before storing computed values and returning them from functions. This is important for smart contracts, where 13 1.5. Integer arithmetic unexpected integer overflows happen to be among the most common source of bugs. 1.5.4. Reduction modulo2 n .TVM also has a primitiveMODPOW2n, which reduces the integer at the top of the stack modulo2 n , with the result ranging from0to2 n −1. 1.5.5.Integeris 257-bit, not 256-bit.One can understand now why TVM’sIntegeris (signed) 257-bit, not 256-bit. The reason is that it is the smallest integer type containing both signed 256-bit integers and unsigned 256-bit integers, which does not require automatic reinterpreting of the same 256-bit string depending on the operation used (cf.1.5.1). 1.5.6. Division and rounding.The most important division primitives areDIV,MOD, andDIVMOD. All of them take two numbers from the stack,x andy(yis taken from the top of the stack, andxis originally under it), compute the quotientqand remainderrof the division ofxbyy(i.e., two integers such thatx=yq+rand|r|<|y|), and return eitherq,r, or both of them. Ifyis zero, then all of the expected results are replaced byNaNs, and (usually) an integer overflow exception is generated. The implementation of division in TVM somewhat differs from most other implementations with regards to rounding. By default, these prim- itives round to−∞, meaning thatq=bx/yc, andrhas the same sign asy. (Most conventional implementations of division use “rounding to zero” instead, meaning thatrhas the same sign asx.) Apart from this “floor rounding”, two other rounding modes are available, called “ceiling rounding” (withq=dx/ye, andrandyhaving opposite signs) and “nearest round- ing” (withq=bx/y+ 1/2cand|r| ≤ |y|/2). These rounding modes are selected by using other division primitives, with lettersCandRappended to their mnemonics. For example,DIVMODRcomputes both the quotient and the remainder using rounding to the nearest integer. 1.5.7. Combined multiply-divide, multiply-shift, and shift-divide operations.To simplify implementation of fixed-point arithmetic, TVM supports combined multiply-divide, multiply-shift, and shift-divide opera- tions with double-length (i.e., 514-bit) intermediate product. For example, MULDIVMODRtakes three integer arguments from the stack,a,b, andc, first computesabusing a 514-bit intermediate result, and then dividesabbyc using rounding to the nearest integer. Ifcis zero or if the quotient does not 14 1.5. Integer arithmetic fit intoInteger, either twoNaNs are returned, or an integer overflow exception is generated, depending on whether a quiet version of the operation has been used. Otherwise, both the quotient and the remainder are pushed into the stack. 15 2.1. Stack calling conventions 2 The stack This chapter contains a general discussion and comparison of register and stack machines, expanded further in AppendixC, and describes the two main classes of stack manipulation primitives employed by TVM: thebasic and thecompound stack manipulation primitives. An informal explanation of their sufficiency for all stack reordering required for correctly invoking other primitives and user-defined functions is also provided. Finally, the problem of efficiently implementing TVM stack manipulation primitives is discussed in2.3. 2.1 Stack calling conventions A stack machine, such as TVM, uses the stack—and especially the values near the top of the stack—to pass arguments to called functions and primi- tives (such as built-in arithmetic operations) and receive their results. This section discusses the TVM stack calling conventions, introduces some no- tation, and compares TVM stack calling conventions with those of certain register machines. 2.1.1. Notation for “stack registers”.Recall that a stack machine, as opposed to a more conventional register machine, lacks general-purpose reg- isters. However, one can treat the values near the top of the stack as a kind of “stack registers”. We denote bys0ors(0)the value at the top of the stack, bys1ors(1) the value immediately under it, and so on. The total number of values in the stack is called itsdepth. If the depth of the stack isn, thens(0),s(1), . . . , s(n−1)are well-defined, whiles(n)and all subsequents(i)withi > nare not. Any attempt to uses(i)withi≥nshould produce a stack underflow exception. A compiler, or a human programmer in “TVM code”, would use these “stack registers” to hold all declared variables and intermediate values, simi- larly to the way general-purpose registers are used on a register machine. 2.1.2. Pushing and popping values.When a valuexispushedinto a stack of depthn, it becomes the news0; at the same time, the olds0becomes the news1, the olds1—the news2, and so on. The depth of the resulting stack isn+ 1. 16 2.1. Stack calling conventions Similarly, when a valuexispoppedfrom a stack of depthn≥1, it is the old value ofs0(i.e., the old value at the top of the stack). After this, it is removed from the stack, and the olds1becomes the news0(the new value at the top of the stack), the olds2becomes the news1, and so on. The depth of the resulting stack isn−1. If originallyn= 0, then the stack isempty, and a value cannot be popped from it. If a primitive attempts to pop a value from an empty stack, astack underflowexception occurs. 2.1.3. Notation for hypothetical general-purpose registers.In order to compare stack machines with sufficiently general register machines, we will denote the general-purpose registers of a register machine byr0,r1, and so on, or byr(0),r(1), . . . ,r(n−1), wherenis the total number of registers. When we need a specific value ofn, we will usen= 16, corresponding to the very popular x86-64 architecture. 2.1.4. The top-of-stack registers0vs. the accumulator registerr0. Some register machine architectures require one of the arguments for most arithmetic and logical operations to reside in a special register called the accumulator. In our comparison, we will assume that the accumulator is the general-purpose registerr0; otherwise we could simply renumber the registers. In this respect, the accumulator is somewhat similar to the top-of- stack “register”s0of a stack machine, because virtually all operations of a stack machine both uses0as one of their arguments and return their result ass0. 2.1.5. Register calling conventions.When compiled for a register ma- chine, high-level language functions usually receive their arguments in certain registers in a predefined order. If there are too many arguments, these func- tions take the remainder from the stack (yes, a register machine usually has a stack, too!). Some register calling conventions pass no arguments in regis- ters at all, however, and only use the stack (for example, the original calling conventions used in implementations of Pascal and C, although modern im- plementations of C use some registers as well). For simplicity, we will assume that up tom≤nfunction arguments are passed in registers, and that these registers arer0,r1, . . . ,r(m−1), in that order (if some other registers are used, we can simply renumber them). 6 6 Our inclusion ofr0here creates a minor conflict with our assumption that the ac- 17 2.1. Stack calling conventions 2.1.6. Order of function arguments.If a function or primitive requires margumentsx 1 , . . . ,x m , they are pushed by the caller into the stack in the same order, starting fromx 1 . Therefore, when the function or primitive is invoked, its first argumentx 1 is ins(m−1), its second argumentx 2 is in s(m−2), and so on. The last argumentx m is ins0(i.e., at the top of the stack). It is the called function or primitive’s responsibility to remove its arguments from the stack. In this respect the TVM stack calling conventions—obeyed, at least, by TMV primitives—match those of Pascal and Forth, and are the opposite of those of C (in which the arguments are pushed into the stack in the reverse order, and are removed by the caller after it regains control, not the callee). Of course, an implementation of a high-level language for TVM might choose some other calling conventions for its functions, different from the default ones. This might be useful for certain functions—for instance, if the total number of arguments depends on the value of the first argument, as happens for “variadic functions” such asscanfandprintf. In such cases, the first one or several arguments are better passed near the top of the stack, not somewhere at some unknown location deep in the stack. 2.1.7. Arguments to arithmetic primitives on register machines. On a stack machine, built-in arithmetic primitives (such asADDorDIVMOD) follow the same calling conventions as user-defined functions. In this respect, user-defined functions (for example, a function computing the square root of a number) might be considered as “extensions” or “custom upgrades” of the stack machine. This is one of the clearest advantages of stack machines (and of stack programming languages such as Forth) compared to register machines. In contrast, arithmetic instructions (built-in operations) on register ma- chines usually get their parameters from general-purpose registers encoded in the full opcode. A binary operation, such asSUB, thus requires two argu- ments,r(i)andr(j), withiandjspecified by the instruction. A register r(k)for storing the result also must be specified. Arithmetic operations can take several possible forms, depending on whetheri,j, andkare allowed to take arbitrary values: •Three-address form — Allows the programmer to arbitrarily choose not only the two source registersr(i)andr(j), but also a separate cumulator register, if present, is alsor0; for simplicity, we will resolve this problem by assuming that the first argument to a function is passed in the accumulator. 18 2.1. Stack calling conventions destination registerr(k). This form is common for most RISC proces- sors, and for the XMM and AVX SIMD instruction sets in the x86-64 architecture. •Two-address form — Uses one of the two operand registers (usually r(i)) to store the result of an operation, so thatk=iis never indicated explicitly. Onlyiandjare encoded inside the instruction. This is the most common form of arithmetic operations on register machines, and is quite popular on microprocessors (including the x86 family). •One-address form — Always takes one of the arguments from the ac- cumulatorr0, and stores the result inr0as well; theni=k= 0, and onlyjneeds to be specified by the instruction. This form is used by some simpler microprocessors (such as Intel 8080). Note that this flexibility is available only for built-in operations, but not for user-defined functions. In this respect, register machines are not as easily “upgradable” as stack machines. 7 2.1.8. Return values of functions.In stack machines such as TVM, when a function or primitive needs to return a result value, it simply pushes it into the stack (from which all arguments to the function have already been removed). Therefore, the caller will be able to access the result value through the top-of-stack “register”s0. This is in complete accordance with Forth calling conventions, but dif- fers slightly from Pascal and C calling conventions, where the accumulator registerr0is normally used for the return value. 2.1.9. Returning several values.Some functions might want to return several valuesy 1 , . . . ,y k , withknot necessarily equal to one. In these cases, thekreturn values are pushed into the stack in their natural order, starting fromy 1 . For example, the “divide with remainder” primitiveDIVMODneeds to re- turn two values, the quotientqand the remainderr. Therefore,DIVMOD pushesqandrinto the stack, in that order, so that the quotient is available 7 For instance, if one writes a function for extracting square roots, this function will always accept its argument and return its result in the same registers, in contrast with a hypothetical built-in square root instruction, which could allow the programmer to arbitrarily choose the source and destination registers. Therefore, a user-defined function is tremendously less flexible than a built-in instruction on a register machine. 19 2.1. Stack calling conventions thereafter ats1and the remainder ats0. The net effect ofDIVMODis to divide the original value ofs1by the original value ofs0, and return the quotient ins1and the remainder ins0. In this particular case the depth of the stack and the values of all other “stack registers” remain unchanged, becauseDIVMODtakes two arguments and returns two results. In general, the values of other “stack registers” that lie in the stack below the arguments passed and the values returned are shifted according to the change of the depth of the stack. In principle, some primitives and user-defined functions might return a variable number of result values. In this respect, the remarks above about variadic functions (cf.2.1.6) apply: the total number of result values and their types should be determined by the values near the top of the stack. (For example, one might push the return valuesy 1 , . . . ,y k , and then push their total numberkas an integer. The caller would then determine the total number of returned values by inspectings0.) In this respect TVM, again, faithfully observes Forth calling conventions. 2.1.10. Stack notation.When a stack of depthncontains valuesz 1 , . . . , z n , in that order, withz 1 the deepest element andz n the top of the stack, the contents of the stack are often represented by a listz 1 z 2 . . .z n , in that order. When a primitive transforms the original stack stateS ′ into a new stateS ′′ , this is often written asS ′ –S ′′ ; this is the so-calledstack notation. For example, the action of the division primitiveDIVcan be described byS x y–Sbx/yc, whereSis any list of values. This is usually abbreviated asx y–bx/yc, tacitly assuming that all other values deeper in the stack remain intact. Alternatively, one can describeDIVas a primitive that runs on a stackS ′ of depthn≥2, dividess1bys0, and returns the floor-rounded quotient as s0of the new stackS ′′ of depthn−1. The new value ofs(i)equals the old value ofs(i+ 1)for1≤i < n−1. These descriptions are equivalent, but saying thatDIVtransformsx yintobx/yc, or . . .x yinto . . .bx/yc, is more concise. The stack notation is extensively used throughout AppendixA, where all currently defined TVM primitives are listed. 2.1.11. Explicitly defining the number of arguments to a function. Stack machines usually pass the current stack in its entirety to the invoked primitive or function. That primitive or function accesses only the several values near the top of the stack that represent its arguments, and pushes the 20 2.2. Stack manipulation primitives return values in their place, by convention leaving all deeper values intact. Then the resulting stack, again in its entirety, is returned to the caller. Most TVM primitives behave in this way, and we expect most user-defined functions to be implemented under such conventions. However, TVM pro- vides mechanisms to specify how many arguments must be passed to a called function (cf.4.1.10). When these mechanisms are employed, the specified number of values are moved from the caller’s stack into the (usually initially empty) stack of the called function, while deeper values remain in the caller’s stack and are inaccessible to the callee. The caller can also specify how many return values it expects from the called function. Such argument-checking mechanisms might be useful, for example, for a library function that calls user-provided functions passed as arguments to it. 2.2 Stack manipulation primitives A stack machine, such as TVM, employs a lot of stack manipulation primi- tives to rearrange arguments to other primitives and user-defined functions, so that they become located near the top of the stack in correct order. This section discusses which stack manipulation primitives are necessary and suf- ficient for achieving this goal, and which of them are used by TVM. Some examples of code using these primitives can be found in AppendixC. 2.2.1. Basic stack manipulation primitives.The most important stack manipulation primitives used by TVM are the following: •Top-of-stack exchange operation:XCHG s0,s(i)orXCHG s(i)— Ex- changes values ofs0ands(i). Wheni= 1, operationXCHG s1is traditionally denoted bySWAP. Wheni= 0, this is aNOP(an operation that does nothing, at least if the stack is non-empty). •Arbitrary exchange operation:XCHG s(i),s(j)— Exchanges values of s(i)ands(j). Notice that this operation is not strictly necessary, be- cause it can be simulated by three top-of-stack exchanges:XCHG s(i); XCHG s(j);XCHG s(i). However, it is useful to have arbitrary exchanges as primitives, because they are required quite often. •Push operation:PUSH s(i)— Pushes a copy of the (old) value ofs(i) into the stack. Traditionally,PUSH s0is also denoted byDUP(it dupli- cates the value at the top of the stack), andPUSH s1byOVER. 21 2.2. Stack manipulation primitives •Pop operation:POPs(i)— Removes the top-of-stack value and puts it into the (new)s(i−1), or the olds(i). Traditionally,POP s0is also denoted byDROP(it simply drops the top-of-stack value), andPOP s1 byNIP. Some other “unsystematic” stack manipulation operations might be also defined (e.g.,ROT, with stack notationa b c–b c a). While such opera- tions are defined in stack languages like Forth (whereDUP,DROP,OVER,NIP andSWAPare also present), they are not strictly necessary because thebasic stack manipulation primitiveslisted above suffice to rearrange stack registers to allow any arithmetic primitives and user-defined functions to be invoked correctly. 2.2.2. Basic stack manipulation primitives suffice.A compiler or a human TVM-code programmer might use the basic stack primitives as fol- lows. Suppose that the function or primitive to be invoked is to be passed, say, three argumentsx,y, andz, currently located in stack registerss(i),s(j), ands(k). In this circumstance, the compiler (or programmer) might issue operationPUSH s(i)(if a copy ofxis needed after the call to this primitive) orXCHG s(i)(if it will not be needed afterwards) to put the first argument xinto the top of the stack. Then, the compiler (or programmer) could use eitherPUSH s(j ′ )orXCHG s(j ′ ), wherej ′ =jorj+ 1, to putyinto the new top of the stack. 8 Proceeding in this manner, we see that we can put the original values of x,y, andz—or their copies, if needed—into locationss2,s1, ands0, using a sequence of push and exchange operations (cf.2.2.4and2.2.5for a more detailed explanation). In order to generate this sequence, the compiler will need to know only the three valuesi,jandk, describing the old locations of variables or temporary values in question, and some flags describing whether each value will be needed thereafter or is needed only for this primitive or function call. The locations of other variables and temporary values will be affected in the process, but a compiler (or a human programmer) can easily track their new locations. 8 Of course, if the second option is used, this will destroy the original arrangement of xin the top of the stack. In this case, one should either issue aSWAPbeforeXCHG s(j ′ ), or replace the previous operationXCHG s(i)withXCHG s1, s(i), so thatxis exchanged withs1from the beginning. 22 2.2. Stack manipulation primitives Similarly, if the results returned from a function need to be discarded or moved to other stack registers, a suitable sequence of exchange and pop operations will do the job. In the typical case of one return value ins0, this is achieved either by anXCHG s(i)or aPOP s(i)(in most cases, aDROP) operation. 9 Rearranging the result value or values before returning from a function is essentially the same problem as arranging arguments for a function call, and is achieved similarly. 2.2.3. Compound stack manipulation primitives.In order to improve the density of the TVM code and simplify development of compilers, com- pound stack manipulation primitives may be defined, each combining up to four exchange and push or exchange and pop basic primitives. Such com- pound stack operations might include, for example: •XCHG2 s(i),s(j)— Equivalent toXCHG s1,s(i);XCHG s(j). •PUSH2 s(i),s(j)— Equivalent toPUSH s(i);PUSH s(j+ 1). •XCPU s(i),s(j)— Equivalent toXCHG s(i);PUSH s(j). •PUXC s(i),s(j)— Equivalent toPUSH s(i);SWAP;XCHG s(j+1). When j6=iandj6= 0, it is also equivalent toXCHG s(j);PUSH s(i);SWAP. •XCHG3 s(i),s(j),s(k)— Equivalent toXCHG s2,s(i);XCHG s1,s(j); XCHG s(k). •PUSH3 s(i),s(j),s(k)— Equivalent toPUSH s(i);PUSH s(j+1);PUSH s(k+ 2). Of course, such operations make sense only if they admit a more compact encoding than the equivalent sequence of basic operations. For example, if all top-of-stack exchanges,XCHG s1,s(i)exchanges, and push and pop operations admit one-byte encodings, the only compound stack operations suggested above that might merit inclusion in the set of stack manipulation primitives arePUXC,XCHG3, andPUSH3. 9 Notice that the most commonXCHGs(i)operation is not really required here if we do not insist on keeping the same temporary value or variable always in the same stack location, but rather keep track of its subsequent locations. We will move it to some other location while preparing the arguments to the next primitive or function call. 23 2.2. Stack manipulation primitives These compound stack operations essentially augment other primitives (instructions) in the code with the “true” locations of their operands, some- what similarly to what happens with two-address or three-address register machine code. However, instead of encoding these locations inside the op- code of the arithmetic or another instruction, as is customary for register machines, we indicate these locations in a preceding compound stack ma- nipulation operation. As already described in2.1.7, the advantage of such an approach is that user-defined functions (or rarely used specific primitives added in a future version of TVM) can benefit from it as well (cf.C.3for a more detailed discussion with examples). 2.2.4. Mnemonics of compound stack operations.The mnemonics of compound stack operations, some examples of which have been provided in2.2.3, are created as follows. Theγ≥2formal argumentss(i 1 ), . . . ,s(i γ )to such an operationO represent the values in the original stack that will end up ins(γ−1), . . . , s0after the execution of this compound operation, at least if alli ν ,1≤ ν≤γ, are distinct and at leastγ. The mnemonic itself of the operation Ois a sequence ofγtwo-letter stringsPUandXC, withPUmeaning that the corresponding argument is to be PUshed (i.e., a copy is to be created), andXCmeaning that the value is to be eXChanged (i.e., no other copy of the original value is created). Sequences of severalPUorXCstrings may be abbreviated to onePUorXCfollowed by the number of copies. (For instance, we writePUXC2PUinstead ofPUXCXCPU.) As an exception, if a mnemonic would consist of onlyPUor onlyXCstrings, so that the compound operation is equivalent to a sequence ofmPUSHes or eXCHanGes, the notationPUSHmorXCHGmis used instead ofPUmorXCm. 2.2.5. Semantics of compound stack operations.Each compoundγ- ary operationOs(i 1 ),. . . ,s(i γ )is translated into an equivalent sequence of basic stack operations by induction inγas follows: •As a base of induction, ifγ= 0, the only nullary compound stack operation corresponds to an empty sequence of basic stack operations. •Equivalently, we might begin the induction fromγ= 1. ThenPU s(i) corresponds to the sequence consisting of one basic operationPUSH s(i), andXC s(i)corresponds to the one-element sequence consisting ofXCHG s(i). 24 2.3. Efficiency of stack manipulation primitives •Forγ≥1(or forγ≥2, if we useγ= 1as induction base), there are two subcases: 1.Os(i 1 ),...,s(i γ ), withO=XCO ′ , whereO ′ is a compound opera- tion of arityγ−1(i.e., the mnemonic ofO ′ consists ofγ−1strings XCandPU). Letαbe the total quantity ofPUshes inO, andβbe that of eXChanges, so thatα+β=γ. Then the original operation is translated intoXCHG s(β−1),s(i 1 ), followed by the translation ofO ′ s(i 2 ),...,s(i γ ), defined by the induction hypothesis. 2.Os(i 1 ),...,s(i γ ), withO=PUO ′ , whereO ′ is a compound op- eration of arityγ−1. Then the original operation is trans- lated intoPUSH s(i 1 );XCHG s(β), followed by the translation of O ′ s(i 2 + 1),...,s(i γ + 1), defined by the induction hypothesis. 10 2.2.6. Stack manipulation instructions are polymorphic.Notice that the stack manipulation instructions are almost the only “polymorphic” prim- itives in TVM—i.e., they work with values of arbitrary types (including the value types that will appear only in future revisions of TVM). For exam- ple,SWAPalways interchanges the two top values of the stack, even if one of them is an integer and the other is a cell. Almost all other instructions, es- pecially the data processing instructions (including arithmetic instructions), require each of their arguments to be of some fixed type (possibly different for different arguments). 2.3 Efficiency of stack manipulation primitives Stack manipulation primitives employed by a stack machine, such as TVM, have to be implemented very efficiently, because they constitute more than half of all the instructions used in a typical program. In fact, TVM performs all these instructions in a (small) constant time, regardless of the values involved (even if they represent very large integers or very large trees of cells). 2.3.1. Implementation of stack manipulation primitives: using ref- erences for operations instead of objects.The efficiency of TVM’s implementation of stack manipulation primitives results from the fact that a 10 An alternative, arguably better, translation ofPUO ′ s(i 1 ),...,s(i γ )consists of the translation ofO ′ s(i 2 ),...,s(i γ ), followed byPUSH s(i 1 +α−1);XCHG s(γ−1). 25 2.3. Efficiency of stack manipulation primitives typical TVM implementation keeps in the stack not the value objects them- selves, but only the references (pointers) to such objects. Therefore, aSWAP instruction only needs to interchange the references ats0ands1, not the actual objects they refer to. 2.3.2. Efficient implementation ofDUPandPUSHinstructions using copy-on-write.Furthermore, aDUP(or, more generally,PUSH s(i)) instruc- tion, which appears to make a copy of a potentially large object, also works in small constant time, because it uses a copy-on-write technique of delayed copying: it copies only the reference instead of the object itself, but increases the “reference counter” inside the object, thus sharing the object between the two references. If an attempt to modify an object with a reference counter greater than one is detected, a separate copy of the object in question is made first (incurring a certain “non-uniqueness penalty” or “copying penalty” for the data manipulation instruction that triggered the creation of a new copy). 2.3.3. Garbage collecting and reference counting.When the refer- ence counter of a TVM object becomes zero (for example, because the last reference to such an object has been consumed by aDROPoperation or an arithmetic instruction), it is immediately freed. Because cyclic references are impossible in TVM data structures, this method of reference counting provides a fast and convenient way of freeing unused objects, replacing slow and unpredictable garbage collectors. 2.3.4. Transparency of the implementation: Stack values are “val- ues”, not “references”.Regardless of the implementation details just dis- cussed, all stack values are really “values”, not “references”, from the perspec- tive of the TVM programmer, similarly to the values of all types in functional programming languages. Any attempt to modify an existing object referred to from any other objects or stack locations will result in a transparent re- placement of this object by its perfect copy before the modification is actually performed. In other words, the programmer should always act as if the objects them- selves were directly manipulated by stack, arithmetic, and other data trans- formation primitives, and treat the previous discussion only as an explanation of the high efficiency of the stack manipulation primitives. 2.3.5. Absence of circular references.One might attempt to create a circular reference between two cells,AandB, as follows: first createAand 26 2.3. Efficiency of stack manipulation primitives write some data into it; then createBand write some data into it, along with a reference to previously constructed cellA; finally, add a reference to BintoA. While it may seem that after this sequence of operations we obtain a cellA, which refers toB, which in turn refers toA, this is not the case. In fact, we obtain a new cellA ′ , which contains a copy of the data originally stored into cellAalong with a reference to cellB, which contains a reference to (the original) cellA. In this way the transparent copy-on-write mechanism and the “everything is a value” paradigm enable us to create new cells using only previously constructed cells, thus forbidding the appearance of circular references. This property also applies to all other data structures: for instance, the absence of circular references enables TVM to use reference counting to immediately free unused memory instead of relying on garbage collectors. Similarly, this property is crucial for storing data in the TON Blockchain. 27 3.1. Generalities on cells 3 Cells, memory, and persistent storage This chapter briefly describes TVM cells, used to represent all data structures inside the TVM memory and its persistent storage, and the basic operations used to create cells, write (or serialize) data into them, and read (or deseri- alize) data from them. 3.1 Generalities on cells This section presents a classification and general descriptions of cell types. 3.1.1. TVM memory and persistent storage consist of cells.Recall that the TVM memory and persistent storage consist of(TVM) cells. Each cell contains up to 1023 bits of data and up to four references to other cells. 11 Circular references are forbidden and cannot be created by means of TVM (cf.2.3.5). In this way, all cells kept in TVM memory and persistent storage constitute a directed acyclic graph (DAG). 3.1.2. Ordinary and exotic cells.Apart from the data and references, a cell has acell type, encoded by an integer−1. . .255. A cell of type−1 is calledordinary; such cells do not require any special processing. Cells of other types are calledexotic, and may beloaded—automatically replaced by other cells when an attempt to deserialize them (i.e., to convert them into aSliceby aCTOSinstruction) is made. They may also exhibit a non-trivial behavior when their hashes are computed. The most common use for exotic cells is to represent some other cells—for instance, cells present in an external library, or pruned from the original tree of cells when a Merkle proof has been created. The type of an exotic cell is stored as the first eight bits of its data. If an exotic cell has less than eight data bits, it is invalid. 3.1.3. The level of a cell.Every cellchas another attributeLvl(c)called its(de Brujn) level, which currently takes integer values in the range 0. . . 3. 11 From the perspective of low-level cell operations, these data bits and cell references are not intermixed. In other words, an (ordinary) cell essentially is a couple consisting of a list of up to 1023 bits and of a list of up to four cell references, without prescribing an order in which the references and the data bits should be deserialized, even though TL-B schemes appear to suggest such an order. 28 3.1. Generalities on cells The level of an ordinary cell is always equal to the maximum of the levels of all its childrenc i : Lvl(c) = max 1≤i≤r Lvl(c i ),(1) for an ordinary cellccontainingrreferences to cellsc 1 , . . . ,c r . Ifr= 0, Lvl(c) = 0. Exotic cells may have different rules for setting their level. A cell’s level affects the number ofhigher hashesit has. More precisely, a levellcell haslhigher hashesHash 1 (c), . . . ,Hash l (c)in addition to its representation hashHash(c) =Hash ∞ (c). Cells of non-zero level appear insideMerkle proofsandMerkle updates, after some branches of the tree of cells representing a value of an abstract data type are pruned. 3.1.4. Standard cell representation.When a cell needs to be transferred by a network protocol or stored in a disk file, it must beserialized. The standard representationCellRepr(c) =CellRepr ∞ (c)of a cellcas an octet (byte) sequence is constructed as follows: 1. Two descriptor bytesd 1 andd 2 are serialized first. Byted 1 equals r+8s+32l, where0≤r≤4is the quantity of cell references contained in the cell,0≤l≤3is the level of the cell, and0≤s≤1is1for exotic cells and0for ordinary cells. Byted 2 equalsbb/8c+db/8e, where 0≤b≤1023is the quantity of data bits inc. 2. Then the data bits are serialized asdb/8e8-bit octets (bytes). Ifbis not a multiple of eight, a binary1and up to six binary0s are appended to the data bits. After that, the data is split intodb/8eeight-bit groups, and each group is interpreted as an unsigned big-endian integer0...255 and stored into an octet. 3. Finally, each of thercell references is represented by 32 bytes contain- ing the 256-bitrepresentation hashHash(c i ), explained below in3.1.5, of the cellc i referred to. In this way,2 +db/8e+ 32rbytes ofCellRepr(c)are obtained. 3.1.5. The representation hash of a cell.The 256-bitrepresentation hashor simplyhashHash(c)of a cellcis recursively defined as thesha256 of the standard representation of the cellc: Hash(c) :=sha256 ( CellRepr(c) ) (2) 29 3.1. Generalities on cells Notice that cyclic cell references are not allowed and cannot be created by means of the TVM (cf.2.3.5), so this recursion always ends, and the repre- sentation hash of any cell is well-defined. 3.1.6. The higher hashes of a cell.Recall that a cellcof levellhasl higher hashesHash i (c),1≤i≤l, as well. Exotic cells have their own rules for computing their higher hashes. Higher hashesHash i (c)of an ordinary cellcare computed similarly to its representation hash, but using the higher hashesHash i (c j )of its childrenc j instead of their representation hashes Hash(c j ). By convention, we setHash ∞ (c) :=Hash(c), andHash i (c) := Hash ∞ (c) =Hash(c)for alli > l. 12 3.1.7. Types of exotic cells.TVM currently supports the following cell types: •Type−1:Ordinary cell— Contains up to 1023 bits of data and up to four cell references. •Type 1:Pruned branch cellc— May have any level1≤l≤3. It contains exactly8 + 256ldata bits: first an 8-bit integer equal to 1 (representing the cell’s type), then itslhigher hashesHash 1 (c), . . . , Hash l (c). The levellof a pruned branch cell may be called itsde Brujn index, because it determines the outer Merkle proof or Merkle update during the construction of which the branch has been pruned. An attempt to load a pruned branch cell usually leads to an exception. •Type 2:Library reference cell— Always has level 0, and contains8+256 data bits, including its 8-bit type integer 2 and the representation hash Hash(c ′ )of the library cell being referred to. When loaded, a library reference cell may be transparently replaced by the cell it refers to, if found in the currentlibrary context. •Type 3:Merkle proof cellc— Has exactly one referencec 1 and level 0≤l≤3, which must be one less than the level of its only childc 1 : Lvl(c) = max(Lvl(c 1 )−1,0)(3) 12 From a theoretical perspective, we might say that a cellchas an infinite sequence of hashes ( Hash i (c) ) i≥1 , which eventually stabilizes:Hash i (c)→Hash ∞ (c). Then the levellis simply the largest indexi, such thatHash i (c)6=Hash ∞ (c). 30 3.1. Generalities on cells The8 + 256data bits of a Merkle proof cell contain its 8-bit type integer 3, followed byHash 1 (c 1 )(assumed to be equal toHash(c 1 )if Lvl(c 1 ) = 0). The higher hashesHash i (c)ofcare computed similarly to the higher hashes of an ordinary cell, but withHash i+1 (c 1 )used instead ofHash i (c 1 ). When loaded, a Merkle proof cell is replaced by c 1 . •Type 4:Merkle update cellc— Has two childrenc 1 andc 2 . Its level 0≤l≤3is given by Lvl(c) = max(Lvl(c 1 )−1,Lvl(c 2 )−1,0)(4) A Merkle update behaves like a Merkle proof for bothc 1 andc 2 , and contains8 + 256 + 256data bits withHash 1 (c 1 )andHash 1 (c 2 ). How- ever, an extra requirement is thatall pruned branch cellsc ′ that are descendants ofc 2 and are bound bycmust also be descendants ofc 1 . 13 When a Merkle update cell is loaded, it is replaced byc 2 . 3.1.8. All values of algebraic data types are trees of cells.Arbitrary values of arbitrary algebraic data types (e.g., all types used in functional programming languages) can be serialized into trees of cells (of level 0), and such representations are used for representing such values within TVM. The copy-on-write mechanism (cf.2.3.2) allows TVM to identify cells containing the same data and references, and to keep only one copy of such cells. This actually transforms a tree of cells into a directed acyclic graph (with the additional property that all its vertices be accessible from a marked vertex called the “root”). However, this is a storage optimization rather than an essential property of TVM. From the perspective of a TVM code programmer, one should think of TVM data structures as trees of cells. 3.1.9. TVM code is a tree of cells.The TVM code itself is also rep- resented by a tree of cells. Indeed, TVM code is simply a value of some complex algebraic data type, and as such, it can be serialized into a tree of cells. The exact way in which the TVM code (e.g., TVM assembly code) is transformed into a tree of cells is explained later (cf.4.1.4and5.2), in sec- tions discussing control flow instructions, continuations, and TVM instruc- tion encoding. 13 A pruned branch cellc ′ of levellisboundby a Merkle (proof or update) cellcif there are exactlylMerkle cells on the path fromcto its descendantc ′ , includingc. 31 3.2. Data manipulation instructions and cells 3.1.10. “Everything is a bag of cells” paradigm.As described in \[1, 2.5.14\], all the data used by the TON Blockchain, including the blocks them- selves and the blockchain state, can be represented—and are represented—as collections, or “bags”, of cells. We see that TVM’s structure of data (cf.3.1.8) and code (cf.3.1.9) nicely fits into this “everything is a bag of cells” paradigm. In this way, TVM can naturally be used to execute smart contracts in the TON Blockchain, and the TON Blockchain can be used to store the code and persistent data of these smart contracts between invocations of TVM. (Of course, both TVM and the TON Blockchain have been designed so that this would become possible.) 3.2 Data manipulation instructions and cells The next large group of TVM instructions consists ofdata manipulation instructions, also known ascell manipulation instructionsor simplycell in- structions. They correspond to memory access instructions of other archi- tectures. 3.2.1. Classes of cell manipulation instructions.The TVM cell in- structions are naturally subdivided into two principal classes: •Cell creation instructionsorserialization instructions, used to con- struct new cells from values previously kept in the stack and previously constructed cells. •Cell parsing instructionsordeserialization instructions, used to extract data previously stored into cells by cell creation instructions. Additionally, there areexotic cell instructionsused to create and inspect exotic cells (cf.3.1.2), which in particular are used to represent pruned branches of Merkle proofs and Merkle proofs themselves. 3.2.2.BuilderandSlicevalues.Cell creation instructions usually work withBuildervalues, which can be kept only in the stack (cf.1.1.3). Such values represent partially constructed cells, for which fast operations for ap- pending bitstrings, integers, other cells, and references to other cells can be defined. Similarly, cell parsing instructions make heavy use ofSlicevalues, which represent either the remainder of a partially parsed cell, or a value (subcell) residing inside such a cell and extracted from it by a parsing in- struction. 32 3.2. Data manipulation instructions and cells 3.2.3.BuilderandSlicevalues exist only as stack values.Notice that BuilderandSliceobjects appear only as values in a TVM stack. They cannot be stored in “memory” (i.e., trees of cells) or “persistent storage” (which is also a bag of cells). In this sense, there are far moreCellobjects thanBuilder orSliceobjects in a TVM environment, but, somewhat paradoxically, a TVM program seesBuilderandSliceobjects in its stack more often thanCells. In fact, a TVM program does not have much use forCellvalues, because they are immutable and opaque; all cell manipulation primitives require that a Cellvalue be transformed into either aBuilderor aSlicefirst, before it can be modified or inspected. 3.2.4. TVM has no separateBitstringvalue type.Notice that TVM offers no separate bitstring value type. Instead, bitstrings are represented by Slices that happen to have no references at all, but can still contain up to 1023 data bits. 3.2.5. Cells and cell primitives are bit-oriented, not byte-oriented. An important point is thatTVM regards data kept in cells as sequences (strings, streams) of (up to 1023) bits, not of bytes. In other words, TVM is abit-oriented machine, not a byte-oriented machine. If necessary, an ap- plication is free to use, say, 21-bit integer fields inside records serialized into TVM cells, thus using fewer persistent storage bytes to represent the same data. 3.2.6. Taxonomy of cell creation (serialization) primitives.Cell cre- ation primitives usually accept aBuilderargument and an argument rep- resenting the value to be serialized. Additional arguments controlling some aspects of the serialization process (e.g., how many bits should be used for serialization) can be also provided, either in the stack or as an immediate value inside the instruction. The result of a cell creation primitive is usually anotherBuilder, representing the concatenation of the original builder and the serialization of the value provided. Therefore, one can suggest a classification of cell serialization primitives according to the answers to the following questions: •Which is the type of values being serialized? •How many bits are used for serialization? If this is a variable number, does it come from the stack, or from the instruction itself? 33 3.2. Data manipulation instructions and cells •What happens if the value does not fit into the prescribed number of bits? Is an exception generated, or is a success flag equal to zero silently returned in the top of stack? •What happens if there is insufficient space left in theBuilder? Is an exception generated, or is a zero success flag returned along with the unmodified originalBuilder? The mnemonics of cell serialization primitives usually begin withST. Subse- quent letters describe the following attributes: •The type of values being serialized and the serialization format (e.g.,I for signed integers,Ufor unsigned integers). •The source of the field width in bits to be used (e.g.,Xfor integer serialization instructions means that the bit widthnis supplied in the stack; otherwise it has to be embedded into the instruction as an immediate value). •The action to be performed if the operation cannot be completed (by default, an exception is generated; “quiet” versions of serialization in- structions are marked by aQletter in their mnemonics). This classification scheme is used to create a more complete taxonomy of cell serialization primitives, which can be found inA.7.1. 3.2.7. Integer serialization primitives.Integer serialization primitives can be classified according to the above taxonomy as well. For example: •There are signed and unsigned (big-endian) integer serialization prim- itives. •The sizenof the bit field to be used (1≤n≤257for signed integers, 0≤n≤256for unsigned integers) can either come from the top of stack or be embedded into the instruction itself. •If the integerxto be serialized is not in the range−2 n−1 ≤x <2 n−1 (for signed integer serialization) or0≤x <2 n (for unsigned integer serialization), a range check exception is usually generated, and ifnbits cannot be stored into the providedBuilder, a cell overflow exception is generated. 34 3.2. Data manipulation instructions and cells •Quiet versions of serialization instructions do not throw exceptions; instead, they push-1on top of the resultingBuilderupon success, or return the originalBuilderwith0on top of it to indicate failure. Integer serialization instructions have mnemonics likeSTU 20(“store an unsigned 20-bit integer value”) orSTIXQ(“quietly store an integer value of variable length provided in the stack”). The full list of these instructions— including their mnemonics, descriptions, and opcodes—is provided inA.7.1. 3.2.8. Integers in cells are big-endian by default.Notice that the default order of bits inIntegers serialized intoCells isbig-endian, not little- endian. 14 In this respectTVM is a big-endian machine. However, this affects only the serialization of integers inside cells. The internal representation of theIntegervalue type is implementation-dependent and irrelevant for the operation of TVM. Besides, there are some special primitives such asSTULE for (de)serializing little-endian integers, which must be stored into an integral number of bytes (otherwise “little-endianness” does not make sense, unless one is also willing to revert the order of bits inside octets). Such primitives are useful for interfacing with the little-endian world—for instance, for parsing custom-format messages arriving to a TON Blockchain smart contract from the outside world. 3.2.9. Other serialization primitives.Other cell creation primitives seri- alize bitstrings (i.e., cell slices without references), either taken from the stack or supplied as literal arguments; cell slices (which are concatenated to the cell builder in an obvious way); otherBuilders (which are also concatenated); and cell references (STREF). 3.2.10. Other cell creation primitives.In addition to the cell serial- ization primitives for certain built-in value types described above, there are simple primitives that create a new emptyBuilderand push it into the stack (NEWC), or transform aBuilderinto aCell(ENDC), thus finishing the cell creation process. AnENDCcan be combined with aSTREFinto a single in- structionENDCST, which finishes the creation of a cell and immediately stores a reference to it in an “outer”Builder. There are also primitives that obtain the quantity of data bits or references already stored in aBuilder, and check how many data bits or references can be stored. 14 Negative numbers are represented using two’s complement. For instance, integer−17 is serialized by instructionSTI 8into bitstringxEF. 35 3.2. Data manipulation instructions and cells 3.2.11. Taxonomy of cell deserialisation primitives.Cell parsing, or deserialization, primitives can be classified as described in3.2.6, with the following modifications: •They work withSlices (representing the remainder of the cell being parsed) instead ofBuilders. •They return deserialized values instead of accepting them as arguments. •They may come in two flavors, depending on whether they remove the deserialized portion from theSlicesupplied (“fetch operations”) or leave it unmodified (“prefetch operations”). •Their mnemonics usually begin withLD(orPLDfor prefetch operations) instead ofST. For example, an unsigned big-endian 20-bit integer previously serialized into a cell by aSTU 20instruction is likely to be deserialized later by a matching LDU 20instruction. Again, more detailed information about these instructions is provided inA.7.2. 3.2.12. Other cell slice primitives.In addition to the cell deserialisation primitives outlined above, TVM provides some obvious primitives for initial- izing and completing the cell deserialization process. For instance, one can convert aCellinto aSlice(CTOS), so that its deserialisation might begin; or check whether aSliceis empty, and generate an exception if it is not (ENDS); or deserialize a cell reference and immediately convert it into aSlice (LDREFTOS, equivalent to two instructionsLDREFandCTOS). 3.2.13. Modifying a serialized value in a cell.The reader might wonder how the values serialized inside a cell may be modified. Suppose a cell con- tains three serialized 29-bit integers,(x,y,z), representing the coordinates of a point in space, and we want to replaceywithy ′ =y+ 1, leaving the other coordinates intact. How would we achieve this? TVM does not offer any ways to modify existing values (cf.2.3.4and 2.3.5), so our example can only be accomplished with a series of operations as follows: 1. Deserialize the original cell into threeIntegersx,y,zin the stack (e.g., byCTOS; LDI 29; LDI 29; LDI 29; ENDS). 36 3.3. Hashmaps, or dictionaries 2. Increaseyby one (e.g., bySWAP; INC; SWAP). 3. Finally, serialize the resultingIntegers into a new cell (e.g., byXCHG s2; NEWC; STI 29; STI 29; STI 29; ENDC). 3.2.14. Modifying the persistent storage of a smart contract.If the TVM code wants to modify its persistent storage, represented by the tree of cells rooted atc4, it simply needs to rewrite control registerc4by the root of the tree of cells containing the new value of its persistent storage. (If only part of the persistent storage needs to be modified, cf.3.2.13.) 3.3 Hashmaps, or dictionaries Hashmaps, ordictionaries, are a specific data structure represented by a tree of cells. Essentially, a hashmap represents a map fromkeys, which are bit- strings of either fixed or variable length, intovaluesof an arbitrary typeX, in such a way that fast lookups and modifications be possible. While any such structure might be inspected or modified with the aid of generic cell se- rialization and deserialization primitives, TVM introduces special primitives to facilitate working with these hashmaps. 3.3.1. Basic hashmap types.The two most basic hashmap types pre- defined in TVM areHashmapEn XorHashmapE(n,X), which represents a partially defined map fromn-bit strings (calledkeys) for some fixed0≤ n≤1023intovaluesof some typeX, andHashmap(n,X), which is similar toHashmapE(n,X)but is not allowed to be empty (i.e., it must contain at least one key-value pair). Other hashmap types are also available—for example, one with keys of arbitrary length up to some predefined bound (up to 1023 bits). 3.3.2. Hashmaps as Patricia trees.The abstract representation of a hashmap in TVM is aPatricia tree, or acompact binary trie. It is a binary tree with edges labelled by bitstrings, such that the concatenation of all edge labels on a path from the root to a leaf equals a key of the hashmap. The corresponding value is kept in this leaf (for hashmaps with keys of fixed length), or optionally in the intermediate vertices as well (for hashmaps with keys of variable length). Furthermore, any intermediate vertex must have two children, and the label of the left child must begin with a binary zero, while the label of the right child must begin with a binary one. This enables us not to store the first bit of the edge labels explicitly. 37 3.3. Hashmaps, or dictionaries It is easy to see that any collection of key-value pairs (with distinct keys) is represented by a unique Patricia tree. 3.3.3. Serialization of hashmaps.The serialization of a hashmap into a tree of cells (or, more generally, into aSlice) is defined by the following TL-B scheme: 15 bit#\_ \_:(## 1) = Bit; 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; hmn\_fork#\_ {n:#} {X:Type} left:^(Hashmap n X) right:^(Hashmap n X) = HashmapNode (n + 1) X; hml\_short$0 {m:#} {n:#} len:(Unary ~n) 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; unary\_zero$0 = Unary ~0; unary\_succ$1 {n:#} x:(Unary ~n) = Unary ~(n + 1); hme\_empty$0 {n:#} {X:Type} = HashmapE n X; hme\_root$1 {n:#} {X:Type} root:^(Hashmap n X) = HashmapE n X; true#\_ = True; \_ {n:#} \_:(Hashmap n True) = BitstringSet n; 3.3.4. Brief explanation of TL-B schemes.A TL-B scheme, like the one above, includes the following components. The right-hand side of each “equation” is atype, either simple (such as BitorTrue) or parametrized (such asHashmapn X). The parameters of a type must be either natural numbers (i.e., non-negative integers, which are required to fit into 32 bits in practice), such asninHashmapn X, or other types, such asXinHashmapn X. 15 A description of an older version of TL may be found athttps://core.telegram. org/mtproto/TL. 38 3.3. Hashmaps, or dictionaries 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 descrip- tion begins with the name of aconstructor, such ashm\_edgeorhml\_long, immediately followed by an optionalconstructor tag, such as#\_or$10, which describes the bitstring used to encode (serialize) the constructor in question. Such tags may be given in either binary (after a dollar sign) or hexadecimal notation (after a hash sign), using the conventions described in1.0. If a tag is not explicitly provided, TL-B computes a default 32-bit constructor tag by hashing the text of the “equation” 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). The constructor and its optional tag are followed byfield definitions. Each field definition is of the formident:type-expr, whereidentis an identifier with the name of the field 16 (replaced by an underscore for anonymous fields), andtype-expris the field’s type. The type provided here is atype expression, which may include simple types or parametrized types with suitable parame- ters.Variables—i.e., the (identifiers of the) previously defined fields of types #(natural numbers) orType(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 beimplicit. 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). 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 op- posite 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 pro- 16 The field’s name is useful for representing values of the type being defined in human- readable form, but it does not affect the binary serialization. 39 3.3. Hashmaps, or dictionaries cess. In other words, a tilde transforms an “input argument” into an “output argument”, and vice versa. 17 Finally, some equalities 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. A caret (ˆ) preceding a typeXmeans that instead of serializing a value of typeXas 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 typeX”. Parametrized type#<=pwithp:#(this notation means “pof type#”, i.e., a natural number) denotes the subtype of the natural numbers type #, consisting of integers0...p; it is serialized intodlog 2 (p+ 1)ebits as an unsigned big-endian integer. Type#by itself is serialized as an unsigned 32-bit integer. Parametrized type##bwithb:#<=31is equivalent to#<= 2 b −1(i.e., it is an unsignedb-bit integer). 3.3.5. Application to the serialization of hashmaps.Let us explain the net result of applying the general rules described in3.3.4to the TL-B scheme presented in3.3.3. Suppose we wish to serialize a value of typeHashmapEn Xfor some integer0≤n≤1023and some typeX(i.e., a dictionary withn-bit keys and values of typeX, admitting an abstract representation as a Patricia tree (cf.3.3.2)). First of all, if our dictionary is empty, it is serialized into a single binary0, which is the tag of nullary constructorhme\_empty. Otherwise, its serialization consists of a binary1(the tag ofhme\_root), along with a reference to a cell containing the serialization of a value of typeHashmapn X(i.e., a necessarily non-empty dictionary). The only way to serialize a value of typeHashmapn Xis given by the hm\_edgeconstructor, which instructs us to serialize first the labellabelof the edge leading to the root of the subtree under consideration (i.e., the com- mon prefix of all keys in our (sub)dictionary). This label is of typeHmLabel l ⊥ n, which means that it is a bitstring of length at mostn, serialized in such a way that the true lengthlof the label,0≤l≤n, becomes known from 17 This is the “linear negation” operation(−) ⊥ of linear logic, hence our notation ̃. 40 3.3. Hashmaps, or dictionaries the serialization of the label. (This special serialization method is described separately in3.3.6.) The label must be followed by the serialization of anodeof typeHashmap- Nodem X, wherem=n−l. It corresponds to a vertex of the Patricia tree, representing a non-empty subdictionary of the original dictionary withm-bit keys, obtained by removing from all the keys of the original subdictionary their common prefix of lengthl. Ifm= 0, a value of typeHashmapNode0Xis given by thehmn\_leaf constructor, which describes a leaf of the Patricia tree—or, equivalently, a subdictionary with0-bit keys. A leaf simply consists of the corresponding valueof typeXand is serialized accordingly. On the other hand, ifm >0, a value of typeHashmapNodem Xcor- responds to a fork (i.e., an intermediate node) in the Patricia tree, and is given by thehmn\_forkconstructor. Its serialization consists ofleftand right, two references to cells containing values of typeHashmapm−1X, which correspond to the left and the right child of the intermediate node in question—or, equivalently, to the two subdictionaries of the original dictio- nary consisting of key-value pairs with keys beginning with a binary0or a binary1, respectively. Because the first bit of all keys in each of these subdictionaries is known and fixed, it is removed, and the resulting (neces- sarily non-empty) subdictionaries are recursively serialized as values of type Hashmapm−1X. 3.3.6. Serialization of labels.There are several ways to serialize a label of length at mostn, if its exact length isl≤n(recall that the exact length must be deducible from the serialization of the label itself, while the upper boundnis known before the label is serialized or deserialized). These ways are described by the three constructorshml\_short,hml\_long, andhml\_same of typeHmLabell ⊥ n: •hml\_short— Describes a way to serialize “short” labels, of small length l≤n. Such a serialization consists of a binary0(the constructor tag ofhml\_short), followed bylbinary1s and one binary0(the unary representation of the lengthl), followed bylbits comprising the label itself. •hml\_long— Describes a way to serialize “long” labels, of arbitrary lengthl≤n. Such a serialization consists of a binary10(the construc- tor tag ofhml\_long), followed by the big-endian binary representation 41 3.3. Hashmaps, or dictionaries of the length0≤l≤nindlog 2 (n+ 1)ebits, followed bylbits com- prising the label itself. •hml\_same— Describes a way to serialize “long” labels, consisting ofl repetitions of the same bitv. Such a serialization consists of11(the constructor tag ofhml\_same), followed by the bitv, followed by the lengthlstored indlog 2 (n+ 1)ebits as before. Each label can always be serialized in at least two different fashions, using hml\_shortorhml\_longconstructors. Usually the shortest serialization (and in the case of a tie—the lexicographically smallest among the shortest) is preferred and is generated by TVM hashmap primitives, while the other variants are still considered valid. This label encoding scheme has been designed to be efficient for dictio- naries with “random” keys (e.g., hashes of some data), as well as for dic- tionaries with “regular” keys (e.g., big-endian representations of integers in some range). 3.3.7. An example of dictionary serialization.Consider a dictionary with three 16-bit keys13,17, and239(considered as big-endian integers) and corresponding 16-bit values169,289, and57121. In binary form: 0000000000001101 => 0000000010101001 0000000000010001 => 0000000100100001 0000000011101111 => 1101111100100001 The corresponding Patricia tree consists of a rootA, two intermediate nodesBandC, and three leaf nodesD,E, andF, corresponding to 13, 17, and 239, respectively. The rootAhas only one child,B; the label on the edgeABis00000000 = 0 8 . The nodeBhas two children: its left child is an intermediate nodeCwith the edgeBClabelled by(0)00, while its right child is the leafFwithBFlabelled by(1)1101111. Finally,Chas two leaf childrenDandE, withCDlabelled by(0)1101andCE—by(1)0001. The corresponding value of typeHashmapE 16 (## 16)may be written in human-readable form as: (hme\_root$1 root:^(hm\_edge label:(hml\_same$11 v:0 n:8) node:(hm\_fork left:^(hm\_edge label:(hml\_short$0 len:$110 s:$00) 42 3.3. Hashmaps, or dictionaries node:(hm\_fork left:^(hm\_edge label:(hml\_long$10 n:4 s:$1101) node:(hm\_leaf value:169)) right:^(hm\_edge label:(hml\_long$10 n:4 s:$0001) node:(hm\_leaf value:289)))) right:^(hm\_edge label:(hml\_long$10 n:7 s:$1101111) node:(hm\_leaf value:57121))))) The serialization of this data structure into a tree of cells consists of six cells with the following binary data contained in them: A := 1 A.0 := 11 0 01000 A.0.0 := 0 110 00 A.0.0.0 := 10 100 1101 0000000010101001 A.0.0.1 := 10 100 0001 0000000100100001 A.0.1 := 10 111 1101111 1101111100100001 HereAis the root cell,A.0is the cell at the first reference ofA,A.1is the cell at the second reference ofA, and so on. This tree of cells can be represented more compactly using the hexadecimal notation described in1.0, using indentation to reflect the tree-of-cells structure: C\_ C8 62\_ A68054C\_ A08090C\_ BEFDF21 A total of 93 data bits and 5 references in 6 cells have been used to serialize this dictionary. Notice that a straightforward representation of three 16- bit keys and their corresponding 16-bit values would already require 96 bits (albeit without any references), so this particular serialization turns out to be quite efficient. 3.3.8. Ways to describe the serialization of typeX.Notice that the built-in TVM primitives for dictionary manipulation need to know something about the serialization of typeX; otherwise, they would not be able to work correctly withHashmapn X, because values of typeXare immediately 43 3.3. Hashmaps, or dictionaries contained in the Patricia tree leaf cells. There are several options available to describe the serialization of typeX: •The simplest case is whenX=ˆYfor some other typeY. In this case the serialization ofXitself always consists of one reference to a cell, which in fact must contain a value of typeY, something that is not relevant for dictionary manipulation primitives. •Another simple case is when the serialization of any value of typeX always consists of0≤b≤1023data bits and0≤r≤4references. In- tegersbandrcan then be passed to a dictionary manipulation primitive as a simple description ofX. (Notice that the previous case corresponds tob= 0,r= 1.) •A more sophisticated case can be described by four integers1≤b 0 ,b 1 ≤ 1023,0≤r 0 ,r 1 ≤4, withb i andr i used when the first bit of the serialization equalsi. Whenb 0 =b 1 andr 0 =r 1 , this case reduces to the previous one. •Finally, the most general description of the serialization of a typeX is given by asplitting function split X forX, which accepts oneSlice parameters, and returns twoSlices,s ′ ands ′′ , wheres ′ is the only prefix ofsthat is the serialization of a value of typeX, ands ′′ is the remainder ofs. If no such prefix exists, the splitting function is expected to throw an exception. Notice that a compiler for a high-level language, which supports some or all algebraic TL-B types, is likely to automatically generate splitting functions for all types defined in the program. 3.3.9. A simplifying assumption on the serialization ofX.One may notice that values of typeXalways occupy the remaining part of an hm\_edge/hme\_leafcell inside the serialization of aHashmapEn X. There- fore, if we do not insist on strict validation of all dictionaries accessed, we may assume that everything left unparsed in anhm\_edge/hme\_leafcell af- ter deserializing itslabelis a value of typeX. This greatly simplifies the creation of dictionary manipulation primitives, because in most cases they turn out not to need any information aboutXat all. 3.3.10. Basic dictionary operations.Let us present a classification of basic operations with dictionaries (i.e., valuesDof typeHashmapEn X): 44 3.3. Hashmaps, or dictionaries •Get(D,k)— GivenD:HashmapE(n,X)and a keyk:n·bit, returns the corresponding valueD\[k\] :X ? kept inD. •Set(D,k,x)— GivenD:HashmapE(n,X), a keyk:n·bit, and a valuex:X, setsD ′ \[k\]toxin a copyD ′ ofD, and returns the resulting dictionaryD ′ (cf.2.3.4). •Add(D,k,x)— Similar toSet, but adds the key-value pair(k,x)to Donly if keykis absent inD. •Replace(D,k,x)— Similar toSet, but changesD ′ \[k\]toxonly if key kis already present inD. •GetSet,GetAdd,GetReplace— Similar toSet,Add, andRe- place, respectively, but returns the old value ofD\[k\]as well. •Delete(D,k)— Deletes keykfrom dictionaryD, and returns the resulting dictionaryD ′ . •GetMin(D),GetMax(D)— Gets the minimal or maximal keyk from dictionaryD, along with the associated valuex:X. •RemoveMin(D),RemoveMax(D)— Similar toGetMinandGet- Max, but also removes the key in question from dictionaryD, and returns the modified dictionaryD ′ . May be used to iterate over all elements ofD, effectively using (a copy of)Ditself as an iterator. •GetNext(D,k)— Computes the minimal keyk ′ > k(ork ′ ≥kin a variant) and returns it along with the corresponding valuex ′ :X. May be used to iterate over all elements ofD. •GetPrev(D,k)— Computes the maximal keyk ′ < k(ork ′ ≤kin a variant) and returns it along with the corresponding valuex ′ :X. •Empty(n)— Creates an empty dictionaryD:HashmapE(n,X). •IsEmpty(D)— Checks whether a dictionary is empty. •Create(n,{(k i ,x i )})— Givenn, creates a dictionary from a list(k i ,x i ) of key-value pairs passed in stack. 45 3.3. Hashmaps, or dictionaries •GetSubdict(D,l,k 0 )— GivenD:HashmapE(n,X)and somel-bit stringk 0 :l·bitfor0≤l≤n, returns subdictionaryD ′ =D/k 0 ofD, consisting of keys beginning withk 0 . The resultD ′ may be of either typeHashmapE(n,X)or typeHashmapE(n−l,X). •ReplaceSubdict(D,l,k 0 ,D ′ )— GivenD:HashmapE(n,X),0≤ l≤n,k 0 :l·bit, andD ′ :HashmapE(n−l,X), replaces withD ′ the subdictionaryD/k 0 ofDconsisting of keys beginning withk 0 , and returns the resulting dictionaryD ′′ :HashmapE(n,X). Some variants ofReplaceSubdictmay also return the old value of the subdictionary D/k 0 in question. •DeleteSubdict(D,l,k 0 )— Equivalent toReplaceSubdictwithD ′ being an empty dictionary. •Split(D)— GivenD:HashmapE(n,X), returnsD 0 :=D/0and D 1 :=D/1 :HashmapE(n−1,X), the two subdictionaries ofDcon- sisting of all keys beginning with0and1, respectively. •Merge(D 0 ,D 1 )— GivenD 0 andD 1 :HashmapE(n−1,X), computes D:HashmapE(n,X), such thatD/0 =D 0 andD/1 =D 1 . •Foreach(D,f)— Executes a functionfwith two argumentskand x, with(k,x)running over all key-value pairs of a dictionaryDin lexicographical order. 18 •ForeachRev(D,f)— Similar toForeach, but processes all key- value pairs in reverse order. •TreeReduce(D,o,f,g)— GivenD:HashmapE(n,X), a valueo:X, and two functionsf:X→Yandg:Y×Y→Y, performs a “tree reduction” ofDby first applyingfto all the leaves, and then usingg to compute the value corresponding to a fork starting from the values assigned to its children. 19 18 In fact,fmay receivemextra arguments and returnmmodified values, which are passed to the next invocation off. This may be used to implement “map” and “reduce” operations with dictionaries. 19 Versions of this operation may be introduced wherefandgreceive an additional bitstring argument, equal to the key (for leaves) or to the common prefix of all keys (for forks) in the corresponding subtree. 46 3.4. Hashmaps with variable-length keys 3.3.11. Taxonomy of dictionary primitives.The dictionary primitives, described in detail inA.10, can be classified according to the following cat- egories: •Which dictionary operation (cf.3.3.10) do they perform? •Are they specialized for the caseX=ˆY? If so, do they represent val- ues of typeYbyCells or bySlices? (Generic versions always represent values of typeXasSlices.) •Are the dictionaries themselves passed and returned asCells or as Slices? (Most primitives represent dictionaries asSlices.) •Is the key lengthnfixed inside the primitive, or is it passed in the stack? •Are the keys represented bySlices, or by signed or unsignedIntegers? In addition, TVM includes special serialization/deserialization primitives, such asSTDICT,LDDICT, andPLDDICT. They can be used to extract a dictio- nary from a serialization of an encompassing object, or to insert a dictionary into such a serialization. 3.4 Hashmaps with variable-length keys TVM provides some support for dictionaries, or hashmaps, with variable- length keys, in addition to its support for dictionaries with fixed-length keys (as described in3.3above). 3.4.1. Serialization of dictionaries with variable-length keys.The serialization of aVarHashmapinto a tree of cells (or, more generally, into a Slice) is defined by a TL-B scheme, similar to that described in3.3.3: vhm\_edge#\_ {n:#} {X:Type} {l:#} {m:#} label:(HmLabel ~l n) {n = (~m) + l} node:(VarHashmapNode m X) = VarHashmap n X; vhmn\_leaf$00 {n:#} {X:Type} value:X = VarHashmapNode n X; vhmn\_fork$01 {n:#} {X:Type} left:^(VarHashmap n X) right:^(VarHashmap n X) value:(Maybe X) = VarHashmapNode (n + 1) X; vhmn\_cont$1 {n:#} {X:Type} branch:bit child:^(VarHashmap n X) 47 3.4. Hashmaps with variable-length keys value:X = VarHashmapNode (n + 1) X; nothing$0 {X:Type} = Maybe X; just$1 {X:Type} value:X = Maybe X; vhme\_empty$0 {n:#} {X:Type} = VarHashmapE n X; vhme\_root$1 {n:#} {X:Type} root:^(VarHashmap n X) = VarHashmapE n X; 3.4.2. Serialization of prefix codes.One special case of a dictionary with variable-length keys is that of aprefix code, where the keys cannot be prefixes of each other. Values in such dictionaries may occur only in the leaves of a Patricia tree. The serialization of a prefix code is defined by the following TL-B scheme: phm\_edge#\_ {n:#} {X:Type} {l:#} {m:#} label:(HmLabel ~l n) {n = (~m) + l} node:(PfxHashmapNode m X) = PfxHashmap n X; phmn\_leaf$0 {n:#} {X:Type} value:X = PfxHashmapNode n X; phmn\_fork$1 {n:#} {X:Type} left:^(PfxHashmap n X) right:^(PfxHashmap n X) = PfxHashmapNode (n + 1) X; phme\_empty$0 {n:#} {X:Type} = PfxHashmapE n X; phme\_root$1 {n:#} {X:Type} root:^(PfxHashmap n X) = PfxHashmapE n X; 48 4.1. Continuations and subroutines 4 Control flow, continuations, and exceptions This chapter describescontinuations, which may represent execution tokens and exception handlers in TVM. Continuations are deeply involved with the control flow of a TVM program; in particular, subroutine calls and condi- tional and iterated execution are implemented in TVM using special primi- tives that accept one or more continuations as their arguments. We conclude this chapter with a discussion of the problem of recursion and of families of mutually recursive functions, exacerbated by the fact that cyclic references are not allowed in TVM data structures (including TVM code). 4.1 Continuations and subroutines Recall (cf.1.1.3) thatContinuationvalues represent “execution tokens” that can be executed later—for example, byEXECUTE=CALLX(“execute” or “call indirect”) orJMPX(“jump indirect”) primitives. As such, the continuations are responsible for the execution of the program, and are heavily used by control flow primitives, enabling subroutine calls, conditional expressions, loops, and so on. 4.1.1. Ordinary continuations.The most common kind of continuations are theordinary continuations, containing the following data: •ASlicecode(cf.1.1.3and3.2.2), containing (the remainder of) the TVM code to be executed. •A (possibly empty)Stackstack, containing the original contents of the stack for the code to be executed. •A (possibly empty) listsaveof pairs(c(i),v i )(also called “savelist”), containing the values of control registers to be restored before the ex- ecution of the code. •A 16-bit integer valuecp, selecting the TVM codepage used to interpret the TVM code fromcode. •An optional non-negative integernargs, indicating the number of ar- guments expected by the continuation. 49 4.1. Continuations and subroutines 4.1.2. Simple ordinary continuations.In most cases, the ordinary con- tinuations are the simplest ones, having emptystackandsave. They consist essentially of a referencecodeto (the remainder of) the code to be executed, and of the codepagecpto be used while decoding the instructions from this code. 4.1.3. Current continuationcc.The “current continuation”ccis an im- portant part of the total state of TVM, representing the code being executed right now (cf.1.1). In particular, what we call “the current stack” (or simply “the stack”) when discussing all other primitives is in fact the stack of the current continuation. All other components of the total state of TVM may be also thought of as parts of the current continuationcc; however, they may be extracted from the current continuation and kept separately as part of the total state for performance reasons. This is why we describe the stack, the control registers, and the codepage as separate parts of the TVM state in1.4. 4.1.4. Normal work of TVM, or the main loop.TVM usually performs the following operations: If the current continuationccis an ordinary one, it decodes the first instruction from theSlicecode, similarly to the way other cells are deseri- alized by TVMLD\*primitives (cf.3.2and3.2.11): it decodes the opcode first, and then the parameters of the instruction (e.g., 4-bit fields indicating “stack registers” involved for stack manipulation primitives, or constant val- ues for “push constant” or “literal” primitives). The remainder of theSlice is then put into thecodeof the newcc, and the decoded operation is exe- cuted on the current stack. This entire process is repeated until there are no operations left incc.code. If thecodeis empty (i.e., contains no bits of data and no references), or if a (rarely needed) explicit subroutine return (RET) instruction is encountered, the current continuation is discarded, and the “return continuation” from control registerc0is loaded intoccinstead (this process is discussed in more detail starting in4.1.6). 20 Then the execution continues by parsing operations from the new current continuation. 4.1.5. Extraordinary continuations.In addition to the ordinary continu- ations considered so far (cf.4.1.1), TVM includes someextraordinary contin- 20 If there are no bits of data left incode, but there is still exactly one reference, an implicitJMPto the cell at that reference is performed instead of an implicitRET. 50 4.1. Continuations and subroutines uations, representing certain less common states. Examples of extraordinary continuations include: •The continuationec\_quitwith its parameter set to zero, which rep- resents the end of the work of TVM. This continuation is the original value ofc0when TVM begins executing the code of a smart contract. •The continuationec\_until, which contains references to two other continuations (ordinary or not) representing the body of the loop being executed and the code to be executed after the loop. Execution of an extraordinary continuation by TVM depends on its specific class, and differs from the operations for ordinary continuations described in 4.1.4. 21 4.1.6. Switching to another continuation:JMPandRET.The process of switching to another continuationcmay be performed by such instructions asJMPX(which takescfrom the stack) orRET(which usesc0asc). This process is slightly more complex than simply setting the value ofcctoc: before doing this, either all values or the topnvalues in the current stack are moved to the stack of the continuationc, and only then is the remainder of the current stack discarded. If all values need to be moved (the most common case), and if the con- tinuationchas an empty stack (also the most common case; notice that extraordinary continuations are assumed to have an empty stack), then the new stack ofcequals the stack of the current continuation, so we can simply transfer the current stack in its entirety toc. (If we keep the current stack as a separate part of the total state of TVM, we have to do nothing at all.) 4.1.7. Determining the numbernof arguments passed to the next continuationc.By default,nequals the depth of the current stack. How- ever, ifchas an explicit value ofnargs(number of arguments to be provided), thennis computed asn ′ , equal toc.nargsminus the current depth ofc’s stack. Furthermore, there are special forms ofJMPXandRETthat provide an explicit valuen ′′ , the number of parameters from the current stack to be passed to continuationc. Ifn ′′ is provided, it must be less than or equal to 21 Technically, TVM may simply invoke a virtual methodrun()of the continuation currently incc. 51 4.1. Continuations and subroutines the depth of the current stack, or else a stack underflow exception occurs. If bothn ′ andn ′′ are provided, we must haven ′ ≤n ′′ , in which casen=n ′ is used. Ifn ′′ is provided andn ′ is not, thenn=n ′′ is used. One could also imagine that the default value ofn ′′ equals the depth of the original stack, and thatn ′′ values are always removed from the top of the original stack even if onlyn ′ of them are actually moved to the stack of the next continuationc. Even though the remainder of the current stack is discarded afterwards, this description will become useful later. 4.1.8. Restoring control registers from the new continuationc.After the new stack is computed, the values of control registers present inc.save are restored accordingly, and the current codepagecpis also set toc.cp. Only then does TVM setccequal to the newcand begin its execution. 22 4.1.9. Subroutine calls:CALLXorEXECUTEprimitives.The execution of continuations as subroutines is slightly more complicated than switching to continuations. Consider theCALLXorEXECUTEprimitive, which takes a continuationc from the (current) stack and executes it as a subroutine. Apart from doing the stack manipulations described in4.1.6and4.1.7 and setting the new control registers and codepage as described in4.1.8, these primitives perform several additional steps: 1. After the topn ′′ values are removed from the current stack (cf.4.1.7), the (usually empty) remainder is not discarded, but instead is stored in the (old) current continuationcc. 2. The old value of the special registerc0is saved into the (previously empty) savelistcc.save. 3. The continuationccthus modified is not discarded, but instead is set as the newc0, which performs the role of “next continuation” or “return continuation” for the subroutine being called. 4. After that, the switching toccontinues as before. In particular, some control registers are restored fromc.save, potentially overwriting the value ofc0set in the previous step. (Therefore, a good optimization would be to check thatc0is present inc.savefrom the very beginning, and skip the three previous steps as useless in this case.) 22 The already used savelistcc.saveof the newccis emptied before the execution starts. 52 4.2. Control flow primitives: conditional and iterated execution In this way, the called subroutine can return control to the caller by switching the current continuation to the return continuation saved inc0. Nested subroutine calls work correctly because the previous value ofc0ends up saved into the newc0’s control register savelistc0.save, from which it is restored later. 4.1.10. Determining the number of arguments passed to and/or return values accepted from a subroutine.Similarly toJMPXandRET, CALLXalso has special (rarely used) forms, which allow us to explicitly specify the numbern ′′ of arguments passed from the current stack to the called subroutine (by default,n ′′ equals the depth of the current stack, i.e., it is passed in its entirety). Furthermore, a second numbern ′′′ can be specified, used to setnargsof the modifiedcccontinuation before storing it into the newc0; the newnargsequals the depth of the old stack minusn ′′ plusn ′′′ . This means that the caller is willing to pass exactlyn ′′ arguments to the called subroutine, and is willing to accept exactlyn ′′′ results in their stead. Such forms ofCALLXandRETare mostly intended for library functions that accept functional arguments and want to invoke them safely. Another application is related to the “virtualization support” of TVM, which enables TVM code to run other TVM code inside a “virtual TVM machine”. Such virtualization techniques might be useful for implementing sophisticated pay- ment channels in the TON Blockchain (cf. \[1, 5\]). 4.1.11.CALLCC: call with current continuation.Notice that TVM sup- ports a form of the “call with current continuation” primitive. Namely, prim- itiveCALLCCis similar toCALLXorJMPXin that it takes a continuationcfrom the stack and switches to it; however,CALLCCdoes not discard the previous current continuationc ′ (asJMPXdoes) and does not writec ′ toc0(asCALLX does), but rather pushesc ′ into the (new) stack as an extra argument toc. The primitiveJMPXDATAdoes a similar thing, but pushes only the (remainder of the) code of the previous current continuation as aSlice. 4.2 Control flow primitives: conditional and iterated execution 4.2.1. Conditional execution:IF,IFNOT,IFELSE.An important modifi- cation ofEXECUTE(orCALLX) consists in its conditional forms. For example, IFaccepts an integerxand a continuationc, and executesc(in the same 53 4.2. Control flow primitives: conditional and iterated execution way asEXECUTEwould do it) only ifxis non-zero; otherwise both values are simply discarded from the stack. Similarly,IFNOTacceptsxandc, but executesconly ifx= 0. Finally,IFELSEacceptsx,c, andc ′ , removes these values from the stack, and executescifx6= 0orc ′ ifx= 0. 4.2.2. Iterated execution and loops.More sophisticated modifications ofEXECUTEinclude: •REPEAT— Takes an integernand a continuationc, and executesc n times. 23 •WHILE— Takesc ′ andc ′′ , executesc ′ , and then takes the top valuex from the stack. Ifxis non-zero, it executesc ′′ and then begins a new loop by executingc ′ again; ifxis zero, it stops. •UNTIL— Takesc, executes it, and then takes the top integerxfrom the stack. Ifxis zero, a new iteration begins; ifxis non-zero, the previously executed code is resumed. 4.2.3. Constant, or literal, continuations.We see that we can create arbitrarily complex conditional expressions and loops in the TVM code, pro- vided we have a means to push constant continuations into the stack. In fact, TVM includes special versions of “literal” or “constant” primitives that cut the nextnbytes or bits from the remainder of the current codecc.codeinto a cell slice, and then push it into the stack not as aSlice(as aPUSHSLICE does) but as a simple ordinaryContinuation(which has onlycodeandcp). The simplest of these primitives isPUSHCONT, which has an immediate argumentndescribing the number of subsequent bytes (in a byte-oriented version of TVM) or bits to be converted into a simple continuation. Another primitive isPUSHREFCONT, which removes the first cell reference from the current continuationcc.code, converts the cell referred to into a cell slice, and finally converts the cell slice into a simple continuation. 4.2.4. Constant continuations combined with conditional or iter- ated execution primitives.Because constant continuations are very often used as arguments to conditional or iterated execution primitives, combined 23 The implementation ofREPEATinvolves an extraordinary continuation that remembers the remaining number of iterations, the body of the loopc, and the return continuation c ′ . (The latter term represents the remainder of the body of the function that invoked REPEAT, which would be normally stored inc0of the newcc.) 54 4.3. Operations with continuations versions of these primitives (e.g.,IFCONTorUNTILREFCONT) may be defined in a future revision of TVM, which combine aPUSHCONTorPUSHREFCONT with another primitive. If one inspects the resulting code,IFCONTlooks very much like the more customary “conditional-branch-forward” instruction. 4.3 Operations with continuations 4.3.1. Continuations are opaque.Notice that all continuations areopaque, at least in the current version of TVM, meaning that there is no way to modify a continuation or inspect its internal data. Almost the only use of a continuation is to supply it to a control flow primitive. While there are some arguments in favor of including support for non- opaque continuations in TVM (along with opaque continuations, which are required for virtualization), the current revision offers no such support. 4.3.2. Allowed operations with continuations.However, some opera- tions with opaque continuations are still possible, mostly because they are equivalent to operations of the kind “create a new continuation, which will do something special, and then invoke the original continuation”. Allowed operations with continuations include: •Push one or several values into the stack of a continuationc(thus creating a partial application of a function, or a closure). •Set the saved value of a control registerc(i)inside the savelistc.save of a continuationc. If there is already a value for the control register in question, this operation silently does nothing. 4.3.3. Example: operations with control registers.TVM has some primitives to set and inspect the values of control registers. The most impor- tant of them arePUSH c(i)(pushes the current value ofc(i)into the stack) andPOP c(i)(sets the value ofc(i)from the stack, if the supplied value is of the correct type). However, there is also a modified version of the latter instruction, calledPOPSAVE c(i), which saves the old value ofc(i)(fori >0) into the continuation atc0as described in4.3.2before setting the new value. 4.3.4. Example: setting the number of arguments to a function in its code.The primitiveLEAVEARGSndemonstrates another application of continuations in an operation: it leaves only the topnvalues of the cur- rent stack, and moves the remainder to the stack of the continuation inc0. 55 4.3. Operations with continuations This primitive enables a called function to “return” unneeded arguments to its caller’s stack, which is useful in some situations (e.g., those related to exception handling). 4.3.5. Boolean circuits.A continuationcmay be thought of as a piece of code with two optional exit points kept in the savelist ofc: the principal exit point given byc.c0:=c.save(c0), and the auxiliary exit point given byc.c1:=c.save(c1). If executed, a continuation performs whatever action it was created for, and then (usually) transfers control to the principal exit point, or, on some occasions, to the auxiliary exit point. We sometimes say that a continuationcwith both exit pointsc.c0andc.c1defined is atwo-exit continuation, or aboolean circuit, especially if the choice of the exit point depends on some internally-checked condition. 4.3.6. Composition of continuations.One cancomposetwo continu- ationscandc ′ simply by settingc.c0orc.c1toc ′ . This creates a new continuation denoted byc◦ 0 c ′ orc◦ 1 c ′ , which differs fromcin its savelist. (Recall that if the savelist ofcalready has an entry corresponding to the con- trol register in question, such an operation silently does nothing as explained in4.3.2). By composing continuations, one can build chains or other graphs, pos- sibly with loops, representing the control flow. In fact, the resulting graph resembles a flow chart, with the boolean circuits corresponding to the “con- dition nodes” (containing code that will transfer control either toc0or toc1 depending on some condition), and the one-exit continuations corresponding to the “action nodes”. 4.3.7. Basic continuation composition primitives.Two basic primi- tives for composing continuations areCOMPOS(also known asSETCONT c0and BOOLAND) andCOMPOSALT(also known asSETCONT c1andBOOLOR), which takecandc ′ from the stack, setc.c0orc.c1toc ′ , and return the result- ing continuationc ′′ =c◦ 0 c ′ orc◦ 1 c ′ . All other continuation composition operations can be expressed in terms of these two primitives. 4.3.8. Advanced continuation composition primitives.However, TVM can compose continuations not only taken from stack, but also taken from c0orc1, or from the current continuationcc; likewise, the result may be pushed into the stack, stored into eitherc0orc1, or used as the new current continuation (i.e., the control may be transferred to it). Furthermore, TVM 56 4.4. Continuations as objects can define conditional composition primitives, performing some of the above actions only if an integer value taken from the stack is non-zero. For instance,EXECUTEcan be described ascc←c◦ 0 cc, with continuation ctaken from the original stack. Similarly,JMPXiscc←c, andRET(also known asRETTRUEin a boolean circuit context) iscc←c0. Other interesting primitives includeTHENRET(c ′ ←c◦ 0 c0) andATEXIT(c0←c◦ 0 c0). Finally, some “experimental” primitives also involvec1and◦ 1 . For ex- ample: •RETALTorRETFALSEdoescc←c1. •Conditional versions ofRETandRETALTmay also be useful:RETBOOL takes an integerxfrom the stack, and performsRETTRUEifx6= 0, RETFALSEotherwise. •INVERTdoesc0↔c1; if the two continuations inc0andc1represent the two branches we should select depending on some boolean expres- sion,INVERTnegates this expression on the outer level. •INVERTCONTdoesc.c0↔c.c1to a continuationctaken from the stack. •Variants ofATEXITincludeATEXITALT(c1←c◦ 1 c1) andSETEXITALT (c1←(c◦ 0 c0)◦ 1 c1). •BOOLEVALtakes a continuationcfrom the stack and doescc← ( (c◦ 0 (PUSH−1))◦ 1 (PUSH0) ) ◦ 0 cc. Ifcrepresents a boolean circuit, the net effect is to evaluate it and push either−1or0into the stack before continuing. 4.4 Continuations as objects 4.4.1. Representing objects using continuations.Object-oriented pro- gramming in Smalltalk (or Objective C) style may be implemented with the aid of continuations. For this, an object is represented by a special continu- ationo. If it has any data fields, they can be kept in the stack ofo, making oa partial application (i.e., a continuation with a non-empty stack). When somebody wants to invoke a methodmofowith argumentsx 1 ,x 2 , . . . ,x n , she pushes the arguments into the stack, then pushes a magic number corresponding to the methodm, and then executesopassingn+1arguments (cf.4.1.10). Thenouses the top-of-stack integermto select the branch with 57 4.5. Exception handling the required method, and executes it. Ifoneeds to modify its state, it simply computes a new continuationo ′ of the same sort (perhaps with the same code aso, but with a different initial stack). The new continuationo ′ is returned to the caller along with whatever other return values need to be returned. 4.4.2. Serializable objects.Another way of representing Smalltalk-style objects as continuations, or even as trees of cells, consists in using the JMPREFDATAprimitive (a variant ofJMPXDATA, cf.4.1.11), which takes the first cell reference from the code of the current continuation, transforms the cell referred to into a simple ordinary continuation, and transfers control to it, first pushing the remainder of the current continuation as aSliceinto the stack. In this way, an object might be represented by a cell ̃othat contains JMPREFDATAat the beginning of its data, and the actual code of the object in the first reference (one might say that the first reference of cell ̃ois the classof object ̃o). Remaining data and references of this cell will be used for storing the fields of the object. Such objects have the advantage of being trees of cells, and not just continuations, meaning that they can be stored into the persistent storage of a TON smart contract. 4.4.3. Unique continuations and capabilities.It might make sense (in a future revision of TVM) to mark some continuations asunique, meaning that they cannot be copied, even in a delayed manner, by increasing their reference counter to a value greater than one. If an opaque continuation is unique, it essentially becomes acapability, which can either be used by its owner exactly once or be transferred to somebody else. For example, imagine a continuation that represents the output stream to a printer (this is an example of a continuation used as an object, cf.4.4.1). When invoked with one integer argumentn, this continuation outputs the character with codento the printer, and returns a new continuation of the same kind reflecting the new state of the stream. Obviously, copying such a continuation and using the two copies in parallel would lead to some unintended side effects; marking it as unique would prohibit such adverse usage. 4.5 Exception handling TVM’s exception handling is quite simple and consists in a transfer of control to the continuation kept in control registerc2. 58 4.5. Exception handling 4.5.1. Two arguments of the exception handler: exception param- eter and exception number.Every exception is characterized by two arguments: theexception number(anInteger) and theexception parameter (any value, most often a zeroInteger). Exception numbers 0–31 are reserved for TVM, while all other exception numbers are available for user-defined exceptions. 4.5.2. Primitives for throwing an exception.There are several spe- cial primitives used for throwing an exception. The most general of them, THROWANY, takes two arguments,vand0≤n <2 16 , from the stack, and throws the exception with numbernand valuev. There are variants of this primitive that assumevto be a zero integer, storenas a literal value, and/or are conditional on an integer value taken from the stack. User-defined exceptions may use arbitrary values asv(e.g., trees of cells) if needed. 4.5.3. Exceptions generated by TVM.Of course, some exceptions are generated by normal primitives. For example, an arithmetic overflow excep- tion is generated whenever the result of an arithmetic operation does not fit into a signed 257-bit integer. In such cases, the arguments of the exception, vandn, are determined by TVM itself. 4.5.4. Exception handling.The exception handling itself consists in a control transfer to the exception handler—i.e., the continuation specified in control registerc2, withvandnsupplied as the two arguments to this continuation, as if aJMPtoc2had been requested withn ′′ = 2arguments (cf.4.1.7and4.1.6). As a consequence,vandnend up in the top of the stack of the exception handler. The remainder of the old stack is discarded. Notice that if the continuation inc2has a value forc2in its savelist, it will be used to set up the new value ofc2before executing the exception handler. In particular, if the exception handler invokesTHROWANY, it will re- throw the original exception with the restored value ofc2. This trick enables the exception handler to handle only some exceptions, and pass the rest to an outer exception handler. 4.5.5. Default exception handler.When an instance of TVM is created, c2contains a reference to the “default exception handler continuation”, which is anec\_fatalextraordinary continuation (cf.4.1.5). Its execution leads to the termination of the execution of TVM, with the argumentsvandn of the exception returned to the outside caller. In the context of the TON Blockchain,nwill be stored as a part of the transaction’s result. 59 4.5. Exception handling 4.5.6.TRYprimitive.ATRYprimitive can be used to implement C++-like exception handling. This primitive accepts two continuations,candc ′ . It stores the old value ofc2into the savelist ofc ′ , setsc2toc ′ , and executesc just asEXECUTEwould, but additionally saving the old value ofc2into the savelist of the newc0as well. Usually a version of theTRYprimitive with an explicit number of argumentsn ′′ passed to the continuationcis used. The net result is roughly equivalent to C++’stry {c} catch(...) {c ′ }operator. 4.5.7. List of predefined exceptions.Predefined exceptions of TVM correspond to exception numbersnin the range 0–31. They include: •Normal termination(n= 0) — Should never be generated, but it is useful for some tricks. •Alternative termination(n= 1) — Again, should never be generated. •Stack underflow(n= 2) — Not enough arguments in the stack for a primitive. •Stack overflow(n= 3) — More values have been stored on a stack than allowed by this version of TVM. •Integer overflow(n= 4) — Integer does not fit into−2 256 ≤x <2 256 , or a division by zero has occurred. •Range check error(n= 5) — Integer out of expected range. •Invalid opcode(n= 6) — Instruction or its immediate arguments can- not be decoded. •Type check error(n= 7) — An argument to a primitive is of incorrect value type. •Cell overflow(n= 8) — Error in one of the serialization primitives. •Cell underflow(n= 9) — Deserialization error. •Dictionary error(n= 10) — Error while deserializing a dictionary object. •Unknown error(n= 11) — Unknown error, may be thrown by user programs. 60 4.6. Functions, recursion, and dictionaries •Fatal error(n= 12) — Thrown by TVM in situations deemed impos- sible. •Out of gas(n= 13) — Thrown by TVM when the remaining gas (g r ) becomes negative. This exception usually cannot be caught and leads to an immediate termination of TVM. Most of these exceptions have no parameter (i.e., use a zero integer instead). The order in which these exceptions are checked is outlined below in4.5.8. 4.5.8. Order of stack underflow, type check, and range check ex- ceptions.All TVM primitives first check whether the stack contains the required number of arguments, generating a stack underflow exception if this is not the case. Only then are the type tags of the arguments and their ranges (e.g., if a primitive expects an argument not only to be anInteger, but also to be in the range from 0 to 256) checked, starting from the value in the top of the stack (the last argument) and proceeding deeper into the stack. If an argument’s type is incorrect, a type-checking exception is generated; if the type is correct, but the value does not fall into the expected range, a range check exception is generated. Some primitives accept a variable number of arguments, depending on the values of some small fixed subset of arguments located near the top of the stack. In this case, the above procedure is first run for all arguments from this small subset. Then it is repeated for the remaining arguments, once their number and types have been determined from the arguments already processed. 4.6 Functions, recursion, and dictionaries 4.6.1. The problem of recursion.The conditional and iterated execution primitives described in4.2—along with the unconditional branch, call, and return primitives described in4.1— enable one to implement more or less arbitrary code with nested loops and conditional expressions, with one no- table exception: one can only create new constant continuations from parts of the current continuation. (In particular, one cannot invoke a subroutine from itself in this way.) Therefore, the code being executed—i.e., the current continuation—gradually becomes smaller and smaller. 24 24 An important point here is that the tree of cells representing a TVM program cannot have cyclic references, so usingCALLREFalong with a reference to a cell higher up the tree 61 4.6. Functions, recursion, and dictionaries 4.6.2.Y-combinator solution: pass a continuation as an argument to itself.One way of dealing with the problem of recursion is by passing a copy of the continuation representing the body of a recursive function as an extra argument to itself. Consider, for example, the following code for a factorial function: 71 PUSHINT 1 9C PUSHCONT { 22 PUSH s2 72 PUSHINT 2 B9 LESS DC IFRET 59 ROTREV 21 PUSH s1 A8 MUL 01 SWAP A5 DEC 02 XCHG s2 20 DUP D9 JMPX } 20 DUP D8 EXECUTE 30 DROP 31 NIP This roughly corresponds to defining an auxiliary functionbodywith three argumentsn,x, andf, such thatbody(n,x,f)equalsxifn <2andf(n− 1,nx,f)otherwise, then invokingbody(n,1,body)to compute the factorial ofn. The recursion is then implemented with the aid of theDUP;EXECUTE construction, orDUP;JMPXin the case of tail recursion. This trick is equivalent to applyingY-combinator to a functionbody. 4.6.3. A variant ofY-combinator solution.Another way of recursively computing the factorial, more closely following the classical recursive defini- tion fact(n) := { 1ifn <2, n·fact(n−1)otherwise (5) would not work. 62 4.6. Functions, recursion, and dictionaries is as follows: 9D PUSHCONT { 21 OVER C102 LESSINT 2 92 PUSHCONT { 5B 2DROP 71 PUSHINT 1 } E0 IFJMP 21 OVER A5 DEC 01 SWAP 20 DUP D8 EXECUTE A8 MUL } 20 DUP D9 JMPX This definition of the factorial function is two bytes shorter than the previous one, but it uses general recursion instead of tail recursion, so it cannot be easily transformed into a loop. 4.6.4. Comparison: non-recursive definition of the factorial func- tion.Incidentally, a non-recursive definition of the factorial with the aid of aREPEATloop is also possible, and it is much shorter than both recursive definitions: 71 PUSHINT 1 01 SWAP 20 DUP 94 PUSHCONT { 66 TUCK A8 MUL 01 SWAP A5 DEC } E4 REPEAT 30 DROP 63 4.6. Functions, recursion, and dictionaries 4.6.5. Several mutually recursive functions.If one has a collection f 1 , . . . ,f n of mutually recursive functions, one can use the same trick by passing the whole collection of continuations{f i }in the stack as an extra narguments to each of these functions. However, asngrows, this becomes more and more cumbersome, since one has to reorder these extra arguments in the stack to work with the “true” arguments, and then push their copies into the top of the stack before any recursive call. 4.6.6. Combining several functions into one tuple.One might also combine a collection of continuations representing functionsf 1 , . . . ,f n into a “tuple”f:= (f 1 ,...,f n ), and pass this tuple as one stack elementf. For instance, whenn≤4, each function can be represented by a cell ̃ f i (along with the tree of cells rooted in this cell), and the tuple may be represented by a cell ̃ f, which has references to its component cells ̃ f i . However, this would lead to the necessity of “unpacking” the needed component from this tuple before each recursive call. 4.6.7. Combining several functions into a selector function.Another approach is to combine several functionsf 1 , . . . ,f n into one “selector func- tion”f, which takes an extra argumenti,1≤i≤n, from the top of the stack, and invokes the appropriate functionf i . Stack machines such as TVM are well-suited to this approach, because they do not require the functionsf i to have the same number and types of arguments. Using this approach, one would need to pass only one extra argument,f, to each of these functions, and push into the stack an extra argumentibefore each recursive call tof to select the correct function to be called. 4.6.8. Using a dedicated register to keep the selector function.How- ever, even if we use one of the two previous approaches to combine all func- tions into one extra argument, passing this argument to all mutually recursive functions is still quite cumbersome and requires a lot of additional stack ma- nipulation operations. Because this argument changes very rarely, one might use a dedicated register to keep it and transparently pass it to all functions called. This is the approach used by TVM by default. 4.6.9. Special registerc3for the selector function.In fact, TVM uses a dedicated registerc3to keep the continuation representing the current or global “selector function”, which can be used to invoke any of a family of mutually recursive functions. Special primitivesCALLnnorCALLDICTnn 64 4.6. Functions, recursion, and dictionaries (cf.A.8.7) are equivalent toPUSHINTnn;PUSH c3;EXECUTE, and similarly JMPnnorJMPDICTnnare equivalent toPUSHINTnn;PUSH c3;JMPX. In this way a TVM program, which ultimately is a large collection of mutually recursive functions, may initializec3with the correct selector function rep- resenting the family of all the functions in the program, and then useCALL nnto invoke any of these functions by its index (sometimes also called the selectorof a function). 4.6.10. Initialization ofc3.A TVM program might initializec3by means of aPOP c3instruction. However, because this usually is the very first ac- tion undertaken by a program (e.g., a smart contract), TVM makes some provisions for the automatic initialization ofc3. Namely,c3is initialized by the code (the initial value ofcc) of the program itself, and an extra zero (or, in some cases, some other predefined numbers) is pushed into the stack before the program’s execution. This is approximately equivalent to invok- ingJMPDICT 0(orJMPDICTs) at the very beginning of a program—i.e., the function with index zero is effectively themain()function for the program. 4.6.11. Creating selector functions andswitchstatements.TVM makes special provisions for simple and concise implementation of selector functions (which usually constitute the top level of a TVM program) or, more generally, arbitraryswitchorcasestatements (which are also useful inTVM programs). The most important primitives included for this purpose are IFBITJMP,IFNBITJMP,IFBITJMPREF, andIFNBITJMPREF(cf.A.8.2). They effectively enable one to combine subroutines, kept either in separate cells or as subslices of certain cells, into a binary decision tree with decisions made according to the indicated bits of the integer passed in the top of the stack. Another instruction, useful for the implementation of sum-product types, isPLDUZ(cf.A.7.2). This instruction preloads the first several bits of aSlice into anInteger, which can later be inspected byIFBITJMPand other similar instructions. 4.6.12. Alternative: using a hashmap to select the correct function. Yet another alternative is to use aHashmap(cf.3.3) to hold the “collection” or “dictionary” of the code of all functions in a program, and use the hashmap lookup primitives (cf.A.10) to select the code of the required function, which can then beBLESSed into a continuation (cf.A.8.5) and executed. Special combined “lookup, bless, and execute” primitives, such asDICTIGETJMPand DICTIGETEXEC, are also available (cf.A.10.11). This approach may be more 65 4.6. Functions, recursion, and dictionaries efficient for larger programs andswitchstatements. 66 5.1. Codepages and interoperability of different TVM versions 5 Codepages and instruction encoding This chapter describes the codepage mechanism, which allows TVM to be flexible and extendable while preserving backward compatibility with respect to previously generated code. We also discuss some general considerations about instruction encodings (applicable to arbitrary machine code, not just TVM), as well as the implica- tions of these considerations for TVM and the choices made while designing TVM’s (experimental) codepage zero. The instruction encodings themselves are presented later in AppendixA. 5.1 Codepages and interoperability of different TVM versions Thecodepagesare an essential mechanism of backward compatibility and of future extensions to TVM. They enable transparent execution of code written for different revisions of TVM, with transparent interaction between instances of such code. The mechanism of the codepages, however, is general and powerful enough to enable some other originally unintended applications. 5.1.1. Codepages in continuations.Every ordinary continuation contains a 16-bitcodepagefieldcp(cf.4.1.1), which determines the codepage that will be used to execute its code. If a continuation is created by aPUSHCONT (cf.4.2.3) or similar primitive, it usually inherits the current codepage (i.e., the codepage ofcc). 25 5.1.2. Current codepage.The current codepagecp(cf.1.4) is the code- page of the current continuationcc. It determines the way the next in- struction will be decoded fromcc.code, the remainder of the current con- tinuation’s code. Once the instruction has been decoded and executed, it determines the next value of the current codepage. In most cases, the cur- rent codepage is left unchanged. On the other hand, all primitives that switch the current continuation load the new value ofcpfrom the new current continuation. In this way, all code in continuations is always interpreted exactly as it was intended to be. 25 This is not exactly true. A more precise statement is that usually the codepage of the newly-created continuation is a known function of the current codepage. 67 5.1. Codepages and interoperability of different TVM versions 5.1.3. Different versions of TVM may use different codepages.Dif- ferent versions of TVM may use different codepages for their code. For example, the original version of TVM might use codepage zero. A newer version might use codepage one, which contains all the previously defined opcodes, along with some newly defined ones, using some of the previously unused opcode space. A subsequent version might use yet another codepage, and so on. However, a newer version of TVM will execute old code for codepage zero exactly as before. If the old code contained an opcode used for some new operations that were undefined in the original version of TVM, it will still generate an invalid opcode exception, because the new operations are absent in codepage zero. 5.1.4. Changing the behavior of old operations.New codepages can also change the effects of some operations present in the old codepages while preserving their opcodes and mnemonics. For example, imagine a future 513-bit upgrade of TVM (replacing the current 257-bit design). It might use a 513-bitIntegertype within the same arithmetic primitives as before. However, while the opcodes and instructions in the new codepage would look exactly like the old ones, they would work differently, accepting 513-bit integer arguments and results. On the other hand, during the execution of the same code in codepage zero, the new machine would generate exceptions whenever the integers used in arithmetic and other primitives do not fit into 257 bits. 26 In this way, the upgrade would not change the behavior of the old code. 5.1.5. Improving instruction encoding.Another application for code- pages is to change instruction encodings, reflecting improved knowledge of the actual frequencies of such instructions in the code base. In this case, the new codepage will have exactly the same instructions as the old one, but with different encodings, potentially of differing lengths. For example, one might create an experimental version of the first version of TVM, using a 26 This is another important mechanism of backward compatibility. All values of newly- added types, as well as values belonging to extended original types that do not belong to the original types (e.g., 513-bit integers that do not fit into 257 bits in the example above), are treated by all instructions (except stack manipulation instructions, which are naturally polymorphic, cf.2.2.6) in the old codepages as “values of incorrect type”, and generate type-checking exceptions accordingly. 68 5.1. Codepages and interoperability of different TVM versions (prefix) bitcode instead of the original bytecode, aiming to achieve higher code density. 5.1.6. Making instruction encoding context-dependent.Another way of using codepages to improve code density is to use several codepages with different subsets of the whole instruction set defined in each of them, or with the whole instruction set defined, but with different length encodings for the same instructions in different codepages. Imagine, for instance, a “stack manipulation” codepage, where stack ma- nipulation primitives have short encodings at the expense of all other op- erations, and a “data processing” codepage, where all other operations are shorter at the expense of stack manipulation operations. If stack manip- ulation operations tend to come one after another, we can automatically switch to “stack manipulation” codepage after executing any such instruc- tion. When a data processing instruction occurs, we switch back to “data processing” codepage. If conditional probabilities of the class of the next in- struction depending on the class of the previous instruction are considerably different from corresponding unconditional probabilities, this technique— automatically switching into stack manipulation mode to rearrange the stack with shorter instructions, then switching back—might considerably improve the code density. 5.1.7. Using codepages for status and control flags.Another potential application of multiple codepages inside the same revision of TVM consists in switching between several codepages depending on the result of the execution of some instructions. For example, imagine a version of TVM that uses two new codepages, 2 and 3. Most operations do not change the current codepage. However, the integer comparison operations will switch to codepage 2 if the condition is false, and to codepage 3 if it is true. Furthermore, a new operation?EXECUTE, similar toEXECUTE, will indeed be equivalent toEXECUTEin codepage 3, but will instead be aDROPin codepage 2. Such a trick effectively uses bit 0 of the current codepage as a status flag. Alternatively, one might create a couple of codepages—say, 4 and 5— which differ only in their cell deserialisation primitives. For instance, in codepage 4 they might work as before, while in codepage 5 they might de- serialize data not from the beginning of aSlice, but from its end. Two new instructions—say,CLDandSTD—might be used for switching to codepage 4 69 5.2. Instruction encoding or codepage 5. Clearly, we have now described a status flag, affecting the execution of some instructions in a certain new manner. 5.1.8. Setting the codepage in the code itself.For convenience, we reserve some opcode in all codepages—say,FFn—for the instructionSETCP n, withnfrom 0 to 255 (cf.A.13). Then by inserting such an instruction into the very beginning of (the main function of) a program (e.g., a TON Blockchain smart contract) or a library function, we can ensure that the code will always be executed in the intended codepage. 5.2 Instruction encoding This section discusses the general principles of instruction encoding valid for all codepages and all versions of TVM. Later,5.3discusses the choices made for the experimental “codepage zero”. 5.2.1. Instructions are encoded by a binary prefix code.All com- plete instructions (i.e., instructions along with all their parameters, such as the names of stack registerss(i)or other embedded constants) of a TVM codepage are encoded by abinary prefix code. This means that a (finite) binary string (i.e., a bitstring) corresponds to each complete instruction, in such a way that binary strings corresponding to different complete instruc- tions do not coincide, and no binary string among the chosen subset is a prefix of another binary string from this subset. 5.2.2. Determining the first instruction from a code stream.As a consequence of this encoding method, any binary string admits at most one prefix, which is an encoding of some complete instruction. In particular, the codecc.codeof the current continuation (which is aSlice, and thus a bitstring along with some cell references) admits at most one such prefix, which corresponds to the (uniquely determined) instruction that TVM will execute first. After execution, this prefix is removed from the code of the current continuation, and the next instruction can be decoded. 5.2.3. Invalid opcode.If no prefix ofcc.codeencodes a valid instruction in the current codepage, aninvalid opcode exceptionis generated (cf.4.5.7). However, the case of an emptycc.codeis treated separately as explained in4.1.4(the exact behavior may depend on the current codepage). 70 5.2. Instruction encoding 5.2.4. Special case: end-of-code padding.As an exception to the above rule, some codepages may accept some values ofcc.codethat are too short to be valid instruction encodings as additional variants ofNOP, thus effectively using the same procedure for them as for an emptycc.code. Such bitstrings may be used for padding the code near its end. For example, if binary string00000000(i.e.,x00, cf.1.0.3) is used in a codepage to encodeNOP, its proper prefixes cannot encode any instructions. So this codepage may accept0,00,000, . . . ,0000000as variants ofNOPif this is all that is left incc.code, instead of generating an invalid opcode exception. Such a padding may be useful, for example, if thePUSHCONTprimitive (cf.4.2.3) creates only continuations with code consisting of an integral number of bytes, but not all instructions are encoded by an integral number of bytes. 5.2.5. TVM code is a bitcode, not a bytecode.Recall that TVM is a bit-oriented machine in the sense that itsCells (andSlices) are naturally considered as sequences of bits, not just of octets (bytes), cf.3.2.5. Because the TVM code is also kept in cells (cf.3.1.9and4.1.4), there is no reason to use only bitstrings of length divisible by eight as encodings of complete instructions. In other words, generally speaking,the TVM code is a bitcode, not a bytecode. That said, some codepages (such as our experimental codepage zero) may opt to use a bytecode (i.e., to use only encodings consisting of an integral number of bytes)—either for simplicity, or for the ease of debugging and of studying memory (i.e., cell) dumps. 27 5.2.6. Opcode space used by a complete instruction.Recall from cod- ing theory that the lengths of bitstringsl i used in a binary prefix code satisfy Kraft–McMillan inequality ∑ i 2 −l i ≤1. This is applicable in particular to the (complete) instruction encoding used by a TVM codepage. We say that a particular complete instruction(or, more precisely,the encoding of a com- plete instruction)utilizes the portion2 −l of the opcode space, if it is encoded by anl-bit string. One can see that all complete instructions together utilize at most1(i.e., “at most the whole opcode space”). 27 If the cell dumps are hexadecimal, encodings consisting of an integral number of hexadecimal digits (i.e., having length divisible by four bits) might be equally convenient. 71 5.2. Instruction encoding 5.2.7. Opcode space used by an instruction, or a class of instruc- tions.The above terminology is extended to instructions (considered with all admissible values of their parameters), or even classes of instructions (e.g., all arithmetic instructions). We say that an (incomplete) instruction, or a class of instructions, occupies portionαof the opcode space, ifαis the sum of the portions of the opcode space occupied by all complete instructions belonging to that class. 5.2.8. Opcode space for bytecodes.A useful approximation of the above definitions is as follows: Consider all 256 possible values for the first byte of an instruction encoding. Suppose thatkof these values correspond to the specific instruction or class of instructions we are considering. Then this instruction or class of instructions occupies approximately the portionk/256 of the opcode space. This approximation shows why all instructions cannot occupy together more than the portion256/256 = 1of the opcode space, at least without compromising the uniqueness of instruction decoding. 5.2.9. Almost optimal encodings.Coding theory tells us that in an op- timally dense encoding, the portion of the opcode space used by a complete instruction (2 −l , if the complete instruction is encoded inlbits) should be approximately equal to the probability or frequency of its occurrence in real programs. 28 The same should hold for (incomplete) instructions, or primi- tives (i.e., generic instructions without specified values of parameters), and for classes of instructions. 5.2.10. Example: stack manipulation primitives.For instance, if stack manipulation instructions constitute approximately half of all instructions in a typical TVM program, one should allocate approximately half of the opcode space for encoding stack manipulation instructions. One might reserve the first bytes (“opcodes”)0x00–0x7ffor such instructions. If a quarter of these instructions areXCHG, it would make sense to reserve0x00–0x1fforXCHGs. Similarly, if half of allXCHGs involve the top of stacks0, it would make sense to use0x00–0x0fto encodeXCHG s0,s(i). 5.2.11. Simple encodings of instructions.In most cases,simpleencod- ings of complete instructions are used. Simple encodings begin with a fixed 28 Notice that it is the probability of occurrence in the code that counts, not the proba- bility of being executed. An instruction occurring in the body of a loop executed a million times is still counted only once. 72 5.3. Instruction encoding in codepage zero bitstring called theopcodeof the instruction, followed by, say, 4-bit fields containing the indicesiof stack registerss(i)specified in the instruction, fol- lowed by all other constant (literal, immediate) parameters included in the complete instruction. While simple encodings may not be exactly optimal, they admit short descriptions, and their decoding and encoding can be easily implemented. If a (generic) instruction uses a simple encoding with anl-bit opcode, then the instruction will utilize2 −l portion of the opcode space. This observation might be useful for considerations described in5.2.9and5.2.10. 5.2.12. Optimizing code density further: Huffman codes.One might construct optimally dense binary code for the set of all complete instructions, provided their probabilities or frequences in real code are known. This is the well-known Huffman code (for the given probability distribution). However, such code would be highly unsystematic and hard to decode. 5.2.13. Practical instruction encodings.In practice, instruction encod- ings used in TVM and other virtual machines offer a compromise between code density and ease of encoding and decoding. Such a compromise may be achieved by selecting simple encodings (cf.5.2.11) for all instructions (maybe with separate simple encodings for some often used variants, such asXCHG s0,s(i)among allXCHG s(i),s(j)), and allocating opcode space for such simple encodings using the heuristics outlined in5.2.9and5.2.10; this is the approach currently used in TVM. 5.3 Instruction encoding in codepage zero This section provides details about the experimental instruction encoding for codepage zero, as described elsewhere in this document (cf. AppendixA) and used in the preliminary test version of TVM. 5.3.1. Upgradability.First of all, even if this preliminary version some- how gets into the production version of the TON Blockchain, the codepage mechanism (cf.5.1) enables us to introduce better versions later without compromising backward compatibility. 29 So in the meantime, we are free to experiment. 29 Notice that any modifications after launch cannot be done unilaterally; rather they would require the support of at least two-thirds of validators. 73 5.3. Instruction encoding in codepage zero 5.3.2. Choice of instructions.We opted to include many “experimental” and not strictly necessary instructions in codepage zero just to see how they might be used in real code. For example, we have both the basic (cf.2.2.1) and the compound (cf.2.2.3) stack manipulation primitives, as well as some “unsystematic” ones such asROT(mostly borrowed from Forth). If such primitives are rarely used, their inclusion just wastes some part of the opcode space and makes the encodings of other instructions slightly less effective, something we can afford at this stage of TVM’s development. 5.3.3. Using experimental instructions.Some of these experimental instructions have been assigned quite long opcodes, just to fit more of them into the opcode space. One should not be afraid to use them just because they are long; if these instructions turn out to be useful, they will receive shorter opcodes in future revisions. Codepage zero is not meant to be fine- tuned in this respect. 5.3.4. Choice of bytecode.We opted to use a bytecode (i.e., to use encod- ings of complete instructions of lengths divisible by eight). While this may not produce optimal code density, because such a length restriction makes it more difficult to match portions of opcode space used for the encoding of instructions with estimated frequencies of these instructions in TVM code (cf.5.2.11and5.2.9), such an approach has its advantages: it admits a simpler instruction decoder and simplifies debugging (cf.5.2.5). After all, we do not have enough data on the relative frequencies of dif- ferent instructions right now, so our code density optimizations are likely to be very approximate at this stage. The ease of debugging and experimenting and the simplicity of implementation are more important at this point. 5.3.5. Simple encodings for all instructions.For similar reasons, we opted to use simple encodings for all instructions (cf.5.2.11and5.2.13), with separate simple encodings for some very frequently used subcases as outlined in5.2.13. That said, we tried to distribute opcode space using the heuristics described in5.2.9and5.2.10. 5.3.6. Lack of context-dependent encodings.This version of TVM also does not use context-dependent encodings (cf.5.1.6). They may be added at a later stage, if deemed useful. 5.3.7. The list of all instructions.The list of all instructions available in 74 5.3. Instruction encoding in codepage zero codepage zero, along with their encodings and (in some cases) short descrip- tions, may be found in AppendixA. 75 References References \[1\]N. Durov,Telegram Open Network, 2017. 76 A.1. Gas prices A Instructions and opcodes This appendix lists all instructions available in the (experimental) codepage zero of TVM, as explained in5.3. We list the instructions in lexicographical opcode order. However, the opcode space is distributed in such way as to make all instructions in each category (e.g., arithmetic primitives) have neighboring opcodes. So we first list a number of stack manipulation primitives, then constant primitives, arithmetic primitives, comparison primitives, cell primitives, continuation primitives, dictionary primitives, and finally application-specific primitives. We use hexadecimal notation (cf.1.0) for bitstrings. Stack registerss(i) usually have0≤i≤15, andiis encoded in a 4-bit field (or, on a few rare occasions, in an 8-bit field). Other immediate parameters are usually 4-bit, 8-bit, or variable length. The stack notation described in2.1.10is extensively used throughout this appendix. A.1 Gas prices The gas price for most primitives equals thebasic gas price, computed as P b := 10 +b+ 5r, wherebis the instruction length in bits andris the number of cell references included in the instruction. When the gas price of an instruction differs from this basic price, it is indicated in parentheses after its mnemonics, either as(x), meaning that the total gas price equals x, or as(+x), meaningP b +x. Apart from integer constants, the following expressions may appear: •C r — The total price of “reading” cells (i.e., transforming cell refer- ences into cell slices). Currently equal to 100 or 25 gas units per cell depending on whether it is the first time a cell with this hash is being “read” during the current run of the VM or not. •L— The total price of loading cells. Depends on the loading action required. •B w — The total price of creating newBuilders. Currently equal to 0 gas units per builder. •C w — The total price of creating newCells fromBuilders. Currently equal to 500 gas units per cell. 77 A.2. Stack manipulation primitives By default, the gas price of an instruction equalsP:=P b +C r +L+B w +C w . A.2 Stack manipulation primitives This section includes both the basic (cf.2.2.1) and the compound (cf.2.2.3) stack manipulation primitives, as well as some “unsystematic” ones. Some compound stack manipulation primitives, such asXCPUorXCHG2, turn out to have the same length as an equivalent sequence of simpler operations. We have included these primitives regardless, so that they can easily be allocated shorter opcodes in a future revision of TVM—or removed for good. Some stack manipulation instructions have two mnemonics: one Forth- style (e.g.,-ROT), the other conforming to the usual rules for identifiers (e.g., ROTREV). Whenever a stack manipulation primitive (e.g.,PICK) accepts an integer parameternfrom the stack, it must be within the range0...255; otherwise a range check exception happens before any further checks. A.2.1. Basic stack manipulation primitives. •00—NOP, does nothing. •01—XCHG s1, also known asSWAP. •0i—XCHG s(i)orXCHG s0,s(i), interchanges the top of the stack with s(i),1≤i≤15. •10ij—XCHG s(i),s(j),1≤i < j≤15, interchangess(i)withs(j). •11ii—XCHG s0,s(ii), with0≤ii≤255. •1i—XCHG s1,s(i),2≤i≤15. •2i—PUSH s(i),0≤i≤15, pushes a copy of the olds(i)into the stack. •20—PUSH s0, also known asDUP. •21—PUSH s1, also known asOVER. •3i—POPs(i),0≤i≤15, pops the old top-of-stack value into the old s(i). •30—POP s0, also known asDROP, discards the top-of-stack value. 78 A.2. Stack manipulation primitives •31—POP s1, also known asNIP. A.2.2. Compound stack manipulation primitives.Parametersi,j, andkof the following primitives all are 4-bit integers in the range0...15. •4ijk—XCHG3 s(i),s(j),s(k), equivalent toXCHG s2,s(i);XCHG s1, s(j);XCHG s0,s(k), with0≤i,j,k≤15. •50ij—XCHG2 s(i),s(j), equivalent toXCHG s1,s(i);XCHG s(j). •51ij—XCPU s(i),s(j), equivalent toXCHG s(i);PUSH s(j). •52ij—PUXC s(i),s(j−1), equivalent toPUSH s(i);SWAP;XCHG s(j). •53ij—PUSH2 s(i),s(j), equivalent toPUSH s(i);PUSH s(j+ 1). •540ijk—XCHG3 s(i),s(j),s(k)(long form). •541ijk—XC2PU s(i),s(j),s(k), equivalent toXCHG2 s(i),s(j);PUSH s(k). •542ijk—XCPUXC s(i),s(j),s(k−1), equivalent toXCHG s1,s(i);PUXC s(j),s(k−1). •543ijk—XCPU2 s(i),s(j),s(k), equivalent toXCHG s(i);PUSH2 s(j), s(k). •544ijk—PUXC2 s(i),s(j−1),s(k−1), equivalent toPUSH s(i);XCHG s2;XCHG2 s(j),s(k). •545ijk—PUXCPU s(i),s(j−1),s(k−1), equivalent toPUXC s(i),s(j− 1);PUSH s(k). •546ijk—PU2XC s(i),s(j−1),s(k−2), equivalent toPUSH s(i);SWAP; PUXC s(j),s(k−1). •547ijk—PUSH3 s(i),s(j),s(k), equivalent toPUSH s(i);PUSH2 s(j+ 1),s(k+ 1). •54C\_— unused. A.2.3. Exotic stack manipulation primitives. 79 A.2. Stack manipulation primitives •55ij—BLKSWAPi+1,j+1, permutes two blockss(j+i+1). . .s(j+1) ands(j). . .s0, for0≤i,j≤15. Equivalent toREVERSEi+ 1,j+ 1; REVERSEj+ 1,0;REVERSEi+j+ 2,0. •5513—ROT2or2ROT(a b c d e f–c d e f a b), rotates the three topmost pairs of stack entries. •550i—ROLLi+ 1, rotates the topi+ 1stack entries. Equivalent to BLKSWAP 1,i+ 1. •55i0—ROLLREVi+1or-ROLLi+1, rotates the topi+1stack entries in the other direction. Equivalent toBLKSWAPi+ 1,1. •56ii—PUSH s(ii)for0≤ii≤255. •57ii—POP s(ii)for0≤ii≤255. •58—ROT(a b c–b c a), equivalent toBLKSWAP 1,2or toXCHG2 s2,s1. •59—ROTREVor-ROT(a b c–c a b), equivalent toBLKSWAP 2,1or to XCHG2 s2,s2. •5A—SWAP2or2SWAP(a b c d–c d a b), equivalent toBLKSWAP 2,2or toXCHG2 s3,s2. •5B—DROP2or2DROP(a b– ), equivalent toDROP;DROP. •5C—DUP2or2DUP(a b–a b a b), equivalent toPUSH2 s1,s0. •5D—OVER2or2OVER(a b c d–a b c d a b), equivalent toPUSH2 s3,s2. •5Eij—REVERSEi+ 2,j, reverses the order ofs(j+i+ 1). . .s(j)for 0≤i,j≤15; equivalent to a sequence ofbi/2c+ 1XCHGs. •5F0i—BLKDROPi, equivalent toDROPperformeditimes. •5Fij—BLKPUSHi,j, equivalent toPUSH s(j)performeditimes,1≤ i≤15,0≤j≤15. •60—PICKorPUSHX, pops integerifrom the stack, then performsPUSH s(i). •61—ROLLX, pops integerifrom the stack, then performsBLKSWAP 1,i. 80 A.3. Tuple, List, and Null primitives •62—-ROLLXorROLLREVX, pops integerifrom the stack, then performs BLKSWAPi,1. •63—BLKSWX, pops integersi,jfrom the stack, then performsBLKSWAP i,j. •64—REVX, pops integersi,jfrom the stack, then performsREVERSE i,j. •65—DROPX, pops integerifrom the stack, then performsBLKDROPi. •66—TUCK(ab−bab), equivalent toSWAP;OVERor toXCPU s1,s1. •67—XCHGX, pops integerifrom the stack, then performsXCHG s(i). •68—DEPTH, pushes the current depth of the stack. •69—CHKDEPTH, pops integerifrom the stack, then checks whether there are at leastielements, generating a stack underflow exception otherwise. •6A—ONLYTOPX, pops integerifrom the stack, then removes all but the topielements. •6B—ONLYX, pops integerifrom the stack, then leaves only the bottom ielements. Approximately equivalent toDEPTH;SWAP;SUB;DROPX. •6C00–6C0F— reserved for stack operations. •6Cij—BLKDROP2i,j, dropsistack elements under the topjelements, where1≤i≤15and0≤j≤15. Equivalent toREVERSEi+j,0; BLKDROPi;REVERSEj,0. A.3 Tuple, List, and Null primitives Tuples are ordered collections consisting of at most 255 TVM stack values of arbitrary types (not necessarily the same). Tuple primitives create, modify, and unpackTuples; they manipulate values of arbitrary types in the process, similarly to the stack primitives. We do not recommend usingTuples of more than 15 elements. When aTupletcontains elementsx 1 , . . . ,x n (in that order), we write t= (x 1 ,...,x n ); numbern≥0is thelengthofTuplet. It is also denoted 81 A.3. Tuple, List, and Null primitives by|t|.Tuples of length two are calledpairs, andTuples of length three are triples. Lisp-style lists are represented with the aid of pairs, i.e., tuples consisting of exactly two elements. An empty list is represented by aNullvalue, and a non-empty list is represented by pair(h,t), wherehis the first element of the list, andtis its tail. A.3.1.Nullprimitives.The following primitives work with (the only) value⊥of typeNull, useful for representing empty lists, empty branches of binary trees, and absence of values inMaybeXtypes. An emptyTuple created byNILcould have been used for the same purpose; however,Nullis more efficient and costs less gas. •6D—NULLorPUSHNULL( –⊥), pushes the only value of typeNull. •6E—ISNULL(x–?), checks whetherxis aNull, and returns−1or0 accordingly. A.3.2. Tuple primitives. •6F0n—TUPLEn(x 1 . . .x n –t), creates a newTuplet= (x 1 ,...,x n ) containingnvaluesx 1 , . . . ,x n , where0≤n≤15. •6F00—NIL( –t), pushes the onlyTuplet= ()of length zero. •6F01—SINGLE(x–t), creates a singletont:= (x), i.e., aTupleof length one. •6F02—PAIRorCONS(x y–t), creates pairt:= (x,y). •6F03—TRIPLE(x y z–t), creates triplet:= (x,y,z). •6F1k—INDEXk(t–x), returns thek-th element of aTuplet, where 0≤k≤15. In other words, returnsx k+1 ift= (x 1 ,...,x n ). Ifk≥n, throws a range check exception. •6F10—FIRSTorCAR(t–x), returns the first element of aTuple. •6F11—SECONDorCDR(t–y), returns the second element of aTuple. •6F12—THIRD(t–z), returns the third element of aTuple. 82 A.3. Tuple, List, and Null primitives •6F2n—UNTUPLEn(t–x 1 . . .x n ), unpacks aTuplet= (x 1 ,...,x n )of length equal to0≤n≤15. Iftis not aTuple, of if|t| 6=n, a type check exception is thrown. •6F21—UNSINGLE(t–x), unpacks a singletont= (x). •6F22—UNPAIRorUNCONS(t–x y), unpacks a pairt= (x,y). •6F23—UNTRIPLE(t–x y z), unpacks a triplet= (x,y,z). •6F3k—UNPACKFIRSTk(t–x 1 . . .x k ), unpacks first0≤k≤15 elements of aTuplet. If|t|< k, throws a type check exception. •6F30—CHKTUPLE(t– ), checks whethertis aTuple. •6F4n—EXPLODEn(t–x 1 . . .x m m), unpacks aTuplet= (x 1 ,...,x m ) and returns its lengthm, but only ifm≤n≤15. Otherwise throws a type check exception. •6F5k—SETINDEXk(t x–t ′ ), computesTuplet ′ that differs fromt only at positiont ′ k+1 , which is set tox. In other words,|t ′ |=|t|,t ′ i =t i fori6=k+ 1, andt ′ k+1 =x, for given0≤k≤15. Ifk≥ |t|, throws a range check exception. •6F50—SETFIRST(t x–t ′ ), sets the first component ofTuplettox and returns the resultingTuplet ′ . •6F51—SETSECOND(t x–t ′ ), sets the second component ofTupletto xand returns the resultingTuplet ′ . •6F52—SETTHIRD(t x–t ′ ), sets the third component ofTuplettox and returns the resultingTuplet ′ . •6F6k—INDEXQk(t–x), returns thek-th element of aTuplet, where 0≤k≤15. In other words, returnsx k+1 ift= (x 1 ,...,x n ). Ifk≥n, or iftisNull, returns aNullinstead ofx. •6F7k—SETINDEXQk(t x–t ′ ), sets thek-th component ofTupletto x, where0≤k <16, and returns the resultingTuplet ′ . If|t|≤k, first extends the originalTupleto lengthk+1by setting all new components toNull. If the original value oftisNull, treats it as an emptyTuple. Iftis notNullorTuple, throws an exception. IfxisNulland either 83 A.3. Tuple, List, and Null primitives |t| ≤kortisNull, then always returnst ′ =t(and does not consume tuple creation gas). •6F80—TUPLEVAR(x 1 . . .x n n–t), creates a newTupletof lengthn similarly toTUPLE, but with0≤n≤255taken from the stack. •6F81—INDEXVAR(t k–x), similar toINDEXk, but with0≤k≤254 taken from the stack. •6F82—UNTUPLEVAR(t n–x 1 . . .x n ), similar toUNTUPLEn, but with 0≤n≤255taken from the stack. •6F83—UNPACKFIRSTVAR(t n–x 1 . . .x n ), similar toUNPACKFIRSTn, but with0≤n≤255taken from the stack. •6F84—EXPLODEVAR(t n–x 1 . . .x m m), similar toEXPLODEn, but with0≤n≤255taken from the stack. •6F85—SETINDEXVAR(t x k–t ′ ), similar toSETINDEXk, but with 0≤k≤254taken from the stack. •6F86—INDEXVARQ(t k–x), similar toINDEXQn, but with0≤k≤254 taken from the stack. •6F87—SETINDEXVARQ(t x k–t ′ ), similar toSETINDEXQk, but with 0≤k≤254taken from the stack. •6F88—TLEN(t–n), returns the length of aTuple. •6F89—QTLEN(t–nor−1), similar toTLEN, but returns−1iftis not aTuple. •6F8A—ISTUPLE(t–?), returns−1or0depending on whethertis a Tuple. •6F8B—LAST(t–x), returns the last elementt |t| of a non-emptyTuplet. •6F8C—TPUSHorCOMMA(t x–t ′ ), appends a valuexto aTuplet= (x 1 ,...,x n ), but only if the resultingTuplet ′ = (x 1 ,...,x n ,x)is of length at most 255. Otherwise throws a type check exception. 84 A.3. Tuple, List, and Null primitives •6F8D—TPOP(t–t ′ x), detaches the last elementx=x n from a non- emptyTuplet= (x 1 ,...,x n ), and returns both the resultingTuplet ′ = (x 1 ,...,x n−1 )and the original last elementx. •6FA0—NULLSWAPIF(x–xor⊥x), pushes aNullunder the topmost Integerx, but only ifx6= 0. •6FA1—NULLSWAPIFNOT(x–xor⊥x), pushes aNullunder the top- mostIntegerx, but only ifx= 0. May be used for stack alignment after quiet primitives such asPLDUXQ. •6FA2—NULLROTRIF(x y–x yor⊥x y), pushes aNullunder the second stack entry from the top, but only if the topmostIntegeryis non-zero. •6FA3—NULLROTRIFNOT(x y–x yor⊥x y), pushes aNullunder the second stack entry from the top, but only if the topmostIntegeryis zero. May be used for stack alignment after quiet primitives such as LDUXQ. •6FA4—NULLSWAPIF2(x–xor⊥ ⊥x), pushes twoNulls under the topmostIntegerx, but only ifx6= 0. Equivalent toNULLSWAPIF; NULLSWAPIF. •6FA5—NULLSWAPIFNOT2(x–xor⊥⊥x), pushes twoNulls under the topmostIntegerx, but only ifx= 0. Equivalent toNULLSWAPIFNOT; NULLSWAPIFNOT. •6FA6—NULLROTRIF2(x y–x yor⊥ ⊥x y), pushes twoNulls under the second stack entry from the top, but only if the topmostIntegery is non-zero. Equivalent toNULLROTRIF;NULLROTRIF. •6FA7—NULLROTRIFNOT2(x y–x yor⊥ ⊥x y), pushes twoNulls under the second stack entry from the top, but only if the topmost Integeryis zero. Equivalent toNULLROTRIFNOT;NULLROTRIFNOT. •6FBij—INDEX2i,j(t–x), recoversx= (t i+1 ) j+1 for0≤i,j≤3. Equivalent toINDEXi;INDEXj. •6FB4—CADR(t–x), recoversx= (t 2 ) 1 . 85 A.4. Constant, or literal primitives •6FB5—CDDR(t–x), recoversx= (t 2 ) 2 . •6FE\_ijk—INDEX3i,j,k(t–x), recoversx= ( (t i+1 ) j+1 ) k+1 for0≤ i,j,k≤3. Equivalent toINDEX2i,j;INDEXk. •6FD4—CADDR(t–x), recoversx= ( (t 2 ) 2 ) 1 . •6FD5—CDDDR(t–x), recoversx= ( (t 2 ) 2 ) 2 . A.4 Constant, or literal primitives The following primitives push into the stack one literal (or unnamed constant) of some type and range, stored as a part (an immediate argument) of the instruction. Therefore, if the immediate argument is absent or too short, an “invalid or too short opcode” exception (code6) is thrown. A.4.1. Integer and boolean constants. •7i—PUSHINTxwith−5≤x≤10, pushes integerxinto the stack; hereiequals four lower-order bits ofx(i.e.,i=xmod 16). •70—ZERO,FALSE, orPUSHINT 0, pushes a zero. •71—ONEorPUSHINT 1. •72—TWOorPUSHINT 2. •7A—TENorPUSHINT10. •7F—TRUEorPUSHINT -1. •80xx—PUSHINTxxwith−128≤xx≤127. •81xxxx—PUSHINTxxxxwith−2 15 ≤xxxx <2 15 a signed 16-bit big-endian integer. •81FC18—PUSHINT−1000. •82lxxx—PUSHINTxxx, where 5-bit0≤l≤30determines the length n= 8l+ 19of signed big-endian integerxxx. The total length of this instruction isl+ 4bytes orn+ 13 = 8l+ 32bits. •821005F5E100—PUSHINT10 8 . 86 A.4. Constant, or literal primitives •83xx—PUSHPOW2xx+ 1, (quietly) pushes2 xx+1 for0≤xx≤255. •83FF—PUSHNAN, pushes aNaN. •84xx—PUSHPOW2DECxx+ 1, pushes2 xx+1 −1for0≤xx≤255. •85xx—PUSHNEGPOW2xx+ 1, pushes−2 xx+1 for0≤xx≤255. •86,87— reserved for integer constants. A.4.2. Constant slices, continuations, cells, and references.Most of the instructions listed below push literal slices, continuations, cells, and cell references, stored as immediate arguments to the instruction. Therefore, if the immediate argument is absent or too short, an “invalid or too short opcode” exception (code6) is thrown. •88—PUSHREF, pushes the first reference ofcc.codeinto the stack as aCell(and removes this reference from the current continuation). •89—PUSHREFSLICE, similar toPUSHREF, but converts the cell into a Slice. •8A—PUSHREFCONT, similar toPUSHREFSLICE, but makes a simple or- dinaryContinuationout of the cell. •8Bxsss—PUSHSLICE sss, pushes the (prefix) subslice ofcc.codecon- sisting of its first8x+ 4bits and no references (i.e., essentially a bit- string), where0≤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. •8B08—PUSHSLICE x8\_, pushes an empty slice (bitstring‘’). •8B04—PUSHSLICE x4\_, pushes bitstring‘0’. •8B0C—PUSHSLICE xC\_, pushes bitstring‘1’. •8Crxxssss—PUSHSLICE ssss, pushes the (prefix) subslice ofcc.code consisting of its first1≤r+ 1≤4references and up to first8xx+ 1 bits of data, with0≤xx≤31. A completion tag is also assumed. 87 A.5. Arithmetic primitives •8C01is equivalent toPUSHREFSLICE. •8Drxxsssss—PUSHSLICE sssss, pushes the subslice ofcc.codecon- sisting of0≤r≤4references and up to8xx+ 6bits of data, with 0≤xx≤127. A completion tag is assumed. •8DE\_— unused (reserved). •8F\_rxxcccc—PUSHCONT cccc, whereccccis the simple ordinary con- tinuation made from the first0≤r≤3references and the first 0≤xx≤127bytes ofcc.code. •9xccc—PUSHCONT ccc, pushes anx-byte continuation for0≤x≤15. A.5 Arithmetic primitives A.5.1. Addition, subtraction, multiplication. •A0—ADD(x y–x+y), adds together two integers. •A1—SUB(x y–x−y). •A2—SUBR(x y–y−x), equivalent toSWAP;SUB. •A3—NEGATE(x–−x), equivalent toMULCONST−1or toZERO; SUBR. Notice that it triggers an integer overflow exception ifx=−2 256 . •A4—INC(x–x+ 1), equivalent toADDCONST 1. •A5—DEC(x–x−1), equivalent toADDCONST−1. •A6cc—ADDCONSTcc(x–x+cc),−128≤cc≤127. •A7cc—MULCONSTcc(x–x·cc),−128≤cc≤127. •A8—MUL(x y–xy). A.5.2. Division. The general encoding of aDIV,DIVMOD, orMODoperation isA9mscdf, with an optional pre-multiplication and an optional replacement of the division or multiplication by a shift. Variable one- or two-bit fieldsm,s,c,d, andfare as follows: 88 A.5. Arithmetic primitives •0≤m≤1— Indicates whether there is pre-multiplication (MULDIV operation 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 form= 1). •0≤c≤1— Indicates whether there is a constant one-byte argument ttfor the shift operator (ifs6= 0). Fors= 0,c= 0. Ifc= 1, then 0≤tt≤255, and the shift is performed bytt+ 1bits. Ifs6= 0 andc= 0, then the shift amount is provided to the instruction as a top-of-stackIntegerin range0...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 (cf.1.5.6). Examples: •A904—DIV(x y–q:=bx/yc). •A905—DIVR(x y–q ′ :=bx/y+ 1/2c). •A906—DIVC(x y–q ′′ :=dx/ye). •A908—MOD(x y–r), whereq:=bx/yc,r:=xmody:=x−yq. •A90C—DIVMOD(x y–q r), whereq:=bx/yc,r:=x−yq. •A90D—DIVMODR(x y–q ′ r ′ ), whereq ′ :=bx/y+ 1/2c,r ′ :=x−yq ′ . •A90E—DIVMODC(x y–q ′′ r ′′ ), whereq ′′ :=dx/ye,r ′′ :=x−yq ′′ . •A924— same asRSHIFT: (x y–bx·2 −y c) for0≤y≤256. •A934tt— same asRSHIFTtt+ 1: (x–bx·2 −tt−1 c). •A938tt—MODPOW2tt+ 1: (x–xmod 2 tt+1 ). •A985—MULDIVR(x y z–q ′ ), whereq ′ =bxy/z+ 1/2c. 89 A.5. Arithmetic primitives •A98C—MULDIVMOD(x y z–q r), whereq:=bx·y/zc,r:=x·ymodz (same as\*/MODin Forth). •A9A4—MULRSHIFT(x y z–bxy·2 −z c) for0≤z≤256. •A9A5—MULRSHIFTR(x y z–bxy·2 −z + 1/2c) for0≤z≤256. •A9B4tt—MULRSHIFTtt+ 1(x y–bxy·2 −tt−1 c). •A9B5tt—MULRSHIFTRtt+ 1(x y–bxy·2 −tt−1 + 1/2c). •A9C4—LSHIFTDIV(x y z–b2 z x/yc) for0≤z≤256. •A9C5—LSHIFTDIVR(x y z–b2 z x/y+ 1/2c) for0≤z≤256. •A9D4tt—LSHIFTDIVtt+ 1(x y–b2 tt+1 x/yc). •A9D5tt—LSHIFTDIVRtt+ 1(x y–b2 tt+1 x/y+ 1/2c). The most useful of these operations areDIV,DIVMOD,MOD,DIVR,DIVC, MODPOW2t, andRSHIFTRt(for integer arithmetic); andMULDIVMOD,MULDIV, MULDIVR,LSHIFTDIVRt, andMULRSHIFTRt(for fixed-point arithmetic). A.5.3. Shifts, logical operations. •AAcc—LSHIFTcc+ 1(x–x·2 cc+1 ),0≤cc≤255. •AA00—LSHIFT 1, equivalent toMULCONST 2or to Forth’s2\*. •ABcc—RSHIFTcc+ 1(x–bx·2 −cc−1 c),0≤cc≤255. •AC—LSHIFT(x y–x·2 y ),0≤y≤1023. •AD—RSHIFT(x y–bx·2 −y c),0≤y≤1023. •AE—POW2(y–2 y ),0≤y≤1023, equivalent toONE;SWAP;LSHIFT. •AF— reserved. •B0—AND(x y–x&y), bitwise “and” of two signed integersxandy, sign-extended to infinity. •B1—OR(x y–x∨y), bitwise “or” of two integers. 90 A.5. Arithmetic primitives •B2—XOR(x y–x⊕y), bitwise “xor” of two integers. •B3—NOT(x–x⊕−1 =−1−x), bitwise “not” of an integer. •B4cc—FITScc+ 1(x–x), checks whetherxis acc+ 1-bit signed integer for0≤cc≤255(i.e., whether−2 cc ≤x <2 cc ). If not, either triggers an integer overflow exception, or replacesxwith aNaN(quiet version). •B400—FITS 1orCHKBOOL(x–x), checks whetherxis a “boolean value” (i.e., either 0 or -1). •B5cc—UFITScc+ 1(x–x), checks whetherxis acc+ 1-bit unsigned integer for0≤cc≤255(i.e., whether0≤x <2 cc+1 ). •B500—UFITS 1orCHKBIT, checks whetherxis a binary digit (i.e., zero or one). •B600—FITSX(x c–x), checks whetherxis ac-bit signed integer for 0≤c≤1023. •B601—UFITSX(x c–x), checks whetherxis ac-bit unsigned integer for0≤c≤1023. •B602—BITSIZE(x–c), computes smallestc≥0such thatxfits into ac-bit signed integer (−2 c−1 ≤c <2 c−1 ). •B603—UBITSIZE(x–c), computes smallestc≥0such thatxfits into ac-bit unsigned integer (0≤x <2 c ), or throws a range check exception. •B608—MIN(x y–xory), computes the minimum of two integersx andy. •B609—MAX(x y–xory), computes the maximum of two integersx andy. •B60A—MINMAXorINTSORT2(x y–x yory x), sorts two integers. Quiet version of this operation returns twoNaNs if any of the arguments are NaNs. •B60B—ABS(x–|x|), computes the absolute value of an integerx. 91 A.6. Comparison primitives A.5.4. Quiet arithmetic primitives.We opted to make all arithmetic operations “non-quiet” (signaling) by default, and create their quiet counter- parts by means of a prefix. Such an encoding is definitely sub-optimal. It is not yet clear whether it should be done in this way, or in the opposite way by making all arithmetic operations quiet by default, or whether quiet and non-quiet operations should be given opcodes of equal length; this can only be settled by practice. •B7xx—QUIETprefix, transforming any arithmetic operation into its “quiet” variant, indicated by prefixing aQto its mnemonic. Such op- erations returnNaNs instead of throwing integer overflow exceptions if the results do not fit inIntegers, or if one of their arguments is aNaN. Notice that this does not extend to shift amounts and other parame- ters that must be within a small range (e.g., 0–1023). Also notice that this does not disable type-checking exceptions if a value of a type other thanIntegeris supplied. •B7A0—QADD(x y–x+y), always works ifxandyareIntegers, but returns aNaNif the addition cannot be performed. •B7A904—QDIV(x y–bx/yc), returns aNaNify= 0, or ify=−1and x=−2 256 , or if either ofxoryis aNaN. •B7B0—QAND(x y–x&y), bitwise “and” (similar toAND), but returns aNaNif eitherxoryis aNaNinstead of throwing an integer overflow exception. However, if one of the arguments is zero, and the other is a NaN, the result is zero. •B7B1—QOR(x y–x∨y), bitwise “or”. Ifx=−1ory=−1, the result is always−1, even if the other argument is aNaN. •B7B507—QUFITS 8(x–x ′ ), checks whetherxis an unsigned byte (i.e., whether0≤x <2 8 ), and replacesxwith aNaNif this is not the case; leavesxintact otherwise (i.e., ifxis an unsigned byte). A.6 Comparison primitives A.6.1. Integer comparison.All integer comparison primitives return in- teger−1(“true”) or0(“false”) to indicate the result of the comparison. We 92 A.6. Comparison primitives do not define their “boolean circuit” counterparts, which would transfer con- trol toc0orc1depending on the result of the comparison. If needed, such instructions can be simulated with the aid ofRETBOOL. Quiet versions of integer comparison primitives are also available, encoded with the aid of theQUIETprefix (B7). If any of the integers being compared areNaNs, the result of a quiet comparison will also be aNaN(“undefined”), instead of a−1(“yes”) or0(“no”), thus effectively supporting ternary logic. •B8—SGN(x–sgn(x)), computes the sign of an integerx:−1ifx <0, 0ifx= 0,1ifx >0. •B9—LESS(x y–x < y), returns−1ifx < y,0otherwise. •BA—EQUAL(x y–x=y), returns−1ifx=y,0otherwise. •BB—LEQ(x y–x≤y). •BC—GREATER(x y–x > y). •BD—NEQ(x y–x6=y), equivalent toEQUAL;NOT. •BE—GEQ(x y–x≥y), equivalent toLESS;NOT. •BF—CMP(x y–sgn(x−y)), computes the sign ofx−y:−1ifx < y, 0ifx=y,1ifx > y. No integer overflow can occur here unlessxory is aNaN. •C0yy—EQINTyy(x–x=yy) for−2 7 ≤yy <2 7 . •C000—ISZERO, checks whether an integer is zero. Corresponds to Forth’s0=. •C1yy—LESSINTyy(x–x < yy) for−2 7 ≤yy <2 7 . •C100—ISNEG, checks whether an integer is negative. Corresponds to Forth’s0<. •C101—ISNPOS, checks whether an integer is non-positive. •C2yy—GTINTyy(x–x > yy) for−2 7 ≤yy <2 7 . •C200—ISPOS, checks whether an integer is positive. Corresponds to Forth’s0>. 93 A.6. Comparison primitives •C2FF—ISNNEG, checks whether an integer is non-negative. •C3yy—NEQINTyy(x–x6=yy) for−2 7 ≤yy <2 7 . •C4—ISNAN(x–x=NaN), checks whetherxis aNaN. •C5—CHKNAN(x–x), throws an arithmetic overflow exception ifxis a NaN. •C6— reserved for integer comparison. A.6.2. Other comparison. Most of these “other comparison” primitives actually compare the data portions ofSlices as bitstrings. •C700—SEMPTY(s–s=∅), checks whether aSlicesis empty (i.e., contains no bits of data and no cell references). •C701—SDEMPTY(s–s≈ ∅), checks whetherSliceshas no bits of data. •C702—SREMPTY(s–r(s) = 0), checks whetherSliceshas no refer- ences. •C703—SDFIRST(s–s 0 = 1), checks whether the first bit ofSlicesis a one. •C704—SDLEXCMP(s s ′ –c), compares the data ofslexicographically with the data ofs ′ , returning−1, 0, or 1 depending on the result. •C705—SDEQ(s s ′ –s≈s ′ ), checks whether the data parts ofsands ′ coincide, equivalent toSDLEXCMP;ISZERO. •C708—SDPFX(s s ′ –?), checks whethersis a prefix ofs ′ . •C709—SDPFXREV(s s ′ –?), checks whethers ′ is a prefix ofs, equivalent toSWAP;SDPFX. •C70A—SDPPFX(s s ′ –?), checks whethersis a proper prefix ofs ′ (i.e., a prefix distinct froms ′ ). •C70B—SDPPFXREV(s s ′ –?), checks whethers ′ is a proper prefix ofs. 94 A.7. Cell primitives •C70C—SDSFX(s s ′ –?), checks whethersis a suffix ofs ′ . •C70D—SDSFXREV(s s ′ –?), checks whethers ′ is a suffix ofs. •C70E—SDPSFX(s s ′ –?), checks whethersis a proper suffix ofs ′ . •C70F—SDPSFXREV(s s ′ –?), checks whethers ′ is a proper suffix ofs. •C710—SDCNTLEAD0(s–n), returns the number of leading zeroes in s. •C711—SDCNTLEAD1(s–n), returns the number of leading ones ins. •C712—SDCNTTRAIL0(s–n), returns the number of trailing zeroes in s. •C713—SDCNTTRAIL1(s–n), returns the number of trailing ones ins. A.7 Cell primitives The cell primitives are mostly eithercell serialization primitives, which work withBuilders, orcell deserialization primitives, which work withSlices. A.7.1. Cell serialization primitives.All these primitives first check whether there is enough space in the Builder, and only then check the range of the value being serialized. •C8—NEWC( –b), creates a new emptyBuilder. •C9—ENDC(b–c), converts aBuilderinto an ordinaryCell. •CAcc—STIcc+ 1(x b–b ′ ), stores a signedcc+ 1-bit integerxinto Builderbfor0≤cc≤255, throws a range check exception ifxdoes not fit intocc+ 1bits. •CBcc—STUcc+ 1(x b–b ′ ), stores an unsignedcc+ 1-bit integerx intoBuilderb. In all other respects it is similar toSTI. •CC—STREF(c b–b ′ ), stores a reference toCellcintoBuilderb. •CD—STBREFRorENDCST(b b ′′ –b), equivalent toENDC;SWAP;STREF. •CE—STSLICE(s b–b ′ ), storesSlicesintoBuilderb. 95 A.7. Cell primitives •CF00—STIX(x b l–b ′ ), stores a signedl-bit integerxintobfor 0≤l≤257. •CF01—STUX(x b l–b ′ ), stores an unsignedl-bit integerxintobfor 0≤l≤256. •CF02—STIXR(b x l–b ′ ), similar toSTIX, but with arguments in a different order. •CF03—STUXR(b x l–b ′ ), similar toSTUX, but with arguments in a different order. •CF04—STIXQ(x b l–x b forb ′ 0), a quiet version ofSTIX. If there is no space inb, setsb ′ =bandf=−1. Ifxdoes not fit intolbits, setsb ′ =bandf= 1. If the operation succeeds,b ′ is the newBuilder andf= 0. However,0≤l≤257, with a range check exception if this is not so. •CF05—STUXQ(x b l–b ′ f). •CF06—STIXRQ(b x l–b x forb ′ 0). •CF07—STUXRQ(b x l–b x forb ′ 0). •CF08cc— a longer version ofSTIcc+ 1. •CF09cc— a longer version ofSTUcc+ 1. •CF0Acc—STIRcc+ 1(b x–b ′ ), equivalent toSWAP;STIcc+ 1. •CF0Bcc—STURcc+ 1(b x–b ′ ), equivalent toSWAP;STUcc+ 1. •CF0Ccc—STIQcc+ 1(x b–x b forb ′ 0). •CF0Dcc—STUQcc+ 1(x b–x b forb ′ 0). •CF0Ecc—STIRQcc+ 1(b x–b x forb ′ 0). •CF0Fcc—STURQcc+ 1(b x–b x forb ′ 0). •CF10— a longer version ofSTREF(c b–b ′ ). •CF11—STBREF(b ′ b–b ′′ ), equivalent toSWAP;STBREFREV. 96 A.7. Cell primitives •CF12— a longer version ofSTSLICE(s b–b ′ ). •CF13—STB(b ′ b–b ′′ ), appends all data fromBuilderb ′ toBuilderb. •CF14—STREFR(b c–b ′ ). •CF15—STBREFR(b b ′ –b ′′ ), a longer encoding ofSTBREFR. •CF16—STSLICER(b s–b ′ ). •CF17—STBR(b b ′ –b ′′ ), concatenates twoBuilders, equivalent toSWAP; STB. •CF18—STREFQ(c b–c b−1orb ′ 0). •CF19—STBREFQ(b ′ b–b ′ b−1orb ′′ 0). •CF1A—STSLICEQ(s b–s b−1orb ′ 0). •CF1B—STBQ(b ′ b–b ′ b−1orb ′′ 0). •CF1C—STREFRQ(b c–b c−1orb ′ 0). •CF1D—STBREFRQ(b b ′ –b b ′ −1orb ′′ 0). •CF1E—STSLICERQ(b s–b s−1orb ′′ 0). •CF1F—STBRQ(b b ′ –b b ′ −1orb ′′ 0). •CF20—STREFCONST, equivalent toPUSHREF;STREFR. •CF21—STREF2CONST, equivalent toSTREFCONST;STREFCONST. •CF23—ENDXC(b x–c), ifx6= 0, creates aspecialorexoticcell (cf.3.1.2) fromBuilderb. The type of the exotic cell must be stored in the first 8 bits ofb. Ifx= 0, it is equivalent toENDC. Otherwise some validity checks on the data and references ofbare performed before creating the exotic cell. •CF28—STILE4(x b–b ′ ), stores a little-endian signed 32-bit integer. •CF29—STULE4(x b–b ′ ), stores a little-endian unsigned 32-bit integer. •CF2A—STILE8(x b–b ′ ), stores a little-endian signed 64-bit integer. 97 A.7. Cell primitives •CF2B—STULE8(x b–b ′ ), stores a little-endian unsigned 64-bit integer. •CF30—BDEPTH(b–x), returns the depth ofBuilderb. If no cell references are stored inb, thenx= 0; otherwisexis one plus the maximum of depths of cells referred to fromb. •CF31—BBITS(b–x), returns the number of data bits already stored inBuilderb. •CF32—BREFS(b–y), returns the number of cell references already stored inb. •CF33—BBITREFS(b–x y), returns the numbers of both data bits and cell references inb. •CF35—BREMBITS(b–x ′ ), returns the number of data bits that can still be stored inb. •CF36—BREMREFS(b–y ′ ). •CF37—BREMBITREFS(b–x ′ y ′ ). •CF38cc—BCHKBITScc+ 1(b–), checks whethercc+ 1bits can be stored intob, where0≤cc≤255. •CF39—BCHKBITS(b x– ), checks whetherxbits can be stored intob, 0≤x≤1023. If there is no space forxmore bits inb, or ifxis not within the range0...1023, throws an exception. •CF3A—BCHKREFS(b y– ), checks whetheryreferences can be stored intob,0≤y≤7. •CF3B—BCHKBITREFS(b x y– ), checks whetherxbits andyreferences can be stored intob,0≤x≤1023,0≤y≤7. •CF3Ccc—BCHKBITSQcc+ 1(b–?), checks whethercc+ 1bits can be stored intob, where0≤cc≤255. •CF3D—BCHKBITSQ(b x–?), checks whetherxbits can be stored into b,0≤x≤1023. •CF3E—BCHKREFSQ(b y–?), checks whetheryreferences can be stored intob,0≤y≤7. 98 A.7. Cell primitives •CF3F—BCHKBITREFSQ(b x y–?), checks whetherxbits andyrefer- ences can be stored intob,0≤x≤1023,0≤y≤7. •CF40—STZEROES(b n–b ′ ), storesnbinary zeroes intoBuilderb. •CF41—STONES(b n–b ′ ), storesnbinary ones intoBuilderb. •CF42—STSAME(b n x–b ′ ), storesnbinaryxes (0≤x≤1) into Builderb. •CFC0\_xysss—STSLICECONSTsss(b–b ′ ), stores a constant subslice sssconsisting of0≤x≤3references and up to8y+ 1data bits, with 0≤y≤7. Completion bit is assumed. •CF81—STSLICECONST ‘0’orSTZERO(b–b ′ ), stores one binary zero. •CF83—STSLICECONST ‘1’orSTONE(b–b ′ ), stores one binary one. •CFA2— equivalent toSTREFCONST. •CFA3— almost equivalent toSTSLICECONST ‘1’;STREFCONST. •CFC2— equivalent toSTREF2CONST. •CFE2—STREF3CONST. A.7.2. Cell deserialization primitives. •D0—CTOS(c–s), converts aCellinto aSlice. Notice thatcmust be either an ordinary cell, or an exotic cell (cf.3.1.2) which is au- tomaticallyloadedto yield an ordinary cellc ′ , converted into aSlice afterwards. •D1—ENDS(s– ), removes aSlicesfrom the stack, and throws an exception if it is not empty. •D2cc—LDIcc+ 1(s–x s ′ ), loads (i.e., parses) a signedcc+ 1-bit integerxfromSlices, and returns the remainder ofsass ′ . •D3cc—LDUcc+ 1(s–x s ′ ), loads an unsignedcc+ 1-bit integerx fromSlices. •D4—LDREF(s–c s ′ ), loads a cell referencecfroms. 99 A.7. Cell primitives •D5—LDREFRTOS(s–s ′ s ′′ ), equivalent toLDREF;SWAP;CTOS. •D6cc—LDSLICEcc+ 1(s–s ′′ s ′ ), cuts the nextcc+ 1bits ofsinto a separateSlices ′′ . •D700—LDIX(s l–x s ′ ), loads a signedl-bit (0≤l≤257) integerx fromSlices, and returns the remainder ofsass ′ . •D701—LDUX(s l–x s ′ ), loads an unsignedl-bit integerxfrom (the firstlbits of)s, with0≤l≤256. •D702—PLDIX(s l–x), preloads a signedl-bit integer fromSlices, for0≤l≤257. •D703—PLDUX(s l–x), preloads an unsignedl-bit integer froms, for 0≤l≤256. •D704—LDIXQ(s l–x s ′ −1ors0), quiet version ofLDIX: loads a signedl-bit integer fromssimilarly toLDIX, but returns a success flag, equal to−1on success or to0on failure (ifsdoes not havelbits), instead of throwing a cell underflow exception. •D705—LDUXQ(s l–x s ′ −1ors0), quiet version ofLDUX. •D706—PLDIXQ(s l–x−1or0), quiet version ofPLDIX. •D707—PLDUXQ(s l–x−1or0), quiet version ofPLDUX. •D708cc—LDIcc+ 1(s–x s ′ ), a longer encoding forLDI. •D709cc—LDUcc+ 1(s–x s ′ ), a longer encoding forLDU. •D70Acc—PLDIcc+1(s–x), preloads a signedcc+1-bit integer from Slices. •D70Bcc—PLDUcc+ 1(s–x), preloads an unsignedcc+ 1-bit integer froms. •D70Ccc—LDIQcc+ 1(s–x s ′ −1ors0), a quiet version ofLDI. •D70Dcc—LDUQcc+ 1(s–x s ′ −1ors0), a quiet version ofLDU. •D70Ecc—PLDIQcc+ 1(s–x−1or0), a quiet version ofPLDI. 100 A.7. Cell primitives •D70Fcc—PLDUQcc+ 1(s–x−1or0), a quiet version ofPLDU. •D714\_c—PLDUZ32(c+ 1)(s–s x), preloads the first32(c+ 1)bits ofSlicesinto an unsigned integerx, for0≤c≤7. Ifsis shorter than necessary, missing bits are assumed to be zero. This operation is intended to be used along withIFBITJMPand similar instructions. •D718—LDSLICEX(s l–s ′′ s ′ ), loads the first0≤l≤1023bits from Slicesinto a separateSlices ′′ , returning the remainder ofsass ′ . •D719—PLDSLICEX(s l–s ′′ ), returns the first0≤l≤1023bits ofs ass ′′ . •D71A—LDSLICEXQ(s l–s ′′ s ′ −1ors0), a quiet version ofLDSLICEX. •D71B—PLDSLICEXQ(s l–s ′ −1or0), a quiet version ofLDSLICEXQ. •D71Ccc—LDSLICEcc+ 1(s–s ′′ s ′ ), a longer encoding forLDSLICE. •D71Dcc—PLDSLICEcc+ 1(s–s ′′ ), returns the first0< cc+ 1≤256 bits ofsass ′′ . •D71Ecc—LDSLICEQcc+ 1(s–s ′′ s ′ −1ors0), a quiet version of LDSLICE. •D71Fcc—PLDSLICEQcc+ 1(s–s ′′ −1or0), a quiet version of PLDSLICE. •D720—SDCUTFIRST(s l–s ′ ), returns the first0≤l≤1023bits ofs. It is equivalent toPLDSLICEX. •D721—SDSKIPFIRST(s l–s ′ ), returns all but the first0≤l≤1023 bits ofs. It is equivalent toLDSLICEX;NIP. •D722—SDCUTLAST(s l–s ′ ), returns the last0≤l≤1023bits ofs. •D723—SDSKIPLAST(s l–s ′ ), returns all but the last0≤l≤1023 bits ofs. •D724—SDSUBSTR(s l l ′ –s ′ ), returns0≤l ′ ≤1023bits ofsstarting from offset0≤l≤1023, thus extracting a bit substring out of the data ofs. 101 A.7. Cell primitives •D726—SDBEGINSX(s s ′ –s ′′ ), checks whethersbegins with (the data bits of)s ′ , and removess ′ fromson success. On failure throws a cell deserialization exception. PrimitiveSDPFXREVcan be considered a quiet version ofSDBEGINSX. •D727—SDBEGINSXQ(s s ′ –s ′′ −1ors0), a quiet version ofSDBEGINSX. •D72A\_xsss—SDBEGINS(s–s ′′ ), checks whethersbegins with constant bitstringsssof length8x+ 3(with continuation bit assumed), where 0≤x≤127, and removessssfromson success. •D72802—SDBEGINS ‘0’(s–s ′′ ), checks whethersbegins with a binary zero. •D72806—SDBEGINS ‘1’(s–s ′′ ), checks whethersbegins with a binary one. •D72E\_xsss—SDBEGINSQ(s–s ′′ −1ors0), a quiet version ofSDBEGINS. •D730—SCUTFIRST(s l r–s ′ ), returns the first0≤l≤1023bits and first0≤r≤4references ofs. •D731—SSKIPFIRST(s l r–s ′ ). •D732—SCUTLAST(s l r–s ′ ), returns the last0≤l≤1023data bits and last0≤r≤4references ofs. •D733—SSKIPLAST(s l r–s ′ ). •D734—SUBSLICE(s l r l ′ r ′ –s ′ ), returns0≤l ′ ≤1023bits and 0≤r ′ ≤4references fromSlices, after skipping the first0≤l≤1023 bits and first0≤r≤4references. •D736—SPLIT(s l r–s ′ s ′′ ), splits the first0≤l≤1023data bits and first0≤r≤4references fromsintos ′ , returning the remainder ofs ass ′′ . •D737—SPLITQ(s l r–s ′ s ′′ −1ors0), a quiet version ofSPLIT. •D739—XCTOS(c–s?), transforms an ordinary or exotic cell into a Slice, as if it were an ordinary cell. A flag is returned indicating whether cis exotic. If that be the case, its type can later be deserialized from the first eight bits ofs. 102 A.7. Cell primitives •D73A—XLOAD(c–c ′ ), loads an exotic cellcand returns an ordinary cellc ′ . Ifcis already ordinary, does nothing. Ifccannot be loaded, throws an exception. •D73B—XLOADQ(c–c ′ −1orc0), loads an exotic cellcasXLOAD, but returns 0 on failure. •D741—SCHKBITS(s l– ), checks whether there are at leastldata bits inSlices. If this is not the case, throws a cell deserialisation (i.e., cell underflow) exception. •D742—SCHKREFS(s r– ), checks whether there are at leastrreferences inSlices. •D743—SCHKBITREFS(s l r– ), checks whether there are at leastl data bits andrreferences inSlices. •D745—SCHKBITSQ(s l–?), checks whether there are at leastldata bits inSlices. •D746—SCHKREFSQ(s r–?), checks whether there are at leastrrefer- ences inSlices. •D747—SCHKBITREFSQ(s l r–?), checks whether there are at leastl data bits andrreferences inSlices. •D748—PLDREFVAR(s n–c), returns then-th cell reference ofSlices for0≤n≤3. •D749—SBITS(s–l), returns the number of data bits inSlices. •D74A—SREFS(s–r), returns the number of references inSlices. •D74B—SBITREFS(s–l r), returns both the number of data bits and the number of references ins. •D74E\_n—PLDREFIDXn(s–c), returns then-th cell reference of Slices, where0≤n≤3. •D74C—PLDREF(s–c), preloads the first cell reference of aSlice. •D750—LDILE4(s–x s ′ ), loads a little-endian signed 32-bit integer. 103 A.7. Cell primitives •D751—LDULE4(s–x s ′ ), loads a little-endian unsigned 32-bit integer. •D752—LDILE8(s–x s ′ ), loads a little-endian signed 64-bit integer. •D753—LDULE8(s–x s ′ ), loads a little-endian unsigned 64-bit integer. •D754—PLDILE4(s–x), preloads a little-endian signed 32-bit integer. •D755—PLDULE4(s–x), preloads a little-endian unsigned 32-bit inte- ger. •D756—PLDILE8(s–x), preloads a little-endian signed 64-bit integer. •D757—PLDULE8(s–x), preloads a little-endian unsigned 64-bit inte- ger. •D758—LDILE4Q(s–x s ′ −1ors0), quietly loads a little-endian signed 32-bit integer. •D759—LDULE4Q(s–x s ′ −1ors0), quietly loads a little-endian unsigned 32-bit integer. •D75A—LDILE8Q(s–x s ′ −1ors0), quietly loads a little-endian signed 64-bit integer. •D75B—LDULE8Q(s–x s ′ −1ors0), quietly loads a little-endian unsigned 64-bit integer. •D75C—PLDILE4Q(s–x−1or0), quietly preloads a little-endian signed 32-bit integer. •D75D—PLDULE4Q(s–x−1or0), quietly preloads a little-endian unsigned 32-bit integer. •D75E—PLDILE8Q(s–x−1or0), quietly preloads a little-endian signed 64-bit integer. •D75F—PLDULE8Q(s–x−1or0), quietly preloads a little-endian unsigned 64-bit integer. •D760—LDZEROES(s–n s ′ ), returns the countnof leading zero bits ins, and removes these bits froms. 104 A.8. Continuation and control flow primitives •D761—LDONES(s–n s ′ ), returns the countnof leading one bits ins, and removes these bits froms. •D762—LDSAME(s x–n s ′ ), returns the countnof leading bits equal to0≤x≤1ins, and removes these bits froms. •D764—SDEPTH(s–x), returns the depth ofSlices. Ifshas no references, thenx= 0; otherwisexis one plus the maximum of depths of cells referred to froms. •D765—CDEPTH(c–x), returns the depth ofCellc. Ifchas no references, thenx= 0; otherwisexis one plus the maximum of depths of cells referred to fromc. Ifcis aNullinstead of aCell, returns zero. A.8 Continuation and control flow primitives A.8.1. Unconditional control flow primitives. •D8—EXECUTEorCALLX(c– ),callsorexecutescontinuationc(i.e., cc←c◦ 0 cc). •D9—JMPX(c– ),jumps, or transfers control, to continuationc(i.e., cc←c◦ 0 c0, or rathercc←(c◦ 0 c0)◦ 1 c1). The remainder of the previous current continuationccis discarded. •DApr—CALLXARGSp,r(c– ),callscontinuationcwithpparameters and expectingrreturn values,0≤p≤15,0≤r≤15. •DB0p—CALLXARGSp,−1(c– ),callscontinuationcwith0≤p≤15 parameters, expecting an arbitrary number of return values. •DB1p—JMPXARGSp(c– ),jumpsto continuationc, passing only the top0≤p≤15values from the current stack to it (the remainder of the current stack is discarded). •DB2r—RETARGSr,returnstoc0, with0≤r≤15return values taken from the current stack. •DB30—RETorRETTRUE,returnsto the continuation atc0(i.e., per- formscc←c0). The remainder of the current continuationccis discarded. Approximately equivalent toPUSH c0;JMPX. 105 A.8. Continuation and control flow primitives •DB31—RETALTorRETFALSE,returnsto the continuation atc1(i.e., cc←c1). Approximately equivalent toPUSH c1;JMPX. •DB32—BRANCHorRETBOOL(f– ), performsRETTRUEif integerf6= 0, orRETFALSEiff= 0. •DB34—CALLCC(c– ),call with current continuation, transfers control toc, pushing the old value ofccintoc’s stack (instead of discarding it or writing it into newc0). •DB35—JMPXDATA(c– ), similar toCALLCC, but the remainder of the current continuation (the old value ofcc) is converted into aSlicebefore pushing it into the stack ofc. •DB36pr—CALLCCARGSp,r(c– ), similar toCALLXARGS, but pushes the old value ofcc(along with the top0≤p≤15values from the original stack) into the stack of newly-invoked continuationc, setting cc.nargsto−1≤r≤14. •DB38—CALLXVARARGS(c p r– ), similar toCALLXARGS, but takes −1≤p,r≤254from the stack. The next three operations also takep andrfrom the stack, both in the range−1...254. •DB39—RETVARARGS(p r– ), similar toRETARGS. •DB3A—JMPXVARARGS(c p r– ), similar toJMPXARGS. •DB3B—CALLCCVARARGS(c p r– ), similar toCALLCCARGS. •DB3C—CALLREF, equivalent toPUSHREFCONT;CALLX. •DB3D—JMPREF, equivalent toPUSHREFCONT;JMPX. •DB3E—JMPREFDATA, equivalent toPUSHREFCONT;JMPXDATA. •DB3F—RETDATA, equivalent toPUSH c0;JMPXDATA. In this way, the remainder of the current continuation is converted into aSliceand returned to the caller. A.8.2. Conditional control flow primitives. •DC—IFRET(f– ), performs aRET, but only if integerfis non-zero. Iffis aNaN, throws an integer overflow exception. 106 A.8. Continuation and control flow primitives •DD—IFNOTRET(f– ), performs aRET, but only if integerfis zero. •DE—IF(f c– ), performsEXECUTEforc(i.e.,executesc), but only if integerfis non-zero. Otherwise simply discards both values. •DF—IFNOT(f c– ), executes continuationc, but only if integerfis zero. Otherwise simply discards both values. •E0—IFJMP(f c– ), jumps toc(similarly toJMPX), but only iffis non-zero. •E1—IFNOTJMP(f c– ), jumps toc(similarly toJMPX), but only iff is zero. •E2—IFELSE(f c c ′ – ), if integerfis non-zero, executesc, otherwise executesc ′ . Equivalent toCONDSELCHK;EXECUTE. •E300—IFREF(f– ), equivalent toPUSHREFCONT;IF, with the opti- mization that the cell reference is not actually loaded into aSliceand then converted into an ordinaryContinuationiff= 0. Similar remarks apply to the next three primitives. •E301—IFNOTREF(f– ), equivalent toPUSHREFCONT;IFNOT. •E302—IFJMPREF(f– ), equivalent toPUSHREFCONT;IFJMP. •E303—IFNOTJMPREF(f– ), equivalent toPUSHREFCONT;IFNOTJMP. •E304—CONDSEL(f x y–xory), if integerfis non-zero, returnsx, otherwise returnsy. Notice that no type checks are performed onx andy; as such, it is more like a conditional stack operation. Roughly equivalent toROT;ISZERO;INC;ROLLX;NIP. •E305—CONDSELCHK(f x y–xory), same asCONDSEL, but first checks whetherxandyhave the same type. •E308—IFRETALT(f–), performsRETALTif integerf6= 0. •E309—IFNOTRETALT(f–), performsRETALTif integerf= 0. 107 A.8. Continuation and control flow primitives •E30D—IFREFELSE(f c–), equivalent toPUSHREFCONT;SWAP;IFELSE, with the optimization that the cell reference is not actually loaded into aSliceand then converted into an ordinaryContinuationiff= 0. Similar remarks apply to the next two primitives:Cells are converted intoContinuations only when necessary. •E30E—IFELSEREF(f c–), equivalent toPUSHREFCONT;IFELSE. •E30F—IFREFELSEREF(f–), equivalent toPUSHREFCONT;PUSHREFCONT; IFELSE. •E310–E31F— reserved for loops with break operators, cf.A.8.3below. •E39\_n—IFBITJMPn(x c–x), checks whether bit0≤n≤31is set in integerx, and if so, performsJMPXto continuationc. Valuexis left in the stack. •E3B\_n—IFNBITJMPn(x c–x), jumps tocif bit0≤n≤31is not set in integerx. •E3D\_n—IFBITJMPREFn(x–x), performs aJMPREFif bit0≤n≤31 is set in integerx. •E3F\_n—IFNBITJMPREFn(x–x), performs aJMPREFif bit0≤n≤31 is not set in integerx. A.8.3. Control flow primitives: loops.Most of the loop primitives listed below are implemented with the aid of extraordinary continuations, such as ec\_until(cf.4.1.5), with the loop body and the original current continua- tionccstored as the arguments to this extraordinary continuation. Typically a suitable extraordinary continuation is constructed, and then saved into the loop body continuation savelist asc0; after that, the modified loop body continuation is loaded intoccand executed in the usual fashion. All of these loop primitives have\*BRKversions, adapted for breaking out of a loop; they additionally setc1to the original current continuation (or originalc0 for\*ENDBRKversions), and save the oldc1into the savelist of the original current continuation (or of the originalc0for\*ENDBRKversions). •E4—REPEAT(n c– ), executes continuationc ntimes, if integern is non-negative. Ifn≥2 31 orn <−2 31 , generates a range check exception. Notice that aRETinside the code ofcworks as acontinue, 108 A.8. Continuation and control flow primitives not as abreak. One should use either alternative (experimental) loops or alternativeRETALT(along with aSETEXITALTbefore the loop) to breakout of a loop. •E5—REPEATEND(n– ), similar toREPEAT, but it is applied to the current continuationcc. •E6—UNTIL(c– ), executes continuationc, then pops an integerx from the resulting stack. Ifxis zero, performs another iteration of this loop. The actual implementation of this primitive involves an extraordinary continuationec\_until(cf.4.1.5) with its arguments set to the body of the loop (continuationc) and the original current continuationcc. This extraordinary continuation is then saved into the savelist ofcasc.c0and the modifiedcis then executed. The other loop primitives are implemented similarly with the aid of suitable extraordinary continuations. •E7—UNTILEND( – ), similar toUNTIL, but executes the current contin- uationccin a loop. When the loop exit condition is satisfied, performs aRET. •E8—WHILE(c ′ c– ), executesc ′ and pops an integerxfrom the resulting stack. Ifxis zero, exists the loop and transfers control to the originalcc. Ifxis non-zero, executesc, and then begins a new iteration. •E9—WHILEEND(c ′ – ), similar toWHILE, but uses the current continu- ationccas the loop body. •EA—AGAIN(c– ), similar toREPEAT, but executescinfinitely many times. ARETonly begins a new iteration of the infinite loop, which can be exited only by an exception, or aRETALT(or an explicitJMPX). •EB—AGAINEND( – ), similar toAGAIN, but performed with respect to the current continuationcc. •E314—REPEATBRK(n c– ), similar toREPEAT, but also setsc1to the originalccafter saving the old value ofc1into the savelist of the originalcc. In this wayRETALTcould be used to break out of the loop body. 109 A.8. Continuation and control flow primitives •E315—REPEATENDBRK(n– ), similar toREPEATEND, but also setsc1 to the originalc0after saving the old value ofc1into the savelist of the originalc0. Equivalent toSAMEALTSAVE;REPEATEND. •E316—UNTILBRK(c– ), similar toUNTIL, but also modifiesc1in the same way asREPEATBRK. •E317—UNTILENDBRK( – ), equivalent toSAMEALTSAVE;UNTILEND. •E318—WHILEBRK(c ′ c– ), similar toWHILE, but also modifiesc1in the same way asREPEATBRK. •E319—WHILEENDBRK(c– ), equivalent toSAMEALTSAVE;WHILEEND. •E31A—AGAINBRK(c– ), similar toAGAIN, but also modifiesc1in the same way asREPEATBRK. •E31B—AGAINENDBRK( – ), equivalent toSAMEALTSAVE;AGAINEND. A.8.4. Manipulating the stack of continuations. •ECrn—SETCONTARGSr,n(x 1 x 2 . . .x r c–c ′ ), similar toSETCONTARGS r, but setsc.nargsto the final size of the stack ofc ′ plusn. In other words, transformscinto aclosureor apartially applied function, with 0≤n≤14arguments missing. •EC0n—SETNUMARGSnorSETCONTARGS0,n(c–c ′ ), setsc.nargsto nplus the current depth ofc’s stack, where0≤n≤14. Ifc.nargsis already set to a non-negative value, does nothing. •ECrF—SETCONTARGSrorSETCONTARGSr,−1(x 1 x 2 . . .x r c–c ′ ), pushes0≤r≤15valuesx 1 ...x r into the stack of (a copy of) the continuationc, starting withx 1 . If the final depth ofc’s stack turns out to be greater thanc.nargs, a stack overflow exception is generated. •ED0p—RETURNARGSp( – ), leaves only the top0≤p≤15values in the current stack (somewhat similarly toONLYTOPX), with all the unused bottom values not discarded, but saved into continuationc0in the same way asSETCONTARGSdoes. •ED10—RETURNVARARGS(p– ), similar toRETURNARGS, but with Integer 0≤p≤255taken from the stack. 110 A.8. Continuation and control flow primitives •ED11—SETCONTVARARGS(x 1 x 2 . . .x r c r n–c ′ ), similar toSETCONTARGS, but with0≤r≤255and−1≤n≤255taken from the stack. •ED12—SETNUMVARARGS(c n–c ′ ), where−1≤n≤255. Ifn=−1, this operation does nothing (c ′ =c). Otherwise its action is similar to SETNUMARGSn, but withntaken from the stack. A.8.5. Creating simple continuations and closures. •ED1E—BLESS(s–c), transforms aSlicesinto a simple ordinary continuationc, withc.code=sand an empty stack and savelist. •ED1F—BLESSVARARGS(x 1 . . .x r s r n–c), equivalent toROT;BLESS; ROTREV;SETCONTVARARGS. •EErn—BLESSARGSr,n(x 1 . . .x r s–c), where0≤r≤15,−1≤ n≤14, equivalent toBLESS;SETCONTARGSr,n. The value ofnis represented inside the instruction by the 4-bit integernmod 16. •EE0n—BLESSNUMARGSnorBLESSARGS 0,n(s–c), also transforms a Slicesinto aContinuationc, but setsc.nargsto0≤n≤14. A.8.6. Operations with continuation savelists and control registers. •ED4i—PUSH c(i)orPUSHCTR c(i)( –x), pushes the current value of control registerc(i). If the control register is not supported in the cur- rent codepage, or if it does not have a value, an exception is triggered. •ED44—PUSH c4orPUSHROOT, pushes the “global data root” cell refer- ence, thus enabling access to persistent smart-contract data. •ED5i—POP c(i)orPOPCTR c(i)(x– ), pops a valuexfrom the stack and stores it into control registerc(i), if supported in the current code- page. Notice that if a control register accepts only values of a specific type, a type-checking exception may occur. •ED54—POP c4orPOPROOT, sets the “global data root” cell reference, thus allowing modification of persistent smart-contract data. •ED6i—SETCONT c(i)orSETCONTCTR c(i)(x c–c ′ ), storesxinto the savelist of continuationcasc(i), and returns the resulting continuation c ′ . Almost all operations with continuations may be expressed in terms ofSETCONTCTR,POPCTR, andPUSHCTR. 111 A.8. Continuation and control flow primitives •ED7i—SETRETCTR c(i)(x– ), equivalent toPUSH c0;SETCONTCTR c(i);POP c0. •ED8i—SETALTCTR c(i)(x– ), equivalent toPUSH c1;SETCONTCTR c(i);POP c0. •ED9i—POPSAVE c(i)orPOPCTRSAVE c(i)(x–), similar toPOP c(i), but also saves the old value ofc(i)into continuationc0. Equivalent (up to exceptions) toSAVECTR c(i);POP c(i). •EDAi—SAVE c(i)orSAVECTR c(i)( – ), saves the current value of c(i)into the savelist of continuationc0. If an entry forc(i)is already present in the savelist ofc0, nothing is done. Equivalent toPUSH c(i); SETRETCTRc(i). •EDBi—SAVEALT c(i)orSAVEALTCTR c(i)( – ), similar toSAVE c(i), but saves the current value ofc(i)into the savelist ofc1, notc0. •EDCi—SAVEBOTH c(i)orSAVEBOTHCTR c(i)( – ), equivalent toDUP; SAVE c(i);SAVEALT c(i). •EDE0—PUSHCTRX(i–x), similar toPUSHCTR c(i), but withi,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 ofxdepends oni. •EDE1—POPCTRX(x i– ), similar toPOPCTR c(i), but with0≤i≤255 from the stack. •EDE2—SETCONTCTRX(x c i–c ′ ), similar toSETCONTCTR c(i), but with 0≤i≤255from the stack. •EDF0—COMPOSorBOOLAND(c c ′ –c ′′ ), computes the compositionc◦ 0 c ′ , which has the meaning of “performc, and, if successful, performc ′ ” (if cis a boolean circuit) or simply “performc, thenc ′ ”. Equivalent to SWAP;SETCONT c0. •EDF1—COMPOSALTorBOOLOR(c c ′ –c ′′ ), computes the alternative compositionc◦ 1 c ′ , which has the meaning of “performc, and, if not successful, performc ′ ” (ifcis a boolean circuit). Equivalent toSWAP; SETCONT c1. 112 A.8. Continuation and control flow primitives •EDF2—COMPOSBOTH(c c ′ –c ′′ ), computes(c◦ 0 c ′ )◦ 1 c ′ , which has the meaning of “compute boolean circuitc, then computec ′ , regardless of the result ofc”. •EDF3—ATEXIT(c– ), setsc0←c◦ 0 c0. In other words,cwill be executed before exiting current subroutine. •EDF4—ATEXITALT(c– ), setsc1←c◦ 1 c1. In other words,cwill be executed before exiting current subroutine by its alternative return path. •EDF5—SETEXITALT(c– ), setsc1←(c◦ 0 c0)◦ 1 c1. In this way, a subsequentRETALTwill first executec, then transfer control to the originalc0. This can be used, for instance, to exit from nested loops. •EDF6—THENRET(c–c ′ ), computesc ′ :=c◦ 0 c0 •EDF7—THENRETALT(c–c ′ ), computesc ′ :=c◦ 0 c1 •EDF8—INVERT( – ), interchangesc0andc1. •EDF9—BOOLEVAL(c–?), performscc← ( c◦ 0 ((PUSH−1)◦ 0 cc) ) ◦ 1 ((PUSH0)◦ 0 cc). Ifcrepresents a boolean circuit, the net effect is to evaluate it and push either−1or0into the stack before continuing. •EDFA—SAMEALT( – ), setsc 1 :=c 0 . Equivalent toPUSH c0;POP c1. •EDFB—SAMEALTSAVE( – ), setsc 1 :=c 0 , but first saves the old value ofc 1 into the savelist ofc 0 . Equivalent toSAVE c1;SAMEALT. •EErn—BLESSARGSr,n(x 1 . . .x r s–c), described inA.8.4. A.8.7. Dictionary subroutine calls and jumps. •F0n—CALLnorCALLDICTn( –n), calls the continuation inc3, push- ing integer0≤n≤255into its stack as an argument. Approximately equivalent toPUSHINTn;PUSH c3;EXECUTE. •F12\_n—CALLnfor0≤n <2 14 ( –n), an encoding ofCALLnfor larger values ofn. 113 A.9. Exception generating and handling primitives •F16\_n—JMPnorJMPDICTn( –n), jumps to the continuation inc3, pushing integer0≤n <2 14 as its argument. Approximately equivalent toPUSHINTn;PUSH c3;JMPX. •F1A\_n—PREPAREnorPREPAREDICTn( –n c), equivalent toPUSHINT n;PUSH c3, for0≤n <2 14 . In this way,CALLnis approximately equivalent toPREPAREn;EXECUTE, andJMPnis approximately equiv- alent toPREPAREn;JMPX. One might use, for instance,CALLARGSor CALLCCinstead ofEXECUTEhere. A.9 Exception generating and handling primitives A.9.1. Throwing exceptions. •F22\_nn—THROWnn( –0nn), throws exception0≤nn≤63with parameter zero. In other words, it transfers control to the continuation inc2, pushing0andnninto its stack, and discarding the old stack altogether. •F26\_nn—THROWIFnn(f– ), throws exception0≤nn≤63with parameter zero only if integerf6= 0. •F2A\_nn—THROWIFNOTnn(f– ), throws exception0≤nn≤63with parameter zero only if integerf= 0. •F2C4\_nn—THROWnnfor0≤nn <2 11 , an encoding ofTHROWnnfor larger values ofnn. •F2CC\_nn—THROWARGnn(x–x nn), throws exception0≤nn < 2 11 with parameterx, by copyingxandnninto the stack ofc2and transferring control toc2. •F2D4\_nn—THROWIFnn(f– ) for0≤nn <2 11 . •F2DC\_nn—THROWARGIFnn(x f– ), throws exception0≤nn <2 11 with parameterxonly if integerf6= 0. •F2E4\_nn—THROWIFNOTnn(f– ) for0≤nn <2 11 . •F2EC\_nn—THROWARGIFNOTnn(x f– ), throws exception0≤nn < 2 11 with parameterxonly if integerf= 0. 114 A.10. Dictionary manipulation primitives •F2F0—THROWANY(n–0n), throws exception0≤n <2 16 with parame- ter zero. Approximately equivalent toPUSHINT 0;SWAP;THROWARGANY. •F2F1—THROWARGANY(x n–x n), throws exception0≤n <2 16 with parameterx, transferring control to the continuation inc2. Approxi- mately equivalent toPUSH c2;JMPXARGS 2. •F2F2—THROWANYIF(n f– ), throws exception0≤n <2 16 with parameter zero only iff6= 0. •F2F3—THROWARGANYIF(x n f– ), throws exception0≤n <2 16 with parameterxonly iff6= 0. •F2F4—THROWANYIFNOT(n f– ), throws exception0≤n <2 16 with parameter zero only iff= 0. •F2F5—THROWARGANYIFNOT(x n f– ), throws exception0≤n <2 16 with parameterxonly iff= 0. A.9.2. Catching and handling exceptions. •F2FF—TRY(c c ′ – ), setsc2toc ′ , first saving the old value ofc2both into the savelist ofc ′ and into the savelist of the current continuation, which is stored intoc.c0andc ′ .c0. Then runscsimilarly toEXECUTE. Ifcdoes not throw any exceptions, the original value ofc2is automati- cally restored on return fromc. If an exception occurs, the execution is transferred toc ′ , but the original value ofc2is restored in the process, so thatc ′ can re-throw the exception byTHROWANYif it cannot handle it by itself. •F3pr—TRYARGSp,r(c c ′ – ), similar toTRY, but withCALLARGS p,rinternally used instead ofEXECUTE. In this way, all but the top 0≤p≤15stack elements will be saved into current continuation’s stack, and then restored upon return from eithercorc ′ , with the top 0≤r≤15values of the resulting stack ofcorc ′ copied as return values. A.10 Dictionary manipulation primitives TVM’s dictionary support is discussed at length in3.3. The basic opera- tions with dictionaries are listed in3.3.10, while the taxonomy of dictionary 115 A.10. Dictionary manipulation primitives manipulation primitives is provided in3.3.11. Here we use the concepts and notation introduced in those sections. Dictionaries admit two different representations as TVM stack values: •ASliceswith a serialization of a TL-B value of typeHashmapE(n,X). In other words,sconsists either of one bit equal to zero (if the dic- tionary is empty), or of one bit equal to one and a reference to aCell containing the root of the binary tree, i.e., a serialized value of type Hashmap(n,X). •A “maybeCell”c ? , i.e., a value that is either aCell(containing a seri- alized value of typeHashmap(n,X)as before) or aNull(corresponding to an empty dictionary). When a “maybeCell”c ? is used to represent a dictionary, we usually denote it byDin the stack notation. Most of the dictionary primitives listed below accept and return dictionar- ies in the second form, which is more convenient for stack manipulation. However, serialized dictionaries inside larger TL-B objects use the first rep- resentation. Opcodes starting withF4andF5are reserved for dictionary operations. A.10.1. Dictionary creation. •6D—NEWDICT( –D), returns a new empty dictionary. It is an alter- native mnemonics forPUSHNULL, cf.A.3.1. •6E—DICTEMPTY(D–?), checks whether dictionaryDis empty, and returns−1or0accordingly. It is an alternative mnemonics forISNULL, cf.A.3.1. A.10.2. Dictionary serialization and deserialization. •CE—STDICTS(s b–b ′ ), stores aSlice-represented dictionarysinto Builderb. It is actually a synonym forSTSLICE. •F400—STDICTorSTOPTREF(D b–b ′ ), stores dictionaryDintoBuilder b, returing the resultingBuilderb ′ . In other words, ifDis a cell, performsSTONEandSTREF; ifDisNull, performsNIPandSTZERO; otherwise throws a type checking exception. •F401—SKIPDICTorSKIPOPTREF(s–s ′ ), equivalent toLDDICT;NIP. 116 A.10. Dictionary manipulation primitives •F402—LDDICTS(s–s ′ s ′′ ), loads (parses) a (Slice-represented) dic- tionarys ′ fromSlices, and returns the remainder ofsass ′′ . This is a “split function” for allHashmapE(n,X)dictionary types. •F403—PLDDICTS(s–s ′ ), preloads a (Slice-represented) dictionarys ′ fromSlices. Approximately equivalent toLDDICTS;DROP. •F404—LDDICTorLDOPTREF(s–D s ′ ), loads (parses) a dictionaryD fromSlices, and returns the remainder ofsass ′ . May be applied to dictionaries or to values of arbitrary(ˆY) ? types. •F405—PLDDICTorPLDOPTREF(s–D), preloads a dictionaryDfrom Slices. Approximately equivalent toLDDICT;DROP. •F406—LDDICTQ(s–D s ′ −1ors0), a quiet version ofLDDICT. •F407—PLDDICTQ(s–D−1or0), a quiet version ofPLDDICT. A.10.3.Getdictionary operations. •F40A—DICTGET(k D n–x−1or0), looks up keyk(represented by aSlice, the first0≤n≤1023data bits of which are used as a key) in dictionaryDof typeHashmapE(n,X)withn-bit keys. On success, returns the value found as aSlicex. •F40B—DICTGETREF(k D n–c−1or0), similar toDICTGET, but with aLDREF;ENDSapplied toxon success. This operation is useful for dictionaries of typeHashmapE(n,ˆY). •F40C—DICTIGET(i D n–x−1or0), similar toDICTGET, but with a signed (big-endian)n-bitIntegerias a key. Ifidoes not fit inton bits, returns0. Ifiis aNaN, throws an integer overflow exception. •F40D—DICTIGETREF(i D n–c−1or0), combinesDICTIGETwith DICTGETREF: it uses signedn-bitIntegerias a key and returns aCell instead of aSliceon success. •F40E—DICTUGET(i D n–x−1or0), similar toDICTIGET, but with unsigned(big-endian)n-bitIntegeriused as a key. •F40F—DICTUGETREF(i D n–c−1or0), similar toDICTIGETREF, but with an unsignedn-bitIntegerkeyi. 117 A.10. Dictionary manipulation primitives A.10.4.Set/Replace/Adddictionary operations.The mnemonics of the following dictionary primitives are constructed in a systematic fashion according to the regular expressionDICT\[,I,U\](SET,REPLACE,ADD)\[GET\]\[REF\] depending on the type of the key used (aSliceor a signed or unsigned Integer), the dictionary operation to be performed, and the way the values are accepted and returned (asCells or asSlices). Therefore, we provide a detailed description only for some primitives, assuming that this information is sufficient for the reader to understand the precise action of the remaining primitives. •F412—DICTSET(x k D n–D ′ ), sets the value associated withn-bit keyk(represented by aSliceas inDICTGET) in dictionaryD(also rep- resented by aSlice) to valuex(again aSlice), and returns the resulting dictionary asD ′ . •F413—DICTSETREF(c k D n–D ′ ), similar toDICTSET, but with the value set to a reference toCellc. •F414—DICTISET(x i D n–D ′ ), similar toDICTSET, but with the key represented by a (big-endian) signedn-bit integeri. Ifidoes not fit intonbits, a range check exception is generated. •F415—DICTISETREF(c i D n–D ′ ), similar toDICTSETREF, but with the key a signedn-bit integer as inDICTISET. •F416—DICTUSET(x i D n–D ′ ), similar toDICTISET, but withian unsignedn-bit integer. •F417—DICTUSETREF(c i D n–D ′ ), similar toDICTISETREF, but with iunsigned. •F41A—DICTSETGET(x k D n–D ′ y−1orD ′ 0), combinesDICTSET withDICTGET: it sets the value corresponding to keyktox, but also returns the old valueyassociated with the key in question, if present. •F41B—DICTSETGETREF(c k D n–D ′ c ′ −1orD ′ 0), combines DICTSETREFwithDICTGETREFsimilarly toDICTSETGET. •F41C—DICTISETGET(x i D n–D ′ y−1orD ′ 0), similar toDICTSETGET, but with the key represented by a big-endian signedn-bitIntegeri. 118 A.10. Dictionary manipulation primitives •F41D—DICTISETGETREF(c i D n–D ′ c ′ −1orD ′ 0), a version of DICTSETGETREFwith signedIntegerias a key. •F41E—DICTUSETGET(x i D n–D ′ y−1orD ′ 0), similar toDICTISETGET, but withian unsignedn-bit integer. •F41F—DICTUSETGETREF(c i D n–D ′ c ′ −1orD ′ 0). •F422—DICTREPLACE(x k D n–D ′ −1orD0), aReplaceoperation, which is similar toDICTSET, but sets the value of keykin dictionary Dtoxonly if the keykwas already present inD. •F423—DICTREPLACEREF(c k D n–D ′ −1orD0), aReplace counterpart ofDICTSETREF. •F424—DICTIREPLACE(x i D n–D ′ −1orD0), a version ofDICTREPLACE with signedn-bitIntegeriused as a key. •F425—DICTIREPLACEREF(c i D n–D ′ −1orD0). •F426—DICTUREPLACE(x i D n–D ′ −1orD0). •F427—DICTUREPLACEREF(c i D n–D ′ −1orD0). •F42A—DICTREPLACEGET(x k D n–D ′ y−1orD0), aReplace counterpart ofDICTSETGET: on success, also returns the old value asso- ciated with the key in question. •F42B—DICTREPLACEGETREF(c k D n–D ′ c ′ −1orD0). •F42C—DICTIREPLACEGET(x i D n–D ′ y−1orD0). •F42D—DICTIREPLACEGETREF(c i D n–D ′ c ′ −1orD0). •F42E—DICTUREPLACEGET(x i D n–D ′ y−1orD0). •F42F—DICTUREPLACEGETREF(c i D n–D ′ c ′ −1orD0). •F432—DICTADD(x k D n–D ′ −1orD0), anAddcounterpart of DICTSET: sets the value associated with keykin dictionaryDtox, but only if it is not already present inD. •F433—DICTADDREF(c k D n–D ′ −1orD0). 119 A.10. Dictionary manipulation primitives •F434—DICTIADD(x i D n–D ′ −1orD0). •F435—DICTIADDREF(c i D n–D ′ −1orD0). •F436—DICTUADD(x i D n–D ′ −1orD0). •F437—DICTUADDREF(c i D n–D ′ −1orD0). •F43A—DICTADDGET(x k D n–D ′ −1orD y0), anAddcounterpart ofDICTSETGET: sets the value associated with keykin dictionaryDto x, but only if keykis not already present inD. Otherwise, just returns the old valueywithout changing the dictionary. •F43B—DICTADDGETREF(c k D n–D ′ −1orD c ′ 0), anAddcoun- terpart ofDICTSETGETREF. •F43C—DICTIADDGET(x i D n–D ′ −1orD y0). •F43D—DICTIADDGETREF(c i D n–D ′ −1orD c ′ 0). •F43E—DICTUADDGET(x i D n–D ′ −1orD y0). •F43F—DICTUADDGETREF(c i D n–D ′ −1orD c ′ 0). A.10.5. Builder-accepting variants ofSetdictionary operations. The following primitives accept the new value as aBuilderbinstead of a Slicex, which often is more convenient if the value needs to be serialized from several components computed in the stack. (This is reflected by appending aBto the mnemonics of the correspondingSetprimitives that work with Slices.) The net effect is roughly equivalent to convertingbinto aSliceby ENDC;CTOSand executing the corresponding primitive listed inA.10.4. •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−1orD ′ 0). •F446—DICTISETGETB(b i D n–D ′ y−1orD ′ 0). •F447—DICTUSETGETB(b i D n–D ′ y−1orD ′ 0). 120 A.10. Dictionary manipulation primitives •F449—DICTREPLACEB(b k D n–D ′ −1orD0). •F44A—DICTIREPLACEB(b i D n–D ′ −1orD0). •F44B—DICTUREPLACEB(b i D n–D ′ −1orD0). •F44D—DICTREPLACEGETB(b k D n–D ′ y−1orD0). •F44E—DICTIREPLACEGETB(b i D n–D ′ y−1orD0). •F44F—DICTUREPLACEGETB(b i D n–D ′ y−1orD0). •F451—DICTADDB(b k D n–D ′ −1orD0). •F452—DICTIADDB(b i D n–D ′ −1orD0). •F453—DICTUADDB(b i D n–D ′ −1orD0). •F455—DICTADDGETB(b k D n–D ′ −1orD y0). •F456—DICTIADDGETB(b i D n–D ′ −1orD y0). •F457—DICTUADDGETB(b i D n–D ′ −1orD y0). A.10.6.Deletedictionary operations. •F459—DICTDEL(k D n–D ′ −1orD0), deletesn-bit key, represented by aSlicek, from dictionaryD. If the key is present, returns the modified dictionaryD ′ and the success flag−1. Otherwise, returns the original dictionaryDand0. •F45A—DICTIDEL(i D n–D ′ ?), a version ofDICTDELwith the key represented by a signedn-bitIntegeri. Ifidoes not fit intonbits, simply returnsD0(“key not found, dictionary unmodified”). •F45B—DICTUDEL(i D n–D ′ ?), similar toDICTIDEL, but withian unsignedn-bit integer. •F462—DICTDELGET(k D n–D ′ x−1orD0), deletesn-bit key, represented by aSlicek, from dictionaryD. If the key is present, returns the modified dictionaryD ′ , the original valuexassociated with the keyk(represented by aSlice), and the success flag−1. Otherwise, returns the original dictionaryDand0. 121 A.10. Dictionary manipulation primitives •F463—DICTDELGETREF(k D n–D ′ c−1orD0), similar toDICTDELGET, but withLDREF;ENDSapplied toxon success, so that the value re- turnedcis aCell. •F464—DICTIDELGET(i D n–D ′ x−1orD0), a variant of primitive DICTDELGETwith signedn-bit integerias a key. •F465—DICTIDELGETREF(i D n–D ′ c−1orD0), a variant of primitiveDICTIDELGETreturning aCellinstead of aSlice. •F466—DICTUDELGET(i D n–D ′ x−1orD0), a variant of primitive DICTDELGETwith unsignedn-bit integerias a key. •F467—DICTUDELGETREF(i D n–D ′ c−1orD0), a variant of primitiveDICTUDELGETreturning aCellinstead of aSlice. A.10.7. “Maybe reference” dictionary operations.The following op- erations assume that a dictionary is used to store valuesc ? of typeCell ? (“Maybe Cell”), which can be used in particular to store dictionaries as val- ues in other dictionaries. The representation is as follows: ifc ? is aCell, it is stored as a value with no data bits and exactly one reference to thisCell. Ifc ? isNull, then the corresponding key must be absent from the dictionary altogether. •F469—DICTGETOPTREF(k D n–c ? ), a variant ofDICTGETREFthat returnsNullinstead of the valuec ? if the keykis absent from dictio- naryD. •F46A—DICTIGETOPTREF(i D n–c ? ), similar toDICTGETOPTREF, but with the key given by signedn-bitIntegeri. If the keyiis out of range, also returnsNull. •F46B—DICTUGETOPTREF(i D n–c ? ), similar toDICTGETOPTREF, but with the key given by unsignedn-bitIntegeri. •F46D—DICTSETGETOPTREF(c ? k D n–D ′ ̃c ? ), a variant of both DICTGETOPTREFandDICTSETGETREFthat sets the value corresponding to keykin dictionaryDtoc ? (ifc ? isNull, then the key is deleted instead), and returns the old value ̃c ? (if the keykwas absent before, returnsNullinstead). 122 A.10. Dictionary manipulation primitives •F46E—DICTISETGETOPTREF(c ? i D n–D ′ ̃c ? ), similar to primitive DICTSETGETOPTREF, but using signedn-bitIntegerias a key. Ifidoes not fit intonbits, throws a range checking exception. •F46F—DICTUSETGETOPTREF(c ? i D n–D ′ ̃c ? ), similar to primitive DICTSETGETOPTREF, but using unsignedn-bitIntegerias a key. A.10.8. Prefix code dictionary operations.These are some basic op- erations for constructing prefix code dictionaries (cf.3.4.2). The primary application for prefix code dictionaries is deserializing TL-B serialized data structures, or, more generally, parsing prefix codes. Therefore, most prefix code dictionaries will be constant and created at compile time, not by the following primitives. SomeGetoperations for prefix code dictionaries may be found inA.10.11. Other prefix code dictionary operations include: •F470—PFXDICTSET(x k D n–D ′ −1orD0). •F471—PFXDICTREPLACE(x k D n–D ′ −1orD0). •F472—PFXDICTADD(x k D n–D ′ −1orD0). •F473—PFXDICTDEL(k D n–D ′ −1orD0). These primitives are completely similar to their non-prefix code counterparts DICTSETetc (cf.A.10.4), with the obvious difference that even aSetmay fail in a prefix code dictionary, so a success flag must be returned byPFXDICTSET as well. A.10.9. Variants ofGetNextandGetPrevoperations. •F474—DICTGETNEXT(k D n–x ′ k ′ −1or0), computes the minimal keyk ′ in dictionaryDthat is lexicographically greater thank, and returnsk ′ (represented by aSlice) along with associated valuex ′ (also represented by aSlice). •F475—DICTGETNEXTEQ(k D n–x ′ k ′ −1or0), similar toDICTGETNEXT, but computes the minimal keyk ′ that is lexicographically greater than or equal tok. •F476—DICTGETPREV(k D n–x ′ k ′ −1or0), similar toDICTGETNEXT, but computes the maximal keyk ′ lexicographically smaller thank. 123 A.10. Dictionary manipulation primitives •F477—DICTGETPREVEQ(k D n–x ′ k ′ −1or0), similar toDICTGETPREV, but computes the maximal keyk ′ lexicographically smaller than or equal tok. •F478—DICTIGETNEXT(i D n–x ′ i ′ −1or0), similar toDICTGETNEXT, but interprets all keys in dictionaryDas big-endian signedn-bit in- tegers, and computes the minimal keyi ′ that is larger thanIntegeri (which does not necessarily fit intonbits). •F479—DICTIGETNEXTEQ(i D n–x ′ i ′ −1or0). •F47A—DICTIGETPREV(i D n–x ′ i ′ −1or0). •F47B—DICTIGETPREVEQ(i D n–x ′ i ′ −1or0). •F47C—DICTUGETNEXT(i D n–x ′ i ′ −1or0), similar toDICTGETNEXT, but interprets all keys in dictionaryDas big-endian unsignedn-bit integers, and computes the minimal keyi ′ that is larger thanIntegeri (which does not necessarily fit intonbits, and is not necessarily non- negative). •F47D—DICTUGETNEXTEQ(i D n–x ′ i ′ −1or0). •F47E—DICTUGETPREV(i D n–x ′ i ′ −1or0). •F47F—DICTUGETPREVEQ(i D n–x ′ i ′ −1or0). A.10.10.GetMin,GetMax,RemoveMin,RemoveMaxopera- tions. •F482—DICTMIN(D n–x k−1or0), computes the minimal keyk (represented by aSlicewithndata bits) in dictionaryD, and returns kalong with the associated valuex. •F483—DICTMINREF(D n–c k−1or0), similar toDICTMIN, but returns the only reference in the value as aCellc. •F484—DICTIMIN(D n–x i−1or0), somewhat similar toDICTMIN, but computes the minimal keyiunder the assumption that all keys are big-endian signedn-bit integers. Notice that the key and value returned may differ from those computed byDICTMINandDICTUMIN. 124 A.10. Dictionary manipulation primitives •F485—DICTIMINREF(D n–c i−1or0). •F486—DICTUMIN(D n–x i−1or0), similar toDICTMIN, but returns the key as an unsignedn-bitIntegeri. •F487—DICTUMINREF(D n–c i−1or0). •F48A—DICTMAX(D n–x k−1or0), computes the maximal keyk (represented by aSlicewithndata bits) in dictionaryD, and returns kalong with the associated valuex. •F48B—DICTMAXREF(D n–c k−1or0). •F48C—DICTIMAX(D n–x i−1or0). •F48D—DICTIMAXREF(D n–c i−1or0). •F48E—DICTUMAX(D n–x i−1or0). •F48F—DICTUMAXREF(D n–c i−1or0). •F492—DICTREMMIN(D n–D ′ x k−1orD0), computes the minimal keyk(represented by aSlicewithndata bits) in dictionaryD, removes kfrom the dictionary, and returnskalong with the associated valuex and the modified dictionaryD ′ . •F493—DICTREMMINREF(D n–D ′ c k−1orD0), similar toDICTREMMIN, but returns the only reference in the value as aCellc. •F494—DICTIREMMIN(D n–D ′ x i−1orD0), somewhat similar toDICTREMMIN, but computes the minimal keyiunder the assumption that all keys are big-endian signedn-bit integers. Notice that the key and value returned may differ from those computed byDICTREMMINand DICTUREMMIN. •F495—DICTIREMMINREF(D n–D ′ c i−1orD0). •F496—DICTUREMMIN(D n–D ′ x i−1orD0), similar toDICTREMMIN, but returns the key as an unsignedn-bitIntegeri. •F497—DICTUREMMINREF(D n–D ′ c i−1orD0). 125 A.10. Dictionary manipulation primitives •F49A—DICTREMMAX(D n–D ′ x k−1orD0), computes the maximal keyk(represented by aSlicewithndata bits) in dictionaryD, removes kfrom the dictionary, and returnskalong with the associated valuex and the modified dictionaryD ′ . •F49B—DICTREMMAXREF(D n–D ′ c k−1orD0). •F49C—DICTIREMMAX(D n–D ′ x i−1orD0). •F49D—DICTIREMMAXREF(D n–D ′ c i−1orD0). •F49E—DICTUREMMAX(D n–D ′ x i−1orD0). •F49F—DICTUREMMAXREF(D n–D ′ c i−1orD0). A.10.11. SpecialGetdictionary and prefix code dictionary opera- tions, and constant dictionaries. •F4A0—DICTIGETJMP(i D n– ), similar toDICTIGET(cf.A.10.12), but withxBLESSed into a continuation with a subsequentJMPXto it on success. On failure, does nothing. This is useful for implementing switch/caseconstructions. •F4A1—DICTUGETJMP(i D n– ), similar toDICTIGETJMP, but performs DICTUGETinstead ofDICTIGET. •F4A2—DICTIGETEXEC(i D n– ), similar toDICTIGETJMP, but with EXECUTEinstead ofJMPX. •F4A3—DICTUGETEXEC(i D n– ), similar toDICTUGETJMP, but with EXECUTEinstead ofJMPX. •F4A6\_n—DICTPUSHCONSTn( –D n), pushes a non-empty constant dictionaryD(as aCell ? ) along with its key length0≤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 completeDICTPUSHCONSTinstruction can be obtained by first serializingxF4A8\_, then the non-empty dictionary itself (one1bit and a cell reference), and then the unsigned 10-bit integern(as if by aSTU 10instruction). An empty dictionary can be pushed by aNEWDICT primitive (cf.A.10.1) instead. 126 A.10. Dictionary manipulation primitives •F4A8—PFXDICTGETQ(s D n–s ′ x s ′′ −1ors0), looks up the unique prefix ofSlicespresent in the prefix code dictionary (cf.3.4.2) rep- resented byCell ? Dand0≤n≤1023. If found, the prefix ofsis returned ass ′ , and the corresponding value (also aSlice) asx. The remainder ofsis returned as aSlices ′′ . If no prefix ofsis a key in prefix code dictionaryD, returns the unchangedsand a zero flag to indicate failure. •F4A9—PFXDICTGET(s D n–s ′ x s ′′ ), similar toPFXDICTGET, but throws a cell deserialization failure exception on failure. •F4AA—PFXDICTGETJMP(s D n–s ′ s ′′ ors), similar toPFXDICTGETQ, but on successBLESSes the valuexinto aContinuationand transfers control to it as if by aJMPX. On failure, returnssunchanged and continues execution. •F4AB—PFXDICTGETEXEC(s D n–s ′ s ′′ ), similar toPFXDICTGETJMP, butEXECutes the continuation found instead of jumping to it. On failure, throws a cell deserialization exception. •F4AE\_n—PFXDICTCONSTGETJMPnorPFXDICTSWITCHn(s–s ′ s ′′ or s), combinesDICTPUSHCONSTnfor0≤n≤1023withPFXDICTGETJMP. •F4BC—DICTIGETJMPZ(i D n–ior nothing), a variant ofDICTIGETJMP that returns indexion failure. •F4BD—DICTUGETJMPZ(i D n–ior nothing), a variant ofDICTUGETJMP that returns indexion failure. •F4BE—DICTIGETEXECZ(i D n–ior nothing), a variant ofDICTIGETEXEC that returns indexion failure. •F4BF—DICTUGETEXECZ(i D n–ior nothing), a variant ofDICTUGETEXEC that returns indexion failure. A.10.12.SubDictdictionary operations. •F4B1—SUBDICTGET(k l D n–D ′ ), constructs a subdictionary con- sisting of all keys beginning with prefixk(represented by aSlice, the first0≤l≤n≤1023data bits of which are used as a key) of lengthl in dictionaryDof typeHashmapE(n,X)withn-bit keys. On success, 127 A.11. Application-specific primitives returns the new subdictionary of the same typeHashmapE(n,X)as a SliceD ′ . •F4B2—SUBDICTIGET(x l D n–D ′ ), variant ofSUBDICTGETwith the prefix represented by a signed big-endianl-bitIntegerx, where necessarilyl≤257. •F4B3—SUBDICTUGET(x l D n–D ′ ), variant ofSUBDICTGETwith the prefix represented by an unsigned big-endianl-bitIntegerx, where necessarilyl≤256. •F4B5—SUBDICTRPGET(k l D n–D ′ ), similar toSUBDICTGET, but removes the common prefixkfrom all keys of the new dictionaryD ′ , which becomes of typeHashmapE(n−l,X). •F4B6—SUBDICTIRPGET(x l D n–D ′ ), variant ofSUBDICTRPGETwith the prefix represented by a signed big-endianl-bitIntegerx, where necessarilyl≤257. •F4B7—SUBDICTURPGET(x l D n–D ′ ), variant ofSUBDICTRPGETwith the prefix represented by an unsigned big-endianl-bitIntegerx, where necessarilyl≤256. •F4BC–F4BF— used byDICT...Zprimitives inA.10.11. A.11 Application-specific primitives Opcode rangeF8. . .FBis reserved for theapplication-specific primitives. When TVM is used to execute TON Blockchain smart contracts, these application- specific primitives are in fact TON Blockchain-specific. A.11.1. External actions and access to blockchain configuration data.Some of the primitives listed below pretend to produce some externally visible actions, such as sending a message to another smart contract. In fact, the execution of a smart contract in TVM never has any effect apart from a modification of the TVM state. All external actions are collected into a linked list stored in special registerc5(“output actions”). Additionally, some primitives use the data kept in the first component of theTuplestored in c7(“root of temporary data”, cf.1.3.2). Smart contracts are free to modify 128 A.11. Application-specific primitives any other data kept in the cellc7, provided the first reference remains in- tact (otherwise some application-specific primitives would be likely to throw exceptions when invoked). Most of the primitives listed below use 16-bit opcodes. A.11.2. Gas-related primitives.Of the following primitives, only the first two are “pure” in the sense that they do not usec5orc7. •F800—ACCEPT, sets current gas limitg l to its maximal allowed value g m , and resets the gas creditg c to zero (cf.1.4), decreasing the value ofg r byg 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. •F801—SETGASLIMIT(g– ), sets current gas limitg l to the minimum ofgandg m , and resets the gas creditg 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 thatSETGASLIMITwith an argumentg≥2 63 −1is equivalent toACCEPT. •F802—BUYGAS(x– ), computes the amount of gas that can be bought forxnanograms, and setsg l accordingly in the same way as SETGASLIMIT. •F804—GRAMTOGAS(x–g), computes the amount of gas that can be bought forxnanograms. Ifxis negative, returns 0. Ifgexceeds2 63 −1, it is replaced with this value. •F805—GASTOGRAM(g–x), computes the price ofggas in nanograms. •F806–F80E— Reserved for gas-related primitives. •F80F—COMMIT( – ), commits the current state of registersc4(“persis- tent data”) andc5(“actions”) so that the current execution is considered “successful” with the saved values even if an exception is thrown later. A.11.3. Pseudo-random number generator primitives.The pseudo- random number generator uses the random seed (parameter #6, cf.A.11.4), an unsigned 256-bitInteger, and (sometimes) other data kept inc7. The 129 A.11. Application-specific primitives 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 runningLTIME; ADDRANDbefore using the pseudo- random number generator for the first time. •F810—RANDU256( –x), generates a new pseudo-random unsigned 256-bitIntegerx. The algorithm is as follows: ifris 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 valuer ′ of the random seed, and the remaining 32 bytes are returned as the next random valuex. •F811—RAND(y–z), generates a new pseudo-random integerzin the range0...y−1(ory ...−1, ify <0). More precisely, an unsigned random valuexis generated as inRAND256U; thenz:=bxy/2 256 cis computed. Equivalent toRANDU256; MULRSHIFT 256. •F814—SETRAND(x– ), sets the random seed to unsigned 256-bit Integerx. •F815—ADDRAND(x– ), mixes unsigned 256-bitIntegerxinto the ran- dom seedrby setting the random seed tosha256of the concatenation of two 32-byte strings: the first with the big-endian representation of the old seedr, and the second with the big-endian representation ofx. •F810–F81F— Reserved for pseudo-random number generator primi- tives. A.11.4. Configuration primitives.The following primitives read con- figuration data provided in theTuplestored in the first component of the Tupleatc7. Whenever TVM is invoked for executing TON Blockchain smart contracts, thisTupleis initialized by aSmartContractInfostructure; config- uration primitives assume that it has remained intact. •F82i—GETPARAMi( –x), returns thei-th parameter from theTuple provided atc7for0≤i <16. Equivalent toPUSH c7;FIRST;INDEX i. If one of these internal operations fails, throws an appropriate type checking or range checking exception. 130 A.11. Application-specific primitives •F823—NOW( –x), returns the current Unix time as anInteger. If it is impossible to recover the requested value starting fromc7, throws a type checking or range checking exception as appropriate. Equivalent toGETPARAM 3. •F824—BLOCKLT( –x), returns the starting logical time of the current block. Equivalent toGETPARAM 4. •F825—LTIME( –x), returns the logical time of the current transaction. Equivalent toGETPARAM 5. •F826—RANDSEED( –x), returns the current random seed as an un- signed 256-bitInteger. Equivalent toGETPARAM 6. •F827—BALANCE( –t), returns the remaining balance of the smart contract as aTupleconsisting of anInteger(the remaining Gram bal- ance in nanograms) and aMaybe Cell(a dictionary with 32-bit keys representing the balance of “extra currencies”). Equivalent toGETPARAM 7. Note thatRAWprimitives such asSENDRAWMSGdo not update this field. •F828—MYADDR( –s), returns the internal address of the current smart contract as aSlicewith aMsgAddressInt. If necessary, it can be parsed further using primitives such asPARSESTDADDRorREWRITESTDADDR. Equivalent toGETPARAM 8. •F829—CONFIGROOT( –D), returns theMaybe CellDwith the current global configuration dictionary. Equivalent toGETPARAM 9. •F830—CONFIGDICT( –D32), returns the global configuration dic- tionary along with its key length (32). Equivalent toCONFIGROOT; PUSHINT 32. •F832—CONFIGPARAM(i–c−1or0), returns the value of the global configuration parameter with integer indexias aCellc, and a flag to indicate success. Equivalent toCONFIGDICT;DICTIGETREF. •F833—CONFIGOPTPARAM(i–c ? ), returns the value of the global config- uration parameter with integer indexias aMaybe Cellc ? . Equivalent toCONFIGDICT;DICTIGETOPTREF. 131 A.11. Application-specific primitives •F820—F83F— Reserved for configuration primitives. A.11.5. Global variable primitives.The “global variables” may be helpful in implementing some high-level smart-contract languages. They are in fact stored as components of theTupleatc7: thek-th global variable simply is thek-th component of thisTuple, for1≤k≤254. By convention, the0-th component is used for the “configuration parameters” ofA.11.4, so it is not available as a global variable. •F840—GETGLOBVAR(k–x), returns thek-th global variable for0≤ k <255. Equivalent toPUSH c7;SWAP;INDEXVARQ(cf.A.3.2). •F85\_k—GETGLOBk( –x), returns thek-th global variable for1≤ k≤31. Equivalent toPUSH c7;INDEXQk. •F860—SETGLOBVAR(x k– ), assignsxto thek-th global variable for 0≤k <255. Equivalent toPUSH c7;ROTREV;SETINDEXVARQ;POP c7. •F87\_k—SETGLOBk(x– ), assignsxto thek-th global variable for 1≤k≤31. Equivalent toPUSH c7;SWAP;SETINDEXQk;POP c7. A.11.6. Hashing and cryptography primitives. •F900—HASHCU(c–x), computes the representation hash (cf.3.1.5) of aCellcand returns it as a 256-bit unsigned integerx. Useful for signing and checking signatures of arbitrary entities represented by a tree of cells. •F901—HASHSU(s–x), computes the hash of aSlicesand returns it as a 256-bit unsigned integerx. The result is the same as if an ordinary cell containing only data and references fromshad been created and its hash computed byHASHCU. •F902—SHA256U(s–x), computessha256of the data bits ofSlices. If the bit length ofsis not divisible by eight, throws a cell underflow exception. The hash value is returned as a 256-bit unsigned integerx. •F910—CHKSIGNU(h s k–?), checks the Ed25519-signaturesof a hashh(a 256-bit unsigned integer, usually computed as the hash of some data) using public keyk(also represented by a 256-bit unsigned integer). The signaturesmust be aSlicecontaining at least 512 data 132 A.11. Application-specific primitives bits; only the first 512 bits are used. The result is−1if the signature is valid,0otherwise. Notice thatCHKSIGNUis equivalent toROT;NEWB; STU 256;ENDB;NEWC;ROTREV;CHKSIGNS, i.e., toCHKSIGNSwith the first argumentdset to 256-bitSlicecontainingh. Therefore, ifhis computed as the hash of some data, these data are hashedtwice, the second hashing occurring insideCHKSIGNS. •F911—CHKSIGNS(d s k–?), checks whethersis a valid Ed25519- signature of the data portion ofSlicedusing public keyk, similarly to CHKSIGNU. If the bit length ofSlicedis not divisible by eight, throws a cell underflow exception. The verification of Ed25519 signatures is the standard one, withsha256used to reducedto the 256-bit number that is actually signed. •F912–F93F— Reserved for hashing and cryptography primitives. A.11.7. Miscellaneous primitives. •F940—CDATASIZEQ(c n–x y z−1or0), recursively computes the count of distinct cellsx, data bitsy, and cell referenceszin the dag rooted atCellc, effectively returning the total storage used by this dag taking into account the identification of equal cells. The values of x,y, andzare 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 cellsxcannot exceed non-negative Integern; otherwise the computation is aborted before visiting the (n+ 1)-st cell and a zero is returned to indicate failure. IfcisNull, returnsx=y=z= 0. •F941—CDATASIZE(c n–x y z), a non-quiet version ofCDATASIZEQ that throws a cell overflow exception (8) on failure. •F942—SDATASIZEQ(s n–x y z−1or0), similar toCDATASIZEQ, but accepting aSlicesinstead of aCell. The returned value ofxdoes not take into account the cell that contains the slicesitself; however, the data bits and the cell references ofsare accounted for inyandz. •F943—SDATASIZE(s n–x y z), a non-quiet version ofSDATASIZEQ that throws a cell overflow exception (8) on failure. 133 A.11. Application-specific primitives •F944–F97F— Reserved for miscellaneous TON-specific primitives that do not fall into any other specific category. A.11.8. Currency manipulation primitives. •FA00—LDGRAMSorLDVARUINT16(s–x s ′ ), loads (deserializes) aGram orVarUInteger 16amount fromCellSlices, and returns the amount asIntegerxalong with the remainders ′ ofs. The expected serial- ization ofxconsists of a 4-bit unsigned big-endian integerl, followed by an8l-bit unsigned big-endian representation ofx. The net effect is approximately equivalent toLDU 4;SWAP;LSHIFT 3;LDUX. •FA01—LDVARINT16(s–x s ′ ), similar toLDVARUINT16, but loads a signed Integerx. Approximately equivalent toLDU 4;SWAP;LSHIFT 3; LDIX. •FA02—STGRAMSorSTVARUINT16(b x–b ′ ), stores (serializes) anInte- gerxin the range0...2 120 −1intoBuilderb, and returns the resulting Builderb ′ . The serialization ofxconsists of a 4-bit unsigned big-endian integerl, which is the smallest integerl≥0, such thatx <2 8l , fol- lowed by an8l-bit unsigned big-endian representation ofx. Ifxdoes not belong to the supported range, a range check exception is thrown. •FA03—STVARINT16(b x–b ′ ), similar toSTVARUINT16, but serializes asigned Integerxin the range−2 119 ...2 119 −1. •FA04—LDVARUINT32(s–x s ′ ), loads (deserializes) aVarUInteger 32fromCellSlices, and returns the deserialized value as anInte- ger0≤x <2 248 . The expected serialization ofxconsists of a 5-bit unsigned big-endian integerl, followed by an8l-bit unsigned big-endian representation ofx. The net effect is approximately equivalent toLDU 5;SWAP;SHIFT 3;LDUX. •FA05—LDVARINT32(s–x s ′ ), deserializes aVarInteger 32from CellSlices, and returns the deserialized value as anInteger−2 247 ≤ x <2 247 . •FA06—STVARUINT32(b x–b ′ ), serializes anInteger0≤x <2 248 as a VarUInteger 32. 134 A.11. Application-specific primitives •FA07—STVARINT32(b x–b ′ ), serializes anInteger−2 247 ≤x <2 247 as aVarInteger 32. •FA08–FA1F— Reserved for currency manipulation primitives. A.11.9. Message and address manipulation primitives.The message and address manipulation primitives listed below serialize and deserialize values according to the following TL-B scheme (cf.3.3.4): 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 deserializedMsgAddressis represented by aTupletas follows: •addr\_noneis represented byt= (0), i.e., aTuplecontaining exactly oneIntegerequal to zero. •addr\_externis represented byt= (1,s), whereSlicescontains the fieldexternal\_address. In other words,tis a pair (aTupleconsisting of two entries), containing anIntegerequal to one andSlices. •addr\_stdis represented byt= (2,u,x,s), whereuis either aNull(if anycastis absent) or aSlices ′ containingrewrite\_pfx(ifanycast is present). Next,Integerxis theworkchain\_id, andSlicescontains theaddress. 135 A.11. Application-specific primitives •addr\_varis represented byt= (3,u,x,s), whereu,x, andshave the same meaning as foraddr\_std. The following primitives, which use the above conventions, are defined: •FA40—LDMSGADDR(s–s ′ s ′′ ), loads fromCellSlicesthe only prefix that is a validMsgAddress, and returns both this prefixs ′ and the remainders ′′ ofsasCellSlices. •FA41—LDMSGADDRQ(s–s ′ s ′′ −1ors0), a quiet version ofLDMSGADDR: on success, pushes an extra−1; on failure, pushes the originalsand a zero. •FA42—PARSEMSGADDR(s–t), decomposesCellSlicescontaining a validMsgAddressinto aTupletwith separate fields of thisMsgAddress. Ifsis not a validMsgAddress, a cell deserialization exception is thrown. •FA43—PARSEMSGADDRQ(s–t−1or0), a quiet version ofPARSEMSGADDR: returns a zero on error instead of throwing an exception. •FA44—REWRITESTDADDR(s–x y), parsesCellSlicescontaining a validMsgAddressInt(usually amsg\_addr\_std), applies rewriting from theanycast(if present) to the same-length prefix of the address, and returns both the workchainxand the 256-bit addressyasIntegers. If the address is not 256-bit, or ifsis not a valid serialization of MsgAddressInt, throws a cell deserialization exception. •FA45—REWRITESTDADDRQ(s–x y−1or0), a quiet version of primitive REWRITESTDADDR. •FA46—REWRITEVARADDR(s–x s ′ ), a variant ofREWRITESTDADDRthat returns the (rewritten) address as aSlices, even if it is not exactly 256 bit long (represented by amsg\_addr\_var). •FA47—REWRITEVARADDRQ(s–x s ′ −1or0), a quiet version of primitive REWRITEVARADDR. •FA48–FA5F— Reserved for message and address manipulation primi- tives. A.11.10. Outbound message and output action primitives. 136 A.11. Application-specific primitives •FB00—SENDRAWMSG(c x– ), sends a raw message contained inCell c, which should contain a correctly serialized objectMessageX, with the only exception that the source address is allowed to have dummy valueaddr\_none(to be automatically replaced with the current smart- contract address), andihr\_fee,fwd\_fee,created\_ltandcreated\_at fields can have arbitrary values (to be rewritten with correct values during the action phase of the current transaction). Integer parameter xcontains the flags. Currentlyx= 0is used for ordinary messages; x= 128is 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= 64is used for messages that carry all the re- maining 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 de- ducted from this amount);x ′ =x+ 1means that the sender wants to pay transfer fees separately;x ′ =x+ 2means that any errors aris- ing while processing this message during the action phase should be ignored. Finally,x ′ =x+ 32means that the current account must be destroyed if its resulting balance is zero. This flag is usually employed together with+128. •FB02—RAWRESERVE(x y– ), creates an output action which would re- serve exactlyxnanograms (ify= 0), at mostxnanograms (ify= 2), or all butxnanograms (ify= 1ory= 3), from the remaining balance of the account. It is roughly equivalent to creating an outbound message carryingxnanograms (orb−xnanograms, wherebis the remaining balance) to oneself, so that the subsequent output actions would not be able to spend more money than the remainder. Bit+2inymeans that the external action does not fail if the specified amount cannot be reserved; instead, all remaining balance is reserved. Bit+8inymeans x←−xbefore performing any further actions. Bit+4inymeans that xis increased by the original balance of the current account (before the compute phase), including all extra currencies, before performing any other checks and actions. Currentlyxmust be a non-negative integer, andymust be in the range0...15. •FB03—RAWRESERVEX(x D y– ), similar toRAWRESERVE, but also accepts a dictionaryD(represented by aCellorNull) with extra cur- rencies. In this way currencies other than Grams can be reserved. 137 A.12. Debug primitives •FB04—SETCODE(c– ), creates an output action that would change this smart contract code to that given byCellc. Notice that this change will take effect only after the successful termination of the current run of the smart contract. •FB06—SETLIBCODE(c x– ), creates an output action that would mod- ify the collection of this smart contract libraries by adding or removing library with code given inCellc. Ifx= 0, the library is actually removed if it was previously present in the collection (if not, this ac- tion does nothing). Ifx= 1, the library is added as a private library, and ifx= 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 tox. Values ofxother than 0...2are invalid. •FB07—CHANGELIB(h x– ), creates an output action similarly to SETLIBCODE, but instead of the library code accepts its hash as an unsigned 256-bit integerh. Ifx6= 0and the library with hashhis absent from the library collection of this smart contract, this output action will fail. •FB08–FB3F— Reserved for output action primitives. A.12 Debug primitives Opcodes beginning withFEare reserved for thedebug primitives. These primitives have known fixed operation length, and behave as (multibyte) NOP operations. In particular, they never change the stack contents, and never throw exceptions, unless there are not enough bits to completely de- code the opcode. However, when invoked in a TVM instance with debug mode enabled, these primitives can produce specific output into the text de- bug log of the TVM instance, never affecting the TVM state (so that from the perspective of TVM the behavior of debug primitives in debug mode is exactly the same). For instance, a debug primitive might dump all or some of the values near the top of the stack, display the current state of TVM and so on. A.12.1. Debug primitives as multibyte NOPs. 138 A.12. Debug primitives •FEnn—DEBUGnn, for0≤nn <240, is a two-byte NOP. •FEFnssss—DEBUGSTRssss, for0≤n <16, is an(n+ 3)-byte NOP, with the(n+ 1)-byte “contents string”ssssskipped as well. A.12.2. Debug primitives as operations without side-effect.Next we describe the debug primitives that might (and actually are) implemented in a version of TVM. Notice that another TVM implementation is free to use these codes for other debug purposes, or treat them as multibyte NOPs. Whenever these primitives need some arguments from the stack, they inspect these arguments, but leave them intact in the stack. If there are insufficient values in the stack, or they have incorrect types, debug primitives may output error messages into the debug log, or behave as NOPs, but they cannot throw exceptions. •FE00—DUMPSTK, dumps the stack (at most the top 255 values) and shows the total stack depth. •FE0n—DUMPSTKTOPn,1≤n <15, dumps the topnvalues from the stack, starting from the deepest of them. If there ared < nvalues available, dumps onlydvalues. •FE10—HEXDUMP, dumpss0in hexadecimal form, be it aSliceor an Integer. •FE11—HEXPRINT, similar toHEXDUMP, except the hexadecimal repre- sentation ofs0is not immediately output, but rather concatenated to an output text buffer. •FE12—BINDUMP, dumpss0in binary form, similarly toHEXDUMP. •FE13—BINPRINT, outputs the binary representation ofs0to a text buffer. •FE14—STRDUMP, dumps theSliceats0as an UTF-8 string. •FE15—STRPRINT, similar toSTRDUMP, but outputs the string into a text buffer (without carriage return). •FE1E—DEBUGOFF, disables all debug output until it is re-enabled by aDEBUGON. More precisely, this primitive increases an internal counter, which disables all debug operations (exceptDEBUGOFFandDEBUGON) when strictly positive. 139 A.13. Codepage primitives •FE1F—DEBUGON, enables debug output (in a debug version of TVM). •FE2n—DUMP s(n),0≤n <15, dumpss(n). •FE3n—PRINT s(n),0≤n <15, concatenates the text representation ofs(n)(without any leading or trailing spaces or carriage returns) to a text buffer which will be output before the output of any other debug operation. •FEC0–FEEF— Use these opcodes for custom/experimental debug oper- ations. •FEFnssss—DUMPTOSFMTssss, dumpss0formatted according to the (n+ 1)-byte stringssss. This string might contain (a prefix of) the name of a TL-B type supported by the debugger. If the string begins with a zero byte, simply outputs it (without the first byte) into the debug log. If the string begins with a byte equal to one, concatenates it to a buffer, which will be output before the output of any other debug operation (effectively outputs a string without a carriage return). •FEFn00ssss—LOGSTRssss, stringssssisnbytes long. •FEF000—LOGFLUSH, flushes all pending debug output from the buffer into the debug log. •FEFn01ssss—PRINTSTRssss, stringssssisnbytes long. A.13 Codepage primitives The following primitives, which begin with byteFF, typically are used at the very beginning of a smart contract’s code or a library subroutine to select another TVM codepage. Notice that we expect all codepages to contain these primitives with the same codes, otherwise switching back to another codepage might be impossible (cf.5.1.8). •FFnn—SETCPnn, selects TVM codepage0≤nn <240. If the codepage is not supported, throws an invalid opcode exception. •FF00—SETCP0, selects TVM (test) codepage zero as described in this document. 140 A.13. Codepage primitives •FFFz—SETCPz−16, selects TVM codepagez−16for1≤z≤15. Negative codepages−13...−1are reserved for restricted versions of TVM needed to validate runs of TVM in other codepages as explained inB.2.6. Negative codepage−14is reserved for experimental code- pages, not necessarily compatible between different TVM implementa- tions, and should be disabled in the production versions of TVM. •FFF0—SETCPX(c– ), selects codepagecwith−2 15 ≤c <2 15 passed in the top of the stack. 141 B.1. Serialization of the TVM state B Formal properties and specifications of TVM This appendix discusses certain formal properties of TVM that are necessary for executing smart contracts in the TON Blockchain and validating such executions afterwards. B.1 Serialization of the TVM state Recall that a virtual machine used for executing smart contracts in a block- chain must bedeterministic, otherwise the validation of each execution would require the inclusion of all intermediate steps of the execution into a block, or at least of the choices made when indeterministic operations have been performed. Furthermore, thestateof such a virtual machine must be (uniquely) se- rializable, so that even if the state itself is not usually included in a block, itshashis still well-defined and can be included into a block for verification purposes. B.1.1. TVM stack values.TVM stack values can be serialized as follows: vm\_stk\_tinyint#01 value:int64 = VmStackValue; vm\_stk\_int#0201\_ value:int257 = VmStackValue; vm\_stk\_nan#02FF = VmStackValue; vm\_stk\_cell#03 cell:^Cell = VmStackValue; \_ cell:^Cell st\_bits:(## 10) end\_bits:(## 10) { st\_bits <= end\_bits } st\_ref:(#<= 4) end\_ref:(#<= 4) { st\_ref <= end\_ref } = VmCellSlice; vm\_stk\_slice#04 \_:VmCellSlice = VmStackValue; vm\_stk\_builder#05 cell:^Cell = VmStackValue; vm\_stk\_cont#06 cont:VmCont = VmStackValue; Of these,vm\_stk\_tinyintis never used by TVM in codepage zero; it is used only in restricted modes. B.1.2. TVM stack.The TVM stack can be serialized as follows: vm\_stack#\_ depth:(## 24) stack:(VmStackList depth) = VmStack; vm\_stk\_cons#\_ {n:#} head:VmStackValue tail:^(VmStackList n) = VmStackList (n + 1); vm\_stk\_nil#\_ = VmStackList 0; 142 B.1. Serialization of the TVM state B.1.3. TVM control registers.Control registers in TVM can be serialized as follows: \_ cregs:(HashmapE 4 VmStackValue) = VmSaveList; B.1.4. TVM gas limits.Gas limits in TVM can be serialized as follows: gas\_limits#\_ remaining:int64 \_:^\[ max\_limit:int64 cur\_limit:int64 credit:int64 \] = VmGasLimits; B.1.5. TVM library environment.The TVM library environment can be serialized as follows: \_ libraries:(HashmapE 256 ^Cell) = VmLibraries; B.1.6. TVM continuations.Continuations in TVM can be serialized as follows: vmc\_std$00 nargs:(## 22) stack:(Maybe VmStack) save:VmSaveList cp:int16 code:VmCellSlice = VmCont; vmc\_envelope$01 nargs:(## 22) stack:(Maybe VmStack) save:VmSaveList next:^VmCont = VmCont; vmc\_quit$1000 exit\_code:int32 = VmCont; vmc\_quit\_exc$1001 = VmCont; vmc\_until$1010 body:^VmCont after:^VmCont = VmCont; vmc\_again$1011 body:^VmCont = VmCont; vmc\_while\_cond$1100 cond:^VmCont body:^VmCont after:^VmCont = VmCont; vmc\_while\_body$1101 cond:^VmCont body:^VmCont after:^VmCont = VmCont; vmc\_pushint$1111 value:int32 next:^VmCont = VmCont; B.1.7. TVM state.The total state of TVM can be serialized as follows: vms\_init$00 cp:int16 step:int32 gas:GasLimits stack:(Maybe VmStack) save:VmSaveList code:VmCellSlice lib:VmLibraries = VmState; vms\_exception$01 cp:int16 step:int32 gas:GasLimits exc\_no:int32 exc\_arg:VmStackValue save:VmSaveList lib:VmLibraries = VmState; 143 B.2. Step function of TVM vms\_running$10 cp:int16 step:int32 gas:GasLimits stack:VmStack save:VmSaveList code:VmCellSlice lib:VmLibraries = VmState; vms\_finished$11 cp:int16 step:int32 gas:GasLimits exit\_code:int32 no\_gas:Boolean stack:VmStack save:VmSaveList lib:VmLibraries = VmState; When TVM is initialized, its state is described by avms\_init, usually with stepset to zero. The step function of TVM does nothing to avms\_finished state, and transforms all other states intovms\_running,vms\_exception, or vms\_finished, withstepincreased by one. B.2 Step function of TVM A formal specification of TVM would be completed by the definition of astep functionf:VmState→VmState. This function deterministically trans- forms a valid VM state into a valid subsequent VM state, and is allowed to throw exceptions or return an invalid subsequent state if the original state was invalid. B.2.1. A high-level definition of the step function.We might present a very long formal definition of the TVM step function in a high-level func- tional programming language. Such a specification, however, would mostly be useful as a reference for the (human) developers. We have chosen another approach, better adapted to automated formal verification by computers. B.2.2. An operational definition of the step function.Notice that the step functionfis a well-defined computable function from trees of cells into trees of cells. As such, it can be computed by a universal Turing machine. Then a programPcomputingfon such a machine would provide a machine- checkable specification of the step functionf. This programPeffectively is anemulatorof TVM on this Turing machine. B.2.3. A reference implementation of the TVM emulator inside TVM.We see that the step function of TVM may be defined by a reference implementation of a TVM emulator on another machine. An obvious idea is to use TVM itself, since it is well-adapted to working with trees of cells. However, an emulator of TVM inside itself is not very useful if we have doubts about a particular implementation of TVM and want to check it. For 144 B.2. Step function of TVM instance, if such an emulator interpreted aDICTISETinstruction simply by invoking this instruction itself, then a bug in the underlying implementation of TVM would remain unnoticed. B.2.4. Reference implementation inside a minimal version of TVM. We see that using TVM itself as a host machine for a reference implementa- tion of TVM emulator would yield little insight. A better idea is to define astripped-down version of TVM, which supports only the bare minimum of primitives and 64-bit integer arithmetic, and provide a reference imple- mentationPof the TVM step functionffor this stripped-down version of TVM. In that case, one must carefully implement and check only a handful of primitives to obtain a stripped-down version of TVM, and compare the reference implementationPrunning on this stripped-down version to the full custom TVM implementation being verified. In particular, if there are any doubts about the validity of a specific run of a custom TVM implementation, they can now be easily resolved with the aid of the reference implementation. B.2.5. Relevance for the TON Blockchain.The TON Blockchain adopts this approach to validate the runs of TVM (e.g., those used for processing inbound messages by smart contracts) when the validators’ results do not match one another. In this case, a reference implementation of TVM, stored inside the masterchain as a configurable parameter (thus defining the current revision of TVM), is used to obtain the correct result. B.2.6. Codepage−1.Codepage−1of TVM is reserved for the stripped- down version of TVM. Its main purpose is to execute the reference imple- mentation of the step function of the full TVM. This codepage contains only special versions of arithmetic primitives working with “tiny integers” (64-bit signed integers); therefore, TVM’s 257-bitIntegerarithmetic must be de- fined in terms of 64-bit arithmetic. Elliptic curve cryptography primitives are also implemented directly in codepage−1, without using any third-party libraries. Finally, a reference implementation of thesha256hash function is also provided in codepage−1. B.2.7. Codepage−2.This bootstrapping process could be iterated even further, by providing an emulator of the stripped-down version of TVM writ- ten for an even simpler version of TVM that supports only boolean values (or integers 0 and 1)—a “codepage−2”. All 64-bit arithmetic used in code- page−1would then need to be defined by means of boolean operations, thus 145 B.2. Step function of TVM providing a reference implementation for the stripped-down version of TVM used in codepage−1. In this way, if some of the TON Blockchain validators did not agree on the results of their 64-bit arithmetic, they could regress to this reference implementation to find the correct answer. 30 30 The preliminary version of TVM does not use codepage−2for this purpose. This may change in the future. 146 C.1. Sample leaf function C Code density of stack and register machines This appendix extends the general consideration of stack manipulation prim- itives provided in2.2, explaining the choice of such primitives for TVM, with a comparison of stack machines and register machines in terms of the quan- tity of primitives used and the code density. We do this by comparing the machine code that might be generated by an optimizing compiler for the same source files, for different (abstract) stack and register machines. It turns out that the stack machines (at least those equipped with the ba- sic stack manipulation primitives described in2.2.1) have far superior code density. Furthermore, the stack machines have excellent extendability with respect to additional arithmetic and arbitrary data processing operations, es- pecially if one considers machine code automatically generated by optimizing compilers. C.1 Sample leaf function We start with a comparison of machine code generated by an (imaginary) optimizing compiler for several abstract register and stack machines, cor- responding to the same high-level language source code that contains the definition of a leaf function (i.e., a function that does not call any other func- tions). For both the register machines and stack machines, we observe the notation and conventions introduced in2.1. C.1.1. Sample source file for a leaf function.The source file we consider contains one functionfthat takes six (integer) arguments,a,b,c,d,e,f, and returns two (integer) values,xandy, which are the solutions of the system of two linear equations { ax+by=e cx+dy=f (6) The source code of the function, in a programming language similar to C, might look as follows: (int, int) f(int a, int b, int c, int d, int e, int f) { int D = a\*d - b\*c; int Dx = e\*d - b\*f; int Dy = a\*f - e\*c; 147 C.1. Sample leaf function return (Dx / D, Dy / D); } We assume (cf.2.1) that the register machines we consider accept the six parametersa. . .fin registersr0. . .r5, and return the two valuesxandyin r0andr1. We also assume that the register machines have 16 registers, and that the stack machine can directly accesss0tos15by its stack manipu- lation primitives; the stack machine will accept the parameters ins5tos0, and return the two values ins0ands1, somewhat similarly to the register machine. Finally, we assume at first that the register machine is allowed to destroy values in all registers (which is slightly unfair towards the stack machine); this assumption will be revisited later. C.1.2. Three-address register machine.The machine code (or rather the corresponding assembly code) for a three-address register machine (cf.2.1.7) might look as follows: IMUL r6,r0,r3 // r6 := r0 \* r3 = ad IMUL r7,r1,r2 // r7 := bc SUB r6,r6,r7 // r6 := ad-bc = D IMUL r3,r4,r3 // r3 := ed IMUL r1,r1,r5 // r1 := bf SUB r3,r3,r1 // r3 := ed-bf = Dx IMUL r1,r0,r5 // r1 := af IMUL r7,r4,r2 // r7 := ec SUB r1,r1,r7 // r1 := af-ec = Dy IDIV r0,r3,r6 // x := Dx/D IDIV r1,r1,r6 // y := Dy/D RET We have used 12 operations and at least 23 bytes (each operation uses3×4 = 12bits to indicate the three registers involved, and at least 4 bits to indicate the operation performed; thus we need two or three bytes to encode each operation). A more realistic estimate would be 34 (three bytes for each arithmetic operation) or 31 bytes (two bytes for addition and subtraction, three bytes for multiplication and division). C.1.3. Two-address register machine.The machine code for a two- address register machine might look as follows: 148 C.1. Sample leaf function MOV r6,r0 // r6 := r0 = a MOV r7,r1 // r7 := b IMUL r6,r3 // r6 := r6\*r3 = ad IMUL r7,r2 // r7 := bc IMUL r3,r4 // r3 := de IMUL r1,r5 // r1 := bf SUB r6,r7 // r6 := ad-bc = D IMUL r5,r0 // r5 := af SUB r3,r1 // r3 := de-bf = Dx IMUL r2,r4 // r2 := ce MOV r0,r3 // r0 := Dx SUB r5,r2 // r5 := af-ce = Dy IDIV r0,r6 // r0 := x = Dx/D MOV r1,r5 // r1 := Dy IDIV r1,r6 // r1 := Dy/D RET We have used 16 operations; optimistically assuming each of them (with the exception ofRET) can be encoded by two bytes, this code would require 31 bytes. 31 C.1.4. One-address register machine.The machine code for a one- address register machine might look as follows: MOV r8,r0 // r8 := r0 = a XCHG r1 // r0 <-> r1; r0 := b, r1 := a MOV r6,r0 // r6 := b IMUL r2 // r0 := r0\*r2; r0 := bc MOV r7,r0 // r7 := bc MOV r0,r8 // r0 := a IMUL r3 // r0 := ad 31 It is interesting to compare this code with that generated by optimizing C compilers for the x86-64 architecture. First of all, the integer division operation for x86-64 uses the one-address form, with the (double-length) dividend to be supplied in accumulator pairr2:r0. The quotient is also returned inr0. As a consequence, two single-to-double extension operations (CDQor CQO) and at least one move operation need to be added. Secondly, the encoding used for arithmetic and move operations is less optimistic than in our example above, requiring about three bytes per operation on average. As a result, we obtain a total of 43 bytes for 32-bit integers, and 68 bytes for 64-bit integers. 149 C.1. Sample leaf function SUB r7 // r0 := ad-bc = D XCHG r1 // r1 := D, r0 := b IMUL r5 // r0 := bf XCHG r3 // r0 := d, r3 := bf IMUL r4 // r0 := de SUB r3 // r0 := de-bf = Dx IDIV r1 // r0 := Dx/D = x XCHG r2 // r0 := c, r2 := x IMUL r4 // r0 := ce XCHG r5 // r0 := f, r5 := ce IMUL r8 // r0 := af SUB r5 // r0 := af-ce = Dy IDIV r1 // r0 := Dy/D = y MOV r1,r0 // r1 := y MOV r0,r2 // r0 := x RET We have used 23 operations; if we assume one-byte encoding for all arithmetic operations andXCHG, and two-byte encodings forMOV, the total size of the code will be 29 bytes. Notice, however, that to obtain the compact code shown above we had to choose a specific order of computation, and made heavy use of the commutativity of multiplication. (For example, we compute bcbeforeaf, andaf−bcimmediately afteraf.) It is not clear whether a compiler would be able to make all such optimizations by itself. C.1.5. Stack machine with basic stack primitives.The machine code for a stack machine equipped with basic stack manipulation primitives de- scribed in2.2.1might look as follows: PUSH s5 // a b c d e f a PUSH s3 // a b c d e f a d IMUL // a b c d e f ad PUSH s5 // a b c d e f ad b PUSH s5 // a b c d e f ad b c IMUL // a b c d e f ad bc SUB // a b c d e f ad-bc XCHG s3 // a b c ad-bc e f d PUSH s2 // a b c ad-bc e f d e IMUL // a b c ad-bc e f de 150 C.1. Sample leaf function XCHG s5 // a de c ad-bc e f b PUSH s1 // a de c ad-bc e f b f IMUL // a de c ad-bc e f bf XCHG s1,s5 // a f c ad-bc e de bf SUB // a f c ad-bc e de-bf XCHG s3 // a f de-bf ad-bc e c IMUL // a f de-bf ad-bc ec XCHG s3 // a ec de-bf ad-bc f XCHG s1,s4 // ad-bc ec de-bf a f IMUL // D ec Dx af XCHG s1 // D ec af Dx XCHG s2 // D Dx af ec SUB // D Dx Dy XCHG s1 // D Dy Dx PUSH s2 // D Dy Dx D IDIV // D Dy x XCHG s2 // x Dy D IDIV // x y RET We have used 29 operations; assuming one-byte encodings for all stack oper- ations involved (includingXCHG s1,s(i)), we have used 29 code bytes as well. Notice that with one-byte encoding, the “unsystematic” operationROT(equiv- alent toXCHG s1; XCHG s2) would reduce the operation and byte count to 28. This shows that such “unsystematic” operations, borrowed from Forth, may indeed reduce the code size on some occasions. Notice as well that we have implicitly used the commutativity of multi- plication in this code, computingde−bfinstead ofed−bfas specified in high-level language source code. If we were not allowed to do so, an extra XCHG s1would need to be inserted before the thirdIMUL, increasing the total size of the code by one operation and one byte. The code presented above might have been produced by a rather unso- phisticated compiler that simply computed all expressions and subexpres- sions in the order they appear, then rearranged the arguments near the top of the stack before each operation as outlined in2.2.2. The only “manual” optimization done here involves computingecbeforeaf; one can check that the other order would lead to slightly shorter code of 28 operations and bytes (or 29, if we are not allowed to use the commutativity of multiplication), but 151 C.1. Sample leaf function theROToptimization would not be applicable. C.1.6. Stack machine with compound stack primitives.A stack ma- chine with compound stack primitives (cf.2.2.3) would not significantly improve code density of the code presented above, at least in terms of bytes used. The only difference is that, if we were not allowed to use commutativ- ity of multiplication, the extraXCHG s1inserted before the thirdIMULmight be combined with two previous operationsXCHG s3,PUSH s2into one com- pound operationPUXC s2,s3; we provide the resulting code below. To make this less redundant, we show a version of the code that computes subexpres- sionafbeforeecas specified in the original source file. We see that this replaces six operations (starting from line 15) with five other operations, and disables theROToptimization: PUSH s5 // a b c d e f a PUSH s3 // a b c d e f a d IMUL // a b c d e f ad PUSH s5 // a b c d e f ad b PUSH s5 // a b c d e f ad b c IMUL // a b c d e f ad bc SUB // a b c d e f ad-bc PUXC s2,s3 // a b c ad-bc e f e d IMUL // a b c ad-bc e f ed XCHG s5 // a ed c ad-bc e f b PUSH s1 // a ed c ad-bc e f b f IMUL // a ed c ad-bc e f bf XCHG s1,s5 // a f c ad-bc e ed bf SUB // a f c ad-bc e ed-bf XCHG s4 // a ed-bf c ad-bc e f XCHG s1,s5 // e Dx c D a f IMUL // e Dx c D af XCHG s2 // e Dx af D c XCHG s1,s4 // D Dx af e c IMUL // D Dx af ec SUB // D Dx Dy XCHG s1 // D Dy Dx PUSH s2 // D Dy Dx D IDIV // D Dy x XCHG s2 // x Dy D 152 C.1. Sample leaf function IDIV // x y RET We have used a total of 27 operations and 28 bytes, the same as the previous version (with theROToptimization). However, we did not use the commuta- tivity of multiplication here, so we can say that compound stack manipulation primitives enable us to reduce the code size from 29 to 28 bytes. Yet again, notice that the above code might have been generated by an unsophisticated compiler. Manual optimizations might lead to more com- pact code; for instance, we could use compound operations such asXCHG3 to prepare in advance not only the correct values ofs0ands1for the next arithmetic operation, but also the value ofs2for the arithmetic operation after that. The next section provides an example of such an optimization. C.1.7. Stack machine with compound stack primitives and manu- ally optimized code.The previous version of code for a stack machine with compound stack primitives can be manually optimized as follows. By interchangingXCHGoperations with precedingXCHG,PUSH, and arith- metic operations whenever possible, we obtain code fragmentXCHG s2,s6; XCHG s1,s0;XCHG s0,s5, which can then be replaced by compound oper- ationXCHG3 s6,s0,s5. This compound operation would admit a two-byte encoding, thus leading to 27-byte code using only 21 operations: PUSH2 s5,s2 // a b c d e f a d IMUL // a b c d e f ad PUSH2 s5,s4 // a b c d e f ad b c IMUL // a b c d e f ad bc SUB // a b c d e f ad-bc PUXC s2,s3 // a b c ad-bc e f e d IMUL // a b c D e f ed XCHG3 s6,s0,s5 // (same as XCHG s2,s6; XCHG s1,s0; XCHG s0,s5) // e f c D a ed b PUSH s5 // e f c D a ed b f IMUL // e f c D a ed bf SUB // e f c D a ed-bf XCHG s4 // e Dx c D a f IMUL // e Dx c D af XCHG2 s4,s2 // D Dx af e c IMUL // D Dx af ec 153 C.2. Comparison of machine code for sample leaf function SUB // D Dx Dy XCPU s1,s2 // D Dy Dx D IDIV // D Dy x XCHG s2 // x Dy D IDIV // x y RET It is interesting to note that this version of stack machine code contains only 9 stack manipulation primitives for 11 arithmetic operations. It is not clear, however, whether an optimizing compiler would be able to reorganize the code in such a manner by itself. C.2 Comparison of machine code for sample leaf func- tion Table1summarizes the properties of machine code corresponding to the same source file described inC.1.1, generated for a hypothetical three-address register machine (cf.C.1.2), with both “optimistic” and “realistic” instruc- tion encodings; a two-address machine (cf.C.1.3); a one-address machine (cf.C.1.4); and a stack machine, similar to TVM, using either only the basic stack manipulation primitives (cf.C.1.5) or both the basic and the composite stack primitives (cf.C.1.7). The meaning of the columns in Table1is as follows: •“Operations” — The quantity of instructions used, split into “data” (i.e., register move and exchange instructions for register machines, and stack manipulation instructions for stack machines) and “arithmetic” (instructions for adding, subtracting, multiplying and dividing integer numbers). The “total” is one more than the sum of these two, because there is also a one-byteRETinstruction at the end of machine code. •“Code bytes” — The total amount of code bytes used. •“Opcode space” — The portion of “opcode space” (i.e., of possible choices for the first byte of the encoding of an instruction) used by data and arithmetic instructions in the assumed instruction encoding. For example, the “optimistic” encoding for the three-address machine assumes two-byte encodings for all arithmetic instructionsopr(i), r(j), r(k). Each arithmetic instruction would then consume portion 154 C.2. Comparison of machine code for sample leaf function OperationsCode bytesOpcode space Machinedata arith totaldata arithtotaldataarithtotal 3-addr. (opt.)01112022230/25664/25665/256 3-addr. (real.)01112030310/25634/25635/256 2-addr.41116822311/2564/2566/256 1-addr.11112317112917/25664/25682/256 stack (basic)16112816112864/2564/25669/256 stack (comp.)9112115112784/2564/25689/256 Table 1: A summary of machine code properties for hypothetical 3-address, 2-address, 1-address, and stack machines, generated for a sample leaf function (cf.C.1.1). The two most important columns, reflectingcode densityandextendabilityto other operations, are marked by bold font. Smaller values are better in both of these columns. 16/256 = 1/16of the opcode space. Notice that for the stack ma- chine we have assumed one-byte encodings forXCHG s(i),PUSH s(i) andPOP s(i)in all cases, augmented byXCHG s1,s(i)for the basic stack instructions case only. As for the compound stack operations, we have assumed two-byte encodings forPUSH3,XCHG3,XCHG2,XCPU, PUXC,PUSH2, but not forXCHG s1,s(i). The “code bytes” column reflects the density of the code for the specific sample source. However, “opcode space” is also important, because it reflects the extendability of the achieved density to other classes of operations (e.g., if one were to complement arithmetic operations with string manipulation operations and so on). Here the “arithmetic” subcolumn is more important than the “data” subcolumn, because no further data manipulation operations would be required for such extensions. We see that the three-address register machine with the “optimistic” en- coding, assuming two-byte encodings for all three-register arithmetic opera- tions, achieves the best code density, requiring only 23 bytes. However, this comes at a price: each arithmetic operation consumes 1/16 of the opcode space, so the four operations already use a quarter of the opcode space. At most 11 other operations, arithmetic or not, might be added to this architec- ture while preserving such high code density. On the other hand, when we consider the “realistic” encoding for the three-address machine, using two- byte encodings only for the most frequently used addition/subtraction oper- ations (and longer encodings for less frequently used multiplication/division operations, reflecting the fact that the possible extension operations would likely fall in this class), then the three-address machine ceases to offer such 155 C.2. Comparison of machine code for sample leaf function attractive code density. In fact, the two-address machine becomes equally attractive at this point: it is capable of achieving the same code size of 31 bytes as the three-address machine with the “realistic” encoding, using only 6/256 of the opcode space for this! However, 31 bytes is the worst result in this table. The one-address machine uses 29 bytes, slightly less than the two-address machine. However, it utilizes a quarter of the opcode space for its arithmetic operations, hampering its extendability. In this respect it is similar to the three-address machine with the “optimistic” encoding, but requires 29 bytes instead of 23! So there is no reason to use the one-address machine at all, in terms of extendability (reflected by opcode space used for arithmetic opera- tions) compared to code density. Finally, the stack machine wins the competition in terms of code density (27 or 28 bytes), losing only to the three-address machine with the “opti- mistic” encoding (which, however, is terrible in terms of extendability). To summarize: the two-address machine and stack machine achieve the best extendability with respect to additional arithmetic or data processing instructions (using only 1/256 of code space for each such instruction), while the stack machine additionally achieves the best code density by a small margin. The stack machine utilizes a significant part of its code space (more than a quarter) for data (i.e., stack) manipulation instructions; however, this does not seriously hamper extendability, because the stack manipulation instructions occupy a constant part of the opcode stace, regardless of all other instructions and extensions. While one might still be tempted to use a two-address register machine, we will explain shortly (cf.C.3) why the two-address register machine offers worse code density and extendability in practice than it appears based on this table. As for the choice between a stack machine with only basic stack manip- ulation primitives or one supporting compound stack primitives as well, the case for the more sophisticated stack machine appears to be weaker: it offers only one or two fewer bytes of code at the expense of using considerably more opcode space for stack manipulation, and the optimized code using these ad- ditional instructions is hard for programmers to write and for compilers to automatically generate. C.2.1. Register calling conventions: some registers must be pre- served by functions.Up to this point, we have considered the machine 156 C.2. Comparison of machine code for sample leaf function code of only one function, without taking into account the interplay between this function and other functions in the same program. Usually a program consists of more than one function, and when a func- tion is not a “simple” or “leaf” function, it must call other functions. There- fore, it becomes important whether a called function preserves all or at least some registers. If it preserves all registers except those used to return re- sults, the caller can safely keep its local and temporary variables in certain registers; however, the callee needs to save all the registers it will use for its temporary values somewhere (usually into the stack, which also exists on register machines), and then restore the original values. On the other hand, if the called function is allowed to destroy all registers, it can be written in the manner described inC.1.2,C.1.3, andC.1.4, but the caller will now be responsible for saving all its temporary values into the stack before the call, and restoring these values afterwards. In most cases, calling conventions for register machines require preserva- tion of some but not all registers. We will assume thatm≤nregisters will be preserved by functions (unless they are used for return values), and that these registers arer(n−m)...r(n−1). Casem= 0corresponds to the case “the callee is free to destroy all registers” considered so far; it is quite painful for the caller. Casem=ncorresponds to the case “the callee must preserve all registers”; it is quite painful for the callee, as we will see in a moment. Usually a value ofmaroundn/2is used in practice. The following sections consider casesm= 0,m= 8, andm= 16for our register machines withn= 16registers. C.2.2. Casem= 0: no registers to preserve.This case has been considered and summarized inC.2and Table1above. C.2.3. Casem=n= 16: all registers must be preserved.This case is the most painful one for the called function. It is especially difficult for leaf functions like the one we have been considering, which do not benefit at all from the fact that other functions preserve some registers when called—they do not call any functions, but instead must preserve all registers themselves. In order to estimate the consequences of assumingm=n= 16, we will assume that all our register machines are equipped with a stack, and with one-byte instructionsPUSH r(i)andPOP r(i), which push or pop a register into/from the stack. For example, the three-address machine code provided inC.1.2destroys the values in registersr2,r3,r6, andr7; this means that the code of this function must be augmented by four instructionsPUSH 157 C.2. Comparison of machine code for sample leaf function OperationsCode bytesOpcode space Machinerdata arith totaldata arithtotaldataarithtotal 3-addr. (opt.)4811 208223132/25664/25697/256 3-addr. (real.)4811 208303932/25634/25667/256 2-addr.514 11 2618 224133/2564/25638/256 1-addr.623 11 3529 114149/25664/256114/256 stack (basic)016 11 2816 112864/2564/25669/256 stack (comp.)0911 2115 112784/2564/25689/256 Table 2: A summary of machine code properties for hypothetical 3-address, 2-address, 1- address, and stack machines, generated for a sample leaf function (cf.C.1.1), assuming all of the 16 registers must be preserved by called functions (m=n= 16). The new column labeledrdenotes the number of registers to be saved and restored, leading to2rmore operations and code bytes compared to Table1. Newly-addedPUSHandPOPinstructions for register machines also utilize32/256of the opcode space. The two rows corresponding to stack machines remain unchanged. r2;PUSH r3;PUSH r6;PUSH r7at the beginning, and by four instructions POP r7;POP r6;POP r3;POP r2right before theRETinstruction, in order to restore the original values of these registers from the stack. These four additionalPUSH/POPpairs would increase the operation count and code size in bytes by4×2 = 8. A similar analysis can be done for other register machines as well, leading to Table2. We see that under these assumptions the stack machines are the obvious winners in terms of code density, and are in the winning group with respect to extendability. C.2.4. Casem= 8,n= 16: registersr8. . .r15must be preserved. The analysis of this case is similar to the previous one. The results are summarized in Table3. Notice that the resulting table is very similar to Table1, apart from the “Opcode space” columns and the row for the one-address machine. Therefore, the conclusions ofC.2still apply in this case, with some minor modifications. We must emphasize, however, thatthese conclusions are valid only for leaf functions, i.e., functions that do not call other functions. Any program aside from the very simplest will have many non-leaf functions, especially if we are minimizing resulting machine code size (which prevents inlining of functions in most cases). C.2.5. A fairer comparison using a binary code instead of a byte code.The reader may have noticed that our preceding discussion ofk- 158 C.3. Sample non-leaf function OperationsCode bytesOpcode space Machinerdata arith totaldata arithtotaldataarithtotal 3-addr. (opt.)0011 120222332/25664/25697/256 3-addr. (real.)0011 120303132/25634/25667/256 2-addr.0411 168223133/2564/25638/256 1-addr.113 11 2519 113149/25664/256114/256 stack (basic)016 11 2816 112864/2564/25669/256 stack (comp.)0911 2115 112784/2564/25689/256 Table 3: A summary of machine code properties for hypothetical 3-address, 2-address, 1-address and stack machines, generated for a sample leaf function (cf.C.1.1), assuming that only the last 8 of the 16 registers must be preserved by called functions (m= 8, n= 16). This table is similar to Table2, but has smaller values ofr. address register machines and stack machines depended very much on our insistence that complete instructions be encoded by an integer number of bytes. If we had been allowed to use a “bit” or “binary code” instead of a byte code for encoding instructions, we could more evenly balance the opcode space used by different machines. For instance, the opcode ofSUBfor a three- address machine had to be either 4-bit (good for code density, bad for opcode space) or 12-bit (very bad for code density), because the complete instruction has to occupy a multiple of eight bits (e.g., 16 or 24 bits), and3·4 = 12of those bits have to be used for the three register names. Therefore, let us get rid of this restriction. Now that we can use any number of bits to encode an instruction, we can choose all opcodes of the same length for all the machines considered. For instance, all arithmetic instructions can have 8-bit opcodes, as the stack machine does, using1/256of the opcode space each; then the three-address register machine will use 20 bits to encode each complete arithmetic instruc- tion. AllMOVs,XCHGs,PUSHes, andPOPs on register machines can be assumed to have 4-bit opcodes, because this is what we do for the most common stack manipulation primitives on a stack machine. The results of these changes are shown in Table4. We can see that the performance of the various machines is much more balanced, with the stack machine still the winner in terms of the code density, but with the three-address machine enjoying the second place it really merits. If we were to consider the decoding speed and the possibility of parallel execution of instructions, we would have to choose the three-address machine, because it uses only 12 instructions instead of 21. 159 C.3. Sample non-leaf function OperationsCode bytesOpcode space Machinerdata arith totaldata arithtotaldataarithtotal 3-addr.0011 120 27.528.564/2564/25669/256 2-addr.0411 166222964/2564/25669/256 1-addr.113 11 2516 16.532.564/2564/25669/256 stack (basic)016 11 2816 112864/2564/25669/256 stack (comp.)0911 2115 112784/2564/25689/256 Table 4: A summary of machine code properties for hypothetical 3-address, 2-address, 1-address and stack machines, generated for a sample leaf function (cf.C.1.1), assuming that only 8 of the 16 registers must be preserved by functions (m= 8,n= 16). This time we can use fractions of bytes to encode instructions, so as to match opcode space used by different machines. All arithmetic instructions have 8-bit opcodes, all data/stack manipulation instructions have 4-bit opcodes. In other respects this table is similar to Table3. C.3 Sample non-leaf function This section compares the machine code for different register machines for a sample non-leaf function. Again, we assume that eitherm= 0,m= 8, or m= 16registers are preserved by called functions, withm= 8representing the compromise made by most modern compilers and operating systems. C.3.1. Sample source code for a non-leaf function.A sample source file may be obtained by replacing the built-in integer type with a customRational type, represented by a pointer to an object in memory, in our function for solving systems of two linear equations (cf.C.1.1): struct Rational; typedef struct Rational \*num; extern num r\_add(num, num); extern num r\_sub(num, num); extern num r\_mul(num, num); extern num r\_div(num, num); (num, num) r\_f(num a, num b, num c, num d, num e, num f) { num D = r\_sub(r\_mul(a, d), r\_mul(b, c)); // a\*d-b\*c num Dx = r\_sub(r\_mul(e, d), r\_mul(b, f)); // e\*d-b\*f num Dy = r\_sub(r\_mul(a, f), r\_mul(e, c)); // a\*f-e\*c return (r\_div(Dx, D), r\_div(Dy, D)); // Dx/D, Dy/D } 160 C.3. Sample non-leaf function We will ignore all questions related to allocating new objects of typeRational in memory (e.g., in heap), and to preventing memory leaks. We may assume that the called subroutinesr\_sub,r\_mul, and so on allocate new objects simply by advancing some pointer in a pre-allocated buffer, and that unused objects are later freed by a garbage collector, external to the code being analysed. Rational numbers will now be represented by pointers, addresses, or ref- erences, which will fit into registers of our hypothetical register machines or into the stack of our stack machines. If we want to use TVM as an instance of these stack machines, we should use values of typeCellto represent such references to objects of typeRationalin memory. We assume that subroutines (or functions) are called by a specialCALL instruction, which is encoded by three bytes, including the specification of the function to be called (e.g., the index in a “global function table”). C.3.2. Three-address and two-address register machines,m= 0pre- served registers.Because our sample function does not use built-in arith- metic instructions at all, compilers for our hypothetical three-address and two-address register machines will produce the same machine code. Apart from the previously introducedPUSH r(i)andPOP r(i)one-byte instructions, we assume that our two- and three-address machines support the following two-byte instructions:MOV r(i),s(j),MOV s(j),r(i), andXCHG r(i),s(j), for 0≤i,j≤15. Such instructions occupy only 3/256 of the opcode space, so their addition seems quite natural. We first assume thatm= 0(i.e., that all subroutines are free to destroy the values of all registers). In this case, our machine code forr\_fdoes not have to preserve any registers, but has to save all registers containing useful values into the stack before calling any subroutines. A size-optimizing compiler might produce the following code: PUSH r4 // STACK: e PUSH r1 // STACK: e b PUSH r0 // .. e b a PUSH r6 // .. e b a f PUSH r2 // .. e b a f c PUSH r3 // .. e b a f c d MOV r0,r1 // b MOV r1,r2 // c CALL r\_mul // bc 161 C.3. Sample non-leaf function PUSH r0 // .. e b a f c d bc MOV r0,s4 // a MOV r1,s1 // d CALL r\_mul // ad POP r1 // bc; .. e b a f c d CALL r\_sub // D:=ad-bc XCHG r0,s4 // b ; .. e D a f c d MOV r1,s2 // f CALL r\_mul // bf POP r1 // d ; .. e D a f c PUSH r0 // .. e D a f c bf MOV r0,s5 // e CALL r\_mul // ed POP r1 // bf; .. e D a f c CALL r\_sub // Dx:=ed-bf XCHG r0,s4 // e ; .. Dx D a f c POP r1 // c ; .. Dx D a f CALL r\_mul // ec XCHG r0,s1 // a ; .. Dx D ec f POP r1 // f ; .. Dx D ec CALL r\_mul // af POP r1 // ec; .. Dx D CALL r\_sub // Dy:=af-ec XCHG r0,s1 // Dx; .. Dy D MOV r1,s0 // D CALL r\_div // x:=Dx/D XCHG r0,s1 // Dy; .. x D POP r1 // D ; .. x CALL r\_div // y:=Dy/D MOV r1,r0 // y POP r0 // x ; .. RET We have used 41 instructions: 17 one-byte (eightPUSH/POPpairs and one RET), 13 two-byte (MOVandXCHG; out of them 11 “new” ones, involving the stack), and 11 three-byte (CALL), for a total of17·1 + 13·2 + 11·3 = 76 bytes. 32 32 Code produced for this function by an optimizing compiler for x86-64 architecture 162 C.3. Sample non-leaf function C.3.3. Three-address and two-address register machines,m= 8 preserved registers.Now we have eight registers,r8tor15, that are preserved by subroutine calls. We might keep some intermediate values there instead of pushing them into the stack. However, the penalty for doing so consists in aPUSH/POPpair for every such register that we choose to use, because our function is also required to preserve its original value. It seems that using these registers under such a penalty does not improve the density of the code, so the optimal code for three- and two-address machines for m= 8preserved registers is the same as that provided inC.3.2, with a total of 42 instructions and 74 code bytes. C.3.4. Three-address and two-address register machines,m= 16 preserved registers.This timeallregisters must be preserved by the subroutines, excluding those used for returning the results. This means that our code must preserve the original values ofr2tor5, as well as any other registers it uses for temporary values. A straightforward way of writing the code of our subroutine would be to push registersr2up to, say,r8into the stack, then perform all the operations required, usingr6–r8for intermediate values, and finally restore registers from the stack. However, this would not optimize code size. We choose another approach: PUSH r0 // STACK: a PUSH r1 // STACK: a b MOV r0,r1 // b MOV r1,r2 // c CALL r\_mul // bc PUSH r0 // .. a b bc MOV r0,s2 // a MOV r1,r3 // d CALL r\_mul // ad POP r1 // bc; .. a b CALL r\_sub // D:=ad-bc XCHG r0,s0 // b; .. a D MOV r1,r5 // f CALL r\_mul // bf PUSH r0 // .. a D bf with size-optimization enabled actually occupied 150 bytes, due mostly to the fact that actual instruction encodings are about twice as long as we had optimistically assumed. 163 C.3. Sample non-leaf function MOV r0,r4 // e MOV r1,r3 // d CALL r\_mul // ed POP r1 // bf; .. a D CALL r\_sub // Dx:=ed-bf XCHG r0,s1 // a ; .. Dx D MOV r1,r5 // f CALL r\_mul // af PUSH r0 // .. Dx D af MOV r0,r4 // e MOV r1,r2 // c CALL r\_mul // ec MOV r1,r0 // ec POP r0 // af; .. Dx D CALL r\_sub // Dy:=af-ec XCHG r0,s1 // Dx; .. Dy D MOV r1,s0 // D CALL r\_div // x:=Dx/D XCHG r0,s1 // Dy; .. x D POP r1 // D ; .. x CALL r\_div // y:=Dy/D MOV r1,r0 // y POP r0 // x RET We have used 39 instructions: 11 one-byte, 17 two-byte (among them 5 “new” instructions), and 11 three-byte, for a total of11·1 + 17·2 + 11·3 = 78 bytes. Somewhat paradoxically, the code size in bytes is slightly longer than in the previous case (cf.C.3.2), contrary to what one might have expected. This is partially due to the fact that we have assumed two-byte encodings for “new”MOVandXCHGinstructions involving the stack, similarly to the “old” instructions. Most existing architectures (such as x86-64) use longer encod- ings (maybe even twice as long) for their counterparts of our “new” move and exchange instructions compared to the “usual” register-register ones. Taking this into account, we see that we would have obtained here 83 bytes (versus 87 for the code inC.3.2) assuming three-byte encodings of new operations, and 88 bytes (versus 98) assuming four-byte encodings. This shows that, for two-address architectures without optimized encodings for register-stack 164 C.3. Sample non-leaf function move and exchange operations,m= 16preserved registers might result in slightly shorter code for some non-leaf functions, at the expense of leaf func- tions (cf.C.2.3andC.2.4), which would become considerably longer. C.3.5. One-address register machine,m= 0preserved registers. For our one-address register machine, we assume that new register-stack in- structions work through the accumulator only. Therefore, we have three new instructions,LD s(j)(equivalent toMOV r0,s(j)of two-address ma- chines),ST s(j)(equivalent toMOV s(j),r0), andXCHG s(j)(equivalent to XCHG r0,s(j)). To make the comparison with two-address machines more interesting, we assume one-byte encodings for these new instructions, even though this would consume48/256 = 3/16of the opcode space. By adapting the code provided inC.3.2to the one-address machine, we obtain the following: PUSH r4 // STACK: e PUSH r1 // STACK: e b PUSH r0 // .. e b a PUSH r6 // .. e b a f PUSH r2 // .. e b a f c PUSH r3 // .. e b a f c d LD s1 // r0:=c XCHG r1 // r0:=b, r1:=c CALL r\_mul // bc PUSH r0 // .. e b a f c d bc LD s1 // d XCHG r1 // r1:=d LD s4 // a CALL r\_mul // ad POP r1 // bc; .. e b a f c d CALL r\_sub // D:=ad-bc XCHG s4 // b ; .. e D a f c d XCHG r1 LD s2 // f XCHG r1 // r0:=b, r1:=f CALL r\_mul // bf POP r1 // d ; .. e D a f c PUSH r0 // .. e D a f c bf LD s5 // e 165 C.3. Sample non-leaf function CALL r\_mul // ed POP r1 // bf; .. e D a f c CALL r\_sub // Dx:=ed-bf XCHG s4 // e ; .. Dx D a f c POP r1 // c ; .. Dx D a f CALL r\_mul // ec XCHG s1 // a ; .. Dx D ec f POP r1 // f ; .. Dx D ec CALL r\_mul // af POP r1 // ec; .. Dx D CALL r\_sub // Dy:=af-ec XCHG s1 // Dx; .. Dy D POP r1 // D ; .. Dy PUSH r1 // .. Dy D CALL r\_div // x:=Dx/D XCHG s1 // Dy; .. x D POP r1 // D ; .. x CALL r\_div // y:=Dy/D XCHG r1 // r1:=y POP r0 // r0:=x ; .. RET We have used 45 instructions: 34 one-byte and 11 three-byte, for a total of 67 bytes. Compared to the 76 bytes used by two- and three-address machines inC.3.2, we see that, again, the one-address register machine code may be denser than that of two-register machines, at the expense of utilizing more opcode space (just as shown inC.2). However, this time the extra 3/16 of the opcode space was used for data manipulation instructions, which do not depend on specific arithmetic operations or user functions invoked. C.3.6. One-address register machine,m= 8preserved registers. As explained inC.3.3, the preservation ofr8–r15between subroutine calls does not improve the size of our previously written code, so the one-address machine will use form= 8the same code provided inC.3.5. C.3.7. One-address register machine,m= 16preserved registers. We simply adapt the code provided inC.3.4to the one-address register machine: PUSH r0 // STACK: a 166 C.3. Sample non-leaf function PUSH r1 // STACK: a b MOV r0,r1 // b MOV r1,r2 // c CALL r\_mul // bc PUSH r0 // .. a b bc LD s2 // a MOV r1,r3 // d CALL r\_mul // ad POP r1 // bc; .. a b CALL r\_sub // D:=ad-bc XCHG s0 // b; .. a D MOV r1,r5 // f CALL r\_mul // bf PUSH r0 // .. a D bf MOV r0,r4 // e MOV r1,r3 // d CALL r\_mul // ed POP r1 // bf; .. a D CALL r\_sub // Dx:=ed-bf XCHG s1 // a ; .. Dx D MOV r1,r5 // f CALL r\_mul // af PUSH r0 // .. Dx D af MOV r0,r4 // e MOV r1,r2 // c CALL r\_mul // ec MOV r1,r0 // ec POP r0 // af; .. Dx D CALL r\_sub // Dy:=af-ec XCHG s1 // Dx; .. Dy D POP r1 // D ; .. Dy PUSH r1 // .. Dy D CALL r\_div // x:=Dx/D XCHG s1 // Dy; .. x D POP r1 // D ; .. x CALL r\_div // y:=Dy/D MOV r1,r0 // y POP r0 // x 167 C.3. Sample non-leaf function RET We have used 40 instructions: 18 one-byte, 11 two-byte, and 11 three-byte, for a total of18·1 + 11·2 + 11·3 = 73bytes. C.3.8. Stack machine with basic stack primitives.We reuse the code provided inC.1.5, simply replacing arithmetic primitives (VM instructions) with subroutine calls. The only substantive modification is the insertion of the previously optionalXCHG s1before the third multiplication, because even an optimizing compiler cannot now know whetherCALL r\_mulis a commutative operation. We have also used the “tail recursion optimization” by replacing the finalCALL r\_divfollowed byRETwithJMP r\_div. PUSH s5 // a b c d e f a PUSH s3 // a b c d e f a d CALL r\_mul // a b c d e f ad PUSH s5 // a b c d e f ad b PUSH s5 // a b c d e f ad b c CALL r\_mul // a b c d e f ad bc CALL r\_sub // a b c d e f ad-bc XCHG s3 // a b c ad-bc e f d PUSH s2 // a b c ad-bc e f d e XCHG s1 // a b c ad-bc e f e d CALL r\_mul // a b c ad-bc e f ed XCHG s5 // a ed c ad-bc e f b PUSH s1 // a ed c ad-bc e f b f CALL r\_mul // a ed c ad-bc e f bf XCHG s1,s5 // a f c ad-bc e ed bf CALL r\_sub // a f c ad-bc e ed-bf XCHG s3 // a f ed-bf ad-bc e c CALL r\_mul // a f ed-bf ad-bc ec XCHG s3 // a ec ed-bf ad-bc f XCHG s1,s4 // ad-bc ec ed-bf a f CALL r\_mul // D ec Dx af XCHG s1 // D ec af Dx XCHG s2 // D Dx af ec CALL r\_sub // D Dx Dy XCHG s1 // D Dy Dx PUSH s2 // D Dy Dx D 168 C.4. Comparison of machine code for sample non-leaf function CALL r\_div // D Dy x XCHG s2 // x Dy D JMP r\_div // x y We have used 29 instructions; assuming one-byte encodings for all stack operations, and three-byte encodings forCALLandJMPinstructions, we end up with 51 bytes. C.3.9. Stack machine with compound stack primitives.We again reuse the code provided inC.1.7, replacing arithmetic primitives with sub- routine calls and making the tail recursion optimization: PUSH2 s5,s2 // a b c d e f a d CALL r\_mul // a b c d e f ad PUSH2 s5,s4 // a b c d e f ad b c CALL r\_mul // a b c d e f ad bc CALL r\_sub // a b c d e f ad-bc PUXC s2,s3 // a b c ad-bc e f e d CALL r\_mul // a b c D e f ed XCHG3 s6,s0,s5 // (same as XCHG s2,s6; XCHG s1,s0; XCHG s0,s5) // e f c D a ed b PUSH s5 // e f c D a ed b f CALL r\_mul // e f c D a ed bf CALL r\_sub // e f c D a ed-bf XCHG s4 // e Dx c D a f CALL r\_mul // e Dx c D af XCHG2 s4,s2 // D Dx af e c CALL r\_mul // D Dx af ec CALL r\_sub // D Dx Dy XCPU s1,s2 // D Dy Dx D CALL r\_div // D Dy x XCHG s2 // x Dy D JMP r\_div // x y This code uses only 20 instructions, 9 stack-related and 11 control flow- related (CALLandJMP), for a total of 48 bytes. 169 C.4. Comparison of machine code for sample non-leaf function OperationsCode bytesOpcode space Machinemdata cont. totaldata cont.totaldataarithtotal 3-addr. 0,829 12 4142 3476 35/25634/25672/256 1627 12 3944 3478 2-addr. 0,829 12 4142 3476 37/2564/25644/256 1627 12 3944 3478 1-addr. 0,833 12 4533 3467 97/25664/256164/256 1628 12 4039 3473 stack (basic)−18 11 2918 335164/2564/25671/256 stack (comp.)−911 2015 334884/2564/25691/256 Table 5: A summary of machine code properties for hypothetical 3-address, 2-address, 1-address, and stack machines, generated for a sample non-leaf function (cf.C.3.1), assumingmof the 16 registers must be preserved by called subroutines. C.4 Comparison of machine code for sample non-leaf function Table5summarizes the properties of machine code corresponding to the same source file provided inC.3.1. We consider only the “realistically” encoded three-address machines. Three-address and two-address machines have the same code density properties, but differ in the utilization of opcode space. The one-address machine, somewhat surprisingly, managed to pro- duced shorter code than the two-address and three-address machines, at the expense of using up more than half of all opcode space. The stack machine is the obvious winner in this code density contest, without compromizing its excellent extendability (measured in opcode space used for arithmetic and other data transformation instructions). C.4.1. Combining with results for leaf functions.It is instructive to compare this table with the results inC.2for a sample leaf function, summarized in Table1(form= 0preserved registers) and the very similar Table3(form= 8preserved registers), and, if one is still interested in case m= 16(which turned out to be worse thanm= 8in almost all situations), also to Table2. We see that the stack machine beats all register machines on non-leaf functions. As for the leaf functions, only the three-address machine with the “optimistic” encoding of arithmetic instructions was able to beat the stack machine, winning by 15%, by compromising its extendability. However, the same three-address machine produces 25% longer code for non-leaf functions. 170 C.4. Comparison of machine code for sample non-leaf function OperationsCode bytesOpcode space Machinemdata cont. totaldata cont.totaldataarithtotal 3-addr. 0,829 12 4135.5 3469.5 110/2564/256117/256 1627 12 3935.5 3469.5 2-addr. 0,829 12 4135.5 3469.5 110/2564/256117/256 1627 12 3935.5 3469.5 1-addr. 0,833 12 4533 3467 112/2564/256119/256 1628 12 4033.5 3467.5 stack (basic)−18 11 2918 335164/2564/25671/256 stack (comp.)−911 2015 334884/2564/25691/256 Table 6: A summary of machine code properties for hypothetical 3-address, 2-address, 1-address, and stack machines, generated for a sample non-leaf function (cf.C.3.1), assumingmof the 16 registers must be preserved by called subroutines. This time we use fractions of bytes to encode instructions, enabling a fairer comparison. Otherwise, this table is similar to Table5. If a typical program consists of a mixture of leaf and non-leaf functions in approximately equal proportion, then the stack machine will still win. C.4.2. A fairer comparison using a binary code instead of a byte code.Similarly toC.2.5, we may offer a fairer comparison of different register machines and the stack machine by using arbitrary binary codes instead of byte codes to encode instructions, and matching the opcode space used for data manipulation and arithmetic instructions by different machines. The results of this modified comparison are summarized in Table6. We see that the stack machines still win by a large margin, while using less opcode space for stack/data manipulation. C.4.3. Comparison with real machines.Note that our hypothetical register machines have been considerably optimized to produce shorter code than actually existing register machines; the latter are subject to other design considerations apart from code density and extendability, such as backward compatibility, faster instruction decoding, parallel execution of neighboring instructions, ease of automatically producing optimized code by compilers, and so on. For example, the very popular two-address register architecture x86-64 produces code that is approximately twice as long as our “ideal” results for the two-address machines. On the other hand, our results for the stack machines are directly applicable to TVM, which has been explicitly designed with the considerations presented in this appendix in mind. Furthermore, the 171 C.4. Comparison of machine code for sample non-leaf function actual TVM code is evenshorter(in bytes) than shown in Table5because of the presence of the two-byteCALLinstruction, allowing TVM to call up to 256 user-defined functions from the dictionary atc3. This means that one should subtract 10 bytes from the results for stack machines in Table5if one wants to specifically consider TVM, rather than an abstract stack machine; this produces a code size of approximately 40 bytes (or shorter), almost half that of an abstract two-address or three-address machine. C.4.4. Automatic generation of optimized code.An interesting point is that the stack machine code in our samples might have been generated automatically by a very simple optimizing compiler, which rearranges values near the top of the stack appropriately before invoking each primitive or calling a function as explained in2.2.2and2.2.5. The only exception is the unimportant “manual”XCHG3optimization described inC.1.7, which enabled us to shorten the code by one more byte. By contrast, the heavily optimized (with respect to size) code for register machines shown inC.3.2andC.3.3is unlikely to be produced automati- cally by an optimizing compiler. Therefore, if we had compared compiler- generated code instead of manually-generated code, the advantages of stack machines with respect to code density would have been even more striking. 172 --- # Unknown \# TON Docs ## Docs - \[Blueprint TypeScript API\](https://docs.ton.org/contract-dev/blueprint/api.md) - \[Benchmarking performance\](https://docs.ton.org/contract-dev/blueprint/benchmarks.md) - \[Blueprint CLI\](https://docs.ton.org/contract-dev/blueprint/cli.md) - \[Configuring Blueprint\](https://docs.ton.org/contract-dev/blueprint/config.md) - \[Collecting test coverage\](https://docs.ton.org/contract-dev/blueprint/coverage.md) - \[Deployment and interaction\](https://docs.ton.org/contract-dev/blueprint/deploy.md) - \[Smart contract development\](https://docs.ton.org/contract-dev/blueprint/develop.md) - \[Blueprint overview\](https://docs.ton.org/contract-dev/blueprint/overview.md) - \[Contract sharding\](https://docs.ton.org/contract-dev/contract-sharding.md) - \[Debugging smart contracts\](https://docs.ton.org/contract-dev/debug.md) - \[Your first smart contract\](https://docs.ton.org/contract-dev/first-smart-contract.md) - \[Estimate gas usage in TON contracts\](https://docs.ton.org/contract-dev/gas.md) - \[TON plugin for IDEs from JetBrains\](https://docs.ton.org/contract-dev/ide/jetbrains.md) - \[IDEs and editor plugins for smart contract development\](https://docs.ton.org/contract-dev/ide/overview.md) - \[TON extension for Visual Studio Code (VS Code) and VSCode-based editors\](https://docs.ton.org/contract-dev/ide/vscode.md) - \[On-chain Jetton processing\](https://docs.ton.org/contract-dev/on-chain-jetton-processing.md) - \[Random number generation\](https://docs.ton.org/contract-dev/random.md) - \[Security best practices\](https://docs.ton.org/contract-dev/security.md) - \[Signing messages\](https://docs.ton.org/contract-dev/signing.md) - \[Overview\](https://docs.ton.org/contract-dev/testing/overview.md) - \[Reference\](https://docs.ton.org/contract-dev/testing/reference.md) - \[Upgrading contracts\](https://docs.ton.org/contract-dev/upgrades.md) - \[Using on-chain libraries\](https://docs.ton.org/contract-dev/using-on-chain-libraries.md) - \[How to use a vanity contract\](https://docs.ton.org/contract-dev/vanity.md) - \[Zero-knowledge proofs on TON\](https://docs.ton.org/contract-dev/zero-knowledge.md) - \[Aside component\](https://docs.ton.org/contribute/snippets/aside.md) - \[FileTree component\](https://docs.ton.org/contribute/snippets/filetree.md) - \[Image component\](https://docs.ton.org/contribute/snippets/image.md) - \[Using components and snippets\](https://docs.ton.org/contribute/snippets/overview.md) - \[Documentation style guide\](https://docs.ton.org/contribute/style-guide.md) - \[Agentic MCP server: @ton/mcp\](https://docs.ton.org/ecosystem/ai/mcp.md) - \[Agentic wallet contracts\](https://docs.ton.org/ecosystem/ai/wallets.md) - \[Analytics and data providers\](https://docs.ton.org/ecosystem/analytics.md) - \[Overview\](https://docs.ton.org/ecosystem/api/overview.md) - \[Jetton prices API\](https://docs.ton.org/ecosystem/api/price.md) - \[Get your TON Center API key\](https://docs.ton.org/ecosystem/api/toncenter/get-api-key.md) - \[Introduction\](https://docs.ton.org/ecosystem/api/toncenter/introduction.md) - \[Rate limits\](https://docs.ton.org/ecosystem/api/toncenter/rate-limit.md) - \[Get Nominator Bookings Method\](https://docs.ton.org/ecosystem/api/toncenter/smc-index/get-nominator-bookings-method.md): Get nominator bookings (debits and credits) in specified pool. - \[Get Nominator Earnings Method\](https://docs.ton.org/ecosystem/api/toncenter/smc-index/get-nominator-earnings-method.md): Get nominator income in specified pool with his stake on each timepoint. - \[Get Nominator Method\](https://docs.ton.org/ecosystem/api/toncenter/smc-index/get-nominator-method.md): Get nominator data in given pool (the only in list) or, if pool is not specified, in all pools where nominator stakes. - \[Get Pool Bookings Method\](https://docs.ton.org/ecosystem/api/toncenter/smc-index/get-pool-bookings-method.md): Get all the bookings (debits and credits) in specified pool. - \[Get Pool Method\](https://docs.ton.org/ecosystem/api/toncenter/smc-index/get-pool-method.md): Get pool data with all its nominators. - \[Lifecheck Method\](https://docs.ton.org/ecosystem/api/toncenter/smc-index/lifecheck-method.md): Check if there are any bookings in the last 19 hours. Returns status "ok" if bookings exist, "dead" otherwise. - \[Streaming API overview\](https://docs.ton.org/ecosystem/api/toncenter/streaming/overview.md) - \[Streaming API notification reference\](https://docs.ton.org/ecosystem/api/toncenter/streaming/reference.md) - \[Streaming API: Server-Sent Events\](https://docs.ton.org/ecosystem/api/toncenter/streaming/sse.md) - \[Streaming API: WebSocket\](https://docs.ton.org/ecosystem/api/toncenter/streaming/wss.md) - \[API authentication\](https://docs.ton.org/ecosystem/api/toncenter/v2-authentication.md) - \[API error codes\](https://docs.ton.org/ecosystem/api/toncenter/v2-errors.md) - \[Tonlib type identifiers\](https://docs.ton.org/ecosystem/api/toncenter/v2-tonlib-types.md) - \[Get address balance\](https://docs.ton.org/ecosystem/api/toncenter/v2/accounts/get-address-balance.md): Returns the TON balance of an account in nanotons. 1 TON = 1,000,000,000 nanotons. A lightweight endpoint that returns only the balance without contract code, data, or other account details. Returns "0" for addresses that have never received any funds. - \[Get address information\](https://docs.ton.org/ecosystem/api/toncenter/v2/accounts/get-address-information.md): Returns the current state of any account on the TON blockchain. Includes the balance (in nanotons), smart contract code and data (if deployed), account status, and a reference to the last transaction. This is the primary endpoint for checking if an address exists and what's deployed there. - \[Get address state\](https://docs.ton.org/ecosystem/api/toncenter/v2/accounts/get-address-state.md): Returns the lifecycle state of an account. Possible values: \`uninitialized\` (address has no deployed contract but can receive TON), \`active\` (contract is deployed and working), \`frozen\` (contract suspended due to zero balance, send TON to unfreeze). Refer to the \[account lifecycle states documentati… - \[Get extended address information\](https://docs.ton.org/ecosystem/api/toncenter/v2/accounts/get-extended-address-information.md): Returns detailed account information with parsed contract state. For wallet contracts, identifies the wallet version (v3, v4, v5) and extracts wallet-specific fields like \`seqno\` and public key. For other contracts, returns the raw state. - \[Get token data\](https://docs.ton.org/ecosystem/api/toncenter/v2/accounts/get-token-data.md): Returns metadata for Jetton or NFT contracts. Automatically detects the contract type and returns appropriate fields. For Jetton masters: total supply, admin, metadata. For Jetton wallets: balance, owner. For NFT items: collection, owner, content. For NFT collections: item count, metadata. - \[Get wallet information\](https://docs.ton.org/ecosystem/api/toncenter/v2/accounts/get-wallet-information.md): Returns wallet-specific information for an address. If the address is a known wallet contract, returns the wallet type, current \`seqno\` (needed for sending transactions), and wallet\_id. Always check \`wallet: true\` before using wallet-specific fields. Call this before sending any transaction to get t… - \[Get block header\](https://docs.ton.org/ecosystem/api/toncenter/v2/blocks/get-block-header.md): Returns block metadata without the full transaction list. Includes timestamps, validator info, and references to previous blocks. Intended for block explorers and other use cases that require block information without transactions. - \[Get consensus block\](https://docs.ton.org/ecosystem/api/toncenter/v2/blocks/get-consensus-block.md): Returns the latest block that has reached consensus and is guaranteed to be final. This block will never be reverted, making it safe for confirming transactions that require absolute finality. - \[Get masterchain block signatures\](https://docs.ton.org/ecosystem/api/toncenter/v2/blocks/get-masterchain-block-signatures.md): Returns validator signatures for a specific masterchain block. Each signature proves that a validator approved this block. Use this for building cryptographic proofs or verifying block authenticity in trustless applications. - \[Get masterchain info\](https://docs.ton.org/ecosystem/api/toncenter/v2/blocks/get-masterchain-info.md): Returns the current state of the TON masterchain. The \`last\` field contains the latest block used for querying current state. The \`seqno\` in \`last\` is the current block height. Use this endpoint to obtain the latest block reference for other queries. - \[Get outbound message queue size\](https://docs.ton.org/ecosystem/api/toncenter/v2/blocks/get-outbound-message-queue-size.md): Returns the current size of the outbound message queue for each shard. A growing queue indicates network congestion. If the queue is large, transactions may take longer to process. Monitor this to detect network issues. - \[Get shard block proof\](https://docs.ton.org/ecosystem/api/toncenter/v2/blocks/get-shard-block-proof.md): Returns a Merkle proof that links a shardchain block to a masterchain block. This proof cryptographically verifies that the shard block is part of the canonical chain. Used by light clients and cross-chain bridges to verify shard data without trusting the API. - \[Get shards\](https://docs.ton.org/ecosystem/api/toncenter/v2/blocks/get-shards.md): Returns the active shardchain block identifiers at a given masterchain block height. Each shard processes a subset of accounts in parallel. The response shows how the basechain is currently partitioned and which block each shard is at. - \[Lookup block\](https://docs.ton.org/ecosystem/api/toncenter/v2/blocks/lookup-block.md): Finds a block by position or time. Specify workchain and shard, then provide either: \`seqno\` (exact block number), lt (find block containing this logical time), or unixtime (find block closest to this timestamp). Returns the full block ID including hashes needed for verification. - \[Get all config parameters\](https://docs.ton.org/ecosystem/api/toncenter/v2/configuration/get-all-config-parameters.md): Returns all blockchain configuration parameters at once. Includes gas prices, validator settings, workchain configs, and governance rules. Use the optional \`seqno\` to get historical configuration at a specific block height. - \[Get config parameter\](https://docs.ton.org/ecosystem/api/toncenter/v2/configuration/get-config-parameter.md): Returns a specific blockchain configuration parameter. TON stores all network settings on-chain as numbered parameters. Common ones: 0 (config contract), 1 (elector), 15 (election timing), 17 (stake limits), 20-21 (gas prices), 34 (current validators). Check TON documentation for the full list. - \[Get libraries\](https://docs.ton.org/ecosystem/api/toncenter/v2/configuration/get-libraries.md): Returns smart contract library code by hash. Some contracts reference shared libraries instead of including all code directly. When a library reference appears in contract code, this endpoint fetches the actual library implementation. - \[API v2 overview\](https://docs.ton.org/ecosystem/api/toncenter/v2/overview.md) - \[JSON-RPC endpoint\](https://docs.ton.org/ecosystem/api/toncenter/v2/rpc/json-rpc-endpoint.md): All API methods are available through this single endpoint using JSON-RPC 2.0 protocol. Send the method name in the \`method\` field and parameters as a dictionary in \`params\`. Useful for calling multiple methods in sequence or when JSON-RPC is preferred over REST. - \[Run get method\](https://docs.ton.org/ecosystem/api/toncenter/v2/run-method/run-get-method.md): Executes a read-only method on a smart contract. Get methods query contract state without sending a transaction. Common methods include \`seqno\` (wallet sequence number), \`get\_wallet\_data\` (wallet info), and \`get\_jetton\_data\` (token info). Method arguments are provided in the \`stack\` array. - \[Run get method (standard)\](https://docs.ton.org/ecosystem/api/toncenter/v2/run-method/run-get-method-standard.md): Executes a read-only method on a smart contract using typed stack entries. Input and output stack entries use explicit types (\`TvmStackEntryNumber\`, \`TvmStackEntryCell\`, etc.) for structured input/output handling. Common methods: \`seqno\` (wallet sequence number), \`get\_wallet\_data\` (wallet info), \`ge… - \[Estimate fee\](https://docs.ton.org/ecosystem/api/toncenter/v2/send/estimate-fee.md): Calculates the fees required to send a message. Provide the destination address and message body. For new contract deployments, also include init\_code and init\_data. Set ignore\_chksig to true when estimating before signing. Returns a breakdown of storage, gas, and forwarding fees. - \[Send BoC\](https://docs.ton.org/ecosystem/api/toncenter/v2/send/send-boc.md): Broadcasts a signed message to the TON network. The \`boc\` parameter must contain a complete, signed external message in base64 format. The API validates the message and forwards it to validators. Returns immediately after acceptance; use getTransactions to confirm the transaction was processed. - \[Send BoC (return hash)\](https://docs.ton.org/ecosystem/api/toncenter/v2/send/send-boc-return-hash.md): Broadcasts a signed message to the TON network and returns the message hash. The \`boc\` parameter must contain a complete, signed external message in base64 format. The API validates the message and forwards it to validators. The returned hash can be used to track the message's processing status. - \[Get block transactions\](https://docs.ton.org/ecosystem/api/toncenter/v2/transactions/get-block-transactions.md): Returns a summary of transactions in a specific block. Each item contains the account address and transaction ID, but not full transaction details. Use \`count\` to limit results and \`after\_lt\`/\`after\_hash\` for pagination. Call getTransactions with each transaction ID to get full details. - \[Get block transactions (extended)\](https://docs.ton.org/ecosystem/api/toncenter/v2/transactions/get-block-transactions-extended.md): Returns full transaction objects for all transactions in a specific block. Each transaction includes complete data: inbound and outbound messages, fees, state changes, and BoC-encoded raw data. Use \`count\` to limit results and \`after\_lt\`/\`after\_hash\` for pagination when \`incomplete\` is true. - \[Get transactions\](https://docs.ton.org/ecosystem/api/toncenter/v2/transactions/get-transactions.md): Returns transaction history for an account. Transactions are returned newest-first. Each transaction shows the incoming message that triggered it, all outgoing messages, and fees paid. For pagination: use the \`lt\` and \`hash\` from the oldest transaction as the starting point for the next request. - \[Get transactions (standard)\](https://docs.ton.org/ecosystem/api/toncenter/v2/transactions/get-transactions-standard.md): Returns transaction history for an account in a standardized format. Transactions are returned newest-first. Each transaction includes the triggering inbound message, all outbound messages, and fees paid. The response includes a \`previous\_transaction\_id\` cursor for paginating through older transacti… - \[Try locate result transaction\](https://docs.ton.org/ecosystem/api/toncenter/v2/transactions/try-locate-result-transaction.md): Finds the transaction that received a specific message. Given message parameters, returns the transaction on the destination account that processed the incoming message. Use this to trace message delivery across accounts. - \[Try locate source transaction\](https://docs.ton.org/ecosystem/api/toncenter/v2/transactions/try-locate-source-transaction.md): Finds the transaction that sent a specific message. Given message parameters, returns the transaction on the source account that created this outgoing message. Useful for tracing where a message originated from. - \[Try locate transaction\](https://docs.ton.org/ecosystem/api/toncenter/v2/transactions/try-locate-transaction.md): Finds a transaction by message parameters. Given a source address, destination address, and message creation time (created\_lt), returns the transaction that processed this message. Useful for locating when a previously sent message was executed. - \[Detect address\](https://docs.ton.org/ecosystem/api/toncenter/v2/utils/detect-address.md): Validates an address and returns it in all standard formats. Use this to convert between address formats or to validate user input. Returns raw format (0:abc), base64 bounceable (EQ), base64 non-bounceable (UQ), and URL-safe variants. - \[Detect hash\](https://docs.ton.org/ecosystem/api/toncenter/v2/utils/detect-hash.md): Validates a hash and returns it in all standard formats. Use this to convert between hex (64 chars) and base64 (44 chars) representations. Works with any 256-bit hash including transaction hashes, block hashes, and message hashes. - \[Pack address\](https://docs.ton.org/ecosystem/api/toncenter/v2/utils/pack-address.md): Converts a raw address to user-friendly base64 format. Raw addresses use the format \`workchain:hex\` (e.g., \`0:abc...\`). The packed format is shorter and includes a checksum for error detection. - \[Unpack address\](https://docs.ton.org/ecosystem/api/toncenter/v2/utils/unpack-address.md): Converts a user-friendly base64 address back to its raw components. Returns the workchain ID, account hex, and flags indicating if the address is bounceable or testnet-only. - \[API authentication\](https://docs.ton.org/ecosystem/api/toncenter/v3-authentication.md) - \[API error codes\](https://docs.ton.org/ecosystem/api/toncenter/v3-errors.md) - \[Pagination\](https://docs.ton.org/ecosystem/api/toncenter/v3-pagination.md) - \[Address Book\](https://docs.ton.org/ecosystem/api/toncenter/v3/accounts/address-book.md): Query address book - \[Get Account States\](https://docs.ton.org/ecosystem/api/toncenter/v3/accounts/get-account-states.md): Query account states - \[Get Wallet States\](https://docs.ton.org/ecosystem/api/toncenter/v3/accounts/get-wallet-states.md): Query wallet information - \[Metadata\](https://docs.ton.org/ecosystem/api/toncenter/v3/accounts/metadata.md): Query address metadata - \[Get Actions\](https://docs.ton.org/ecosystem/api/toncenter/v3/actions-and-traces/get-actions.md): Get actions by specified filter. - \[Get Pending Actions\](https://docs.ton.org/ecosystem/api/toncenter/v3/actions-and-traces/get-pending-actions.md): Get actions by specified filter. - \[Get Pending Traces\](https://docs.ton.org/ecosystem/api/toncenter/v3/actions-and-traces/get-pending-traces.md): Get traces by specified filter. - \[Get Traces\](https://docs.ton.org/ecosystem/api/toncenter/v3/actions-and-traces/get-traces.md): Get traces by specified filter. - \[Estimate Fee\](https://docs.ton.org/ecosystem/api/toncenter/v3/apiv2/estimate-fee.md): Estimate fees required for query processing. Fields body, init-code and init-data accepted in serialized format (b64-encoded). - \[Get Address Information\](https://docs.ton.org/ecosystem/api/toncenter/v3/apiv2/get-address-information.md): Get smart contract information. - \[Get Wallet Information\](https://docs.ton.org/ecosystem/api/toncenter/v3/apiv2/get-wallet-information.md): Get wallet smart contract information. The following wallets are supported: \`v1r1\`, \`v1r2\`, \`v1r3\`, \`v2r1\`, \`v2r2\`, \`v3r1\`, \`v3r2\`, \`v4r1\`, \`v4r2\`, \`v5beta\`, \`v5r1\`. In case the account is not a wallet error code 409 is returned. - \[Run Get-Method\](https://docs.ton.org/ecosystem/api/toncenter/v3/apiv2/run-get-method.md): Run get method of smart contract. Stack supports only \`num\`, \`cell\` and \`slice\` types: \`\`\` \[ { "type": "num", "value": "0x12a" }, { "type": "cell", "value": "te6..." // base64 encoded boc with cell }, { "type": "slice", "value": "te6..." // base64 encoded boc with slice } \] \`\`\` - \[Send Message\](https://docs.ton.org/ecosystem/api/toncenter/v3/apiv2/send-message.md): Send an external message to the TON network. - \[Get Adjacent Transactions\](https://docs.ton.org/ecosystem/api/toncenter/v3/blockchain-data/get-adjacent-transactions.md): Get parent and/or children for specified transaction. - \[Get blocks\](https://docs.ton.org/ecosystem/api/toncenter/v3/blockchain-data/get-blocks.md): Returns blocks by specified filters. - \[Get masterchain block shard state\](https://docs.ton.org/ecosystem/api/toncenter/v3/blockchain-data/get-masterchain-block-shard-state.md): Get masterchain block shard state. Same as /api/v2/shards. - \[Get masterchain block shard state\](https://docs.ton.org/ecosystem/api/toncenter/v3/blockchain-data/get-masterchain-block-shard-state-1.md): Returns all worchain blocks, that appeared after previous masterchain block. - \[Get Masterchain Info\](https://docs.ton.org/ecosystem/api/toncenter/v3/blockchain-data/get-masterchain-info.md): Get first and last indexed block - \[Get messages\](https://docs.ton.org/ecosystem/api/toncenter/v3/blockchain-data/get-messages.md): Get messages by specified filters. - \[Get pending transactions\](https://docs.ton.org/ecosystem/api/toncenter/v3/blockchain-data/get-pending-transactions.md): Get pending transactions by specified filter. - \[Get transactions\](https://docs.ton.org/ecosystem/api/toncenter/v3/blockchain-data/get-transactions.md): Get transactions by specified filter. - \[Get transactions by Masterchain block\](https://docs.ton.org/ecosystem/api/toncenter/v3/blockchain-data/get-transactions-by-masterchain-block.md): Returns transactions from masterchain block and from all shards. - \[Get transactions by message\](https://docs.ton.org/ecosystem/api/toncenter/v3/blockchain-data/get-transactions-by-message.md): Get transactions whose inbound/outbound message has the specified hash. \\ - \[Get DNS Records\](https://docs.ton.org/ecosystem/api/toncenter/v3/dns/get-dns-records.md): Query DNS records by specified filters. Currently .ton and .t.me DNS are supported. - \[Get Jetton Burns\](https://docs.ton.org/ecosystem/api/toncenter/v3/jettons/get-jetton-burns.md): Get Jetton burns by specified filters - \[Get Jetton Masters\](https://docs.ton.org/ecosystem/api/toncenter/v3/jettons/get-jetton-masters.md): Get Jetton masters by specified filters - \[Get Jetton Transfers\](https://docs.ton.org/ecosystem/api/toncenter/v3/jettons/get-jetton-transfers.md): Get Jetton transfers by specified filters - \[Get Jetton Wallets\](https://docs.ton.org/ecosystem/api/toncenter/v3/jettons/get-jetton-wallets.md): Get Jetton wallets by specified filters - \[Get Multisig Orders\](https://docs.ton.org/ecosystem/api/toncenter/v3/multisig/get-multisig-orders.md): Get multisig orders by specified filters - \[Get Multisig Wallets\](https://docs.ton.org/ecosystem/api/toncenter/v3/multisig/get-multisig-wallets.md): Get multisig contracts by specified filters with associated orders - \[Get NFT collections\](https://docs.ton.org/ecosystem/api/toncenter/v3/nfts/get-nft-collections.md): Get NFT collections by specified filters - \[Get NFT items\](https://docs.ton.org/ecosystem/api/toncenter/v3/nfts/get-nft-items.md): Get NFT items by specified filters - \[Get NFT Transfers\](https://docs.ton.org/ecosystem/api/toncenter/v3/nfts/get-nft-transfers.md): Get transfers of NFT items by specified filters - \[API v3 overview\](https://docs.ton.org/ecosystem/api/toncenter/v3/overview.md) - \[Get Top Accounts By Balance\](https://docs.ton.org/ecosystem/api/toncenter/v3/stats/get-top-accounts-by-balance.md): Get list of accounts sorted descending by balance. - \[Decode Opcodes and Bodies\](https://docs.ton.org/ecosystem/api/toncenter/v3/utils/decode-opcodes-and-bodies.md): Decode opcodes and message bodies. Opcodes can be in hex (with or without 0x prefix) or decimal format. Bodies should be in base64 or hex format. - \[Decode Opcodes and Bodies\](https://docs.ton.org/ecosystem/api/toncenter/v3/utils/decode-opcodes-and-bodies-1.md): Decode opcodes and message bodies. Opcodes can be in hex (with or without 0x prefix) or decimal format. Bodies should be in base64 or hex format. Use POST method for long parameters that may be truncated in GET requests. - \[Get Vesting Contracts\](https://docs.ton.org/ecosystem/api/toncenter/v3/vesting/get-vesting-contracts.md): Get vesting contracts by specified filters - \[How to initialize the TON Connect's AppKit\](https://docs.ton.org/ecosystem/appkit/init.md) - \[How to work with Jettons using AppKit\](https://docs.ton.org/ecosystem/appkit/jettons.md) - \[How to work with NFTs using AppKit\](https://docs.ton.org/ecosystem/appkit/nfts.md) - \[AppKit: SDK for decentralized applications (dApps)\](https://docs.ton.org/ecosystem/appkit/overview.md) - \[How to work with Toncoin using AppKit\](https://docs.ton.org/ecosystem/appkit/toncoin.md) - \[Bridges\](https://docs.ton.org/ecosystem/bridges.md) - \[Overview\](https://docs.ton.org/ecosystem/explorers/overview.md) - \[Using Tonviewer\](https://docs.ton.org/ecosystem/explorers/tonviewer.md) - \[Integrate MyTonCtrl with Prometheus\](https://docs.ton.org/ecosystem/nodes/cpp/integrating-with-prometheus.md) - \[Telegram alerting\](https://docs.ton.org/ecosystem/nodes/cpp/mytonctrl/alerting.md) - \[Backup\](https://docs.ton.org/ecosystem/nodes/cpp/mytonctrl/backups.md): MyTonCtrl bundles helper scripts for creating and restoring node backups. - \[BTC Teleport\](https://docs.ton.org/ecosystem/nodes/cpp/mytonctrl/btc-teleport.md): The BTC Teleport module manages the optional Bitcoin bridge (Teleport) client shipped with MyTonCtrl. Use these commands to inspect proposals, vote on them, or remove the Teleport installation when no longer needed. - \[Collator\](https://docs.ton.org/ecosystem/nodes/cpp/mytonctrl/collator.md): Collator mode lets a node produce blocks for selected shardchains without running the full validator stack. The commands below help you configure local collators, adjust the validator allowlist, and manage collator-specific configuration JSON. - \[Core\](https://docs.ton.org/ecosystem/nodes/cpp/mytonctrl/core.md): Inspecting node health, managing modes and settings, maintaining the software stack, and running diagnostics. - \[Custom overlays\](https://docs.ton.org/ecosystem/nodes/cpp/mytonctrl/custom-overlays.md): Sets up a custom overlay to speed up synchronization for a group of nodes. - \[Installer\](https://docs.ton.org/ecosystem/nodes/cpp/mytonctrl/installer.md): MyTonInstaller complements MyTonCtrl by bootstrapping and maintaining TON node components. - \[Liquid staking\](https://docs.ton.org/ecosystem/nodes/cpp/mytonctrl/liquid-staking.md): Liquid staking mode orchestrates controller deployment and maintenance for jetton-based staking pools. The commands below cover controller lifecycle management, funding flows, validator-set updates, and diagnostic helpers. - \[Overview\](https://docs.ton.org/ecosystem/nodes/cpp/mytonctrl/overview.md) - \[Nominator pools\](https://docs.ton.org/ecosystem/nodes/cpp/mytonctrl/pools.md): Pool-focused commands help you manage validator-run nominator pools and Orbs single-nominator pools. The console exposes utilities that create local pool descriptors, deploy the contracts on-chain, and move stake in or out. - \[Utilities\](https://docs.ton.org/ecosystem/nodes/cpp/mytonctrl/utilities.md): Utility commands provide quick inspection and helper tools for accounts, bookmarks, governance artifacts, and validator data. - \[Validator\](https://docs.ton.org/ecosystem/nodes/cpp/mytonctrl/validator.md): Validator mode automates governance voting, election participation, efficiency tracking, and the local collator registry. - \[Wallet\](https://docs.ton.org/ecosystem/nodes/cpp/mytonctrl/wallet.md): Wallet mode provides convenience utilities for generating, activating, importing, exporting, and moving funds between TON wallets managed by MyTonCtrl. - \[Run a validator\](https://docs.ton.org/ecosystem/nodes/cpp/run-validator.md): Run a validator node with MyTonCtrl - \[Setting up a local blockchain using MyLocalTon\](https://docs.ton.org/ecosystem/nodes/cpp/setup-mylocalton.md): Install MyLocalTon to spin up a self-contained TON network for development and testing. - \[Run a node with MyTonCtrl\](https://docs.ton.org/ecosystem/nodes/cpp/setup-mytonctrl.md): Provision hardware, install MyTonCtrl, and follow runbooks for validator, liteserver, or archive roles. - \[Blockchain nodes overview\](https://docs.ton.org/ecosystem/nodes/overview.md): Pick the right TON node setup and understand the operational work it requires. - \[Architecture reference\](https://docs.ton.org/ecosystem/nodes/rust/architecture.md) - \[How to configure global JSON file\](https://docs.ton.org/ecosystem/nodes/rust/global-config.md) - \[How to configure logging YAML file\](https://docs.ton.org/ecosystem/nodes/rust/logs-config.md) - \[Metrics\](https://docs.ton.org/ecosystem/nodes/rust/metrics.md) - \[Monitoring\](https://docs.ton.org/ecosystem/nodes/rust/monitoring.md) - \[How to configure node JSON file\](https://docs.ton.org/ecosystem/nodes/rust/node-config.md) - \[Node configuration reference\](https://docs.ton.org/ecosystem/nodes/rust/node-config-ref.md) - \[Health probes\](https://docs.ton.org/ecosystem/nodes/rust/probes.md) - \[Rust node quick start\](https://docs.ton.org/ecosystem/nodes/rust/quick-start.md) - \[Oracles overview\](https://docs.ton.org/ecosystem/oracles/overview.md) - \[Pyth oracle\](https://docs.ton.org/ecosystem/oracles/pyth.md) - \[RedStone oracle\](https://docs.ton.org/ecosystem/oracles/redstone.md) - \[SDKs\](https://docs.ton.org/ecosystem/sdks.md) - \[Liquid staking contracts\](https://docs.ton.org/ecosystem/staking/liquid-staking.md) - \[Nominator pool contracts\](https://docs.ton.org/ecosystem/staking/nominator-pools.md) - \[Staking overview\](https://docs.ton.org/ecosystem/staking/overview.md) - \[Single nominator pool contracts\](https://docs.ton.org/ecosystem/staking/single-nominator.md) - \[Stake calculation\](https://docs.ton.org/ecosystem/staking/stake-calculation.md) - \[Network status\](https://docs.ton.org/ecosystem/status.md) - \[How to adopt sub-second finality\](https://docs.ton.org/ecosystem/subsecond.md) - \[Telegram analytics\](https://docs.ton.org/ecosystem/tma/analytics/analytics.md) - \[API Endpoints\](https://docs.ton.org/ecosystem/tma/analytics/api-endpoints.md) - \[FAQ\](https://docs.ton.org/ecosystem/tma/analytics/faq.md) - \[Installation via NPM package\](https://docs.ton.org/ecosystem/tma/analytics/install-via-npm.md) - \[Installation via script tag\](https://docs.ton.org/ecosystem/tma/analytics/install-via-script.md) - \[Managing integration\](https://docs.ton.org/ecosystem/tma/analytics/managing-integration.md) - \[Preparations\](https://docs.ton.org/ecosystem/tma/analytics/preparation.md) - \[Supported events\](https://docs.ton.org/ecosystem/tma/analytics/supported-events.md) - \[TMA create CLI\](https://docs.ton.org/ecosystem/tma/create-mini-app.md) - \[TMA: Telegram Mini Apps overview\](https://docs.ton.org/ecosystem/tma/overview.md) - \[Getting started\](https://docs.ton.org/ecosystem/tma/telegram-ui/getting-started.md) - \[Overview\](https://docs.ton.org/ecosystem/tma/telegram-ui/overview.md) - \[AppRoot component\](https://docs.ton.org/ecosystem/tma/telegram-ui/platform-and-palette.md) - \[Avatar\](https://docs.ton.org/ecosystem/tma/telegram-ui/reference/avatar.md) - \[How to integrate a decentralized application (dApp)\](https://docs.ton.org/ecosystem/ton-connect/dapp.md) - \[TON Connect manifests\](https://docs.ton.org/ecosystem/ton-connect/manifest.md) - \[Message lookup\](https://docs.ton.org/ecosystem/ton-connect/message-lookup.md) - \[TON Connect overview\](https://docs.ton.org/ecosystem/ton-connect/overview.md) - \[How to integrate a wallet with TON\](https://docs.ton.org/ecosystem/ton-connect/wallet.md) - \[WalletConnect support\](https://docs.ton.org/ecosystem/ton-connect/wallet-connect.md) - \[API reference\](https://docs.ton.org/ecosystem/ton-pay/api-reference.md) - \[On-ramp in TON Pay SDK\](https://docs.ton.org/ecosystem/ton-pay/on-ramp.md) - \[TON Pay SDK overview\](https://docs.ton.org/ecosystem/ton-pay/overview.md) - \[How to send payments using TON Pay React hook\](https://docs.ton.org/ecosystem/ton-pay/payment-integration/payments-react.md) - \[How to send payments using TON Connect\](https://docs.ton.org/ecosystem/ton-pay/payment-integration/payments-tonconnect.md) - \[How to check status and retrieve info\](https://docs.ton.org/ecosystem/ton-pay/payment-integration/status-info.md) - \[How to build a transfer\](https://docs.ton.org/ecosystem/ton-pay/payment-integration/transfer.md) - \[Quick start\](https://docs.ton.org/ecosystem/ton-pay/quick-start.md) - \[How to add a TON Pay button using JS\](https://docs.ton.org/ecosystem/ton-pay/ui-integration/button-js.md) - \[How to add a TON Pay button using React\](https://docs.ton.org/ecosystem/ton-pay/ui-integration/button-react.md) - \[TON Pay webhooks\](https://docs.ton.org/ecosystem/ton-pay/webhooks.md) - \[Addresses workflow\](https://docs.ton.org/ecosystem/wallet-apps/addresses-workflow.md) - \[Deep links\](https://docs.ton.org/ecosystem/wallet-apps/deep-links.md) - \[How to get coins on testnet\](https://docs.ton.org/ecosystem/wallet-apps/get-coins.md) - \[Tonkeeper\](https://docs.ton.org/ecosystem/wallet-apps/tonkeeper.md) - \[wallet.ton.org\](https://docs.ton.org/ecosystem/wallet-apps/web.md) - \[How to retrieve wallet information, jettons, and NFTs with WalletKit on the Android platform\](https://docs.ton.org/ecosystem/walletkit/android/data.md) - \[How to connect to dApp and handle wallet events on the Android platform\](https://docs.ton.org/ecosystem/walletkit/android/events.md) - \[How to initialize the TON Connect's WalletKit on the Android platform\](https://docs.ton.org/ecosystem/walletkit/android/init.md) - \[How to install the TON Connect's WalletKit on the Android platform\](https://docs.ton.org/ecosystem/walletkit/android/installation.md) - \[How to transfer Toncoin, Jettons and NFTs with WalletKit on the Android platform\](https://docs.ton.org/ecosystem/walletkit/android/transactions.md) - \[How to manage TON wallets with WalletKit on the Android platform\](https://docs.ton.org/ecosystem/walletkit/android/wallets.md) - \[How to inject TON's WalletKit into WebView on Android platform\](https://docs.ton.org/ecosystem/walletkit/android/webview.md) - \[Custodian integration for in-wallet browsers and browser extensions\](https://docs.ton.org/ecosystem/walletkit/browser-extension.md) - \[How to retrieve wallet information, jettons, and NFTs with WalletKit on the iOS platform\](https://docs.ton.org/ecosystem/walletkit/ios/data.md) - \[How to connect to dApp and handle wallet events on the iOS platform\](https://docs.ton.org/ecosystem/walletkit/ios/events.md) - \[How to initialize the TON Connect's WalletKit on the iOS platform\](https://docs.ton.org/ecosystem/walletkit/ios/init.md) - \[How to install the TON Connect's WalletKit on the iOS platform\](https://docs.ton.org/ecosystem/walletkit/ios/installation.md) - \[How to transfer Toncoin, Jettons and NFTs with WalletKit on the iOS platform\](https://docs.ton.org/ecosystem/walletkit/ios/transactions.md) - \[How to manage TON wallets with WalletKit on the iOS platform\](https://docs.ton.org/ecosystem/walletkit/ios/wallets.md) - \[How to inject TON's WalletKit into WebView on iOS platform\](https://docs.ton.org/ecosystem/walletkit/ios/webview.md) - \[Custodian integration for native and web wallets\](https://docs.ton.org/ecosystem/walletkit/native-web.md) - \[WalletKit: SDK for custodial and non-custodial wallet services\](https://docs.ton.org/ecosystem/walletkit/overview.md) - \[Integration QA guide\](https://docs.ton.org/ecosystem/walletkit/qa-guide.md) - \[How to handle connections with WalletKit on the Web platform\](https://docs.ton.org/ecosystem/walletkit/web/connections.md) - \[How to handle other events with WalletKit on the Web platform\](https://docs.ton.org/ecosystem/walletkit/web/events.md) - \[How to initialize the TON Connect's WalletKit on the Web platform\](https://docs.ton.org/ecosystem/walletkit/web/init.md) - \[How to work with Jettons using WalletKit on the Web platform\](https://docs.ton.org/ecosystem/walletkit/web/jettons.md) - \[How to work with NFTs using WalletKit on the Web platform\](https://docs.ton.org/ecosystem/walletkit/web/nfts.md) - \[How to work with Toncoin using WalletKit on the Web platform\](https://docs.ton.org/ecosystem/walletkit/web/toncoin.md) - \[How to manage TON wallets with WalletKit on the Web platform\](https://docs.ton.org/ecosystem/walletkit/web/wallets.md) - \[Change library\](https://docs.ton.org/foundations/actions/change-library.md) - \[Actions\](https://docs.ton.org/foundations/actions/overview.md) - \[Reserve coins\](https://docs.ton.org/foundations/actions/reserve.md) - \[Send message\](https://docs.ton.org/foundations/actions/send.md) - \[Set code\](https://docs.ton.org/foundations/actions/set-code.md) - \[Deriving addresses\](https://docs.ton.org/foundations/addresses/derive.md) - \[Internal address formats\](https://docs.ton.org/foundations/addresses/formats.md) - \[Addresses overview\](https://docs.ton.org/foundations/addresses/overview.md) - \[Reading and writing addresses\](https://docs.ton.org/foundations/addresses/serialize.md) - \[Blockchain config\](https://docs.ton.org/foundations/config.md) - \[Catchain & BCP visualizer\](https://docs.ton.org/foundations/consensus/catchain-visualizer.md): Interactive visual simulation of Catchain + BCP rounds - \[Transaction fees\](https://docs.ton.org/foundations/fees.md) - \[Glossary\](https://docs.ton.org/foundations/glossary.md) - \[Blockchain limits\](https://docs.ton.org/foundations/limits.md) - \[Deploy message\](https://docs.ton.org/foundations/messages/deploy.md) - \[Incoming external messages\](https://docs.ton.org/foundations/messages/external-in.md) - \[Outbound external messages\](https://docs.ton.org/foundations/messages/external-out.md) - \[Internal messages\](https://docs.ton.org/foundations/messages/internal.md) - \[Sending modes\](https://docs.ton.org/foundations/messages/modes.md) - \[Ordinary transactions\](https://docs.ton.org/foundations/messages/ordinary-tx.md) - \[Overview\](https://docs.ton.org/foundations/messages/overview.md) - \[Execution phases\](https://docs.ton.org/foundations/phases.md) - \[Precompiled contracts\](https://docs.ton.org/foundations/precompiled.md) - \[Overview\](https://docs.ton.org/foundations/proofs/overview.md) - \[Liteserver proof verification\](https://docs.ton.org/foundations/proofs/verifying-liteserver-proofs.md) - \[Bag of cells\](https://docs.ton.org/foundations/serialization/boc.md) - \[Cells\](https://docs.ton.org/foundations/serialization/cells.md) - \[Library references\](https://docs.ton.org/foundations/serialization/library.md) - \[Merkle proofs\](https://docs.ton.org/foundations/serialization/merkle.md) - \[Merkle updates\](https://docs.ton.org/foundations/serialization/merkle-update.md) - \[Pruned branches\](https://docs.ton.org/foundations/serialization/pruned.md) - \[Blockchain sharding\](https://docs.ton.org/foundations/shards.md) - \[Account status\](https://docs.ton.org/foundations/status.md) - \[System contracts\](https://docs.ton.org/foundations/system.md) - \[Traces\](https://docs.ton.org/foundations/traces.md) - \[Web3 services\](https://docs.ton.org/foundations/web3/overview.md) - \[TON DNS\](https://docs.ton.org/foundations/web3/ton-dns.md): On-chain hierarchical domain name service for TON Network - \[TON Proxy\](https://docs.ton.org/foundations/web3/ton-proxy.md): HTTP-to-ADNL bridge for accessing and hosting TON Sites from a conventional browser - \[TON Sites\](https://docs.ton.org/foundations/web3/ton-sites.md): Web services accessible through TON Network via ADNL and RLDP - \[TON Storage\](https://docs.ton.org/foundations/web3/ton-storage.md): Distributed file storage for the TON Blockchain using torrent-like technology and on-chain payment contracts - \[Catchain consensus: an outline\](https://docs.ton.org/foundations/whitepapers/catchain.md): Whitepaper by Dr. Nikolai Durov - \[Overview\](https://docs.ton.org/foundations/whitepapers/overview.md) - \[Telegram Open Network (TON) Blockchain Specification\](https://docs.ton.org/foundations/whitepapers/tblkch.md): Whitepaper by Dr. Nikolai Durov - \[The Open Network\](https://docs.ton.org/foundations/whitepapers/ton.md): Whitepaper by Dr. Nikolai Durov - \[Telegram Open Network Virtual Machine\](https://docs.ton.org/foundations/whitepapers/tvm.md): Whitepaper by Dr. Nikolai Durov - \[Coming from Ethereum\](https://docs.ton.org/from-ethereum.md) - \[Get support\](https://docs.ton.org/get-support.md) - \[Complex and non-trivial TL-B examples\](https://docs.ton.org/languages/tl-b/complex-and-non-trivial-examples.md) - \[TL-B overview\](https://docs.ton.org/languages/tl-b/overview.md) - \[Simple TL-B examples\](https://docs.ton.org/languages/tl-b/simple-examples.md) - \[TL-B syntax and semantics\](https://docs.ton.org/languages/tl-b/syntax-and-semantics.md) - \[TEP TL-B examples\](https://docs.ton.org/languages/tl-b/tep-examples.md) - \[TL-B tooling\](https://docs.ton.org/languages/tl-b/tooling.md) - \[Other resources\](https://docs.ton.org/more-tutorials.md) - \[Old documentation\](https://docs.ton.org/old.md) - \[Jettons payments processing\](https://docs.ton.org/payments/jettons.md) - \[Payment processing overview\](https://docs.ton.org/payments/overview.md) - \[Toncoin payments processing\](https://docs.ton.org/payments/toncoin.md) - \[Airdrop\](https://docs.ton.org/standard/tokens/airdrop.md) - \[API\](https://docs.ton.org/standard/tokens/jettons/api.md) - \[Burn\](https://docs.ton.org/standard/tokens/jettons/burn.md) - \[Jetton comparison\](https://docs.ton.org/standard/tokens/jettons/comparison.md) - \[How to find Jetton wallet\](https://docs.ton.org/standard/tokens/jettons/find.md) - \[How it works\](https://docs.ton.org/standard/tokens/jettons/how-it-works.md) - \[How to mint new jettons\](https://docs.ton.org/standard/tokens/jettons/mint.md) - \[How to deploy mintless Jetton\](https://docs.ton.org/standard/tokens/jettons/mintless/deploy.md) - \[Mintless Jetton\](https://docs.ton.org/standard/tokens/jettons/mintless/overview.md) - \[Overview\](https://docs.ton.org/standard/tokens/jettons/overview.md) - \[How to get supply data\](https://docs.ton.org/standard/tokens/jettons/supply-data.md) - \[How to transfer Jettons\](https://docs.ton.org/standard/tokens/jettons/transfer.md) - \[How to get Jetton wallet data\](https://docs.ton.org/standard/tokens/jettons/wallet-data.md) - \[Metadata\](https://docs.ton.org/standard/tokens/metadata.md) - \[API\](https://docs.ton.org/standard/tokens/nft/api.md) - \[NFT comparison\](https://docs.ton.org/standard/tokens/nft/comparison.md) - \[How to deploy an NFT item\](https://docs.ton.org/standard/tokens/nft/deploy.md) - \[NFT: How it works\](https://docs.ton.org/standard/tokens/nft/how-it-works.md) - \[How to get NFT item metadata\](https://docs.ton.org/standard/tokens/nft/metadata.md) - \[NFT 2.0\](https://docs.ton.org/standard/tokens/nft/nft-2.0.md) - \[NFT: Non-fungible token\](https://docs.ton.org/standard/tokens/nft/overview.md) - \[NFT: reference implementation\](https://docs.ton.org/standard/tokens/nft/reference.md) - \[SBT: How it works\](https://docs.ton.org/standard/tokens/nft/sbt.md) - \[How to transfer an NFT\](https://docs.ton.org/standard/tokens/nft/transfer.md) - \[How to verify NFT item\](https://docs.ton.org/standard/tokens/nft/verify.md) - \[Token overview\](https://docs.ton.org/standard/tokens/overview.md) - \[Vesting contracts\](https://docs.ton.org/standard/vesting.md) - \[Comparison\](https://docs.ton.org/standard/wallets/comparison.md) - \[Highload wallets\](https://docs.ton.org/standard/wallets/highload/overview.md) - \[Highload Wallet v2 — specification\](https://docs.ton.org/standard/wallets/highload/v2/specification.md) - \[How to create Highload Wallet v3\](https://docs.ton.org/standard/wallets/highload/v3/create.md) - \[How to send a batch of transfers\](https://docs.ton.org/standard/wallets/highload/v3/send-batch-transfers.md) - \[How to send a single transfer\](https://docs.ton.org/standard/wallets/highload/v3/send-single-transfer.md) - \[Highload Wallet v3 — specification\](https://docs.ton.org/standard/wallets/highload/v3/specification.md) - \[How to verify message is processed\](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed.md) - \[Wallets history\](https://docs.ton.org/standard/wallets/history.md) - \[How TON wallets work\](https://docs.ton.org/standard/wallets/how-it-works.md) - \[How to interact with wallet\](https://docs.ton.org/standard/wallets/interact.md) - \[Lockup wallet\](https://docs.ton.org/standard/wallets/lockup.md) - \[Mnemonics\](https://docs.ton.org/standard/wallets/mnemonics.md) - \[Performance benchmark\](https://docs.ton.org/standard/wallets/performance.md) - \[How to interact with Preprocessed Wallet V2\](https://docs.ton.org/standard/wallets/preprocessed-v2/interact.md) - \[Preprocessed Wallet V2 — specification\](https://docs.ton.org/standard/wallets/preprocessed-v2/specification.md) - \[Restricted wallet\](https://docs.ton.org/standard/wallets/restricted.md) - \[Wallet V4\](https://docs.ton.org/standard/wallets/v4.md) - \[Wallet V5\](https://docs.ton.org/standard/wallets/v5.md) - \[Wallet V5 API\](https://docs.ton.org/standard/wallets/v5-api.md) - \[Start here\](https://docs.ton.org/start-here.md) - \[Basic syntax\](https://docs.ton.org/tolk/basic-syntax.md) - \[Changelog\](https://docs.ton.org/tolk/changelog.md) - \[Tolk contract examples\](https://docs.ton.org/tolk/examples.md) - \[Assembler functions\](https://docs.ton.org/tolk/features/asm-functions.md) - \[Automatic serialization\](https://docs.ton.org/tolk/features/auto-serialization.md) - \[Compiler optimizations\](https://docs.ton.org/tolk/features/compiler-optimizations.md) - \[Contract getters\](https://docs.ton.org/tolk/features/contract-getters.md) - \[Contract storage\](https://docs.ton.org/tolk/features/contract-storage.md) - \[Forward payload in jettons\](https://docs.ton.org/tolk/features/jetton-payload.md) - \[Lazy loading\](https://docs.ton.org/tolk/features/lazy-loading.md) - \[Handling messages\](https://docs.ton.org/tolk/features/message-handling.md) - \[Sending messages\](https://docs.ton.org/tolk/features/message-sending.md) - \[Standard library\](https://docs.ton.org/tolk/features/standard-library.md) - \[FunC-to-Tolk converter\](https://docs.ton.org/tolk/from-func/converter.md) - \[Standard libraries comparison\](https://docs.ton.org/tolk/from-func/stdlib-comparison.md) - \[Tolk vs FunC\](https://docs.ton.org/tolk/from-func/tolk-vs-func.md) - \[Idioms and conventions\](https://docs.ton.org/tolk/idioms-conventions.md) - \[Tolk language\](https://docs.ton.org/tolk/overview.md) - \[Conditions and loops\](https://docs.ton.org/tolk/syntax/conditions-loops.md) - \[Exceptions in Tolk\](https://docs.ton.org/tolk/syntax/exceptions.md) - \[Functions and methods\](https://docs.ton.org/tolk/syntax/functions-methods.md) - \[Imports and name resolution\](https://docs.ton.org/tolk/syntax/imports.md) - \[Mutability\](https://docs.ton.org/tolk/syntax/mutability.md) - \[Operators\](https://docs.ton.org/tolk/syntax/operators.md) - \[Pattern matching\](https://docs.ton.org/tolk/syntax/pattern-matching.md) - \[Structures and fields\](https://docs.ton.org/tolk/syntax/structures-fields.md) - \[Variables\](https://docs.ton.org/tolk/syntax/variables.md) - \[Address\](https://docs.ton.org/tolk/types/address.md) - \[Type aliases\](https://docs.ton.org/tolk/types/aliases.md) - \[Booleans\](https://docs.ton.org/tolk/types/booleans.md) - \[Callables\](https://docs.ton.org/tolk/types/callables.md) - \[Cells, slices, builders\](https://docs.ton.org/tolk/types/cells.md) - \[Enums\](https://docs.ton.org/tolk/types/enums.md) - \[Generic structs and aliases\](https://docs.ton.org/tolk/types/generics.md) - \[Type system overview\](https://docs.ton.org/tolk/types/list-of-types.md) - \[Maps\](https://docs.ton.org/tolk/types/maps.md) - \[Nullable types and null safety\](https://docs.ton.org/tolk/types/nullable.md) - \[Numbers\](https://docs.ton.org/tolk/types/numbers.md) - \[Serialization\](https://docs.ton.org/tolk/types/overall-serialization.md) - \[TVM stack representation\](https://docs.ton.org/tolk/types/overall-tvm-stack.md) - \[Strings\](https://docs.ton.org/tolk/types/strings.md) - \[Structures\](https://docs.ton.org/tolk/types/structures.md) - \[Tensors\](https://docs.ton.org/tolk/types/tensors.md) - \[Arrays and tuples\](https://docs.ton.org/tolk/types/tuples.md) - \[Type checks and casts\](https://docs.ton.org/tolk/types/type-checks-and-casts.md) - \[Union types\](https://docs.ton.org/tolk/types/unions.md) - \[The unknown type\](https://docs.ton.org/tolk/types/unknown.md) - \[Void and never types\](https://docs.ton.org/tolk/types/void-never.md) - \[Builders and Slices\](https://docs.ton.org/tvm/builders-and-slices.md) - \[Continuations\](https://docs.ton.org/tvm/continuations.md) - \[Exit codes\](https://docs.ton.org/tvm/exit-codes.md) - \[Gas\](https://docs.ton.org/tvm/gas.md) - \[Get methods\](https://docs.ton.org/tvm/get-method.md) - \[Initialization\](https://docs.ton.org/tvm/initialization.md): State of TVM before smart contract execution - \[Instructions\](https://docs.ton.org/tvm/instructions.md): Interactive reference for TVM instructions - \[TVM overview\](https://docs.ton.org/tvm/overview.md) - \[Registers\](https://docs.ton.org/tvm/registers.md) - \[Retracer\](https://docs.ton.org/tvm/tools/retracer.md) - \[TON Decompiler\](https://docs.ton.org/tvm/tools/ton-decompiler.md) - \[TVM Explorer\](https://docs.ton.org/tvm/tools/tvm-explorer.md) - \[TxTracer\](https://docs.ton.org/tvm/tools/txtracer.md) ## OpenAPI Specs - \[v2\](https://docs.ton.org/ecosystem/api/toncenter/v2.json) - \[v3\](https://docs.ton.org/ecosystem/api/toncenter/v3.yaml) - \[smc-index\](https://docs.ton.org/ecosystem/api/toncenter/smc-index.json) - \[openapi\](https://docs.ton.org/api-reference/openapi.json) --- # TxTracer - TON Docs [Skip to main content](https://docs.ton.org/tvm/tools/txtracer#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Tools TxTracer [TxTracer](https://txtracer.ton.org/) is a multipurpose debugging tool for TVM, Tolk, and FunC. Tools from a screenshot are described below in their separate sections. Its source code can be found on [GitHub](https://github.com/ton-blockchain/txtracer) . [​](https://docs.ton.org/tvm/tools/txtracer#1-txtracer) 1\. TxTracer ----------------------------------------------------------------------- TxTracer’s main tool allows stepping over TVM execution by transaction hash. Put a transaction hash into the input. Use playback controls on the right to step through execution of the TVM bitcode that happened when this transaction was executed. Below those controls, the UI displays a current TVM stack. [​](https://docs.ton.org/tvm/tools/txtracer#2-playground) 2\. Playground --------------------------------------------------------------------------- Playground is for stepping over arbitrary TVM Assembly (TASM) or FunC code. Put the code into the code editor on the left. Use playback controls on the right to step through execution of the TVM bitcode that happened when this transaction was executed. Below those controls, the UI displays a current TVM stack. [​](https://docs.ton.org/tvm/tools/txtracer#3-code-explorer) 3\. Code Explorer --------------------------------------------------------------------------------- Explorer converts FunC/Tolk code to TVM Assembly (TASM). Put the code into the code editor on the left. The corresponding assembly code is on the right. [​](https://docs.ton.org/tvm/tools/txtracer#4-tvm-specification) 4\. TVM Specification ----------------------------------------------------------------------------------------- A modern version of TVM Specification. Put instruction name into the search field. Read about description, stack signature, and other effects of the instruction. [​](https://docs.ton.org/tvm/tools/txtracer#5-sandbox) 5\. Sandbox --------------------------------------------------------------------- Web interface that displays a trace from local [`@ton/sandbox`](https://docs.ton.org/contract-dev/testing/reference) . Follow instructions on the main page of the tool on how to set it up. The tool displays a trace of what happened during execution of the code in a local `@ton/sandbox`. [​](https://docs.ton.org/tvm/tools/txtracer#6-emulate) 6\. Emulate --------------------------------------------------------------------- Web interface that displays a trace from its [BoC](https://docs.ton.org/foundations/serialization/boc) . Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/tvm/tools/txtracer.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/tvm/tools/txtracer) [Previous](https://docs.ton.org/tvm/overview) [Retracer\ \ Next](https://docs.ton.org/tvm/tools/retracer) ⌘I On this page * [1\. TxTracer](https://docs.ton.org/tvm/tools/txtracer#1-txtracer) * [2\. Playground](https://docs.ton.org/tvm/tools/txtracer#2-playground) * [3\. Code Explorer](https://docs.ton.org/tvm/tools/txtracer#3-code-explorer) * [4\. TVM Specification](https://docs.ton.org/tvm/tools/txtracer#4-tvm-specification) * [5\. Sandbox](https://docs.ton.org/tvm/tools/txtracer#5-sandbox) * [6\. Emulate](https://docs.ton.org/tvm/tools/txtracer#6-emulate) --- # Fift and TVM assembly - TON Docs [Skip to main content](https://docs.ton.org/languages/fift/fift-and-tvm-assembly#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Fift Fift and TVM assembly Fift is a stack-based programming language with TON-specific features that can work with cells. TVM assembly is another stack-based language designed for TON that also handles cells. What’s the difference between them? [​](https://docs.ton.org/languages/fift/fift-and-tvm-assembly#key-differences) Key differences ------------------------------------------------------------------------------------------------- Fift executes at **compile-time** - when your compiler builds the smart contract code BoC after processing FunC code. Fift can appear in different forms: * TVM opcode definitions in `Asm.fif`: // Tuple primitives x{6F0} @Defop(4u) TUPLE x{6F00} @Defop NIL x{6F01} @Defop SINGLE x{6F02} dup @Defop PAIR @Defop CONS * `wallet_v3_r2.fif`: "Asm.fif" include <{ SETCP0 DUP IFNOTRET // Return if recv_internal DUP 85143 INT EQUAL OVER 78748 INT EQUAL OR IFJMP:<{ // "seqno" and "get_public_key" get-methods 1 INT AND c4 PUSHCTR CTOS 32 LDU 32 LDU NIP 256 PLDU CONDSEL // cnt or pubk }> INC 32 THROWIF // Fail unless recv_external 9 PUSHPOW2 LDSLICEX DUP 32 LDU 32 LDU 32 LDU // signature in_msg subwallet_id valid_until msg_seqno cs NOW s1 s3 XCHG LEQ 35 THROWIF // signature in_msg subwallet_id cs msg_seqno c4 PUSH CTOS 32 LDU 32 LDU 256 LDU ENDS // signature in_msg subwallet_id cs msg_seqno stored_seqno stored_subwallet public_key s3 s2 XCPU EQUAL 33 THROWIFNOT // signature in_msg subwallet_id cs public_key stored_seqno stored_subwallet s4 s4 XCPU EQUAL 34 THROWIFNOT // signature in_msg stored_subwallet cs public_key stored_seqno s0 s4 XCHG HASHSU // signature stored_seqno stored_subwallet cs public_key msg_hash s0 s5 s5 XC2PU // public_key stored_seqno stored_subwallet cs msg_hash signature public_key CHKSIGNU 35 THROWIFNOT // public_key stored_seqno stored_subwallet cs ACCEPT WHILE:<{ DUP SREFS // public_key stored_seqno stored_subwallet cs _51 }>DO<{ // public_key stored_seqno stored_subwallet cs 8 LDU LDREF s0 s2 XCHG // public_key stored_seqno stored_subwallet cs _56 mode SENDRAWMSG }> // public_key stored_seqno stored_subwallet cs ENDS SWAP INC // public_key stored_subwallet seqno' NEWC 32 STU 32 STU 256 STU ENDC c4 POP }>c The last code fragment resembles TVM assembly because most of it actually is TVM assembly. Here’s why: Imagine explaining programming concepts to a trainee. Your instructions become part of their program, processed twice - similar to how opcodes in capital letters (SETCP0, DUP, etc.) are processed by both Fift and TVM. Think of Fift as a teaching language where you can introduce high-level concepts to a learner. Just as a trainee programmer gradually absorbs and applies new concepts, Fift allows you to define custom commands and abstractions. The `Asm.fif` file demonstrates this perfectly - it’s essentially a collection of TVM opcode definitions. TVM assembly, in contrast, is like the trainee’s final working program. While it operates with fewer built-in features (it can’t perform cryptographic signing, for instance), it has direct access to the blockchain environment during contract execution. Where Fift works at compile-time to shape the contract’s code, TVM assembly runs that code on the actual blockchain. [​](https://docs.ton.org/languages/fift/fift-and-tvm-assembly#smart-contract-usage) Smart contract usage ----------------------------------------------------------------------------------------------------------- ### [​](https://docs.ton.org/languages/fift/fift-and-tvm-assembly#fift-including-large-bocs-in-contracts) (Fift) Including large BoCs in contracts When using `toncli`, you can include large BoCs by: 1. Editing `project.yaml` to include `fift/blob.fif`: contract: fift: - fift/blob.fif func: - func/code.fc 2. Adding the BoC to `fift/blob.boc` 3. Including this code in `fift/blob.fif`: B B>boc ref, b> DO<{ SWAP TEN DIVMOD s1 s2 XCHG TPUSH }> NIP"; builder store_number(builder msg, tuple t) asm "WHILE:<{ DUP TLEN }>DO<{ TPOP 48 ADDCONST ROT 8 STU SWAP }> DROP"; builder store_signed(builder msg, int v) inline_ref { if (v < 0) { return msg.store_uint(45, 8).store_number(digitize_number(-v)); } elseif (v == 0) { return msg.store_uint(48, 8); } else { return msg.store_number(digitize_number(v)); } } ### [​](https://docs.ton.org/languages/fift/fift-and-tvm-assembly#tvm-assembly-efficient-modulo-multiplication) (TVM assembly) Efficient modulo multiplication Compare these implementations: int mul_mod(int a, int b, int m) inline_ref { ;; 1232 gas units (_, int r) = muldivmod(a % m, b % m, m); return r; } int mul_mod_better(int a, int b, int m) inline_ref { ;; 1110 gas units (_, int r) = muldivmod(a, b, m); return r; } int mul_mod_best(int a, int b, int m) asm "x{A988} s,"; ;; 65 gas units The `x{A988}` opcode implements an optimized division operation with built-in multiplication (as specified in [section 5.2 Division](https://docs.ton.org/tvm/instructions#A988) ). This specialized instruction directly computes just the modulo remainder of the operation, skipping unnecessary computation steps. The `s,` suffix then handles the result storage - it takes the resulting slice from the stack’s top and efficiently writes it into the target builder. Together, this combination delivers substantial gas savings compared to conventional approaches. Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/languages/fift/fift-and-tvm-assembly.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/languages/fift/fift-and-tvm-assembly) [Previous](https://docs.ton.org/languages/fift/overview) [Deep dive\ \ Next](https://docs.ton.org/languages/fift/deep-dive) ⌘I On this page * [Key differences](https://docs.ton.org/languages/fift/fift-and-tvm-assembly#key-differences) * [Smart contract usage](https://docs.ton.org/languages/fift/fift-and-tvm-assembly#smart-contract-usage) * [(Fift) Including large BoCs in contracts](https://docs.ton.org/languages/fift/fift-and-tvm-assembly#fift-including-large-bocs-in-contracts) * [(TVM assembly) Converting integers to strings](https://docs.ton.org/languages/fift/fift-and-tvm-assembly#tvm-assembly-converting-integers-to-strings) * [(TVM assembly) Efficient modulo multiplication](https://docs.ton.org/languages/fift/fift-and-tvm-assembly#tvm-assembly-efficient-modulo-multiplication) --- # Retracer - TON Docs [Skip to main content](https://docs.ton.org/tvm/tools/retracer#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Tools Retracer [Retracer](https://retracer.ton.org/) is a classic TVM transaction tracing tool for inspecting transaction execution step by step. Use it to: * inspect complex transaction flows; * debug smart contract execution; * review gas usage and fees. Source code: [`ton-blockchain/tvm-web-viewer` on GitHub](https://github.com/ton-blockchain/tvm-web-viewer/) . The screenshot shows the main parts of the Retracer interface: * Transaction details show the sender, destination contract, transferred amounts, timestamp, logical time (LT), fees, and balances; * C5 button displays the action list for the transaction; * Logs button displays detailed execution logs; * On the left, the instruction list shows the TVM instructions executed by the contract; * On the right, the stack panel shows the stack state for the selected instruction. Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/tvm/tools/retracer.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/tvm/tools/retracer) [Previous](https://docs.ton.org/tvm/tools/txtracer) [TVM Explorer\ \ Next](https://docs.ton.org/tvm/tools/tvm-explorer) ⌘I --- # Fift deep dive - TON Docs [Skip to main content](https://docs.ton.org/languages/fift/deep-dive#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Fift Fift deep dive Fift is a high-level stack-based language used for local manipulation of cells and other TVM primitives. Its primary purpose is to compile TVM assembly code into contract code as a bag-of-cells (BoC). [​](https://docs.ton.org/languages/fift/deep-dive#simple-arithmetic) Simple arithmetic ----------------------------------------------------------------------------------------- Use the Fift interpreter as a calculator with reverse Polish notation: 6 17 17 * * 289 + . 2023 ok This example calculates: 1. `17 * 17 = 289` 2. `6 * 289 = 1734` 3. `1734 + 289 = 2023` [​](https://docs.ton.org/languages/fift/deep-dive#standard-output) Standard output ------------------------------------------------------------------------------------- 27 emit ."[30;1mgrey text" 27 emit ."[37m"\ grey text ok\ \ \ * `emit` prints the Unicode character corresponding to the number on top of the stack\ * `."..."` outputs a constant string\ \ [​](https://docs.ton.org/languages/fift/deep-dive#defining-functions-fift-words)\ \ Defining functions (Fift words)\ -------------------------------------------------------------------------------------------------------------------\ \ To define a word, follow these steps:\ \ 1. **Enclose the word’s effects** in curly braces `{}`.\ 2. **Add a colon `:`** after the closing brace.\ 3. **Specify the word’s name** after the colon.\ \ The first line defines the word `increment` as a function that increases `x` by `1`. **Examples:**\ \ // Fift.fif\ { x 1 + } : increment\ { minmax drop } : min\ { minmax nip } : max\ \ \ In TON, multiple **defining words** exist, not just `:`. They differ in behavior:\ \ * **Active words** – Operate inside curly braces `{}`.\ * **Prefix words** – Do not require a trailing space.\ \ // Fift.fif\ { bl word 1 2 ' (create) } "::" 1 (create)\ { bl word 0 2 ' (create) } :: :\ { bl word 2 2 ' (create) } :: :_\ { bl word 3 2 ' (create) } :: ::_\ { bl word 0 (create) } : create\ \ \ [​](https://docs.ton.org/languages/fift/deep-dive#conditional-execution)\ \ Conditional execution\ -------------------------------------------------------------------------------------------------\ \ Execute code blocks conditionally using `cond`:\ \ { { ."true " } { ."false " } cond } : ?. 4 5 = ?. 4 5 < ?.\ false true ok\ { ."hello " } execute ."world"\ hello world ok\ \ \ [​](https://docs.ton.org/languages/fift/deep-dive#loops)\ \ Loops\ -----------------------------------------------------------------\ \ Use loop primitives for repetitive operations:\ \ // GetOpt.fif\ // ( l c -- l') Removes first c elements from list l\ { ' safe-cdr swap times } : list-delete-first\ \ \ Loop word `times` takes two arguments - let’s call them `cont` and `n` - and executes `cont` `n` times. Here `list-delete-first` takes continuation of `safe-cdr` (command deleting head from Lisp-style list), places it under `c`, and then `c` times removes head from list present on stack. `while`/`until` provide conditional looping.\ \ [​](https://docs.ton.org/languages/fift/deep-dive#comments)\ \ Comments\ -----------------------------------------------------------------------\ \ Comments in Fift are defined in `Fift.fif` and come in two forms:\ \ 1. **Single-line comments**: Start with `//` and continue to the end of the line\ 2. **Multiline comments**: Start with `/*` and end with `*/`\ \ // Fift.fif\ { 0 word drop 0 'nop } :: //\ { char " word 1 { swap { abort } if drop } } ::_ abort"\ { { bl word dup "" $= abort"comment extends after end of file" "*/" $= } until 0 'nop } :: /*\ \ \ #### \ \ [​](https://docs.ton.org/languages/fift/deep-dive#how-comments-work)\ \ How comments work\ \ Fift programs are sequences of words that transform the stack or define new words. Comments must work even during word definitions, requiring them to be **active words** (defined with `::`). Breaking down the `//` definition:\ \ 1. `0` - Pushes zero onto the stack\ 2. `word` - Reads characters until reaching one matching the top stack value (zero is special - skips leading spaces then reads to end of line)\ 3. `drop` - Removes the comment text from the stack\ 4. `0` - Pushes zero again (number of results for `::` definition)\ 5. `'nop` - Pushes an execution token that does nothing (equivalent to `{ nop }`)\ \ [​](https://docs.ton.org/languages/fift/deep-dive#using-fift-for-defining-tvm-assembly-codes)\ \ Using Fift for defining TVM assembly codes\ -------------------------------------------------------------------------------------------------------------------------------------------\ \ // Asm.fif (line order reversed)\ x{00} @Defop NOP\ { 1 ' @addop does create } : @Defop\ { tuck sbitrefs @ensurebitrefs swap s, } : @addop\ { @havebitrefs ' @| ifnot } : @ensurebitrefs\ { 2 pick brembitrefs 1- 2x<= } : @havebitrefs\ { rot >= -rot <= and } : 2x<=\ ...\ \ \ ### \ \ [​](https://docs.ton.org/languages/fift/deep-dive#how-@defop-works)\ \ How `@Defop` works\ \ `@Defop` checks available space for the opcode using `@havebitrefs`. If space is insufficient, it writes to another builder via `@|` (implicit jump). **Important:** Always use `x{A988} @addop` instead of `x{A988} s,` to avoid compilation failures when space is limited.\ \ ### \ \ [​](https://docs.ton.org/languages/fift/deep-dive#including-cells-in-contracts)\ \ Including cells in contracts\ \ You can embed large bag-of-cells into contracts:\ \ B B>boc ref, b> pub`** - Derives a public key from a private key\ * **`ed25519_sign[_uint]`** - Creates a signature for given data using a private key\ * **`ed25519_chksign`** - Verifies an Ed25519 signature\ \ ### \ \ [​](https://docs.ton.org/languages/fift/deep-dive#tvm-interaction)\ \ TVM interaction\ \ * **`runvmcode` and similar commands** - Executes TVM with a code slice taken from the stack\ \ ### \ \ [​](https://docs.ton.org/languages/fift/deep-dive#file-operations)\ \ File operations\ \ * **Save BoC to file**:\ \ boc>B ".../contract.boc" B>file\ \ \ \ [​](https://docs.ton.org/languages/fift/deep-dive#continue-learning)\ \ Continue learning\ -----------------------------------------------------------------------------------------\ \ * [Fift: A Brief Introduction](https://docs.ton.org/resources/pdfs/fiftbase.pdf)\ - _Nikolai Durov_\ \ Was this page helpful?\ \ YesNo\ \ [Suggest edits](https://github.com/ton-org/docs/edit/main/languages/fift/deep-dive.mdx)\ [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/languages/fift/deep-dive)\ \ [Previous](https://docs.ton.org/languages/fift/fift-and-tvm-assembly)\ [Simple multisig contract\ \ Next](https://docs.ton.org/languages/fift/multisig)\ \ ⌘I\ \ On this page\ \ * [Simple arithmetic](https://docs.ton.org/languages/fift/deep-dive#simple-arithmetic)\ \ * [Standard output](https://docs.ton.org/languages/fift/deep-dive#standard-output)\ \ * [Defining functions (Fift words)](https://docs.ton.org/languages/fift/deep-dive#defining-functions-fift-words)\ \ * [Conditional execution](https://docs.ton.org/languages/fift/deep-dive#conditional-execution)\ \ * [Loops](https://docs.ton.org/languages/fift/deep-dive#loops)\ \ * [Comments](https://docs.ton.org/languages/fift/deep-dive#comments)\ \ * [How comments work](https://docs.ton.org/languages/fift/deep-dive#how-comments-work)\ \ * [Using Fift for defining TVM assembly codes](https://docs.ton.org/languages/fift/deep-dive#using-fift-for-defining-tvm-assembly-codes)\ \ * [How @Defop works](https://docs.ton.org/languages/fift/deep-dive#how-%40defop-works)\ \ * [Including cells in contracts](https://docs.ton.org/languages/fift/deep-dive#including-cells-in-contracts)\ \ * [Special features](https://docs.ton.org/languages/fift/deep-dive#special-features)\ \ * [Ed25519 cryptography](https://docs.ton.org/languages/fift/deep-dive#ed25519-cryptography)\ \ * [TVM interaction](https://docs.ton.org/languages/fift/deep-dive#tvm-interaction)\ \ * [File operations](https://docs.ton.org/languages/fift/deep-dive#file-operations)\ \ * [Continue learning](https://docs.ton.org/languages/fift/deep-dive#continue-learning) --- # TVM Explorer - TON Docs [Skip to main content](https://docs.ton.org/tvm/tools/tvm-explorer#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Tools TVM Explorer [TVM Explorer](https://tvm-explorer.netlify.app/) is an interactive tool for exploring TVM assembly. Use it to see how your [Fift](https://docs.ton.org/languages/fift) code compiles to TVM assembly. It allows * examining TVM bitcode and understanding instruction behavior; * seeing how Fift code translates to TVM instructions. For more modern languages use TxTracer’s [Playground](https://docs.ton.org/tvm/tools/txtracer#2-playground) . Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/tvm/tools/tvm-explorer.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/tvm/tools/tvm-explorer) [Previous](https://docs.ton.org/tvm/tools/retracer) [TON Decompiler\ \ Next](https://docs.ton.org/tvm/tools/ton-decompiler) ⌘I --- # Simple multisig contract with Fift - TON Docs [Skip to main content](https://docs.ton.org/languages/fift/multisig#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Fift Simple multisig contract with Fift This information is **very low-level**. It could be hard for newcomers and designed for advanced people who want to understand [Fift](https://docs.ton.org/languages/fift) . The use of Fift is not required in everyday tasks. [​](https://docs.ton.org/languages/fift/multisig#overview) Overview ---------------------------------------------------------------------- This tutorial helps you learn how to deploy your multisig contract. Recall that a (n,k)(n, k)(n,k)\-multisig contract is a multi-signature wallet with nnn private key holders, which accepts requests to send messages if the request (a.k.a. order, query) collects at least kkk holders’ signatures. Based on the original multisig contract code and updates by akifoq: * [Original TON Blockchain multisig-code.fc](https://github.com/ton-blockchain/ton/blob/master/crypto/smartcont/multisig-code.fc) * [akifoq/multisig](https://github.com/akifoq/multisig) with Fift libraries to work with multisig. [​](https://docs.ton.org/languages/fift/multisig#what-you%E2%80%99ll-learn) What you’ll learn ------------------------------------------------------------------------------------------------ * How to create and customize a simple multisig wallet. * How to deploy a multisig wallet using a Lite client. * How to sign a request and send it in a message to the blockchain. [​](https://docs.ton.org/languages/fift/multisig#set-up-your-environment) Set up your environment ---------------------------------------------------------------------------------------------------- Before we begin our journey, check and prepare your environment. * Install `func`, `fift`, `lite-client` binaries, and `fiftlib` from the [latest GitHub release](https://github.com/ton-blockchain/ton/releases/latest) . * Clone the [repository](https://github.com/akifoq/multisig) and open its directory in CLI. git clone https://github.com/akifoq/multisig.git cd ./multisig [​](https://docs.ton.org/languages/fift/multisig#get-started) Get started ---------------------------------------------------------------------------- 1. Compile the code to Fift. 2. Prepare multisig owner’s keys. 3. Deploy your contract. 4. Interact with the deployed multisig wallet in the blockchain. ### [​](https://docs.ton.org/languages/fift/multisig#compile-the-contract) Compile the contract Compile the contract to Fift with: func -o multisig-code.fif -SPA stdlib.fc multisig-code.fc ### [​](https://docs.ton.org/languages/fift/multisig#prepare-multisig-owner%E2%80%99s-keys) Prepare multisig owner’s keys #### [​](https://docs.ton.org/languages/fift/multisig#create-participant%E2%80%99s-keys) Create participant’s keys To create a key, you need to run: fift -s new-key.fif $KEY_NAME$ * Where `KEY_NAME` is the file name where the private key will be written. For example: fift -s new-key.fif multisig_key We’ll receive a `multisig_key.pk` file with the private key inside. #### [​](https://docs.ton.org/languages/fift/multisig#collect-public-keys) Collect public keys Also, the script will issue a public key in the format: Public key = Pub5XqPLwPgP8rtryoUDg2sadfuGjkT4DLRaVeIr08lb8CB5HW Anything after `Public key =` needs to be saved somewhere! Let’s store it in a file called `keys.txt`. It’s essential to have one public key per line. ### [​](https://docs.ton.org/languages/fift/multisig#deploy-your-contract) Deploy your contract #### [​](https://docs.ton.org/languages/fift/multisig#deploy-via-lite-client) Deploy via `lite-client` After creating all the keys, you need to collect the public keys into a text file, `keys.txt`. For example: PubExXl3MdwPVuffxRXkhKN1avcGYrm6QgJfsqdf4dUc0an7/IA PubH821csswh8R1uO9rLYyP1laCpYWxhNkx+epOkqwdWXgzY4 After that, you need to run: fift -s new-multisig.fif 0 $WALLET_ID$ wallet $KEYS_COUNT$ ./keys.txt * `$WALLET_ID$`: the wallet number assigned to the current key. It is recommended that each new wallet with the same key use a unique `$WALLET_ID$`. * `$KEYS_COUNT$`: the number of keys needed for confirmation, usually equal to the number of public keys. The script will output something like: new wallet address = 0:4bbb2660097db5c72dd5e9086115010f0f8c8501e0b8fef1fe318d9de5d0e501 (Saving address to file wallet.addr) Non-bounceable address (for init): 0QBLuyZgCX21xy3V6QhhFQEPD4yFAeC4_vH-MY2d5dDlAbel Bounceable address (for later access): kQBLuyZgCX21xy3V6QhhFQEPD4yFAeC4_vH-MY2d5dDlAepg (Saved wallet creating query to file wallet-create.boc) Keep the bounceable address — this is the wallet address we will be using. #### [​](https://docs.ton.org/languages/fift/multisig#activate-your-contract) Activate your contract You need to send some TON to the newly generated wallet. For example, 0.5 TON. You can send testnet coins via [`@testgiver_ton_bot`](https://t.me/testgiver_ton_bot) . After that, run `lite-client`: lite-client -C global.config.json After starting a Lite client, it’s best to run the `time` command in the `lite-client` console to make sure the connection was successful: time Okay, Lite client works! After that, you need to deploy the wallet. Run the command: sendfile ./wallet-create.boc After that, the wallet will be ready to work within a minute. ### [​](https://docs.ton.org/languages/fift/multisig#interact-with-a-multisig-wallet) Interact with a multisig wallet #### [​](https://docs.ton.org/languages/fift/multisig#create-a-request) Create a request First, you need to create a message request: fift -s create-msg.fif $ADDRESS$ $AMOUNT$ $MESSAGE$ * `$ADDRESS$` - address where to send coins. * `$AMOUNT$` - number of coins (in TON). * `$MESSAGE$` - the file name for the compiled message. For example: fift -s create-msg.fif EQApAj3rEnJJSxEjEHVKrH3QZgto_MQMOmk8l72azaXlY1zB 0.1 message #### [​](https://docs.ton.org/languages/fift/multisig#choose-a-wallet) Choose a wallet Next, you need to choose a wallet to send coins from: fift -s create-order.fif $WALLET_ID$ $MESSAGE$ -t $AWAIT_TIME$ Where: * `$WALLET_ID$` — ID of the wallet backed by this multisig contract. * `$AWAIT_TIME$` — time in seconds the smart contract will await signatures from the multisig wallet owners for the request. * `$MESSAGE$` — name of the message BoC file created in the previous step. For example: fift -s create-order.fif 0 message -t 7200 The resulting file is saved as `order.boc`. #### [​](https://docs.ton.org/languages/fift/multisig#sign-your-part) Sign your part To sign, run: fift -s add-signature.fif $KEY$ $KEY_INDEX$ * `$KEY$` - file name containing the private key to sign, without extension. * `$KEY_INDEX$` - index of the given key in `keys.txt` (zero-based). For example, for our `multisig_key.pk` file: fift -s add-signature.fif multisig_key 0 #### [​](https://docs.ton.org/languages/fift/multisig#create-a-message) Create a message After everyone has signed the order, it needs to be turned into a message for the wallet and signed again with the following command: fift -s create-external-message.fif wallet $KEY$ $KEY_INDEX$ In this case, only one signature from a wallet owner is enough. The idea is that you can’t attack a contract with invalid signatures. For example: fift -s create-external-message.fif wallet multisig_key 0 #### [​](https://docs.ton.org/languages/fift/multisig#send-the-signed-message-to-the-ton-blockchain) Send the signed message to the TON blockchain After that, start `lite-client` again: lite-client -C global.config.json And finally, we want to send our sign! Just run: sendfile wallet-query.boc If everyone else signed the request, it would be completed! You did it! [​](https://docs.ton.org/languages/fift/multisig#see-also) See also ---------------------------------------------------------------------- * [Multisignature wallet v2](https://github.com/ton-blockchain/multisig-contract-v2) Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/languages/fift/multisig.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/languages/fift/multisig) [Previous](https://docs.ton.org/languages/fift/deep-dive) [WhitepaperWhitepaper by Dr. Nikolai Durov\ \ Next](https://docs.ton.org/languages/fift/whitepaper) ⌘I On this page * [Overview](https://docs.ton.org/languages/fift/multisig#overview) * [What you’ll learn](https://docs.ton.org/languages/fift/multisig#what-you%E2%80%99ll-learn) * [Set up your environment](https://docs.ton.org/languages/fift/multisig#set-up-your-environment) * [Get started](https://docs.ton.org/languages/fift/multisig#get-started) * [Compile the contract](https://docs.ton.org/languages/fift/multisig#compile-the-contract) * [Prepare multisig owner’s keys](https://docs.ton.org/languages/fift/multisig#prepare-multisig-owner%E2%80%99s-keys) * [Create participant’s keys](https://docs.ton.org/languages/fift/multisig#create-participant%E2%80%99s-keys) * [Collect public keys](https://docs.ton.org/languages/fift/multisig#collect-public-keys) * [Deploy your contract](https://docs.ton.org/languages/fift/multisig#deploy-your-contract) * [Deploy via lite-client](https://docs.ton.org/languages/fift/multisig#deploy-via-lite-client) * [Activate your contract](https://docs.ton.org/languages/fift/multisig#activate-your-contract) * [Interact with a multisig wallet](https://docs.ton.org/languages/fift/multisig#interact-with-a-multisig-wallet) * [Create a request](https://docs.ton.org/languages/fift/multisig#create-a-request) * [Choose a wallet](https://docs.ton.org/languages/fift/multisig#choose-a-wallet) * [Sign your part](https://docs.ton.org/languages/fift/multisig#sign-your-part) * [Create a message](https://docs.ton.org/languages/fift/multisig#create-a-message) * [Send the signed message to the TON blockchain](https://docs.ton.org/languages/fift/multisig#send-the-signed-message-to-the-ton-blockchain) * [See also](https://docs.ton.org/languages/fift/multisig#see-also) --- # TON Decompiler - TON Docs [Skip to main content](https://docs.ton.org/tvm/tools/ton-decompiler#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Tools TON Decompiler [TON Decompiler](https://github.com/tact-lang/ton-opcode) is an utility for converting [BoC](https://docs.ton.org/foundations/serialization/boc) of the contract into a [Fift](https://docs.ton.org/languages/fift/overview) \-like pseudocode. Decompiled code cannot match match the original source. At the very least, variable names and high-level structure is removed during compilation. Variables and methods will get some generated names, for example, `?fun_ref_12345678`. The resulting pseudocode might not compile back to the same BoC either. [​](https://docs.ton.org/tvm/tools/ton-decompiler#cli-usage) CLI usage ------------------------------------------------------------------------- Install Tact language tool suite. npm install -g @tact-lang/compiler Then run it on a BoC file: unboc example.boc [​](https://docs.ton.org/tvm/tools/ton-decompiler#api-usage) API usage ------------------------------------------------------------------------- Add it to the project npm install @tact-lang/ton-decompiler Then call a disassembler to decompile it, and a writer to put the result back into Fift-like pseudocode. import { Cell } from "@ton/core"; import { disassembleRoot } from "./decompiler/disasm"; import { AssemblyWriter } from "./printer/assembly-writer"; const cell: Cell = ...; // your TVM contract bytecode const program = disassembleRoot(cell); const writer = new AssemblyWriter(); const code = writer.write(program); console.log(code); Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/tvm/tools/ton-decompiler.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/tvm/tools/ton-decompiler) [Previous](https://docs.ton.org/tvm/tools/tvm-explorer) [InstructionsInteractive reference for TVM instructions\ \ Next](https://docs.ton.org/tvm/instructions) ⌘I On this page * [CLI usage](https://docs.ton.org/tvm/tools/ton-decompiler#cli-usage) * [API usage](https://docs.ton.org/tvm/tools/ton-decompiler#api-usage) --- # FunC language overview - TON Docs [Skip to main content](https://docs.ton.org/languages/func/overview#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation FunC FunC language overview FunC is a domain-specific, statically typed language with C-like syntax designed to write smart contracts on TON. It can be characterized as an intermediate-level language sitting on top of the [Fift](https://docs.ton.org/languages/fift) assembly language. Example of a FunC function for sending funds: () send_money(slice address, int amount) impure inline { var msg = begin_cell() ;; Set the message to be non-bounceable .store_uint(0x10, 6) .store_slice(address) .store_coins(amount) .end_cell(); send_raw_message(msg, 64); } where * [`()`](https://docs.ton.org/languages/func/types#tensor-types) is the return type, that stands for “do not return value”, similar to `void` in C; * `send_money` is the name of the function; * `slice address` is the first parameter, address to send money to; it’s type is [`slice`](https://docs.ton.org/languages/func/types#atomic-types) ; * `int amount` is the second parameter, amount to be sent; it’s type is [`int`](https://docs.ton.org/languages/func/types#atomic-types) ; * `impure inline` are [specifiers](https://docs.ton.org/languages/func/functions#specifiers) , which are flags that tell the compiler to process the method in a specific way; * `var msg = ...` defines a variable without specifying its type; it will hold a [cell](https://docs.ton.org/foundations/serialization/cells) with a [message](https://docs.ton.org/foundations/messages/overview) ; * [`begin_cell()`](https://docs.ton.org/languages/func/stdlib#begin-cell) creates a [cell builder](https://docs.ton.org/tvm/builders-and-slices) ; * [`store_uint`](https://docs.ton.org/languages/func/stdlib#store-uint) , [`store_slice`](https://docs.ton.org/languages/func/stdlib#store-slice) , [`store_coins`](https://docs.ton.org/languages/func/stdlib#store-coins) methods store data into the builder: * [flags](https://docs.ton.org/foundations/messages/internal) ; * receiving address; * amount on Toncoin to attach to the message. * [`.end_cell()`](https://docs.ton.org/languages/func/stdlib#end-cell) method finalizes the builder and turns it into a cell; * [`send_raw_message`](https://docs.ton.org/languages/func/stdlib#send-raw-message) function sends the message, where the parameter `64` describes a [sending mode](https://docs.ton.org/foundations/messages/internal) . [​](https://docs.ton.org/languages/func/overview#compiler) Compiler ---------------------------------------------------------------------- The compiler converts FunC programs into [Fift](https://docs.ton.org/languages/fift) assembly code. The Fift assembly code is then compiled down to the [TON Virtual Machine](https://docs.ton.org/tvm/overview) bitcode by the [Fift](https://docs.ton.org/languages/fift) compiler. Developers can use the compiled bitcode, structured as a [bag of cells](https://docs.ton.org/foundations/serialization/boc) like all data in the TON blockchain, to test smart contracts, send messages, or execute it in a local TVM instance. ### [​](https://docs.ton.org/languages/func/overview#end-to-end-tooling) End-to-end tooling The easiest way to install the FunC compiler is the [`@ton-community/func-js`](https://www.npmjs.com/package/@ton-community/func-js) NPM package. It requires [Node.js](https://nodejs.org/en/download) v22 or later. The package has both the FunC and [Fift](https://docs.ton.org/languages/fift) compilers, and produces bitcode directly from the FunC source code, without manually invoking Fift. To install it, run the following command in the project root folder: npm i @ton-community/func-js Then, to compile a specific FunC file, run the following command: npx func-js ./contract.fc --boc ./output.boc where `contract.fc` is the FunC source file in the project root, and `output.boc` is the compiled bitcode output. FunC standard library is supplied separately from the language. Download `smartcont_lib.zip` from the [latest release](https://github.com/ton-blockchain/ton/releases) , extract it, and copy `stdlib.fc` to the project root. Alternatively, use the [Blueprint](https://docs.ton.org/contract-dev/blueprint/overview) to start a project pre-configured for development in FunC. ### [​](https://docs.ton.org/languages/func/overview#compile-manually-using-the-binaries) Compile manually using the binaries Prebuilt FunC compiler binaries for Windows, macOS (Intel or ARM64), and Ubuntu are available on the [GitHub](https://github.com/ton-blockchain/ton/releases) . 1. Download the corresponding binary for operating system: * Linux: `func-linux-x86_64` (Intel/AMD) and `func-linux-arm64` (ARM64) * Mac: `func-mac-x86-64` (Intel/AMD) and `func-mac-arm64` (ARM64) * Windows: `func.exe` Rename the executable, for example, to `func`, for easier use on the command line, and add it to system’s `PATH`. 2. Download the FunC standard library. Get the `smartcont_lib.zip` from the same [GitHub](https://github.com/ton-blockchain/ton/releases/tag/v2025.07) , extract it, and copy `stdlib.fc` to project root. 3. Compile a FunC file to Fift assembly code. Run the following command in the project root: func contract.fc -o output.fif where `contract.fc` is the FunC file to compile, and `output.fif` is the generated Fift output. To compile the generated Fift file `output.fif` further down to TVM bitcode, use the Fift compiler. See the [Fift](https://docs.ton.org/languages/fift) for download and usage instructions. [​](https://docs.ton.org/languages/func/overview#tutorials) Tutorials ------------------------------------------------------------------------ * [Challenge 1: Simple NFT deploy](https://github.com/romanovichim/TONQuest1/) * [Challenge 2: Chatbot contract](https://github.com/romanovichim/TONQuest2/) * [Challenge 3: Jetton vending machine](https://github.com/romanovichim/TONQuest3/) * [Challenge 4: Lottery/raffle](https://github.com/romanovichim/TONQuest4/) * [Challenge 5: Create UI to interact with the contract in 5 minutes](https://github.com/romanovichim/TONQuest5/) * [Challenge 6: Analyzing NFT sales on the Getgems marketplace](https://github.com/romanovichim/TONQuest6/) * [TON hello world Part 2: guide for writing your first smart contract](https://ton-community.github.io/tutorials/02-contract/) * [TON hello world Part 4: guide for testing your first smart contract](https://ton-community.github.io/tutorials/04-testing/) * [10 lessons for developing contracts in FunC](https://github.com/romanovichim/TonFunClessons_Eng/) — [Russian version](https://github.com/romanovichim/TonFunClessons_ru/) * [FunC quiz](https://t.me/toncontests/60/) — a short Telegram quiz focused on FunC, with a few general TON questions. [​](https://docs.ton.org/languages/func/overview#contests) Contests ---------------------------------------------------------------------- | Contest | Tasks | Solutions | | --- | --- | --- | | TSC #5 (Dec 2023) | [Tasks](https://github.com/ton-community/tsc5/) | — | | TSC #4 (Sep 2023) | [Tasks](https://github.com/ton-community/tsc4/) | [1](https://github.com/aSpite/tsc4-contracts)
[2](https://github.com/ProgramCrafter/tsc4)
[3](https://github.com/Gusarich/tsc4)
[4](https://github.com/akifoq/tsc4) | | TSC #3 (Dec 2022) | [Tasks](https://github.com/ton-blockchain/func-contest3/) | [Solutions](https://github.com/nns2009/TON-FunC-contest-3/) | | TSC #2 (Jul 2022) | [Tasks](https://github.com/ton-blockchain/func-contest2/) | [Solutions](https://github.com/ton-blockchain/func-contest2-solutions/) | | TSC #1 (Mar 2022) | [Tasks](https://github.com/ton-blockchain/func-contest1/) | [Solutions](https://github.com/ton-blockchain/func-contest1-solutions/) | [​](https://docs.ton.org/languages/func/overview#changelog) Changelog ------------------------------------------------------------------------ [History of FunC](https://docs.ton.org/languages/func/changelog) Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/languages/func/overview.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/languages/func/overview) [Previous](https://docs.ton.org/languages/fift/whitepaper) [Cookbook\ \ Next](https://docs.ton.org/languages/func/cookbook) ⌘I On this page * [Compiler](https://docs.ton.org/languages/func/overview#compiler) * [End-to-end tooling](https://docs.ton.org/languages/func/overview#end-to-end-tooling) * [Compile manually using the binaries](https://docs.ton.org/languages/func/overview#compile-manually-using-the-binaries) * [Tutorials](https://docs.ton.org/languages/func/overview#tutorials) * [Contests](https://docs.ton.org/languages/func/overview#contests) * [Changelog](https://docs.ton.org/languages/func/overview#changelog) --- # Wallet V5 - TON Docs [Skip to main content](https://docs.ton.org/standard/wallets/v5#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation V5 Wallet V5 The V5 wallet standard offers many benefits that improve the experience for both users and developers. V5 supports gasless transactions, account delegation and recovery, subscription payments using Jettons and Toncoin, and low-cost multi-transfers. In addition to retaining the previous functionality (V4), the new contract allows you to send up to 255 messages at a time. This article provides only a high-level wallet V5 contract overview. If you want to learn more about how to use its interfaces or develop extensions, check out the [wallet V5 API](https://docs.ton.org/standard/wallets/v5-api) article. Source links: * [Wallet V5 source code](https://github.com/ton-blockchain/wallet-contract-v5) . * [TL-B scheme for V5](https://github.com/ton-blockchain/wallet-contract-v5/blob/321186127e8cc5e395ad3b2f1870839237c56f5f/types.tlb) [​](https://docs.ton.org/standard/wallets/v5#persistent-memory-layout) Persistent memory layout -------------------------------------------------------------------------------------------------- contract_state$_ is_signature_allowed:(## 1) seqno:(## 32) wallet_id:(## 32) public_key:(## 256) extensions_dict:(HashmapE 256 int1) = ContractState; * `is_signature_allowed`: 1-bit flag that restricts or allows access through the signature and stored public key. * `seqno`: 32-bit sequence number. * `wallet_id`: 32-bit wallet ID (equivalent to subwallet\_id in previous versions). * `public_key`: 256-bit public key. * `extensions_dict`: dictionary containing extensions (may be empty). As you can see, the `ContractState`, compared to previous versions, hasn’t changed much. The main difference is the new `is_signature_allowed` 1-bit flag, which restricts or allows access through the signature and stored public key. We will describe the importance of this change in later topics. [​](https://docs.ton.org/standard/wallets/v5#message-layout) Message layout ------------------------------------------------------------------------------ ### [​](https://docs.ton.org/standard/wallets/v5#external-message-body-layout) External message body layout * `wallet_id`: 32-bit long wallet ID. * `valid_until`: 32-bit long Unix time integer. * `msg_seqno`: 32-bit long sequence number. * `inner`: InnerRequest containing the actual actions to perform. * `signature`: 512-bit long [Ed25519](https://en.wikipedia.org/wiki/EdDSA#Ed25519) signature. ### [​](https://docs.ton.org/standard/wallets/v5#internal-message-body-layout) Internal message body layout Learn more about internal message serialization [here](https://docs.ton.org/standard/wallets/v5-api) . [​](https://docs.ton.org/standard/wallets/v5#authentication-process) Authentication process ---------------------------------------------------------------------------------------------- internal_signed#73696e74 signed:SignedRequest = InternalMsgBody; internal_extension#6578746e query_id:(## 64) inner:InnerRequest = InternalMsgBody; Before we get to the actual payload of our messages — `InnerRequest` — let’s first look at how version 5 differs from previous versions in the authentication process. The `InternalMsgBody` combinator describes two ways to access wallet actions through internal messages. The first method is one we are already familiar with from version 4: authentication as a previously registered extension, the address of which is stored in `extensions_dict`. The second method is authentication through the stored public key and signature, similar to external requests. At first, this might seem like an unnecessary feature, but it actually enables requests to be processed through external services (smart contracts) that are not part of your wallet’s extension infrastructure — a key feature of V5. Gasless transactions rely on this functionality. Any received internal message that doesn’t pass the authentication process will be considered a transfer. [​](https://docs.ton.org/standard/wallets/v5#actions) Actions ---------------------------------------------------------------- The first thing that we should notice is `InnerRequest`, which we have already seen in the authentication process. In contrast to the previous version, both external and internal messages have access to the same functionality, except for changing the signature mode (i.e., the `is_signature_allowed` flag). We can consider `InnerRequest` as two lists of actions: the first, `OutList`, is an optional chain of cell references, each containing a send message request led by the message mode. The second, `ActionList`, is led by a one-bit flag, `has_other_actions`, which marks the presence of extended actions, starting from the first cell and continuing as a chain of cell references. We are already familiar with the first two extended actions, `action_add_ext` and `action_delete_ext`, followed by the internal address that we want to add or delete from the extensions dictionary. The third, `action_set_signature_auth_allowed`, restricts or allows authentication through the public key, leaving the only way to interact with the wallet through extensions. This functionality might be extremely important in the case of a lost or compromised private key. Learn more about actions [here](https://docs.ton.org/standard/wallets/v5-api) . [​](https://docs.ton.org/standard/wallets/v5#exit-codes) Exit codes ---------------------------------------------------------------------- | Exit code | Description | | --- | --- | | 132 | Authentication attempt through signature while it’s disabled | | 133 | `seqno` check failed, replay protection occurred | | 134 | `wallet_id` does not correspond to the stored one | | 135 | `signature` check failed | | 136 | `valid_until` check failed | | 137 | Enforce that `send_mode` has the +2 bit (ignore errors) set for external messages. | | 138 | `external_signed` prefix doesn’t correspond to the received one | | 139 | Add extension operation was not successful | | 140 | Remove extension operation was not successful | | 141 | Unsupported extended message prefix | | 142 | Tried to disable auth by signature while the extension dictionary is empty | | 143 | Attempt to set signature to an already set state | | 144 | Tried to remove the last extension when signature is disabled | | 145 | Extension has the wrong workchain | | 146 | Tried to change signature mode through external message | | 147 | Invalid `c5`, `action_send_msg` verification failed | | 0 | Standard successful execution exit code. | [​](https://docs.ton.org/standard/wallets/v5#get-methods) Get methods ------------------------------------------------------------------------ 1. `int is_signature_allowed()` returns stored `is_signature_allowed` flag. 2. `int seqno()` returns current stored seqno. 3. `int get_wallet_id()` returns current wallet ID. 4. `int get_public_key()` returns current stored public key. 5. `cell get_extensions()` returns extensions dictionary. [​](https://docs.ton.org/standard/wallets/v5#gasless-transactions) Gasless transactions ------------------------------------------------------------------------------------------ Starting with v5, the wallet smart contract supports owner-signed internal messages (`internal_signed`), which enables gasless transactions—for example, paying network fees in USDT when transferring USDT. Gasless transactions are supported not at the network protocol level, meaning that to pay fees in USDT it is necessary to rely on some off-chain infrastructure, e.g., like in Tonkeeper. Flow scheme for Tonkeeper gasless transactions looks like this: ### [​](https://docs.ton.org/standard/wallets/v5#flow-details) Flow details 1. When sending USDT, the user signs one message containing two outgoing USDT transfers: 1. USDT transfer to the recipient’s address. 2. Transfer of a small amount of USDT in favor of the service. 2. This signed message is sent off-chain by HTTPS to the service backend. The service backend sends it to the TON Blockchain, paying Toncoin for network fees. The beta version of the gasless backend API is available at [`tonapi.io/api-v2`](https://tonapi.io/api-v2) . If you are developing a wallet app and have feedback about these methods, please share it in [`@tonapitech`](https://t.me/tonapitech) chat. Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/standard/wallets/v5.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/standard/wallets/v5) [Previous](https://docs.ton.org/standard/wallets/v4) [How to interact\ \ Next](https://docs.ton.org/standard/wallets/v5-api) ⌘I On this page * [Persistent memory layout](https://docs.ton.org/standard/wallets/v5#persistent-memory-layout) * [Message layout](https://docs.ton.org/standard/wallets/v5#message-layout) * [External message body layout](https://docs.ton.org/standard/wallets/v5#external-message-body-layout) * [Internal message body layout](https://docs.ton.org/standard/wallets/v5#internal-message-body-layout) * [Authentication process](https://docs.ton.org/standard/wallets/v5#authentication-process) * [Actions](https://docs.ton.org/standard/wallets/v5#actions) * [Exit codes](https://docs.ton.org/standard/wallets/v5#exit-codes) * [Get methods](https://docs.ton.org/standard/wallets/v5#get-methods) * [Gasless transactions](https://docs.ton.org/standard/wallets/v5#gasless-transactions) * [Flow details](https://docs.ton.org/standard/wallets/v5#flow-details) --- # Mnemonics - TON Docs [Skip to main content](https://docs.ton.org/standard/wallets/mnemonics#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Wallets Mnemonics [​](https://docs.ton.org/standard/wallets/mnemonics#key-pair) Key pair ------------------------------------------------------------------------- TON Blockchain uses asymmetric cryptography, such as the [Ed25519](https://en.wikipedia.org/wiki/EdDSA#Ed25519) signature scheme. There are multiple ways to derive a key pair from a mnemonic. Below is the most common approach in TON. [​](https://docs.ton.org/standard/wallets/mnemonics#key-pair-from-a-mnemonic) Key pair from a mnemonic --------------------------------------------------------------------------------------------------------- To transform a mnemonic phrase into a key pair, a `seed` is first derived using [PBKDF2](https://en.wikipedia.org/wiki/PBKDF2) , and the key pair is then derived from that `seed`. PBKDF2 has [five input parameters](https://en.wikipedia.org/wiki/PBKDF2#Key_derivation_process) : `PRF`, `Password`, `Salt`, `c`, and `dkLen`. Each of those parameters is assigned a concrete value. The most commonly used values are: | Parameter | Description | Value | | --- | --- | --- | | `PRF` | Pseudo-random function of two parameters | [HMAC‑SHA512](https://en.wikipedia.org/wiki/HMAC) | | `Password` | Master password from which a derived key is generated | `""` | | `Salt` | Sequence of bits, known as a [cryptographic salt](https://en.wikipedia.org/wiki/Salt_(cryptography)) | `"TON default seed"` | | `c` | Number of iterations desired | 100000 | | `dkLen` | Desired bit-length of the derived key | 64 | ### [​](https://docs.ton.org/standard/wallets/mnemonics#generate-a-key-pair) Generate a key pair TypeScript import { mnemonicToPrivateKey, mnemonicNew } from "@ton/crypto"; // Replace with your own persisted mnemonic phrase (see note below). const mnemonicArray = await mnemonicNew(); // derive private and public keys from the mnemonic const keyPair = await mnemonicToPrivateKey(mnemonicArray); console.log("Public Key: " + keyPair.publicKey.toString('hex')); console.log("Private Key: " + keyPair.secretKey.toString('hex')); The private key is needed to sign messages, and the public key is stored in the wallet’s smart contract. When new external messages arrive on that smart contract, the public key would be used to check the authenticity of the messages signed using the corresponding private key. [​](https://docs.ton.org/standard/wallets/mnemonics#mnemonic-validation) Mnemonic validation ----------------------------------------------------------------------------------------------- 1. Check that all the words are from the list of [BIP-39](https://github.com/ton-org/ton-crypto/blob/c3435833a0da52a96f674c352c4c6f91fcc07f6d/src/mnemonic/wordlist.ts#L9) . 2. If a password is used: the first byte of the derived `seed` computed with `c = 1` and `salt = 'TON fast seed version'` must equal `0`. 3. If no password is used: the first byte of the derived `seed` computed with `c = floor(100000/256) = 390` and `salt = 'TON seed version'` must equal `1`. Random mnemonic phrases are generated until PBKDF2 yields a seed whose first byte matches the expected version (0 for the ‘fast seed’ parameters, 1 for the ‘seed version’ parameters); then a valid mnemonic is returned. ### [​](https://docs.ton.org/standard/wallets/mnemonics#generate-a-mnemonic) Generate a mnemonic TypeScript import { mnemonicNew } from "@ton/crypto"; const mnemonicArray = await mnemonicNew(); console.log(mnemonicArray); Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/standard/wallets/mnemonics.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/standard/wallets/mnemonics) [Previous](https://docs.ton.org/standard/wallets/how-it-works) [Comparison\ \ Next](https://docs.ton.org/standard/wallets/comparison) ⌘I On this page * [Key pair](https://docs.ton.org/standard/wallets/mnemonics#key-pair) * [Key pair from a mnemonic](https://docs.ton.org/standard/wallets/mnemonics#key-pair-from-a-mnemonic) * [Generate a key pair](https://docs.ton.org/standard/wallets/mnemonics#generate-a-key-pair) * [Mnemonic validation](https://docs.ton.org/standard/wallets/mnemonics#mnemonic-validation) * [Generate a mnemonic](https://docs.ton.org/standard/wallets/mnemonics#generate-a-mnemonic) --- # Performance benchmark - TON Docs [Skip to main content](https://docs.ton.org/standard/wallets/performance#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Wallets Performance benchmark The following benchmarks compare gas consumption and throughput across different wallet versions when sending multiple messages. These measurements help determine the most cost-effective wallet for specific use cases. The benchmarks measure the gas consumed by the wallet contract itself, including `fwd_fee` and gas costs. The final transaction fee may vary depending on the destination address and message processing requirements. Each benchmark includes theoretical and real-time measurements: theoretically, messages can be sent every 3-5 seconds when a new block appears, but in practice, messages can be sent every 12-14 seconds due to network conditions and block confirmation times. ### [​](https://docs.ton.org/standard/wallets/performance#sending-tons) Sending TONs #### [​](https://docs.ton.org/standard/wallets/performance#1-messages) 1 Messages | Wallet Version | Gas delta % | Fee delta % | Requests | Total Gas | Gas/Msg | Total Fee (TON) | Fee/Msg (TON) | Real Time (s) | Theory Time (s) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | **Wallet V2R1** ✅ | **Best** | **Best** | 1 | 2,769 | 2,769 | 0.0017108 | 0.0017108 | 13s | 4s | | Wallet V2R2 | +2.78% | +1.80% | 1 | 2,846 | 2,846 | 0.0017416 | 0.0017416 | 13s | 4s | | Wallet V3R1 | +5.34% | +3.46% | 1 | 2,917 | 2,917 | 0.0017700 | 0.0017700 | 13s | 4s | | Wallet V3R2 | +8.12% | +5.26% | 1 | 2,994 | 2,994 | 0.0018008 | 0.0018008 | 13s | 4s | | Wallet V4R2 | +19.46% | +12.60% | 1 | 3,308 | 3,308 | 0.0019264 | 0.0019264 | 13s | 4s | | Wallet V5R1 | +78.36% | +56.34% | 1 | 4,939 | 4,939 | 0.0026748 | 0.0026748 | 13s | 4s | | Highload Wallet V3 | +187.32% | +187.14% | 1 | 7,956 | 7,956 | 0.0049124 | 0.0049124 | 13s | 4s | **Preprocessed Wallet V2** | Wallet Version | Gas delta % | Fee delta % | Requests | Total Gas | Gas/Msg | Total Fee (TON) | Fee/Msg (TON) | Real Time (s) | Theory Time (s) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Preprocessed Wallet V2 | \-44.49% | \-18.98% | 1 | 1,537 | 1,537 | 0.0013860 | 0.0013860 | 13s | 4s | #### [​](https://docs.ton.org/standard/wallets/performance#4-messages) 4 Messages | Wallet Version | Gas delta % | Fee delta % | Requests | Total Gas | Gas/Msg | Total Fee (TON) | Fee/Msg (TON) | Real Time (s) | Theory Time (s) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | **Wallet V2R1** ✅ | **Best** | **Best** | 1 | 4,695 | 1,173 | 0.0030908 | 0.0007727 | 13s | 4s | | Wallet V2R2 | +1.70% | +0.99% | 1 | 4,772 | 1,193 | 0.0031216 | 0.0007804 | 13s | 4s | | Wallet V3R1 | +3.15% | +1.91% | 1 | 4,843 | 1,210 | 0.0031500 | 0.0007875 | 13s | 4s | | Wallet V3R2 | +4.85% | +2.91% | 1 | 4,920 | 1,230 | 0.0031808 | 0.0007952 | 13s | 4s | | Wallet V4R2 | +11.50% | +6.97% | 1 | 5,234 | 1,308 | 0.0033064 | 0.0008266 | 13s | 4s | | Wallet V5R1 | +51.06% | +39.53% | 1 | 7,090 | 1,772 | 0.0043128 | 0.0010782 | 13s | 4s | | Highload Wallet V3 | +69.56% | +109.25% | 1 | 7,956 | 1,989 | 0.0064676 | 0.0016169 | 13s | 4s | **Preprocessed Wallet V2** | Wallet Version | Gas delta % | Fee delta % | Requests | Total Gas | Gas/Msg | Total Fee (TON) | Fee/Msg (TON) | Real Time (s) | Theory Time (s) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Preprocessed Wallet V2 | \-67.26% | \-29.99% | 1 | 1,537 | 384 | 0.0021636 | 0.0005409 | 13s | 4s | #### [​](https://docs.ton.org/standard/wallets/performance#200-messages) 200 Messages | Wallet Version | Gas delta % | Fee delta % | Requests | Total Gas | Gas/Msg | Total Fee (TON) | Fee/Msg (TON) | Real Time (s) | Theory Time (s) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Wallet V2R1 | +2907.69% | +42.99% | 50 | 234,750 | 1,173 | 0.1545400 | 0.000772700 | 10m 50s | 3m 20s | | Wallet V2R2 | +2958.97% | +44.41% | 50 | 238,600 | 1,193 | 0.1560800 | 0.000780400 | 10m 50s | 3m 20s | | Wallet V3R1 | +3002.56% | +45.73% | 50 | 242,150 | 1,210 | 0.1575000 | 0.000787500 | 10m 50s | 3m 20s | | Wallet V3R2 | +3053.84% | +47.15% | 50 | 246,000 | 1,230 | 0.1590400 | 0.000795200 | 10m 50s | 3m 20s | | Wallet V4R2 | +3253.84% | +52.96% | 50 | 261,700 | 1,308 | 0.1653200 | 0.000826600 | 10m 50s | 3m 20s | | Wallet V5R1 | +1792.30% | +3.01% | 1 | 147,622 | 738 | 0.1113288 | 0.000556644 | 13s | 4s | | **Highload Wallet V3** ✅ | **Best** | **Best** | 1 | 7,956 | 39 | 0.1080740 | 0.000540370 | 13s | 4s | **Preprocessed Wallet V2** | Wallet Version | Gas delta % | Fee delta % | Requests | Total Gas | Gas/Msg | Total Fee (TON) | Fee/Msg (TON) | Real Time (s) | Theory Time (s) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Preprocessed Wallet V2 | \-82.05% | \-50.99% | 1 | 1,537 | 7 | 0.0529668 | 0.000264834 | 13s | 4s | #### [​](https://docs.ton.org/standard/wallets/performance#1000-messages) 1000 Messages | Wallet Version | Gas delta % | Fee delta % | Requests | Total Gas | Gas/Msg | Total Fee (TON) | Fee/Msg (TON) | Real Time (s) | Theory Time (s) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Wallet V2R1 | +3683.87% | +44.18% | 250 | 1,173,750 | 1,173 | 0.7727000 | 0.000772700 | 54m 10s | 16m 40s | | Wallet V2R2 | +3748.38% | +45.61% | 250 | 1,193,000 | 1,193 | 0.7804000 | 0.000780400 | 54m 10s | 16m 40s | | Wallet V3R1 | +3803.22% | +46.94% | 250 | 1,210,750 | 1,210 | 0.7875000 | 0.000787500 | 54m 10s | 16m 40s | | Wallet V3R2 | +3867.74% | +48.37% | 250 | 1,230,000 | 1,230 | 0.7952000 | 0.000795200 | 54m 10s | 16m 40s | | Wallet V4R2 | +4119.35% | +54.23% | 250 | 1,308,500 | 1,308 | 0.8266000 | 0.000826600 | 54m 10s | 16m 40s | | Wallet V5R1 | +2264.51% | +3.46% | 4 | 733,888 | 733 | 0.5545152 | 0.000554515 | 52s | 16s | | **Highload Wallet V3** ✅ | **Best** | **Best** | 4 | 31,689 | 31 | 0.5359220 | 0.000535922 | 13s | 4s | **Preprocessed Wallet V2** | Wallet Version | Gas delta % | Fee delta % | Requests | Total Gas | Gas/Msg | Total Fee (TON) | Fee/Msg (TON) | Real Time (s) | Theory Time (s) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Preprocessed Wallet V2 | \-80.64% | \-50.79% | 4 | 6,148 | 6 | 0.2637072 | 0.000263707 | 52s | 16s | ### [​](https://docs.ton.org/standard/wallets/performance#sending-comment) Sending Comment #### [​](https://docs.ton.org/standard/wallets/performance#1-messages-2) 1 Messages | Wallet Version | Gas delta % | Fee delta % | Requests | Total Gas | Gas/Msg | Total Fee (TON) | Fee/Msg (TON) | Real Time (s) | Theory Time (s) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | **Wallet V2R1** ✅ | **Best** | **Best** | 1 | 2,769 | 2,769 | 0.0017620 | 0.0017620 | 13s | 4s | | Wallet V2R2 | +2.78% | +1.74% | 1 | 2,846 | 2,846 | 0.0017928 | 0.0017928 | 13s | 4s | | Wallet V3R1 | +5.34% | +3.35% | 1 | 2,917 | 2,917 | 0.0018212 | 0.0018212 | 13s | 4s | | Wallet V3R2 | +8.12% | +5.10% | 1 | 2,994 | 2,994 | 0.0018520 | 0.0018520 | 13s | 4s | | Wallet V4R2 | +19.46% | +12.23% | 1 | 3,308 | 3,308 | 0.0019776 | 0.0019776 | 13s | 4s | | Wallet V5R1 | +78.36% | +54.71% | 1 | 4,939 | 4,939 | 0.0027260 | 0.0027260 | 13s | 4s | | Highload Wallet V3 | +187.32% | +184.60% | 1 | 7,956 | 7,956 | 0.0050148 | 0.0050148 | 13s | 4s | **Preprocessed Wallet V2** | Wallet Version | Gas delta % | Fee delta % | Requests | Total Gas | Gas/Msg | Total Fee (TON) | Fee/Msg (TON) | Real Time (s) | Theory Time (s) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Preprocessed Wallet V2 | \-44.49% | \-18.43% | 1 | 1,537 | 1,537 | 0.0014372 | 0.0014372 | 13s | 4s | #### [​](https://docs.ton.org/standard/wallets/performance#4-messages-2) 4 Messages | Wallet Version | Gas delta % | Fee delta % | Requests | Total Gas | Gas/Msg | Total Fee (TON) | Fee/Msg (TON) | Real Time (s) | Theory Time (s) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | **Wallet V2R1** ✅ | **Best** | **Best** | 1 | 4,695 | 1,173 | 0.0032956 | 0.0008239 | 13s | 4s | | Wallet V2R2 | +1.70% | +0.93% | 1 | 4,772 | 1,193 | 0.0033264 | 0.0008316 | 13s | 4s | | Wallet V3R1 | +3.15% | +1.79% | 1 | 4,843 | 1,210 | 0.0033548 | 0.0008387 | 13s | 4s | | Wallet V3R2 | +4.85% | +2.73% | 1 | 4,920 | 1,230 | 0.0033856 | 0.0008464 | 13s | 4s | | Wallet V4R2 | +11.50% | +6.54% | 1 | 5,234 | 1,308 | 0.0035112 | 0.0008778 | 13s | 4s | | Wallet V5R1 | +51.06% | +37.07% | 1 | 7,090 | 1,772 | 0.0045176 | 0.0011294 | 13s | 4s | | Highload Wallet V3 | +69.56% | +108.67% | 1 | 7,956 | 1,989 | 0.0068772 | 0.0017193 | 13s | 4s | **Preprocessed Wallet V2** | Wallet Version | Gas delta % | Fee delta % | Requests | Total Gas | Gas/Msg | Total Fee (TON) | Fee/Msg (TON) | Real Time (s) | Theory Time (s) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Preprocessed Wallet V2 | \-67.26% | \-28.13% | 1 | 1,537 | 384 | 0.0023684 | 0.0005921 | 13s | 4s | #### [​](https://docs.ton.org/standard/wallets/performance#200-messages-2) 200 Messages | Wallet Version | Gas delta % | Fee delta % | Requests | Total Gas | Gas/Msg | Total Fee (TON) | Fee/Msg (TON) | Real Time (s) | Theory Time (s) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Wallet V2R1 | +2907.69% | +35.54% | 50 | 234,750 | 1,173 | 0.1647800 | 0.000823900 | 10m 50s | 3m 20s | | Wallet V2R2 | +2958.97% | +36.81% | 50 | 238,600 | 1,193 | 0.1663200 | 0.000831600 | 10m 50s | 3m 20s | | Wallet V3R1 | +3002.56% | +37.97% | 50 | 242,150 | 1,210 | 0.1677400 | 0.000838700 | 10m 50s | 3m 20s | | Wallet V3R2 | +3053.84% | +39.24% | 50 | 246,000 | 1,230 | 0.1692800 | 0.000846400 | 10m 50s | 3m 20s | | Wallet V4R2 | +3253.84% | +44.41% | 50 | 261,700 | 1,308 | 0.1755600 | 0.000877800 | 10m 50s | 3m 20s | | **Wallet V5R1** ✅ | +1792.30% | **Best** | 1 | 147,622 | 738 | 0.1215688 | 0.000607844 | 13s | 4s | | **Highload Wallet V3** | **Best** | +5.74% | 1 | 7,956 | 39 | 0.1285540 | 0.000642770 | 13s | 4s | **Preprocessed Wallet V2** | Wallet Version | Gas delta % | Fee delta % | Requests | Total Gas | Gas/Msg | Total Fee (TON) | Fee/Msg (TON) | Real Time (s) | Theory Time (s) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Preprocessed Wallet V2 | \-82.05% | \-48.00% | 1 | 1,537 | 7 | 0.0632068 | 0.000316034 | 13s | 4s | #### [​](https://docs.ton.org/standard/wallets/performance#1000-messages-2) 1000 Messages | Wallet Version | Gas delta % | Fee delta % | Requests | Total Gas | Gas/Msg | Total Fee (TON) | Fee/Msg (TON) | Real Time (s) | Theory Time (s) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Wallet V2R1 | +3683.87% | +36.02% | 250 | 1,173,750 | 1,173 | 0.8239000 | 0.000823900 | 54m 10s | 16m 40s | | Wallet V2R2 | +3748.38% | +37.29% | 250 | 1,193,000 | 1,193 | 0.8316000 | 0.000831600 | 54m 10s | 16m 40s | | Wallet V3R1 | +3803.22% | +38.46% | 250 | 1,210,750 | 1,210 | 0.8387000 | 0.000838700 | 54m 10s | 16m 40s | | Wallet V3R2 | +3867.74% | +39.73% | 250 | 1,230,000 | 1,230 | 0.8464000 | 0.000846400 | 54m 10s | 16m 40s | | Wallet V4R2 | +4119.35% | +44.91% | 250 | 1,308,500 | 1,308 | 0.8778000 | 0.000877800 | 54m 10s | 16m 40s | | **Wallet V5R1** ✅ | +2264.51% | **Best** | 4 | 733,888 | 733 | 0.6057152 | 0.000605715 | 52s | 16s | | **Highload Wallet V3** | **Best** | +5.38% | 4 | 31,689 | 31 | 0.6383220 | 0.000638322 | 13s | 4s | **Preprocessed Wallet V2** | Wallet Version | Gas delta % | Fee delta % | Requests | Total Gas | Gas/Msg | Total Fee (TON) | Fee/Msg (TON) | Real Time (s) | Theory Time (s) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Preprocessed Wallet V2 | \-80.64% | \-48.01% | 4 | 6,148 | 6 | 0.3149072 | 0.000314907 | 52s | 16s | ### [​](https://docs.ton.org/standard/wallets/performance#sending-jettons) Sending Jettons #### [​](https://docs.ton.org/standard/wallets/performance#1-messages-3) 1 Messages | Wallet Version | Gas delta % | Fee delta % | Requests | Total Gas | Gas/Msg | Total Fee (TON) | Fee/Msg (TON) | Real Time (s) | Theory Time (s) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | **Wallet V2R1** ✅ | **Best** | **Best** | 1 | 2,769 | 2,769 | 0.0021012 | 0.0021012 | 13s | 4s | | Wallet V2R2 | +2.78% | +1.46% | 1 | 2,846 | 2,846 | 0.0021320 | 0.0021320 | 13s | 4s | | Wallet V3R1 | +5.34% | +2.81% | 1 | 2,917 | 2,917 | 0.0021604 | 0.0021604 | 13s | 4s | | Wallet V3R2 | +8.12% | +4.28% | 1 | 2,994 | 2,994 | 0.0021912 | 0.0021912 | 13s | 4s | | Wallet V4R2 | +19.46% | +10.26% | 1 | 3,308 | 3,308 | 0.0023168 | 0.0023168 | 13s | 4s | | Wallet V5R1 | +78.36% | +45.87% | 1 | 4,939 | 4,939 | 0.0030652 | 0.0030652 | 13s | 4s | | Highload Wallet V3 | +187.32% | +170.94% | 1 | 7,956 | 7,956 | 0.0056932 | 0.0056932 | 13s | 4s | **Preprocessed Wallet V2** | Wallet Version | Gas delta % | Fee delta % | Requests | Total Gas | Gas/Msg | Total Fee (TON) | Fee/Msg (TON) | Real Time (s) | Theory Time (s) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Preprocessed Wallet V2 | \-44.49% | \-15.45% | 1 | 1,537 | 1,537 | 0.0017764 | 0.0017764 | 13s | 4s | #### [​](https://docs.ton.org/standard/wallets/performance#4-messages-3) 4 Messages | Wallet Version | Gas delta % | Fee delta % | Requests | Total Gas | Gas/Msg | Total Fee (TON) | Fee/Msg (TON) | Real Time (s) | Theory Time (s) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | **Wallet V2R1** ✅ | **Best** | **Best** | 1 | 4,695 | 1,173 | 0.0046524 | 0.0011631 | 13s | 4s | | Wallet V2R2 | +1.70% | +0.66% | 1 | 4,772 | 1,193 | 0.0046832 | 0.0011708 | 13s | 4s | | Wallet V3R1 | +3.15% | +1.27% | 1 | 4,843 | 1,210 | 0.0047116 | 0.0011779 | 13s | 4s | | Wallet V3R2 | +4.85% | +1.93% | 1 | 4,920 | 1,230 | 0.0047424 | 0.0011856 | 13s | 4s | | Wallet V4R2 | +11.50% | +4.63% | 1 | 5,234 | 1,308 | 0.0048680 | 0.0012170 | 13s | 4s | | Wallet V5R1 | +51.06% | +26.26% | 1 | 7,090 | 1,772 | 0.0058744 | 0.0014686 | 13s | 4s | | Highload Wallet V3 | +69.56% | +106.14% | 1 | 7,956 | 1,989 | 0.0095908 | 0.0023977 | 13s | 4s | **Preprocessed Wallet V2** | Wallet Version | Gas delta % | Fee delta % | Requests | Total Gas | Gas/Msg | Total Fee (TON) | Fee/Msg (TON) | Real Time (s) | Theory Time (s) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Preprocessed Wallet V2 | \-67.26% | \-19.92% | 1 | 1,537 | 384 | 0.0037252 | 0.0009313 | 13s | 4s | #### [​](https://docs.ton.org/standard/wallets/performance#200-messages-3) 200 Messages | Wallet Version | Gas delta % | Fee delta % | Requests | Total Gas | Gas/Msg | Total Fee (TON) | Fee/Msg (TON) | Real Time (s) | Theory Time (s) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Wallet V2R1 | +2907.69% | +22.81% | 50 | 234,750 | 1,173 | 0.2326200 | 0.001163100 | 10m 50s | 3m 20s | | Wallet V2R2 | +2958.97% | +23.62% | 50 | 238,600 | 1,193 | 0.2341600 | 0.001170800 | 10m 50s | 3m 20s | | Wallet V3R1 | +3002.56% | +24.37% | 50 | 242,150 | 1,210 | 0.2355800 | 0.001177900 | 10m 50s | 3m 20s | | Wallet V3R2 | +3053.84% | +25.18% | 50 | 246,000 | 1,230 | 0.2371200 | 0.001185600 | 10m 50s | 3m 20s | | Wallet V4R2 | +3253.84% | +28.50% | 50 | 261,700 | 1,308 | 0.2434000 | 0.001217000 | 10m 50s | 3m 20s | | **Wallet V5R1** ✅ | +1792.30% | **Best** | 1 | 147,622 | 738 | 0.1894088 | 0.000947044 | 13s | 4s | | **Highload Wallet V3** | **Best** | +39.50% | 1 | 7,956 | 39 | 0.2642340 | 0.001321170 | 13s | 4s | **Preprocessed Wallet V2** | Wallet Version | Gas delta % | Fee delta % | Requests | Total Gas | Gas/Msg | Total Fee (TON) | Fee/Msg (TON) | Real Time (s) | Theory Time (s) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Preprocessed Wallet V2 | \-82.05% | \-30.81% | 1 | 1,537 | 7 | 0.1310468 | 0.000655234 | 13s | 4s | #### [​](https://docs.ton.org/standard/wallets/performance#1000-messages-3) 1000 Messages | Wallet Version | Gas delta % | Fee delta % | Requests | Total Gas | Gas/Msg | Total Fee (TON) | Fee/Msg (TON) | Real Time (s) | Theory Time (s) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Wallet V2R1 | +3683.87% | +23.09% | 250 | 1,173,750 | 1,173 | 1.1631000 | 0.001163100 | 54m 10s | 16m 40s | | Wallet V2R2 | +3748.38% | +23.90% | 250 | 1,193,000 | 1,193 | 1.1708000 | 0.001170800 | 54m 10s | 16m 40s | | Wallet V3R1 | +3803.22% | +24.65% | 250 | 1,210,750 | 1,210 | 1.1779000 | 0.001177900 | 54m 10s | 16m 40s | | Wallet V3R2 | +3867.74% | +25.47% | 250 | 1,230,000 | 1,230 | 1.1856000 | 0.001185600 | 54m 10s | 16m 40s | | Wallet V4R2 | +4119.35% | +28.79% | 250 | 1,308,500 | 1,308 | 1.2170000 | 0.001217000 | 54m 10s | 16m 40s | | **Wallet V5R1** ✅ | +2264.51% | **Best** | 4 | 733,888 | 733 | 0.9449152 | 0.000944915 | 52s | 16s | | **Highload Wallet V3** | **Best** | +39.34% | 4 | 31,689 | 31 | 1.3167220 | 0.001316722 | 13s | 4s | **Preprocessed Wallet V2** | Wallet Version | Gas delta % | Fee delta % | Requests | Total Gas | Gas/Msg | Total Fee (TON) | Fee/Msg (TON) | Real Time (s) | Theory Time (s) | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | Preprocessed Wallet V2 | \-80.64% | \-30.77% | 4 | 6,148 | 6 | 0.6541072 | 0.000654107 | 52s | 16s | Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/standard/wallets/performance.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/standard/wallets/performance) [Previous](https://docs.ton.org/standard/wallets/comparison) [How to interact\ \ Next](https://docs.ton.org/standard/wallets/interact) ⌘I --- # Wallets history - TON Docs [Skip to main content](https://docs.ton.org/standard/wallets/history#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Wallets Wallets history You may have heard about different versions of wallets on TON Blockchain. But what do these versions actually mean, and how do they differ? In this article, we will explore the various versions and modifications of TON wallets. [​](https://docs.ton.org/standard/wallets/history#common-concept) Common concept ----------------------------------------------------------------------------------- We should first understand that wallets are not a specific entity in the TON ecosystem. They are still just smart contracts consisting of code and data, and in that sense, are equal to any other actor (i.e., smart contract) in TON. Read more about [differences](https://docs.ton.org/from-ethereum) . Like your own custom smart contract, or any other one, wallets can receive external and internal messages, send internal messages and logs, and provide `get methods`. So the question is: what functionality do they provide, and how do they differ between versions? You can consider each wallet version as a smart contract implementation providing a standard external interface, allowing different external clients to interact with the wallets in the same way. You can find these implementations in FunC and Fift languages in the main TON monorepo: * [`ton/crypto/smartcont/`](https://github.com/ton-blockchain/ton/blob/master/crypto/smartcont/) [​](https://docs.ton.org/standard/wallets/history#basic-wallets) Basic wallets --------------------------------------------------------------------------------- ### [​](https://docs.ton.org/standard/wallets/history#wallet-contract-hashes) Wallet contract hashes Here, you can find the current hashes of the wallet contract code versions. For detailed specifications of each wallet contract, please refer to the sections further down this page. | Contract version | Hash | | --- | --- | | [V1 R1](https://docs.ton.org/standard/wallets/history#wallet-v1) | `a0cfc2c48aee16a271f2cfc0b7382d81756cecb1017d077faaab3bb602f6868c` | | [V1 R2](https://docs.ton.org/standard/wallets/history#wallet-v1) | `d4902fcc9fad74698fa8e353220a68da0dcf72e32bcb2eb9ee04217c17d3062c` | | [V1 R3](https://docs.ton.org/standard/wallets/history#wallet-v1) | `587cc789eff1c84f46ec3797e45fc809a14ff5ae24f1e0c7a6a99cc9dc9061ff` | | [V2 R1](https://docs.ton.org/standard/wallets/history#wallet-v2) | `5c9a5e68c108e18721a07c42f9956bfb39ad77ec6d624b60c576ec88eee65329` | | [V2 R2](https://docs.ton.org/standard/wallets/history#wallet-v2) | `fe9530d3243853083ef2ef0b4c2908c0abf6fa1c31ea243aacaa5bf8c7d753f1` | | [V3 R1](https://docs.ton.org/standard/wallets/history#wallet-v3) | `b61041a58a7980b946e8fb9e198e3c904d24799ffa36574ea4251c41a566f581` | | [V3 R2](https://docs.ton.org/standard/wallets/history#wallet-v3) | `84dafa449f98a6987789ba232358072bc0f76dc4524002a5d0918b9a75d2d599` | | [V4 R1](https://docs.ton.org/standard/wallets/history#wallet-v4) | `64dd54805522c5be8a9db59cea0105ccf0d08786ca79beb8cb79e880a8d7322d` | | [V4 R2](https://docs.ton.org/standard/wallets/history#wallet-v4) | `feb5ff6820e2ff0d9483e7e0d62c817d846789fb4ae580c878866d959dabd5c0` | | [V5 R1](https://docs.ton.org/standard/wallets/history#wallet-v5) | `20834b7b72b112147e1b2fb457b84e74d1a30f04f737d4f62a668e9552d2b72f` | **Note:** These hashes can also be found in the explorers. ### [​](https://docs.ton.org/standard/wallets/history#wallet-v1) Wallet V1 This is the simplest one. It only allows you to send four transactions at a time and doesn’t check anything besides your signature and seqno. Wallet source code: * [`ton/crypto/smartcont/new-wallet.fif`](https://github.com/ton-blockchain/ton/blob/master/crypto/smartcont/new-wallet.fif) This version isn’t even used in regular apps because it has some major issues: * No easy way to retrieve the seqno and public key from the contract. * No `valid_until` check, so you can’t be sure that the transaction won’t be confirmed too late. The first issue was fixed in `V1R2` and `V1R3`. The `R` stands for **revision**. Usually, revisions are just minor updates that only add get methods; you can find all of those in the changes history of [`new-wallet.fif`](https://github.com/ton-blockchain/ton/blob/master/crypto/smartcont/new-wallet.fif) . Hereinafter, we will consider only the latest revisions. Nevertheless, because each subsequent version inherits the functionality of the previous one, we should still stick to it, as this will help us with later versions. #### [​](https://docs.ton.org/standard/wallets/history#official-code-hashes) Official code hashes | Contract version | Hash | | --- | --- | | V1 R1 | `a0cfc2c48aee16a271f2cfc0b7382d81756cecb1017d077faaab3bb602f6868c` | | V1 R2 | `d4902fcc9fad74698fa8e353220a68da0dcf72e32bcb2eb9ee04217c17d3062c` | | V1 R3 | `587cc789eff1c84f46ec3797e45fc809a14ff5ae24f1e0c7a6a99cc9dc9061ff` | #### [​](https://docs.ton.org/standard/wallets/history#persistent-memory-layout) Persistent memory layout * `seqno`: 32-bit long sequence number. * `public-key`: 256-bit long public key. #### [​](https://docs.ton.org/standard/wallets/history#external-message-body-layout) External message body layout 1. Data: * `signature`: 512-bit long Ed25519 signature. * `msg-seqno`: 32-bit long sequence number. * `(0-4) mode`: up to four 8-bit long integers defining sending mode for each message. 2. Up to 4 references to cells containing messages. As you can see, the main functionality of the wallet is to provide a safe way to communicate with TON Blockchain from the outside world. The `seqno` mechanism protects against replay attacks, and the `Ed25519 signature` provides authorized access to wallet functionality. The payload data consists of up to 4 references to cells and the corresponding number of modes, which will be directly transferred to the `send_raw_message` method. #### [​](https://docs.ton.org/standard/wallets/history#exit-codes) Exit codes | Exit code | Description | | --- | --- | | 33 | `seqno` check failed, replay protection occurred | | 34 | `Ed25519 signature` check failed | | 0 | Standard successful execution exit code. | #### [​](https://docs.ton.org/standard/wallets/history#get-methods) Get methods 1. `int seqno()` returns current stored seqno. 2. `int get_public_key()` returns the current stored public key. ### [​](https://docs.ton.org/standard/wallets/history#wallet-v2) Wallet V2 Wallet source code: * [`ton/crypto/smartcont/wallet-code.fc`](https://github.com/ton-blockchain/ton/blob/master/crypto/smartcont/wallet-code.fc) This version introduces the `valid_until` parameter, which is used to set a time limit for a transaction in case you don’t want it to be confirmed too late. This version also does not have a get method for the public key, which was added in `V2R2`. All differences compared to the previous version are a consequence of adding the `valid_until` functionality. A new exit code was added: `35`, marking the failure of the `valid_until` check. Additionally, a new Unix time field has been added to the external message body layout, setting the time limit for the transaction. All get methods remain the same. #### [​](https://docs.ton.org/standard/wallets/history#official-code-hashes-2) Official code hashes | Contract version | Hash | | --- | --- | | V2 R1 | `5c9a5e68c108e18721a07c42f9956bfb39ad77ec6d624b60c576ec88eee65329` | | V2 R2 | `fe9530d3243853083ef2ef0b4c2908c0abf6fa1c31ea243aacaa5bf8c7d753f1` | #### [​](https://docs.ton.org/standard/wallets/history#external-message-body-layout-2) External message body layout 1. Data: * `signature`: 512-bit long Ed25519 signature. * `msg-seqno`: 32-bit long sequence number. * `valid-until`: 32-bit long Unix time integer. * `(0-4) mode`: up to four 8-bit integers defining the sending mode for each message. 2. Up to 4 references to cells containing messages. ### [​](https://docs.ton.org/standard/wallets/history#wallet-v3) Wallet V3 This version introduces the `subwallet_id` parameter, which allows you to create multiple wallets using the same public key (so you can have only one seed phrase and multiple wallets). As before, `V3R2` only adds the get method for the public key. Wallet source code: * [`ton/crypto/smartcont/wallet3-code.fc`](https://github.com/ton-blockchain/ton/blob/master/crypto/smartcont/wallet3-code.fc) Essentially, `subwallet_id` is just a number added to the contract state when it’s deployed. Since the contract address in TON is a hash of its state and code, the wallet address will change with a different `subwallet_id`. This version is the most widely used right now. It covers most use cases and remains clean, simple, and mostly the same as previous versions. All get methods remain the same. #### [​](https://docs.ton.org/standard/wallets/history#official-code-hashes-3) Official code hashes | Contract version | Hash | | --- | --- | | V3 R1 | `b61041a58a7980b946e8fb9e198e3c904d24799ffa36574ea4251c41a566f581` | | V3 R2 | `84dafa449f98a6987789ba232358072bc0f76dc4524002a5d0918b9a75d2d599` | #### [​](https://docs.ton.org/standard/wallets/history#persistent-memory-layout-2) Persistent memory layout * `seqno`: 32-bit sequence number. * `subwallet_id`: 32-bit subwallet ID. * `public_key`: 256-bit public key. #### [​](https://docs.ton.org/standard/wallets/history#external-message-body-layout-3) External message body layout 1. Data: * `signature`: 512-bit Ed25519 signature. * `subwallet_id`: 32-bit subwallet ID. * `msg-seqno`: 32-bit sequence number. * `valid-until`: 32-bit Unix time integer. * `(0-4) mode`: up to four 8-bit integers defining the sending mode for each message. 2. Up to 4 references to cells containing messages. #### [​](https://docs.ton.org/standard/wallets/history#exit-codes-2) Exit codes | Exit code | Description | | --- | --- | | 33 | `seqno` check failed; replay protection triggered | | 34 | `subwallet_id` does not match the stored one | | 35 | `valid_until` check failed; transaction confirmation attempted too late | | 35 | `Ed25519 signature` check failed | | 0 | Standard successful execution exit code. | ### [​](https://docs.ton.org/standard/wallets/history#wallet-v4) Wallet V4 **Why V4 was created**: V4 was developed to introduce plugin functionality, allowing third-party smart contracts to interact with wallets in a controlled manner. This enabled features like automated payments, subscriptions, and complex DApp integrations while maintaining security through an allowlist system. Read about this standard iteration on its dedicated page: [V4 wallet standard](https://docs.ton.org/standard/wallets/v4) . ### [​](https://docs.ton.org/standard/wallets/history#wallet-v5) Wallet V5 **Why V5 was created**: V5 was developed by the Tonkeeper team to address the growing need for gasless transactions, improved extensibility, and better user experience. It adds support for owner-signed internal messages, enabling gasless transactions where users can pay fees in tokens like USDt instead of Toncoin. It is the most modern wallet version at the moment, aimed at replacing V4 and allowing arbitrary extensions. Read more: * [V5 wallet standard](https://docs.ton.org/standard/wallets/v5) * [How to interact with V5 wallet](https://docs.ton.org/standard/wallets/v5-api) [​](https://docs.ton.org/standard/wallets/history#special-wallets) Special wallets ------------------------------------------------------------------------------------- Sometimes the functionality of basic wallets isn’t enough. That’s why there are several types of specialized wallets: `high-load`, `lockup`, and `restricted`. Let’s have a look at them. ### [​](https://docs.ton.org/standard/wallets/history#highload-wallets) Highload wallets When working with many messages in a short period, there is a need for a special wallet called a Highload Wallet. Read [the article](https://docs.ton.org/standard/wallets/highload) for more information. ### [​](https://docs.ton.org/standard/wallets/history#lockup-wallet) Lockup wallet If you, for some reason, need to lock coins in a wallet for some time without the possibility of withdrawing them before that time passes, have a look at the lockup wallet. It allows you to set the time until which you won’t be able to withdraw anything from the wallet. You can also customize it by setting unlock periods so that you will be able to spend some coins during these set periods. For example, you can create a wallet that will hold 1 million coins with a total vesting time of 10 years. Set the cliff duration to one year, so the funds will be locked for the first year after the wallet is created. Then, you can set the unlock period to one month, so `1'000'000 Toncoin / 120 months = ~8333 Toncoin` will unlock every month. Wallet source code: * [ton-blockchain/lockup-wallet-contract](https://github.com/ton-blockchain/lockup-wallet-contract) ### [​](https://docs.ton.org/standard/wallets/history#restricted-wallet) Restricted wallet This wallet’s function is to act like a regular wallet, but restrict transfers to only one pre-defined destination address. You can set the destination when you create this wallet, and then you’ll only be able to transfer funds from it to that address. But note that you can still transfer funds to validation contracts, so you can run a validator with this wallet. Wallet source code: * [EmelyanenkoK/nomination-contract/restricted-wallet](https://github.com/EmelyanenkoK/nomination-contract/tree/master/restricted-wallet) [​](https://docs.ton.org/standard/wallets/history#conclusion) Conclusion --------------------------------------------------------------------------- As you can see, there are many different versions of wallets in TON. For new deployments, prefer `V5`. Use `V3R2` or `V4R2` only for legacy compatibility or specific constraints. You can also use one of the special wallets if you want additional functionality like periodic unlocking of funds. [​](https://docs.ton.org/standard/wallets/history#see-also) See also ----------------------------------------------------------------------- * [Sources of basic wallets](https://github.com/ton-blockchain/ton/tree/master/crypto/smartcont) * [More technical description of versions](https://github.com/toncenter/tonweb/blob/master/src/contract/wallet/WalletSources.md) * [Wallet V4 sources and detailed description](https://github.com/ton-blockchain/wallet-contract) * [Lockup wallet sources and detailed description](https://github.com/ton-blockchain/lockup-wallet-contract) * [Restricted wallet sources](https://github.com/EmelyanenkoK/nomination-contract/tree/master/restricted-wallet) * [Gasless transactions on TON](https://medium.com/@buidlingmachine/gasless-transactions-on-ton-75469259eff2) Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/standard/wallets/history.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/standard/wallets/history) [Previous](https://docs.ton.org/standard/wallets/interact) [V4\ \ Next](https://docs.ton.org/standard/wallets/v4) ⌘I On this page * [Common concept](https://docs.ton.org/standard/wallets/history#common-concept) * [Basic wallets](https://docs.ton.org/standard/wallets/history#basic-wallets) * [Wallet contract hashes](https://docs.ton.org/standard/wallets/history#wallet-contract-hashes) * [Wallet V1](https://docs.ton.org/standard/wallets/history#wallet-v1) * [Official code hashes](https://docs.ton.org/standard/wallets/history#official-code-hashes) * [Persistent memory layout](https://docs.ton.org/standard/wallets/history#persistent-memory-layout) * [External message body layout](https://docs.ton.org/standard/wallets/history#external-message-body-layout) * [Exit codes](https://docs.ton.org/standard/wallets/history#exit-codes) * [Get methods](https://docs.ton.org/standard/wallets/history#get-methods) * [Wallet V2](https://docs.ton.org/standard/wallets/history#wallet-v2) * [Official code hashes](https://docs.ton.org/standard/wallets/history#official-code-hashes-2) * [External message body layout](https://docs.ton.org/standard/wallets/history#external-message-body-layout-2) * [Wallet V3](https://docs.ton.org/standard/wallets/history#wallet-v3) * [Official code hashes](https://docs.ton.org/standard/wallets/history#official-code-hashes-3) * [Persistent memory layout](https://docs.ton.org/standard/wallets/history#persistent-memory-layout-2) * [External message body layout](https://docs.ton.org/standard/wallets/history#external-message-body-layout-3) * [Exit codes](https://docs.ton.org/standard/wallets/history#exit-codes-2) * [Wallet V4](https://docs.ton.org/standard/wallets/history#wallet-v4) * [Wallet V5](https://docs.ton.org/standard/wallets/history#wallet-v5) * [Special wallets](https://docs.ton.org/standard/wallets/history#special-wallets) * [Highload wallets](https://docs.ton.org/standard/wallets/history#highload-wallets) * [Lockup wallet](https://docs.ton.org/standard/wallets/history#lockup-wallet) * [Restricted wallet](https://docs.ton.org/standard/wallets/history#restricted-wallet) * [Conclusion](https://docs.ton.org/standard/wallets/history#conclusion) * [See also](https://docs.ton.org/standard/wallets/history#see-also) --- # How to interact with wallet - TON Docs [Skip to main content](https://docs.ton.org/standard/wallets/interact#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Wallets How to interact with wallet Creating a wallet involves several steps * Generate a mnemonic; wallet will be still in [`nonexist`](https://docs.ton.org/foundations/status#status-variety) status. * Derive the public key and the wallet address out of it. * Put some funds to the address; wallet account will move to [`uninit`](https://docs.ton.org/foundations/status#status-variety) status. * Deploy code of wallet contract to that address; account will move to [`active`](https://docs.ton.org/foundations/status#status-variety) status. [​](https://docs.ton.org/standard/wallets/interact#derive-wallet-address) Derive wallet address -------------------------------------------------------------------------------------------------- The following algorithm is used by wallet apps, and has to be replicated if the same wallet address should be generated programmatically. A wallet account’s address is [derived](https://docs.ton.org/foundations/addresses/derive) from [`StateInit`](https://docs.ton.org/foundations/messages/deploy) that stores in its `data` field two values: * `public_key`, dependent on the [mnemonic](https://docs.ton.org/standard/wallets/mnemonics) ; * `wallet_id`, a special [salt-like](https://en.wikipedia.org/wiki/Salt_(cryptography)) field, dependent on the wallet contract type and the `network_id`. This means that the mnemonic alone does not determine an address uniquely: `wallet_id` has to be known to compute the address. ### [​](https://docs.ton.org/standard/wallets/interact#default-wallet_id-values) Default `wallet_id` values | Network | [V4R2](https://docs.ton.org/standard/wallets/v4) | [V5](https://docs.ton.org/standard/wallets/v5) | | --- | --- | --- | | Mainnet | `0x29a9a317` (698983191) | `0x7FFFFF11` (2147483409) | | Testnet | `0x29a9a317` (698983191) | `0x7FFFFFFD` (2147483645) | For Wallet V4R2 `wallet_id` is defined as first 4 bytes from TON mainnet blockchain initial state hash. There is no specific logic why this number was chosen, community needed some default value and this one works well enough. For Wallet V5, `wallet_id` is different between Mainnet and Testnet for security reasons. There will be different wallet addresses for different networks with the same mnemonic. This prevents replaying transactions from testnet on mainnet, and ensuing loss of funds. The `wallet_id` value is obtained from * `network_id`: `-239` for mainnet, `-3` for testnet, * `wallet_version`: currently always `0`, * `subwallet_number`: `0` by default, * `workchain`: `0` for basechain by the following algorithm: type WalletIdV5 = { // currently always 0 readonly walletVersion: number; // -239 for mainnet, -3 for testnet readonly networkGlobalId: number; // 0 for basechain readonly workchain: number; // 0 for the first wallet with this mnemonic readonly subwalletNumber: number; } export function storeWalletIdV5(walletId: WalletIdV5) { return (builder: Builder) => { builder.storeInt(walletId.networkGlobalId, 32); builder.storeInt(walletId.workchain, 8); builder.storeUint(walletId.walletVersion, 8); builder.storeUint(walletId.subwalletNumber, 32); } } ### [​](https://docs.ton.org/standard/wallets/interact#examples) Examples The following examples use wrappers for wallet contracts from the [`@ton/ton`](https://github.com/ton-org/ton) TypeScript SDK. #### [​](https://docs.ton.org/standard/wallets/interact#wallet-v4r2) Wallet V4R2 import { mnemonicToPrivateKey } from '@ton/crypto'; import { WalletContractV4 } from '@ton/ton'; // 12‑ or 24‑word mnemonic (space‑separated) const mnemonic = 'bread table ...'; // async function for await const main = async () => { const keyPair = await mnemonicToPrivateKey( mnemonic.split(' ') ); const walletContractV4 = WalletContractV4.create({ workchain: 0, publicKey: keyPair.publicKey, // this magic number is default wallet_id for V4R2 wallet contract walletId: 0x29a9a317, }); console.log(walletContractV4.address); } void main(); See all 21 lines #### [​](https://docs.ton.org/standard/wallets/interact#wallet-v5) Wallet V5 import { mnemonicToPrivateKey } from '@ton/crypto'; import { WalletContractV5R1 } from '@ton/ton'; // 12‑ or 24‑word mnemonic (space‑separated). const mnemonic = 'foo bar baz ...'; // async function for await const main = async () => { const keyPair = await mnemonicToPrivateKey( mnemonic.split(' '), ); // testnet const testnetV5Wallet = WalletContractV5R1.create({ walletId: { networkGlobalId: -3, }, publicKey: keyPair.publicKey, workchain: 0, }); console.log(testnetV5Wallet.address); // mainnet const mainnetV5Wallet = WalletContractV5R1.create({ walletId: { networkGlobalId: -239, }, publicKey: keyPair.publicKey, workchain: 0, }); console.log(mainnetV5Wallet.address); }; void main(); See all 36 lines This wallet contract instance can be used to [send messages](https://docs.ton.org/standard/wallets/v5-api) to the blockchain. [​](https://docs.ton.org/standard/wallets/interact#comments) Comments ------------------------------------------------------------------------ Wallet apps can attach short human-readable notes — commonly called _comments_ — to outgoing internal messages. On-chain they are just message bodies with a specific layout that ecosystem agreed to interpret as text. ### [​](https://docs.ton.org/standard/wallets/interact#comment-format) Comment format * The first 32 bits of the incoming message body must be the opcode `0x00000000`. This value signals that the rest of the payload should be treated as a comment. * The remaining bytes are UTF-8 encoded text. Wallet apps should tolerate invalid or empty strings — many senders emit messages without a comment or with zero-length payloads. * When parsing, always inspect the opcode before assuming a text comment. If the opcode differs, fall back to handling other contract-specific payloads. Because comments ride inside ordinary internal messages, the format works identically for: * native Toncoin transfers between wallets; * [Jetton transfers](https://docs.ton.org/standard/tokens/jettons/api#forward-payload-formats) , where the wallet forwards an internal message to the token wallet along with the comment payload; * [NFT transfers](https://docs.ton.org/standard/tokens/nft/api#forward-payload-formats) , where the comment travels in the same forwarding message that moves the ownership record. ### [​](https://docs.ton.org/standard/wallets/interact#attaching-a-comment-when-sending) Attaching a comment when sending To include a comment in an outgoing transfer, construct an internal message body that starts with `0x00000000` and append the UTF-8 bytes of the note YOU want to share. Most wallet libraries expose helpers for this, but the underlying steps are: 1. Allocate a cell. 2. Store the 32-bit zero opcode. 3. Store the text as a [byte string](https://docs.ton.org/standard/tokens/metadata#snake-data-encoding) (UTF-8 encoded). 4. Send the internal message along with the desired Toncoin, [Jettons](https://docs.ton.org/standard/tokens/jettons/how-it-works) , or [NFT](https://docs.ton.org/standard/tokens/nft/how-it-works) payload. Receivers that follow the convention will display the decoded text to the user. Contracts that do not recognize the opcode will simply ignore it or treat the message body as opaque data, so comments are backward-compatible with existing transfers. ### [​](https://docs.ton.org/standard/wallets/interact#example-sending-a-comment-with-@ton/core) Example: Sending a comment with `@ton/core` import { Cell, beginCell } from '@ton/core'; function createCommentCell(comment: string): Cell { return beginCell() // opcode for comment .storeUint(0, 32) // UTF-8 encoded text in snake encoding .storeStringTail(comment) .endCell(); } Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/standard/wallets/interact.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/standard/wallets/interact) [Previous](https://docs.ton.org/standard/wallets/performance) [History\ \ Next](https://docs.ton.org/standard/wallets/history) ⌘I On this page * [Derive wallet address](https://docs.ton.org/standard/wallets/interact#derive-wallet-address) * [Default wallet\_id values](https://docs.ton.org/standard/wallets/interact#default-wallet_id-values) * [Examples](https://docs.ton.org/standard/wallets/interact#examples) * [Wallet V4R2](https://docs.ton.org/standard/wallets/interact#wallet-v4r2) * [Wallet V5](https://docs.ton.org/standard/wallets/interact#wallet-v5) * [Comments](https://docs.ton.org/standard/wallets/interact#comments) * [Comment format](https://docs.ton.org/standard/wallets/interact#comment-format) * [Attaching a comment when sending](https://docs.ton.org/standard/wallets/interact#attaching-a-comment-when-sending) * [Example: Sending a comment with @ton/core](https://docs.ton.org/standard/wallets/interact#example-sending-a-comment-with-%40ton%2Fcore) --- # Wallet V4 - TON Docs [Skip to main content](https://docs.ton.org/standard/wallets/v4#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Wallets Wallet V4 This version retains all the functionality of the previous versions and introduces plugins. Plugins enable developers to implement custom logic that integrates with wallet functionality. When a plugin is installed on a wallet through a signed transaction, it can force wallet to send internal message with predefined opcode (`0xf06c7567`) and any available Toncoin amount to specified addresses. Plugins are separate smart contracts that can implement their own custom logic. Here you can view [wallet V4 source code](https://github.com/ton-blockchain/wallet-contract) . [​](https://docs.ton.org/standard/wallets/v4#plugins) Plugins ---------------------------------------------------------------- Plugins are essentially other smart contracts on TON that developers are free to implement as they wish. In relation to the wallet, they are simply addresses of smart contracts stored in a dictionary in the wallet’s persistent memory. These plugins are allowed to request funds and remove themselves from the “allowed list” by sending internal messages to the wallet. ### [​](https://docs.ton.org/standard/wallets/v4#plugin-interaction-flow) Plugin interaction flow [​](https://docs.ton.org/standard/wallets/v4#persistent-memory-layout) Persistent memory layout -------------------------------------------------------------------------------------------------- Here we will break down wallet V4 storage structure. contract_state$_ seqno:(## 32) wallet_id:(## 32) public_key:(## 256) plugins:(HashmapE 256 int1) = ContractState; * `seqno`: 32-bit long sequence number. * `wallet_id`: 32-bit long wallet\_id. This is a number that allows you to create multiple wallets with the same private key but different addresses. * `public_key`: 256-bit long public key. * `plugins`: dictionary containing plugins (may be empty). [​](https://docs.ton.org/standard/wallets/v4#receiving-internal-messages) Receiving internal messages -------------------------------------------------------------------------------------------------------- All previous versions of wallets had a straightforward implementation for receiving internal messages. They simply accepted incoming funds from any sender, ignoring the internal message body if present, or in other words, they had an empty `recv_internal` method. However, as mentioned earlier, the fourth version of the wallet introduces two additional available operations. Let’s take a look at the internal message body layout: * `opcode` (optional): 32-bit long operation code. This is an optional field. Any message containing less than 32 bits in the message body, an incorrect opcode, or a sender address that isn’t registered as a plugin will be considered a simple transfer, similar to previous wallet versions. * `query_id`: 64-bit long integer. This field has no effect on the smart contract’s behavior; it is used to track chains of messages between contracts. 1. opcode = `0x706c7567`, request funds operation. * `amount`: [Coins](https://docs.ton.org/tvm/instructions#fa02-stgrams) amount of requested Toncoin. * `extra_currencies`: dictionary containing the amount of requested extra currencies (may be empty). 2. opcode = `0x64737472`, request removal of the plugin that sent this message from the allowed list. TL-B for plugin operations: request_funds#706c7567 amount:Coins extra_currencies:ExtraCurrencyCollection = InternalMsgBody; self_destroy#64737472 = InternalMsgBody; [​](https://docs.ton.org/standard/wallets/v4#external-message-body-layout) External message body layout ---------------------------------------------------------------------------------------------------------- * `signature`: 512-bit long [Ed25519](https://en.wikipedia.org/wiki/EdDSA#Ed25519) signature. * `wallet_id`: 32-bit long subwallet ID. * `valid_until`: 32-bit long Unix time integer. * `msg_seqno`: 32-bit long sequence number. * `opcode`: 32-bit long operation code. * other data depending on the opcode Next, let’s explore the types of messages: ### [​](https://docs.ton.org/standard/wallets/v4#simple-send-opcode-=-0x0) Simple send (opcode = 0x0) The simple send operation processes a chain of messages, where each message contains a mode and a reference to the actual message cell: **Processing logic:** if (op == 0) { ;; simple send while (cs.slice_refs()) { var mode = cs~load_uint(8); send_raw_message(cs~load_ref(), mode); } } * `mode`: up to four 8-bit integers defining the sending mode for each message. * `out_msg`: up to four references to cells containing messages. ### [​](https://docs.ton.org/standard/wallets/v4#deploy-and-install-plugin-opcode-=-0x1) Deploy and install plugin (opcode = 0x1) deploy_and_install_plugin#01 workchain:(## 8) balance:Coins state_init:^Cell body:^Cell = WalletAction; Deploys a new plugin contract and adds it to the wallet’s plugin allowlist: * `workchain`: 8-bit workchain ID where the plugin will be deployed * `balance`: Initial Toncoin balance for the plugin contract * `state_init`: Cell reference containing the plugin’s initial state and code * `body`: Cell reference containing the deployment message body ### [​](https://docs.ton.org/standard/wallets/v4#install-plugin-opcode-=-0x2) Install plugin (opcode = 0x2) wc_n_address#_ wc:(## 8) hash:(## 256) = WorkchainWithAddress; install_plugin#02 wc_n_address:WorkchainWithAddress balance:Coins query_id:(## 64) = WalletAction; Adds an existing plugin contract to the wallet’s allowlist: * `wc_n_address`: Combined 8-bit workchain ID and 256-bit plugin address * `balance`: Toncoin amount to send during installation * `query_id`: 64-bit identifier for tracking the operation ### [​](https://docs.ton.org/standard/wallets/v4#remove-plugin-opcode-=-0x3) Remove plugin (opcode = 0x3) wc_n_address#_ wc:(## 8) hash:(## 256) = WorkchainWithAddress; remove_plugin#03 wc_n_address:WorkchainWithAddress balance:Coins query_id:(## 64) = WalletAction; Removes a plugin from the wallet’s allowlist: * `wc_n_address`: Combined 8-bit workchain ID and 256-bit plugin address * `balance`: Toncoin amount * `query_id`: 64-bit identifier for tracking the operation Wallet V4 provides standard functionality through the `0x0` opcode, similar to previous versions (see [wallet overview](https://docs.ton.org/standard/wallets/history) for details on message layout). The `0x2` and `0x3` operations allow manipulation of the plugin dictionary. [​](https://docs.ton.org/standard/wallets/v4#exit-codes) Exit codes ---------------------------------------------------------------------- | Exit code | Description | | --- | --- | | 33 | `seqno` check failed, replay protection triggered | | 34 | `wallet_id` does not match the stored one | | 35 | `signature` check failed | | 36 | `valid_until` check failed, transaction attempted too late | | 39 | Plugins dictionary manipulation failed (0x1-0x3 recv\_external opcodes) | | 80 | Not enough funds for the plugin funds request | | 0 | Standard successful execution exit code. | [​](https://docs.ton.org/standard/wallets/v4#get-methods) Get methods ------------------------------------------------------------------------ 1. `int seqno()` returns current stored seqno. 2. `int get_public_key()` returns current stored public key. 3. `int get_subwallet_id()` returns current subwallet ID. 4. `int is_plugin_installed(int wc, int addr_hash)` checks if plugin with defined workchain\_id and address hash is installed. Returns `-1` (true) if the plugin is installed, `0` (false) if not installed. 5. `tuple get_plugin_list()` returns list of plugins. Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/standard/wallets/v4.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/standard/wallets/v4) [Previous](https://docs.ton.org/standard/wallets/history) [Overview\ \ Next](https://docs.ton.org/standard/wallets/v5) ⌘I On this page * [Plugins](https://docs.ton.org/standard/wallets/v4#plugins) * [Plugin interaction flow](https://docs.ton.org/standard/wallets/v4#plugin-interaction-flow) * [Persistent memory layout](https://docs.ton.org/standard/wallets/v4#persistent-memory-layout) * [Receiving internal messages](https://docs.ton.org/standard/wallets/v4#receiving-internal-messages) * [External message body layout](https://docs.ton.org/standard/wallets/v4#external-message-body-layout) * [Simple send (opcode = 0x0)](https://docs.ton.org/standard/wallets/v4#simple-send-opcode-%3D-0x0) * [Deploy and install plugin (opcode = 0x1)](https://docs.ton.org/standard/wallets/v4#deploy-and-install-plugin-opcode-%3D-0x1) * [Install plugin (opcode = 0x2)](https://docs.ton.org/standard/wallets/v4#install-plugin-opcode-%3D-0x2) * [Remove plugin (opcode = 0x3)](https://docs.ton.org/standard/wallets/v4#remove-plugin-opcode-%3D-0x3) * [Exit codes](https://docs.ton.org/standard/wallets/v4#exit-codes) * [Get methods](https://docs.ton.org/standard/wallets/v4#get-methods) --- # FunC changelog - TON Docs [Skip to main content](https://docs.ton.org/languages/func/changelog#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation FunC FunC changelog [​](https://docs.ton.org/languages/func/changelog#version-0-4-6) Version 0.4.6 --------------------------------------------------------------------------------- Released in [Dec 2024](https://github.com/ton-blockchain/ton/releases/tag/v2024.12-1) . **Fixes:** * `try/catch` handling. * Pure flag for functions stored in variables. [​](https://docs.ton.org/languages/func/changelog#version-0-4-5) Version 0.4.5 --------------------------------------------------------------------------------- Released in [Oct 2024](https://github.com/ton-blockchain/ton/releases/tag/v2024.10) . **Fixes:** * Bug in optimization of [operator `<<`](https://docs.ton.org/languages/func/operators#shift-left%2C-%3C%3C) . [​](https://docs.ton.org/languages/func/changelog#version-0-4-4) Version 0.4.4 --------------------------------------------------------------------------------- Released in [May 2023](https://github.com/ton-blockchain/ton/releases/tag/v2023.05) . **New features:** * Better error-handling. **Fixes:** * `catch` stack recovery. [​](https://docs.ton.org/languages/func/changelog#version-0-4-3) Version 0.4.3 --------------------------------------------------------------------------------- Released in [Apr 2023](https://github.com/ton-blockchain/ton/releases/tag/v2023.04) . **New features:** * Improved optimization of int constants and unused variables. **Fixes:** * Better handling of incorrect inputs: fix UB and prevent crashes on some inputs. * Analysis of repeat loops. [​](https://docs.ton.org/languages/func/changelog#version-0-4-2) Version 0.4.2 --------------------------------------------------------------------------------- Released in [Mar 2023](https://github.com/ton-blockchain/ton/releases/tag/v2023.03) . **New features:** * [FunC Mathlib](https://github.com/ton-blockchain/ton/blob/master/crypto/smartcont/mathlib.fc/) . **Fixes:** * Handling of incorrect integer literal values. [​](https://docs.ton.org/languages/func/changelog#version-0-4-1) Version 0.4.1 --------------------------------------------------------------------------------- Released in [Jan 2023](https://github.com/ton-blockchain/ton/releases/tag/v2023.01) . **New features:** * Added pragmas for precise control of computation order: [`allow-post-modification`](https://docs.ton.org/languages/func/compiler-directives#%23pragma-allow-post-modification) and [`compute-asm-ltr`](https://docs.ton.org/languages/func/compiler-directives#%23pragma-compute-asm-ltr) . * Added legacy tester, a collection of smart-contracts which is used to check whether a compiler update changes compilation results. **Fixes:** * Compiler crashes for some exotic inputs. [​](https://docs.ton.org/languages/func/changelog#version-0-4-0) Version 0.4.0 --------------------------------------------------------------------------------- Released in [Jan 2023](https://github.com/ton-blockchain/ton/releases/tag/v2022.12/) . **New features:** * [`try/catch` statements](https://docs.ton.org/languages/func/statements#try-catch-statement) . * [`throw_arg`](https://docs.ton.org/languages/func/built-ins#throw-arg) , [`throw_arg_if`](https://docs.ton.org/languages/func/built-ins#throw-arg-if) , and [`throw_arg_unless`](https://docs.ton.org/languages/func/built-ins#throw-arg-unless) functions. * Support for in-place modification and mass assignment of global variables, e.g., `a~inc()` and `(a, b) = (3, 5)`, where `a` is global. **Fixes:** * Disallowed ambiguous modification of local variables after their usage in the same expression. For example, `var x = (ds, ds~load_uint(32), ds~load_unit(64));` is forbidden, while `var x = (ds~load_uint(32), ds~load_unit(64), ds);` is allowed. * Allowed empty inline functions. * Fixed a rare optimization bug in `while` loops. [​](https://docs.ton.org/languages/func/changelog#version-0-3-0) Version 0.3.0 --------------------------------------------------------------------------------- Released in [Oct 2022](https://github.com/ton-blockchain/ton/releases/tag/v2022.10/) . **New features:** * Support for [multiline `asm` statements](https://docs.ton.org/languages/func/asm-functions#multi-line-asms) . * Allow duplicate definitions of identical constants and `asm` statements. * Enable bitwise operations for constants. [​](https://docs.ton.org/languages/func/changelog#version-0-2-0) Version 0.2.0 --------------------------------------------------------------------------------- Released in [Aug 2022](https://github.com/ton-blockchain/ton/releases/tag/v2022.08/) . **New features:** * Unbalanced `if/else` branches, where some branches return a value while others do not. **Fixes:** * FunC incorrectly handles `while(false)` loops [(#377)](https://github.com/ton-blockchain/ton/issues/377/) . * FunC generates incorrect code for `if/else` branches [(#374)](https://github.com/ton-blockchain/ton/issues/374/) . * FunC incorrectly returns from conditions in inline functions [(#370)](https://github.com/ton-blockchain/ton/issues/370/) . * `Asm.fif`: splitting large function bodies incorrectly interferes with inline [(#375)](https://github.com/ton-blockchain/ton/issues/375/) . [​](https://docs.ton.org/languages/func/changelog#version-0-1-0) Version 0.1.0 --------------------------------------------------------------------------------- Released in [May 2022](https://github.com/ton-blockchain/ton/releases/tag/v2022.05/) . **New features:** * [Constants](https://docs.ton.org/languages/func/literals#constants) * [Compile-time built-ins](https://docs.ton.org/languages/func/literals#compile-time-built-ins) * [Semver pragmas](https://docs.ton.org/languages/func/compiler-directives#%23pragma-version) * [Includes](https://docs.ton.org/languages/func/compiler-directives#%23include) **Fixes:** * Resolved rare bugs in `Asm.fif`. [​](https://docs.ton.org/languages/func/changelog#initial-version) Initial version ------------------------------------------------------------------------------------- The initial version of FunC was developed by Telegram, but active development stopped after May 2020. The May 2020 release is referred to as the “initial” version. Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/languages/func/changelog.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/languages/func/changelog) [Previous](https://docs.ton.org/languages/func/libraries) [Known issues\ \ Next](https://docs.ton.org/languages/func/known-issues) ⌘I On this page * [Version 0.4.6](https://docs.ton.org/languages/func/changelog#version-0-4-6) * [Version 0.4.5](https://docs.ton.org/languages/func/changelog#version-0-4-5) * [Version 0.4.4](https://docs.ton.org/languages/func/changelog#version-0-4-4) * [Version 0.4.3](https://docs.ton.org/languages/func/changelog#version-0-4-3) * [Version 0.4.2](https://docs.ton.org/languages/func/changelog#version-0-4-2) * [Version 0.4.1](https://docs.ton.org/languages/func/changelog#version-0-4-1) * [Version 0.4.0](https://docs.ton.org/languages/func/changelog#version-0-4-0) * [Version 0.3.0](https://docs.ton.org/languages/func/changelog#version-0-3-0) * [Version 0.2.0](https://docs.ton.org/languages/func/changelog#version-0-2-0) * [Version 0.1.0](https://docs.ton.org/languages/func/changelog#version-0-1-0) * [Initial version](https://docs.ton.org/languages/func/changelog#initial-version) --- # Restricted wallet - TON Docs [Skip to main content](https://docs.ton.org/standard/wallets/restricted#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Wallets Restricted wallet Restricted Wallet is a specialized wallet contract that restricts transfers to predefined owner address, and some operations with Elector and Config contracts. It is used in [Single Nominator](https://github.com/orbs-network/single-nominator) project to securely hold a validator stake and participate in elections without a risk of stealing funds from it. [​](https://docs.ton.org/standard/wallets/restricted#what-makes-it-different) What makes it different -------------------------------------------------------------------------------------------------------- Unlike standard wallets that allow transfers to any address, Restricted Wallet implements address-based restrictions that limit where funds can be sent. **Standard wallet behavior:** You can send funds to any valid address. **Restricted Wallet behavior:** You can only send funds to the predefined owner address or do operations with [Elector](https://docs.ton.org/foundations/system#elector) (new stake, recover stake request, new complaint, and vote for a complaint) and [Config](https://docs.ton.org/foundations/system#config) (vote for specific proposal to change config) contracts. [​](https://docs.ton.org/standard/wallets/restricted#how-it-works) How it works ---------------------------------------------------------------------------------- ### [​](https://docs.ton.org/standard/wallets/restricted#allowed-actions) Allowed actions 1. Send a message to the owner of this wallet. 2. Send “vote for a configuration proposal” message to the [Config contract](https://docs.ton.org/foundations/system#config) . 3. Send “new stake”, “recover stake request”, “new complaint”, or “vote for a complaint” messages to the [Elector contract](https://docs.ton.org/foundations/system#elector) . It is allowed to use [message modes](https://docs.ton.org/languages/func/stdlib#send-raw-message) 128, 64, 2, and 1. Mode 2 (ignore errors) is always enabled when sending messages from this wallet. [​](https://docs.ton.org/standard/wallets/restricted#implementation) Implementation -------------------------------------------------------------------------------------- ### [​](https://docs.ton.org/standard/wallets/restricted#source-code) Source code * Repository: [EmelyanenkoK/nomination-contract/restricted-wallet](https://github.com/EmelyanenkoK/nomination-contract/tree/master/restricted-wallet) Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/standard/wallets/restricted.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/standard/wallets/restricted) [Previous](https://docs.ton.org/standard/wallets/preprocessed-v2/interact) [Overview\ \ Next](https://docs.ton.org/standard/tokens/overview) ⌘I On this page * [What makes it different](https://docs.ton.org/standard/wallets/restricted#what-makes-it-different) * [How it works](https://docs.ton.org/standard/wallets/restricted#how-it-works) * [Allowed actions](https://docs.ton.org/standard/wallets/restricted#allowed-actions) * [Implementation](https://docs.ton.org/standard/wallets/restricted#implementation) * [Source code](https://docs.ton.org/standard/wallets/restricted#source-code) --- # Lockup wallet - TON Docs [Skip to main content](https://docs.ton.org/standard/wallets/lockup#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Wallets Lockup wallet Lockup wallet is a specialized wallet contract that locks funds until a specified time. The [repository](https://github.com/ton-blockchain/lockup-wallet-contract) contains two implementations with different unlocking mechanisms. [​](https://docs.ton.org/standard/wallets/lockup#universal-lockup-wallet) Universal Lockup Wallet ---------------------------------------------------------------------------------------------------- [Universal Lockup Wallet](https://github.com/ton-blockchain/lockup-wallet-contract/tree/c2c9f73394853780621e6215410a95475ac7cf4f/universal) implements time-based fund locking with allowlist functionality. All funds unlock simultaneously when the time restrictions expire. Source code: [`universal/uni-lockup-wallet.fc`](https://github.com/ton-blockchain/lockup-wallet-contract/blob/c2c9f73394853780621e6215410a95475ac7cf4f/universal/uni-lockup-wallet.fc) ### [​](https://docs.ton.org/standard/wallets/lockup#use-cases) Use cases Escrow services. Lock funds until conditions are met, with allowlist of valid recipients. ### [​](https://docs.ton.org/standard/wallets/lockup#persistent-memory-layout) Persistent memory layout storage$_ seqno:uint32 subwallet_id:uint32 public_key:uint256 config_public_key:uint256 allowed_destinations:(PfxHashmapE 267 ^Cell) total_locked_value:Coins locked:HashmapE 32 Coins total_restricted_value:Coins restricted:HashmapE 32 Coins = Storage; * `seqno`: 32-bit sequence number for replay protection. * `subwallet_id`: 32-bit wallet identifier. * `public_key`: 256-bit Ed25519 public key for signing external messages (wallet operations). * `config_public_key`: 256-bit Ed25519 public key for signing internal messages that add locked funds. This separation allows a third party to initialize and fund the lockup wallet without having access to spend the funds. * `allowed_destinations`: Prefix dictionary of allowlisted destination addresses (uses `pfxdict_get?` for prefix matching). * `total_locked_value`: Total amount of locked funds (unrestricted destinations). * `locked`: Dictionary mapping unlock timestamps to locked amounts. * `total_restricted_value`: Total amount of restricted funds (allowlist-only). * `restricted`: Dictionary mapping unlock timestamps to restricted amounts. ### [​](https://docs.ton.org/standard/wallets/lockup#message-layout) Message layout #### [​](https://docs.ton.org/standard/wallets/lockup#external-message-body-layout) External message body layout * `signature`: 512-bit Ed25519 signature. * `subwallet_id`: 32-bit subwallet identifier. * `valid_until`: 32-bit Unix timestamp. * `msg_seqno`: 32-bit sequence number. * Message list: References to messages to send. The contract unlocks expired funds, reserves locked amounts using `raw_reserve(effectively_locked, 2)`, and sends messages. Each message is sent with its specified mode, but if mode is not 2, it’s forced to mode 3 (pay fees separately, ignore errors). #### [​](https://docs.ton.org/standard/wallets/lockup#internal-message-body-layout) Internal message body layout Internal messages with `op = 0x82eaf9c4` (`rwallet_op`) allow adding locked funds: rwallet_op#82eaf9c4 signature:(## 512) cmd:(## 32) only_restrict:(## 1) timestamp:(## 32) = InternalMsgBody; Message requirements: * Must carry ≥1 TON value. * Contain valid signature from `config_public_key`. * `cmd` must be `0x373aa9f4` (`restricted_transfer`). * `only_restrict`: Flag determining lock type: `1` for restricted funds, `0` for locked funds. * `timestamp`: Unix timestamp for unlock. ### [​](https://docs.ton.org/standard/wallets/lockup#get-methods) Get methods 1. `int seqno()` returns current sequence number. 2. `int wallet_id()` returns current subwallet ID. 3. `int get_public_key()` returns stored public key. 4. `(int, int, int) get_balances_at(int time)` returns balance, restricted value, and locked value at specified time. 5. `(int, int, int) get_balances()` returns current balance, restricted value, and locked value. 6. `int check_destination(slice destination)` returns whether destination address is allowlisted. ### [​](https://docs.ton.org/standard/wallets/lockup#exit-codes) Exit codes | Exit code | Description | | --- | --- | | 31 | Signature verification failed (`wrong_signature`) | | 32 | Config signature verification failed | | 33 | Message value too small (< 1 TON) | | 34 | Sequence number mismatch (`wrong_seqno`) | | 35 | Subwallet ID mismatch (`wrong_subwallet_id`) | | 36 | Message expired (`replay_protection`) | | 40 | Unknown operation code (`unknown_op`) | | 41 | Unknown command (`unknown_cmd`) | [​](https://docs.ton.org/standard/wallets/lockup#vesting-wallet) Vesting Wallet ---------------------------------------------------------------------------------- [Vesting Wallet](https://github.com/ton-blockchain/lockup-wallet-contract/tree/c2c9f73394853780621e6215410a95475ac7cf4f/vesting) implements gradual fund unlocking over time with an optional cliff period. The funds unlock linearly according to a vesting schedule. Available through [web interface](https://toncenter.github.io/lockup-sender) . [Source code](https://github.com/ton-blockchain/lockup-wallet-contract/blob/c2c9f73394853780621e6215410a95475ac7cf4f/vesting/vesting-lockup-wallet.fc) . ### [​](https://docs.ton.org/standard/wallets/lockup#use-cases-2) Use cases Employee token vesting. Lock employee tokens with vesting schedule (e.g., 4 years with 1-year cliff). ### [​](https://docs.ton.org/standard/wallets/lockup#persistent-memory-layout-2) Persistent memory layout storage$_ stored_seqno:uint32 stored_subwallet:uint32 public_key:uint256 start_time:uint64 total_duration:uint32 unlock_period:uint32 cliff_duration:uint32 total_amount:Coins allow_elector:Bool = Storage; * `stored_seqno`: 32-bit sequence number (replay protection). * `stored_subwallet`: 32-bit wallet identifier. * `public_key`: 256-bit Ed25519 public key for signing external messages. * `start_time`: 64-bit Unix timestamp when vesting begins. * `total_duration`: 32-bit total vesting duration in seconds. * `unlock_period`: 32-bit period between unlocks in seconds. * `cliff_duration`: 32-bit cliff period before first unlock. * `total_amount`: Total amount subject to vesting. * `allow_elector`: Boolean flag that bypasses vesting restrictions for transfers to [Elector](https://docs.ton.org/foundations/system#elector) and [Config](https://docs.ton.org/foundations/system#config) contracts. ### [​](https://docs.ton.org/standard/wallets/lockup#message-layout-2) Message layout #### [​](https://docs.ton.org/standard/wallets/lockup#external-message-body-layout-2) External message body layout * `signature`: 512-bit Ed25519 signature. * `subwallet_id`: 32-bit subwallet identifier. * `valid_until`: 32-bit Unix timestamp. * `msg_seqno`: 32-bit sequence number. * Optional: One message reference. If present, mode MUST be 3 (pay fees separately, ignore errors). The contract calculates locked amount based on vesting schedule: * Before `start_time + cliff_duration`: All funds locked. * During vesting: Linear unlock based on `unlock_period`. * After `start_time + total_duration`: All funds unlocked. When `allow_elector` is enabled, vesting restrictions are bypassed for transfers to system contracts (see `allow_elector` field description above). #### [​](https://docs.ton.org/standard/wallets/lockup#internal-message-body-layout-2) Internal message body layout Internal messages are ignored (no operations performed). ### [​](https://docs.ton.org/standard/wallets/lockup#get-methods-2) Get methods 1. `int seqno()` returns current sequence number. 2. `int get_public_key()` returns stored public key. 3. `int get_locked_amount(int now_time)` returns locked amount at specified time. 4. `(int, int, int, int, int, int) get_lockup_data()` returns `(start_time, total_duration, unlock_period, cliff_duration, total_amount, allow_elector)`. ### [​](https://docs.ton.org/standard/wallets/lockup#exit-codes-2) Exit codes | Exit code | Description | | --- | --- | | 33 | Sequence number mismatch | | 34 | Subwallet ID mismatch | | 35 | Signature verification failed | | 36 | Message expired (`valid_until` check failed) | | 37 | Invalid number of message references | | 38 | Invalid send mode (must be 3 if message present) | Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/standard/wallets/lockup.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/standard/wallets/lockup) [Previous](https://docs.ton.org/standard/wallets/highload/v2/specification) [Specification\ \ Next](https://docs.ton.org/standard/wallets/preprocessed-v2/specification) ⌘I On this page * [Universal Lockup Wallet](https://docs.ton.org/standard/wallets/lockup#universal-lockup-wallet) * [Use cases](https://docs.ton.org/standard/wallets/lockup#use-cases) * [Persistent memory layout](https://docs.ton.org/standard/wallets/lockup#persistent-memory-layout) * [Message layout](https://docs.ton.org/standard/wallets/lockup#message-layout) * [External message body layout](https://docs.ton.org/standard/wallets/lockup#external-message-body-layout) * [Internal message body layout](https://docs.ton.org/standard/wallets/lockup#internal-message-body-layout) * [Get methods](https://docs.ton.org/standard/wallets/lockup#get-methods) * [Exit codes](https://docs.ton.org/standard/wallets/lockup#exit-codes) * [Vesting Wallet](https://docs.ton.org/standard/wallets/lockup#vesting-wallet) * [Use cases](https://docs.ton.org/standard/wallets/lockup#use-cases-2) * [Persistent memory layout](https://docs.ton.org/standard/wallets/lockup#persistent-memory-layout-2) * [Message layout](https://docs.ton.org/standard/wallets/lockup#message-layout-2) * [External message body layout](https://docs.ton.org/standard/wallets/lockup#external-message-body-layout-2) * [Internal message body layout](https://docs.ton.org/standard/wallets/lockup#internal-message-body-layout-2) * [Get methods](https://docs.ton.org/standard/wallets/lockup#get-methods-2) * [Exit codes](https://docs.ton.org/standard/wallets/lockup#exit-codes-2) --- # Known issues of FunC - TON Docs [Skip to main content](https://docs.ton.org/languages/func/known-issues#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation FunC Known issues of FunC [​](https://docs.ton.org/languages/func/known-issues#constant-evaluation-breaks-function-argument-substitution) Constant evaluation breaks function argument substitution ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ### [​](https://docs.ton.org/languages/func/known-issues#removes-division-by-zero-exception) Removes division by zero exception For the following operators and arithmetic functions, the compiler carries out optimizations during constant evaluation that removes the expected division by zero exception. #### [​](https://docs.ton.org/languages/func/known-issues#multiplication/division-built-ins) Multiplication/division built-ins Issue page: [#1678](https://github.com/ton-blockchain/ton/issues/1678) For functions [`muldiv`](https://docs.ton.org/languages/func/built-ins#muldiv) , [`muldivc`](https://docs.ton.org/languages/func/built-ins#muldivc) and [`muldivr`](https://docs.ton.org/languages/func/built-ins#muldivr) , if any of their first two arguments is zero at compilation time, the compiler replaces the function call with 0, irrespective of the function’s third argument, i.e., the divisor. This means that the function calls get replaced by 0 even when the divisor is 0, effectively removing the expected division by zero exception. Examples: ;; All these produce 0, irrespective of divisor z, ;; even when z is 0. muldiv(0, 1, z); muldivc(1, 0, z); muldivr(0, 1, z); #### [​](https://docs.ton.org/languages/func/known-issues#operators-/-%-combined-with-comparison-operators) Operators /, % combined with comparison operators Issue pages: [#1659](https://github.com/ton-blockchain/ton/issues/1659) , [#1660](https://github.com/ton-blockchain/ton/issues/1660) , [#1661](https://github.com/ton-blockchain/ton/issues/1661) , [#1662](https://github.com/ton-blockchain/ton/issues/1662) . The compiler simplifies the [division `/`](https://docs.ton.org/languages/func/operators#division%2C-%2F) and [modulo `%`](https://docs.ton.org/languages/func/operators#modulo%2C-%25) operators when their left argument is `0`, but only when `/` and `%` are used in tandem with comparison operators like `>=`, `>`, `==`, etc. For example, the following expressions are **not** simplified to 0 at compile-time, which is the correct behavior: 0 / z; ;; NOT replaced by 0 0 % z; ;; NOT replaced by 0 However, when comparison operators are used, the following expressions get simplified, irrespective of the value of `z`: (0 % z) >= 0; ;; Replaced by true (0 / z) >= 0; ;; Replaced by true (0 % z) != 1; ;; Replaced by true This means that the FunC compiler removes the expected division by zero exception in the above examples when `z = 0`. The following are further examples where the left operand of `/` and `%` is simplified to `0` by FunC, resulting in a final expression that the compiler simplifies to `true`, irrespective of the value of `z`: (~(-1) / z) >= 0; ((1 & (~ 1)) / z) >= 0; ((z & 0) / z) >= 0; ((z * 0) / z) >= 0; (~(-1) % z) >= 0; ((1 & (~ 1)) % z) >= 0; ((z & 0) % z) >= 0; ((z * 0) % z) >= 0; ((x & 0) % z) == 1; ((x * 0) % z) == 1; ((-1 % z) % 1) <= 0; ### [​](https://docs.ton.org/languages/func/known-issues#removes-integer-overflow-exception) Removes integer overflow exception Issue pages: [#1656](https://github.com/ton-blockchain/ton/issues/1656) , [#1657](https://github.com/ton-blockchain/ton/issues/1657) , [#1658](https://github.com/ton-blockchain/ton/issues/1658) . The following expressions should produce overflows for particular values of `z`, but the FunC compiler simplifies them irrespective of `z`: (0 & (- z)) <= 0; ;; Should overflow for z = -115792089237316195423570985008687907853269984665640564039457584007913129639936, ;; but simplified to true (0 * (- z)) <= 0; ;; Should overflow for z = -115792089237316195423570985008687907853269984665640564039457584007913129639936, ;; but simplified to true ((z / -1) % 2) > -2; ;; Should overflow for z = -115792089237316195423570985008687907853269984665640564039457584007913129639936, ;; but simplified to true The following are further examples of expressions that should produce integer overflows at the indicated values, but the FunC compiler simplifies them to `true` irrespective of the value of `z`: (~(-1) & (-1 * z)) <= 0; ;; for z = MIN_INT. ((1 & (~ 1)) & (z / -1)) <= 0; ;; for z = MIN_INT. ((z & 0) & (z * 2)) <= 0; ;; for z = MAX_INT ((z * 0) & (z + 1)) <= 0; ;; for z = MAX_INT. (~(-1) * (-1 * z)) <= 0; ;; for z = MIN_INT ((1 & (~ 1)) * (z / -1)) <= 0; ;; for z = MIN_INT ((z & 0) * (z * 2)) <= 0; ;; for z = MAX_INT ((z * 0) * (z + 1)) <= 0; ;; for z = MAX_INT ((-1 * z) % 2) > -2; ;; for z = MIN_INT ((- z) % 2) > -2; ;; for z = MIN_INT ((z * 2) % 2) > -2; ;; for z = MAX_INT ((z + 1) % 2) > -2; ;; for z = MAX_INT where `MIN_INT = -115792089237316195423570985008687907853269984665640564039457584007913129639936` and `MAX_INT = 115792089237316195423570985008687907853269984665640564039457584007913129639935`. ### [​](https://docs.ton.org/languages/func/known-issues#incorrect-results) Incorrect results #### [​](https://docs.ton.org/languages/func/known-issues#involving-operator-%) Involving operator `~%` Issue Page: [#1670](https://github.com/ton-blockchain/ton/issues/1670) In the following code: int calc(int x) { return ((x ~% -3) <= 0); } int calc3(int x, int y, int z) { return ((x ~% y) <= z); } calling `calc(1)` produces `-1`. But calling `calc3(1,-3,0)` produces `0`. But the expected behavior is `calc(1) = calc3(1,-3,0)`, since `calc` is just a specialization of `calc3`. The same happens with comparison operators: `<=>`, `!=`, and `==`, i.e., the following expressions also produce differing results: * `((x ~% -3) <=> 1)` in `calc` function, and `((x ~% y) <=> z)` in `cal3` function. Produces `calc(1) = -1`, and `calc3(1,-3,1) = 0`. * `((x ~% -3) != 1)` in `calc` function, and `((x ~% y) != z)` in `cal3` function. Produces `calc(1) = -1`, and `calc3(1,-3,1) = 0`. * `((x ~% -3) == 1)` in `calc` function, and `((x ~% y) == z)` in `cal3` function. Produces `calc(1) = 0`, and `calc3(1,-3,1) = -1`. #### [​](https://docs.ton.org/languages/func/known-issues#involving-operator-^%) Involving operator `^%` Issue Page: [#1669](https://github.com/ton-blockchain/ton/issues/1669) In the following code: int calc(int x) { return ((x ^% -2) <= 0); } int calc3(int x, int y, int z) { return ((x ^% y) <= z); } calling `calc(1)` produces `-1`. But calling `calc3(1,-2,0)` produces `0`. But the expected behavior is `calc(1) = calc3(1,-2,0)`, since `calc` is just a specialization of `calc3`. The same happens with comparison operators: `<=>`, `!=`, and `==`. The following expressions also produce differing results: * `((x ^% -2) <=> 1)` in `calc` function, and `((x ^% y) <=> z)` in `cal3` function. Produces `calc(1) = -1`, and `calc3(1,-2,1) = 0`. * `((x ^% -2) != 1)` in `calc` function, and `((x ^% y) != z)` in `cal3` function. Produces `calc(1) = -1`, and `calc3(1,-2,1) = 0`. * `((x ^% -2) == 1)` in `calc` function, and `((x ^% y) == z)` in `cal3` function. Produces `calc(1) = 0`, and `calc3(1,-2,1) = -1`. [​](https://docs.ton.org/languages/func/known-issues#stack-underflow-in-run_methodx-functions) Stack underflow in `run_methodX` functions -------------------------------------------------------------------------------------------------------------------------------------------- Issue Page: [#1883](https://github.com/ton-blockchain/ton/issues/1883) . The following code produces a stack underflow when `run_method3` executes: () test(int a, int b, int c) impure method_id(16384) { ~dump(a); ~dump(b); ~dump(c); } () recv_internal() impure { run_method3(16384, 100, 200, 300); } The expected behavior is that `test` function prints `100`, `200`, and `300` in the debug logs when `run_method3` executes. The functions `run_method0`, `run_method1`, and `run_method2` have similar problems with stack underflow. [​](https://docs.ton.org/languages/func/known-issues#func-does-not-throw-on-1024-bits-long-slice-constant-creation-withs-literal) FunC does not throw on 1024 bits long slice constant creation with s literal ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Issue page: [#1153](https://github.com/ton-blockchain/ton/issues/1153) . The following is successfully compiled: const slice s = "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"s; () main () { ~dump(s); } But the compiler should have thrown a compilation error due to the string being too long. [​](https://docs.ton.org/languages/func/known-issues#func-ignores-argument-order-when-calling-built-ins-or-asm-functions-via-variables) FunC ignores argument order when calling built-ins or asm functions via variables ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Page issue: [#1681](https://github.com/ton-blockchain/ton/issues/1681) . ;; Correct: directly calls built-in, respects ret_order (int, int) correctBuiltin(int a, int b) { return moddiv(a, b); } ;; Incorrect: calling built-in via variable, ignores ret_order (int, int) incorrectBuiltin(int a, int b) { var f = moddiv; return f(a, b); } ;; Define the asm function with explicit ret_order (int, int) myAsm(int a, int b) asm(-> 1 0) "SWAP"; ;; Correct: directly calls asm function with explicit ret_order (int, int) correctAsm(int a, int b) { return myAsm(a, b); } ;; Incorrect: calls asm function via variable, ignores ret_order (int, int) incorrectAsm(int a, int b) { var f = myAsm; return f(a, b); } () main () { ~dump([correctBuiltin(5, 1)]); ;; [0 5] Correct ~dump([incorrectBuiltin(5, 1)]); ;; [5 0] Incorrect ~dump([correctAsm(5, 1)]); ;; [5 1] Correct ~dump([incorrectAsm(5, 1)]); ;; [1 5] Incorrect } [​](https://docs.ton.org/languages/func/known-issues#func-crashes-with-fatal-assertion-when-tensor-exceeds-254-elements) FunC crashes with fatal assertion when tensor exceeds 254 elements ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Issue Page: [1682](https://github.com/ton-blockchain/ton/issues/1682) The compiler crashes with a fatal internal assertion if a tensor exceeds 254 elements, instead of a proper user-facing error. Example: () main() { var x = ( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); } which crashes with message: fatal: Assertion failed at analyzer.cpp:46: k <= 254 && n <= 0x7fff00 Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/languages/func/known-issues.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/languages/func/known-issues) [Previous](https://docs.ton.org/languages/func/changelog) [Tact\ \ Next](https://docs.ton.org/languages/tact) ⌘I On this page * [Constant evaluation breaks function argument substitution](https://docs.ton.org/languages/func/known-issues#constant-evaluation-breaks-function-argument-substitution) * [Removes division by zero exception](https://docs.ton.org/languages/func/known-issues#removes-division-by-zero-exception) * [Multiplication/division built-ins](https://docs.ton.org/languages/func/known-issues#multiplication%2Fdivision-built-ins) * [Operators /, % combined with comparison operators](https://docs.ton.org/languages/func/known-issues#operators-%2F-%25-combined-with-comparison-operators) * [Removes integer overflow exception](https://docs.ton.org/languages/func/known-issues#removes-integer-overflow-exception) * [Incorrect results](https://docs.ton.org/languages/func/known-issues#incorrect-results) * [Involving operator ~%](https://docs.ton.org/languages/func/known-issues#involving-operator-%25) * [Involving operator ^%](https://docs.ton.org/languages/func/known-issues#involving-operator-%5E%25) * [Stack underflow in run\_methodX functions](https://docs.ton.org/languages/func/known-issues#stack-underflow-in-run_methodx-functions) * [FunC does not throw on 1024 bits long slice constant creation with s literal](https://docs.ton.org/languages/func/known-issues#func-does-not-throw-on-1024-bits-long-slice-constant-creation-withs-literal) * [FunC ignores argument order when calling built-ins or asm functions via variables](https://docs.ton.org/languages/func/known-issues#func-ignores-argument-order-when-calling-built-ins-or-asm-functions-via-variables) * [FunC crashes with fatal assertion when tensor exceeds 254 elements](https://docs.ton.org/languages/func/known-issues#func-crashes-with-fatal-assertion-when-tensor-exceeds-254-elements) --- # Wallet V5 API - TON Docs [Skip to main content](https://docs.ton.org/standard/wallets/v5-api#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation V5 Wallet V5 API This article provides overview of wallet V5 public interfaces, how to interact with them and serialize used data structures. There are several ways how you can interact with deployed V5 wallet smart contract: * Send external signed message * Send internal signed message * Send internal message from extension Let’s first explore message structure, that is used to perform different actions on wallet contract. [​](https://docs.ton.org/standard/wallets/v5-api#tl-b) TL-B -------------------------------------------------------------- This is TL-B for V5 wallet actions, it includes some [complex TL-B patterns](https://docs.ton.org/languages/tl-b/complex-and-non-trivial-examples.mdx) . You can also find it on [GitHub](https://github.com/ton-blockchain/wallet-contract-v5/blob/321186127e8cc5e395ad3b2f1870839237c56f5f/types.tlb) , in the wallet repo. // Contract state contract_state$_ is_signature_allowed: (## 1) seqno: # wallet_id: # public_key: (## 256) extensions_dict: (HashmapE 256 int1) = ContractState; // Extended actions in W5: add_extension#02 addr:MsgAddressInt = W5ExtendedAction; delete_extension#03 addr:MsgAddressInt = W5ExtendedAction; set_signature_auth_allowed#04 allowed:Bool = W5ExtendedAction; // note: `m = extended actions count - 1`, so the last ref is not empty cell extended_list_last$_ action:W5ExtendedAction = W5ExtendedActionList 0; extended_list_action$_ {n:#} action:W5ExtendedAction prev:^(W5ExtendedActionList n) = W5ExtendedActionList (n + 1); // `OutList m` is standard actions from block.tlb: w5_actions_request$_ {m:#} {n:#} out_actions:(Maybe ^(OutList m)) extended_actions:(Maybe (W5ExtendedActionList n)) = W5InnerRequest m n; w5_signed_request$_ {m:#} {n:#} wallet_id: # valid_until: # msg_seqno: # inner: (W5InnerRequest m n) signature: bits512 = W5SignedRequest m n; // actions_count = m, extended_actions_count - 1 = n w5_internal_signed_request#73696e74 {m:#} {n:#} request:(W5SignedRequest m n) = W5MsgBody m n; w5_external_signed_request#7369676e {m:#} {n:#} request:(W5SignedRequest m n) = W5MsgBody m n; w5_extension_action_request#6578746e {m:#} {n:#} query_id:uint64 request:(W5InnerRequest m n) = W5MsgBody m n; // opcode detection, actual InternalMsgBody / ExternalMsgBody is in W5MsgBody w5_internal_signed_request#73696e74 rest:Any = InternalMsgBody; w5_external_signed_request#7369676e rest:Any = InternalMsgBody; w5_extension_action_request#6578746e rest:Any = InternalMsgBody; See all 40 lines Three types of messages that were described above can be seen here: w5_internal_signed_request#73696e74 {m:#} {n:#} request:(W5SignedRequest m n) = W5MsgBody m n; w5_external_signed_request#7369676e {m:#} {n:#} request:(W5SignedRequest m n) = W5MsgBody m n; w5_extension_action_request#6578746e {m:#} {n:#} query_id:uint64 request:(W5InnerRequest m n) = W5MsgBody m n; Each of them includes the same `W5InnerRequest` field that dictates whats need to be done by wallet contract. In case of signed messages, the request needs to be verified, so `W5InnerRequest` is wrapped in `W5SignedRequest` structure, which contains necessary information for this. Let’s break down these data structures. [​](https://docs.ton.org/standard/wallets/v5-api#message-structure) Message structure ---------------------------------------------------------------------------------------- Message structure for V5 wallet contract is quite cumbersome and hard to read, it’s made for optimal (de-)serialization and not optimized for understanding. It is described in [TL-B](https://docs.ton.org/languages/tl-b/overview) languages and includes snake-cell pattern. We will try to get a grip of it by breaking down core data structures and how they are used. You can skip to [Examples section](https://docs.ton.org/standard/wallets/v5-api#examples) , where we would use existing high-level libraries that abstract low level logic from the user. [​](https://docs.ton.org/standard/wallets/v5-api#inner-request) Inner Request -------------------------------------------------------------------------------- Inner request is defined as follows: w5_actions_request$_ {m:#} {n:#} out_actions:(Maybe ^(OutList m)) extended_actions:(Maybe (W5ExtendedActionList n)) = W5InnerRequest m n; V5 wallet supports two main types of actions that can be performed: The action structure allows for: * **Send Message Actions**: Standard message sending with specified mode * **Extended Actions**: Advanced wallet management operations * **Add Extension**: Register new extension addresses * **Delete Extension**: Remove extension addresses * **Set Signature Auth**: Enable/disable signature-based authentication As you can see in TL-B, `out_actions` are snake-cell list of ordinary out messages, followed then by binary flag `has_other_actions` and `other_actions` extended action list. #### [​](https://docs.ton.org/standard/wallets/v5-api#inner-request-structure) Inner Request Structure The Inner Request serialization follows this structure: #### [​](https://docs.ton.org/standard/wallets/v5-api#serialization-layout) Serialization Layout The Inner Request is serialized in the following order: [​](https://docs.ton.org/standard/wallets/v5-api#signed-request) Signed Request ---------------------------------------------------------------------------------- Signed message is a message that was signed using owners private key from his dedicated keypair, method from asymmetric cryptography. Later this message will be verified on-chain using public key stored in wallet smart contract - [read more](https://docs.ton.org/standard/wallets/how-it-works#how-ownership-verification-works) about how ownership verification works. Before V5 standard, there was only one way to deliver signed message to wallet contract - via external-in message. However, external messages has certain limitations, e.g. you can only send external-out messages from the smart contracts themselves. This means that it wasn’t possible to deliver signed message from inside the blockchain, from another smart contract. V5 standard adds this functionality, partially enabling [gasless transaction](https://docs.ton.org/standard/wallets/v5#preparing-for-gasless-transactions) . Besides `W5InnerRequest` field that contains actual actions that will be performed, `W5SignedRequest` structure contains usual wallet message fields that were in-place in previous versions, read more about them [here](https://docs.ton.org/standard/wallets/how-it-works) . [​](https://docs.ton.org/standard/wallets/v5-api#examples) Examples ---------------------------------------------------------------------- Here we will take a look at code examples in Typescript using low level serialization library _@ton/core_. ### [​](https://docs.ton.org/standard/wallets/v5-api#how-to-create-inner-request) How to create Inner Request As per message structure section above, `Inner Request` consists of 2 kinds of actions, basic _send message_ actions and _extended actions_ that affect contract behavior. Let’s write code that handles packing for extended actions: import { Address, beginCell, Builder, Cell } from '@ton/core'; // declare actions as tagged union export type OutActionAddExtension = { type: 'addExtension'; address: Address; } export type OutActionRemoveExtension = { type: 'removeExtension'; address: Address; } export type OutActionSetIsPublicKeyEnabled = { type: 'setIsPublicKeyEnabled'; isEnabled: boolean; } export type OutActionExtended = OutActionSetIsPublicKeyEnabled | OutActionAddExtension | OutActionRemoveExtension; // store each action content as described in its TL-B specification: // 8 bits for action tag and then useful payload const outActionAddExtensionTag = 0x02; function storeOutActionAddExtension(action: OutActionAddExtension) { return (builder: Builder) => { builder.storeUint(outActionAddExtensionTag, 8).storeAddress(action.address) } } const outActionRemoveExtensionTag = 0x03; function storeOutActionRemoveExtension(action: OutActionRemoveExtension) { return (builder: Builder) => { builder.storeUint(outActionRemoveExtensionTag, 8).storeAddress(action.address) } } const outActionSetIsPublicKeyEnabledTag = 0x04; function storeOutActionSetIsPublicKeyEnabled(action: OutActionSetIsPublicKeyEnabled) { return (builder: Builder) => { builder.storeUint(outActionSetIsPublicKeyEnabledTag, 8).storeUint(action.isEnabled ? 1 : 0, 1) } } // entry point for storing any extended action export function storeOutActionExtendedV5R1(action: OutActionExtended) { switch (action.type) { case 'setIsPublicKeyEnabled': return storeOutActionSetIsPublicKeyEnabled(action); case 'addExtension': return storeOutActionAddExtension(action); case 'removeExtension': return storeOutActionRemoveExtension(action); default: throw new Error('Unknown action type' + (action as OutActionExtended)?.type); } } // and now the hard part - list snake-cell serialization; // we will use this function recursively, to store actions as reference cells one by one function packExtendedActionsRec(extendedActions: OutActionExtended[]): Cell { const [first, ...rest] = extendedActions; let builder = beginCell() .store(storeOutActionExtendedV5R1(first)); if (rest.length > 0) { // if there are more actions, store them recursively builder = builder.storeRef(packExtendedActionsRec(rest)); } return builder.endCell(); } See all 78 lines Now we have to deal with basic action serialization. However, since these are the messages that are described in [`block.tlb`](https://docs.ton.org/languages/tl-b/overview) , we can use contract-agnostic code from serialization library to store them. Here is a code snippet for storing V5 wallet actions as per `Inner Request` TL-B: import { beginCell, Builder, Cell, loadOutList, OutActionSendMsg, SendMode, Slice, storeOutList } from '@ton/core'; // helper functions export function isOutActionExtended(action: OutActionSendMsg | OutActionExtended): action is OutActionExtended { return ( action.type === 'setIsPublicKeyEnabled' || action.type === 'addExtension' || action.type === 'removeExtension' ); } export function isOutActionBasic(action: OutActionSendMsg | OutActionExtended): action is OutActionSendMsg { return !isOutActionExtended(action); } // main entrypoint for storing any actions list export function storeOutListExtendedV5(actions: (OutActionExtended | OutActionSendMsg)[]) { const extendedActions = actions.filter(isOutActionExtended); const basicActions = actions.filter(isOutActionBasic); return (builder: Builder) => { // here we use "storeOutList", serialization function from @ton/core const outListPacked = basicActions.length ? beginCell().store(storeOutList(basicActions.slice())) : null; builder.storeMaybeRef(outListPacked); if (extendedActions.length === 0) { // has_more_actions flag to false builder.storeUint(0, 1); } else { const [first, ...rest] = extendedActions; builder // has_more_actions flag to true .storeUint(1, 1) // here we use our store function from previous code section .store(storeOutActionExtendedV5(first)); // if there are more actions - store them one by one if (rest.length > 0) { builder.storeRef(packExtendedActionsRec(rest)); } } } } See all 49 lines With this, we can serialize and store list of actions, in next section we will learn how to use them to send signed message. ### [​](https://docs.ton.org/standard/wallets/v5-api#how-to-create-and-send-signed-request) How to create and send Signed Request There are several additional arguments that we need to create signed message besides the list of actions from previous section: * `walletId` * `seqno` * `privateKey` * `validUntil` You can read more about where to obtain them and what there purpose is in [How it works](https://docs.ton.org/standard/wallets/how-it-works) section. In this code snippet we will learn how to create signed serialized message. import { sign } from "@ton/crypto"; export type WalletV5BasicSendArgs = { seqno: number; validUntil: number; privateKey: Buffer; } // w5_internal_signed_request#73696e74 {m:#} {n:#} request:(W5SignedRequest m n) = W5MsgBody m n; // w5_external_signed_request#7369676e {m:#} {n:#} request:(W5SignedRequest m n) = W5MsgBody m n; export type WalletV5SendArgsSinged = WalletV5BasicSendArgs & { authType?: 'external' | 'internal';}; // w5_extension_action_request#6578746e {m:#} {n:#} query_id:uint64 request:(W5InnerRequest m n) = W5MsgBody m n; export type Wallet5VSendArgsExtensionAuth = WalletV5BasicSendArgs & { authType: 'extension'; queryId?: bigint; } export type WalletV5SendArgs = | WalletV5SendArgsSinged | Wallet5VSendArgsExtensionAuth; const OpCodes = { authExtension: 0x6578746e, authSignedExternal: 0x7369676e, authSignedInternal: 0x73696e74 } export function createWalletTransferV5R1( args: T extends Wallet5VSendArgsExtensionAuth // action types are from Inner Request section ? T & { actions: (OutActionSendMsg | OutActionExtended)[]} : T & { actions: (OutActionSendMsg | OutActionExtended)[], walletId: (builder: Builder) => void } ): Cell { // Check number of actions if (args.actions.length > 255) { throw Error("Maximum number of OutActions in a single request is 255"); } // store each message type according to its TL-B if (args.authType === 'extension') { return beginCell() .storeUint(OpCodes.authExtension, 32) .storeUint(args.queryId ?? 0, 64) // use storeOutListExtendedV5 .store(storeOutListExtendedV5(args.actions)) .endCell(); } const signingMessage = beginCell() .storeUint(args.authType === 'internal' ? OpCodes.authSignedInternal : OpCodes.authSignedExternal, 32) .store(args.walletId); // now we store common part for both messages signingMessage.storeUint(args.timeout || Math.floor(Date.now() / 1e3) + 60, 32); // Default timeout: 60 seconds signingMessage .storeUint(args.seqno, 32) .store(storeOutListExtendedV5(args.actions)); // now we need to sign message const signature = sign(signingMessage.endCell().hash(), args.secretKey); return beginCell().storeBuilder(signingMessage).storeBuffer(signature).endCell(); } See all 70 lines Now what is left is sending the message. The way we send created message is dependent on the message type. #### [​](https://docs.ton.org/standard/wallets/v5-api#sending-external_signed-message) Sending external\_signed message After obtaining signed message cell we need to serialize it as external message and send it to the blockchain. import { Address, beginCell, Cell, external, storeMessage } from '@ton/core'; // with authType = 'external' const msgCell = createWalletTransferV5(...); const v5WalletAddress = Address.parse("EQ...."); const serializedExternal = external({ to: v5WalletAddress, body: msgCell }); // BoC: bag of cells const boc = beginCell() .store(storeMessage(serializedExternal)) .endCell() .toBoc(); You can send this BoC to the network in any convenient way, e.g. with API provider like [TonCenter /message](https://toncenter.com/api/v3/index.html#/api%2Fv2/api_v3_post_v2_message) or with your own [liteserver](https://docs.ton.org/ecosystem/nodes/overview) . #### [​](https://docs.ton.org/standard/wallets/v5-api#sending-internal_extension-and-internal_signed) Sending internal\_extension and internal\_signed These two types of messages are internal messages, meaning that they need to come from another contract. However strange that may sound, the easiest way to send internal message from another contract is to ask another wallet contract to send internal message to our wallet contract with body that will contain our constructed message. For simplicity, we will use wallet V4 contract with existing client serialization library that will take care of all low level stuff. import {beginCell, toNano, TonClient, WalletContractV4, internal, fromNano} from "@ton/ton" import {getHttpEndpoint} from "@orbs-network/ton-access" import {mnemonicToPrivateKey} from "@ton/crypto" // v4 wallet mnemonic const mnemonics = "dog bacon bread ..." const endpoint = await getHttpEndpoint({network: 'testnet'}) const client = new TonClient({ endpoint: endpoint, }) const keyPair = await mnemonicToPrivateKey(mnemonics.split(" ")) const secretKey = keyPair.secretKey const workchain = 0 // we are working in basechain. const deployerWallet = WalletContractV4.create({ workchain: workchain, publicKey: keyPair.publicKey, }) const deployerWalletContract = client.open(deployerWallet) // with authType = 'internal' or 'extension' const internalMsgBody = createWalletTransferV5(...); // here we use function from previous section to create V5 wallet message cell // next, we will send it as internal message using V4 wallet // address of our V5 wallet contract const v5WalletAddress = Address.parse("EQ...."); const seqnoForV4Wallet: number = await deployerWalletContract.getSeqno() await deployerWalletContract.sendTransfer({ seqno, secretKey, messages: [\ internal({\ to: v5WalletAddress,\ value: toNano("0.05"),\ body: internalMsgBody,\ }),\ ], }) See all 44 lines Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/standard/wallets/v5-api.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/standard/wallets/v5-api) [Previous](https://docs.ton.org/standard/wallets/v5) [Overview\ \ Next](https://docs.ton.org/standard/wallets/highload/overview) ⌘I On this page * [TL-B](https://docs.ton.org/standard/wallets/v5-api#tl-b) * [Message structure](https://docs.ton.org/standard/wallets/v5-api#message-structure) * [Inner Request](https://docs.ton.org/standard/wallets/v5-api#inner-request) * [Inner Request Structure](https://docs.ton.org/standard/wallets/v5-api#inner-request-structure) * [Serialization Layout](https://docs.ton.org/standard/wallets/v5-api#serialization-layout) * [Signed Request](https://docs.ton.org/standard/wallets/v5-api#signed-request) * [Examples](https://docs.ton.org/standard/wallets/v5-api#examples) * [How to create Inner Request](https://docs.ton.org/standard/wallets/v5-api#how-to-create-inner-request) * [How to create and send Signed Request](https://docs.ton.org/standard/wallets/v5-api#how-to-create-and-send-signed-request) * [Sending external\_signed message](https://docs.ton.org/standard/wallets/v5-api#sending-external_signed-message) * [Sending internal\_extension and internal\_signed](https://docs.ton.org/standard/wallets/v5-api#sending-internal_extension-and-internal_signed) --- # FunC cookbook - TON Docs [Skip to main content](https://docs.ton.org/languages/func/cookbook#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation FunC FunC cookbook The FunC cookbook was created to consolidate all the knowledge and best practices from experienced FunC developers in one place. The goal is to make it easier for future developers to build smart contracts efficiently. Unlike the rest of the official FunC documentation, this guide focuses on solving everyday challenges that FunC developers encounter during smart contract development. [​](https://docs.ton.org/languages/func/cookbook#statements) Statements -------------------------------------------------------------------------- ### [​](https://docs.ton.org/languages/func/cookbook#how-to-use-flags-in-if-statements) How to use flags in if statements To check whether an event is relevant, use a flag variable of type integer. The flag can either be `0`, representing `false`, or `-1`, representing `true`. See [absence of boolean type](https://docs.ton.org/languages/func/types#no-boolean-type) . When checking the flag in [if..else statements](https://docs.ton.org/languages/func/statements#if%E2%80%A6else-statement) , it is unnecessary to use the [`==` operator](https://docs.ton.org/languages/func/operators#equality%2C-%3D%3D) , since a `0` evaluates to `false`, and any nonzero value is considered to be `true` in `if..else` statements. int flag = 0; ;; false ;; ... ;; ... if (flag) { ;; No need to use flag == -1 ;; do something } else { ;; reject } ### [​](https://docs.ton.org/languages/func/cookbook#how-to-write-a-repeat-loop) How to write a repeat loop A [repeat loop](https://docs.ton.org/languages/func/statements#repeat-loop) helps execute an action a fixed number of times. The example below computes exponentiation of `number` to the exponent `exponent`, and illustrates it with specific values `number = 2` and `exponent = 5`: int number = 2; int exponent = 5; int result = 1; ;; Will store the final result: number^exponent repeat(exponent) { ;; The repeat multiplies variable "number", ;; exactly an "exponent" number of times result *= number; } ;; result holds value 32 ### [​](https://docs.ton.org/languages/func/cookbook#how-to-write-a-while-loop) How to write a while loop A [while loop](https://docs.ton.org/languages/func/statements#while-loop) is useful when the number of iterations is unknown. The following example processes the references in the message [cell](https://docs.ton.org/foundations/serialization/cells) . Each cell can store up to four references to other cells: cell inner_cell = begin_cell() ;; Create a new empty builder .store_uint(123, 16) ;; Store uint with value 123 and length 16 bits .end_cell(); ;; Convert builder to a cell ;; Create a cell, which will have two references to inner_cell cell message = begin_cell() .store_ref(inner_cell) ;; Store cell as reference .store_ref(inner_cell) ;; A second time .end_cell(); slice msg = message.begin_parse(); ;; Convert cell to slice while (msg.slice_refs_empty?() != -1) { ;; Iterate while there are refs to process ;; Recall that -1 is true. cell inner_cell = msg~load_ref(); ;; Load cell from slice msg ;; do something } **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [`begin_cell`](https://docs.ton.org/languages/func/stdlib#begin-cell) * [`store_uint`](https://docs.ton.org/languages/func/stdlib#store-uint) * [`end_cell`](https://docs.ton.org/languages/func/stdlib#end-cell) * [`store_ref`](https://docs.ton.org/languages/func/stdlib#store-ref) * [`begin_parse`](https://docs.ton.org/languages/func/stdlib#begin-parse) * [`slice_refs_empty?`](https://docs.ton.org/languages/func/stdlib#slice-refs-empty%3F) * [`load_ref`](https://docs.ton.org/languages/func/stdlib#load-ref) ### [​](https://docs.ton.org/languages/func/cookbook#how-to-write-a-do-until-loop) How to write a do until loop Use a [`do..until` loop](https://docs.ton.org/languages/func/statements#until-loop) when the loop must execute at least once. int flag = 0; do { ;; iterate this as long as "flag" is false (0). ;; It would execute at least once even if the flag ;; were already true before entering the loop. } until (flag == -1); ;; Stop when "flag" becomes -1 [​](https://docs.ton.org/languages/func/cookbook#cells-and-slices) Cells and slices -------------------------------------------------------------------------------------- ### [​](https://docs.ton.org/languages/func/cookbook#how-to-determine-if-a-slice-is-empty) How to determine if a slice is empty Before working with a slice, checking whether it contains any data is essential to ensure proper processing. The `slice_empty?` method can be used for this purpose. However, it returns `0` (`false`) if the slice contains at least one `bit` of data or one reference. ;; Creating empty slice slice empty_slice = ""; ;; compile-time built-in "" produces a slice with no bits ;; `slice_empty?()` returns `true` because the slice doesn't have any `bits` and `refs`. empty_slice.slice_empty?(); ;; Creating slice which contains bits only slice slice_with_bits_only = "Hello, world!"; ;; compile-time built-in produces a slice ;; containing the ASCII binary code of the string ;; `slice_empty?()` returns `false` because the slice has bits. slice_with_bits_only.slice_empty?(); ;; Create an empty dummy cell for use later cell dummy_cell = begin_cell().end_cell(); ;; Creating slice which contains refs only slice slice_with_refs_only = begin_cell() .store_ref(dummy_cell) ;; Add the dummy cell as a reference .end_cell() ;; this creates the cell .begin_parse(); ;; this creates a slice from the cell ;; `slice_empty?()` returns `false` because the slice has cell references. slice_with_refs_only.slice_empty?(); ;; Creating slice which contains bits and refs slice slice_with_bits_and_refs = begin_cell() .store_slice("Hello, world!") ;; Add bits from the slice computed ;; using the compile-time built-in .store_ref(dummy_cell) ;; Add the dummy cell as a reference .end_cell() .begin_parse(); ;; `slice_empty?()` returns `false` because the slice has bits and references. slice_with_bits_and_refs.slice_empty?(); **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [`""` compile-time builtin](https://docs.ton.org/languages/func/literals#string-without-suffix) , where `` is an ASCII string * [`slice_empty?`](https://docs.ton.org/languages/func/stdlib#slice-empty%3F) * [`begin_cell`](https://docs.ton.org/languages/func/stdlib#begin-cell) * [`end_cell`](https://docs.ton.org/languages/func/stdlib#end-cell) * [`store_ref`](https://docs.ton.org/languages/func/stdlib#store-ref) * [`begin_parse`](https://docs.ton.org/languages/func/stdlib#begin-parse) * [`store_slice`](https://docs.ton.org/languages/func/stdlib#store-slice) ### [​](https://docs.ton.org/languages/func/cookbook#how-to-determine-if-slice-is-empty-no-bits-but-may-have-refs) How to determine if slice is empty (no bits, but may have refs) If only the presence of bits matters and the cell references in the slice can be ignored, use the `slice_data_empty?` function. ;; Creating empty slice slice empty_slice = ""; ;; compile-time built-in "" produces a slice with no bits ;; `slice_data_empty?()` returns `true` because the slice doesn't have any bits. empty_slice.slice_data_empty?(); ;; Creating slice which contains bits only slice slice_with_bits_only = "Hello, world!"; ;; compile-time built-in produces a slice ;; containing the ASCII binary code of the string ;; `slice_data_empty?()` returns `false` because the slice has bits. slice_with_bits_only.slice_data_empty?(); ;; Create an empty dummy cell for use later cell dummy_cell = begin_cell().end_cell(); ;; Creating slice which contains refs only slice slice_with_refs_only = begin_cell() .store_ref(dummy_cell) ;; Add the dummy cell as a reference .end_cell() ;; this creates the cell .begin_parse(); ;; this creates a slice from the cell ;; `slice_data_empty?()` returns `true` because the slice doesn't have any bits slice_with_refs_only.slice_data_empty?(); ;; Creating slice which contains bits and refs slice slice_with_bits_and_refs = begin_cell() .store_slice("Hello, world!") ;; Add bits from the slice computed ;; using the compile-time built-in .store_ref(dummy_cell) ;; Add the dummy cell as a reference .end_cell() .begin_parse(); ;; `slice_data_empty?()` returns `false` because the slice has bits. slice_with_bits_and_refs.slice_data_empty?(); **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [`""` compile-time builtin](https://docs.ton.org/languages/func/literals#string-without-suffix) , where `` is an ASCII string. * [`slice_data_empty?`](https://docs.ton.org/languages/func/stdlib#slice-data-empty%3F) * [`begin_cell`](https://docs.ton.org/languages/func/stdlib#begin-cell) * [`end_cell`](https://docs.ton.org/languages/func/stdlib#end-cell) * [`store_ref`](https://docs.ton.org/languages/func/stdlib#store-ref) * [`begin_parse`](https://docs.ton.org/languages/func/stdlib#begin-parse) * [`store_slice`](https://docs.ton.org/languages/func/stdlib#store-slice) ### [​](https://docs.ton.org/languages/func/cookbook#how-to-determine-if-slice-is-empty-no-refs-but-may-have-bits) How to determine if slice is empty (no refs, but may have bits) If only cell references are of interest, their presence can be checked using the `slice_refs_empty?` function. ;; Creating empty slice slice empty_slice = ""; ;; compile-time built-in "" produces a slice with no bits ;; `slice_refs_empty?()` returns `true` because the slice doesn't have any cell references. empty_slice.slice_refs_empty?(); ;; Creating slice which contains bits only slice slice_with_bits_only = "Hello, world!"; ;; compile-time built-in produces a slice ;; containing the ASCII binary code of the string ;; `slice_refs_empty?()` returns `true` because the slice doesn't have any cell references. slice_with_bits_only.slice_refs_empty?(); ;; Create an empty dummy cell for use later cell dummy_cell = begin_cell().end_cell(); ;; Creating slice which contains refs only slice slice_with_refs_only = begin_cell() .store_ref(dummy_cell) ;; Add the dummy cell as a reference .end_cell() ;; this creates the cell .begin_parse(); ;; this creates a slice from the cell ;; `slice_refs_empty?()` returns `false` because the slice has cell references. slice_with_refs_only.slice_refs_empty?(); ;; Creating slice which contains bits and refs slice slice_with_bits_and_refs = begin_cell() .store_slice("Hello, world!") ;; Add bits from the slice computed ;; using the compile-time built-in .store_ref(dummy_cell) ;; Add the dummy cell as a reference .end_cell() .begin_parse(); ;; `slice_refs_empty?()` returns `false` because the slice has cell references. slice_with_bits_and_refs.slice_refs_empty?(); **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [`""` compile-time builtin](https://docs.ton.org/languages/func/literals#string-without-suffix) , where `` is an ASCII string. * [`slice_refs_empty?`](https://docs.ton.org/languages/func/stdlib#slice-refs-empty%3F) * [`begin_cell`](https://docs.ton.org/languages/func/stdlib#begin-cell) * [`end_cell`](https://docs.ton.org/languages/func/stdlib#end-cell) * [`store_ref`](https://docs.ton.org/languages/func/stdlib#store-ref) * [`begin_parse`](https://docs.ton.org/languages/func/stdlib#begin-parse) * [`store_slice`](https://docs.ton.org/languages/func/stdlib#store-slice) ### [​](https://docs.ton.org/languages/func/cookbook#how-to-determine-if-a-cell-is-empty) How to determine if a cell is empty To check whether a cell contains any data, it must first be converted into a slice. * If only the data bits matter, use `slice_data_empty?`. * If only cell references matter, use `slice_refs_empty?`. * If the presence of any data (bits or cell references) needs to be checked, use `slice_empty?`. ;; Create an empty dummy cell for use later cell dummy_cell = begin_cell().end_cell(); cell cell_with_bits_and_refs = begin_cell() .store_uint(1337, 16) .store_ref(dummy_cell) .end_cell(); ;; To check that cell_with_bits_and_refs is empty, ;; first obtain a slice slice cs = cell_with_bits_and_refs.begin_parse(); ;; Determine if the slice is empty. if (cs.slice_empty?()) { ;; Cell is empty } else { ;; Cell is not empty } **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [`begin_cell`](https://docs.ton.org/languages/func/stdlib#begin-cell) * [`end_cell`](https://docs.ton.org/languages/func/stdlib#end-cell) * [`store_ref`](https://docs.ton.org/languages/func/stdlib#store-ref) * [`begin_parse`](https://docs.ton.org/languages/func/stdlib#begin-parse) * [`slice_empty?`](https://docs.ton.org/languages/func/stdlib#slice-empty%3F) * [`slice_data_empty?`](https://docs.ton.org/languages/func/stdlib#slice-data-empty%3F) * [`slice_refs_empty?`](https://docs.ton.org/languages/func/stdlib#slice-refs-empty%3F) ### [​](https://docs.ton.org/languages/func/cookbook#determine-if-the-data-bits-of-slices-are-equal) Determine if the data bits of slices are equal There are three ways to check if the data bits of two slices are equal: 1. Comparing their hashes. 2. Using the SDEQ asm instruction. 3. Using the `equal_slice_bits` function. int are_slices_equal_1? (slice a, slice b) { return a.slice_hash() == b.slice_hash(); } int are_slices_equal_2? (slice a, slice b) asm "SDEQ"; int are_slices_equal_3? (slice a, slice b) { return equal_slice_bits(a, b); } () main () { slice s1 = "Some text"; ;; load a slice with the ASCII code of the string slice s2 = "Some text"; ~dump(are_slices_equal_1?(s1, s2)); ;; -1 = true ~dump(are_slices_equal_2?(s1, s2)); ;; -1 = true ~dump(are_slices_equal_3?(s1, s2)); ;; -1 = true s1 = "Text"; ;; load a slice with the address encoded in the provided string s2 = "EQDKbjIcfM6ezt8KjKJJLshZJJSqX7XOA4ff-W72r5gqPrHF"a; ~dump(are_slices_equal_1?(s1, s2)); ;; 0 = false ~dump(are_slices_equal_2?(s1, s2)); ;; 0 = false ~dump(are_slices_equal_3?(s1, s2)); ;; 0 = false } **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [`""` compile-time builtin](https://docs.ton.org/languages/func/literals#string-without-suffix) , where `` is an ASCII string. * [`"
"a` compile-time builtin](https://docs.ton.org/languages/func/literals#string-with-suffix-a) , where `
` is a string encoding an address. * [`slice_hash`](https://docs.ton.org/languages/func/stdlib#slice-hash) * [`SDEQ` asm instruction](https://docs.ton.org/tvm/instructions#c705-sdeq) * `equal_slice_bits` ### [​](https://docs.ton.org/languages/func/cookbook#determine-if-the-cells-are-equal) Determine if the cells are equal Determine whether two cells are equal by comparing their hashes. int are_cells_equal? (cell a, cell b) { return a.cell_hash() == b.cell_hash(); } () main () { cell a = begin_cell() .store_uint(123, 16) .end_cell(); cell b = begin_cell() .store_uint(123, 16) .end_cell(); ~dump(are_cells_equal?(a, b)); ;; -1 = true cell dummy_cell = begin_cell().end_cell(); cell c = begin_cell() ;; Like cell a, but it has an extra reference .store_uint(123, 16) .store_ref(dummy_cell) .end_cell(); ~dump(are_cells_equal?(a, c)); ;; 0 = false } **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [`cell_hash`](https://docs.ton.org/languages/func/stdlib#cell-hash) * [`begin_cell`](https://docs.ton.org/languages/func/stdlib#begin-cell) * [`end_cell`](https://docs.ton.org/languages/func/stdlib#end-cell) * [`store_uint`](https://docs.ton.org/languages/func/stdlib#store-uint) * [`store_ref`](https://docs.ton.org/languages/func/stdlib#store-ref) ### [​](https://docs.ton.org/languages/func/cookbook#how-to-get-only-the-data-bits-from-a-slice) How to get only the data bits from a slice If the cell references within a slice are not needed, the raw data bits can be extracted for further processing using the function `preload_bits`: ;; Define a slice with data bits and two cell references slice s = begin_cell() .store_slice("Some data bits...") .store_ref(begin_cell().end_cell()) ;; some reference .store_ref(begin_cell().end_cell()) ;; some reference .end_cell() .begin_parse(); ;; Extract the data bits as a new slice slice s_only_data = s.preload_bits(s.slice_bits()); Function `preload_bits` requires as argument the amount of bits to extract. `s.slice_bits()` obtains the amount of data bits in the slice. **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [Builder primitives](https://docs.ton.org/languages/func/stdlib#builder-primitives) * [Slice primitives](https://docs.ton.org/languages/func/stdlib#slice-primitives) * [`preload_bits`](https://docs.ton.org/languages/func/stdlib#preload-bits) * [`slice_bits`](https://docs.ton.org/languages/func/stdlib#slice-bits) ### [​](https://docs.ton.org/languages/func/cookbook#how-to-build-a-stateinit-cell) How to build a `StateInit` cell The code follows the TL-B for [`StateInit`](https://docs.ton.org/foundations/messages/deploy) : _ split_depth:(Maybe (## 5)) special:(Maybe TickTock) code:(Maybe ^Cell) data:(Maybe ^Cell) library:(HashmapE 256 SimpleLib) = StateInit; which states that `code` and `data` should be added as cell references. Fields `split_depth` and `special` are usually set to `None` (i.e., `0`) in standard programming tasks. The `library` field usually set to `0` as well. cell build_stateinit(cell init_code, cell init_data) { var state_init = begin_cell() .store_uint(0, 1) ;; split_depth: Maybe (## 5), set to "None" .store_uint(0, 1) ;; special: Maybe TickTock, set to "None" .store_uint(1, 1) ;; code: Maybe ^Cell, set to "Some cell", ;; but the cell is provided later as a reference .store_uint(1, 1) ;; data: Maybe ^Cell, set to "Some cell", ;; but the cell is provided later as a reference .store_uint(0, 1) ;; library: HashmapE 256 SimpleLib, set to 0 .store_ref(init_code) ;; the code as a cell reference .store_ref(init_data) ;; the data as a cell reference .end_cell(); return state_int; } **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [TL-B for `StateInit`](https://github.com/ton-blockchain/ton/blob/f58297f1b668c7b49e8b30b65062951ca7c18acc/crypto/block/block.tlb#L144-L146) * [Builder primitives](https://docs.ton.org/languages/func/stdlib#builder-primitives) [​](https://docs.ton.org/languages/func/cookbook#data-structures) Data structures ------------------------------------------------------------------------------------ ### [​](https://docs.ton.org/languages/func/cookbook#how-to-determine-if-a-dict-is-empty) How to determine if a dict is empty The `dict_empty?` function checks whether a dictionary contains any data. This method is functionally equivalent to `cell_null?`, as a `null` cell typically represents an empty dictionary. cell d = new_dict(); ;; Create an empty dictionary ;; Set value of key 0 to be a slice containing the ASCII string "hello" d~udict_set(256, 0, "hello"); ;; Set value of key 1 to be a slice containing the ASCII string "world" d~udict_set(256, 1, "world"); if (d.dict_empty?()) { ;; Determine if the dict is empty ;; dict is empty } else { ;; dict is not empty. ;; For dictionary d, execution flow will enter this ;; branch, since d has two elements. } In `d~udict_set(256, 0, "hello")`, the function expects unsigned 256-bit integers as keys; also, `d~udict_set(256, 0, "hello")` will mutate the dictionary `d`, since `udict_set` is called using [modifying notation with the symbol `~`](https://docs.ton.org/languages/func/expressions#modifying-notation) . **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [Modifying notation using ~](https://docs.ton.org/languages/func/expressions#modifying-notation) * [`""` compile-time builtin](https://docs.ton.org/languages/func/literals#string-without-suffix) , where `` is an ASCII string. * [`new_dict`](https://docs.ton.org/languages/func/stdlib#new-dict) * [`dict_set` primitives](https://docs.ton.org/languages/func/stdlib#dict-set) * [`dict_empty?`](https://docs.ton.org/languages/func/stdlib#dict-empty%3F) ### [​](https://docs.ton.org/languages/func/cookbook#how-to-store-and-load-a-dictionary-in-permanent-storage) How to store and load a dictionary in permanent storage The logic for loading a dictionary from local storage is as follows: ;; Obtain the contract's local persistent storage slice local_storage = get_data().begin_parse(); ;; This initial assignment ensures that if the condition below ;; fails to find a dictionary already in local storage, ;; `dictionary_cell` will remain with a new empty dictionary. cell dictionary_cell = new_dict(); if (~ slice_empty?(local_storage)) { ;; A dictionary is already in local storage, load it dictionary_cell = local_storage~load_dict(); } Storing the dictionary in local storage is also simple: set_data(begin_cell().store_dict(dictionary_cell).end_cell()); **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [Modifying notation using ~](https://docs.ton.org/languages/func/expressions#modifying-notation) * [Slice primitives](https://docs.ton.org/languages/func/stdlib#slice-primitives) * [`get_data`](https://docs.ton.org/languages/func/stdlib#get-data) * [`set_data`](https://docs.ton.org/languages/func/stdlib#set-data) * [Builder primitives](https://docs.ton.org/languages/func/stdlib#builder-primitives) * [`new_dict`](https://docs.ton.org/languages/func/stdlib#new-dict) * [`slice_empty?`](https://docs.ton.org/languages/func/stdlib#slice-empty%3F) * [`load_dict`](https://docs.ton.org/languages/func/stdlib#load-dict) ### [​](https://docs.ton.org/languages/func/cookbook#how-to-iterate-dictionaries) How to iterate dictionaries To iterate a dictionary from the smallest to biggest key, first call a [`dict_get_min?` primitive](https://docs.ton.org/languages/func/stdlib#dict-get-min%3F) to obtain the smallest key in the dictionary, and then call a [`dict_get_next?` primitive](https://docs.ton.org/languages/func/stdlib#dict-get-next%3F) inside a loop while checking a flag for existence of further key-value pairs to process. Similarly, to iterate a dictionary from the biggest to smallest key, first call a [`dict_get_max?` primitive](https://docs.ton.org/languages/func/stdlib#dict-get-max%3F) to obtain the biggest key in the dictionary, and then call a [`dict_get_prev?` primitive](https://docs.ton.org/languages/func/stdlib#dict-get-prev%3F) inside a loop while checking a flag for existence of further key-value pairs to process. ;; Initialize an example dictionary. ;; keys will be unsigned 256-bit integers. Values are slices. ;; Since keys are unsigned, ;; should use 'unsigned' versions of the ;; dict_set, dict_get_min?, dict_get_max?, ;; dict_get_next?, and dict_get_prev? primitives. cell d = new_dict(); d~udict_set(256, 1, "value 1"); ;; Map key 1 to a slice containing string "value 1" d~udict_set(256, 5, "value 2"); ;; Map key 5 to a slice containing string "value 2" d~udict_set(256, 12, "value 3"); ;; Map key 12 to a slice containing string "value 3" ;; First, iterate from smallest to biggest key: ;; Obtain the smallest key. (int key, slice val, int flag) = d.udict_get_min?(256); ;; Repeat while there are keys to iterate, indicated by "flag". while (flag) { ;; do something with "key" and "val". ;; Obtain the smallest key bigger than "key". ;; i.e., the one next to "key" in numerical value. ;; "flag" will indicate if such key exists. (key, val, flag) = d.udict_get_next?(256, key); } ;; Now, iterate from biggest to smallest key: ;; Obtain the biggest key. (key, val, flag) = d.udict_get_max?(256); ;; Repeat while there are keys to iterate, indicated by "flag". while (flag) { ;; do something with "key" and "val". ;; Obtain the biggest key smaller than "key", ;; i.e., the one previous to "key" in numerical value. ;; "flag" will indicate if there is a previous key. (key, val, flag) = d.udict_get_prev?(256, key); } **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [Modifying notation using ~](https://docs.ton.org/languages/func/expressions#modifying-notation) * [`""` compile-time builtin](https://docs.ton.org/languages/func/literals#string-without-suffix) , where `` is an ASCII string. * [`new_dict`](https://docs.ton.org/languages/func/stdlib#new-dict) * [`dict_set` primitives](https://docs.ton.org/languages/func/stdlib#dict-set) * [`dict_get_min?` primitives](https://docs.ton.org/languages/func/stdlib#dict-get-min%3F) * [`dict_get_max?` primitives](https://docs.ton.org/languages/func/stdlib#dict-get-max%3F) * [`dict_get_next?` primitives](https://docs.ton.org/languages/func/stdlib#dict-get-next%3F) * [`dict_get_prev?` primitives](https://docs.ton.org/languages/func/stdlib#dict-get-prev%3F) ### [​](https://docs.ton.org/languages/func/cookbook#how-to-delete-a-value-from-a-dictionary) How to delete a value from a dictionary Use the [`dict_delete?` primitives](https://docs.ton.org/languages/func/stdlib#dict-delete%3F) to delete keys in a dictionary. ;; Initialize an example dictionary. ;; keys will be unsigned 256-bit integers. Values are slices. ;; Since keys are unsigned, ;; should use 'unsigned' versions of the ;; dict_set, dict_delete?, dict_get? primitives. cell names = new_dict(); names~udict_set(256, 27, "Alice"); ;; Map key 27 to a slice containing string "Alice" names~udict_set(256, 25, "Bob"); ;; Delete key-value pair with key 27 ;; This mutates "names" dictionary, because ;; udict_delete? is called using ~ names~udict_delete?(256, 27); ;; Look up the key 27 ;; since it was deleted, the "found" flag returns 0 (slice val, int found) = names.udict_get?(256, 27); ~dump(found); ;; 0, means that key was not found in the dictionary **References:** * [`""` compile-time builtin](https://docs.ton.org/languages/func/literals#string-without-suffix) , where `` is an ASCII string. * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [Modifying notation using ~](https://docs.ton.org/languages/func/expressions#modifying-notation) * [`new_dict`](https://docs.ton.org/languages/func/stdlib#new-dict) * [`dict_set` primitives](https://docs.ton.org/languages/func/stdlib#dict-set) * [`dict_delete?` primitives](https://docs.ton.org/languages/func/stdlib#dict-delete%3F) * [`dict_get?` primitives](https://docs.ton.org/languages/func/stdlib#dict-get%3F) ### [​](https://docs.ton.org/languages/func/cookbook#how-to-determine-if-a-tuple-is-empty) How to determine if a tuple is empty When working with `tuples`, checking for existing values before extracting them is crucial. Extracting a value from an empty tuple will result in an error: [“not a tuple of valid size” - `exit code 7`](https://docs.ton.org/tvm/exit-codes#7) . ;; Declare the tlen assembler function because it's not present in stdlib ;; tlen determines the length of a tuple int tlen (tuple t) asm "TLEN"; () main () { tuple t = empty_tuple(); ;; t is [] t~tpush(13); ;; t is [13] t~tpush(37); ;; t is [13, 37] if (t.tlen() == 0) { ;; Evaluates to false ;; tuple is empty } else { ;; tuple is not empty } } The `tlen` [assembler function](https://docs.ton.org/languages/func/asm-functions) uses the [TVM instruction `TLEN`](https://docs.ton.org/tvm/instructions#6f88-tlen) to determine the number of elements in the tuple. The `tpush` function appends an element to the tuple, so that it becomes the last element. **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [Modifying notation using ~](https://docs.ton.org/languages/func/expressions#modifying-notation) * [Assembler functions](https://docs.ton.org/languages/func/asm-functions) * [`empty_tuple`](https://docs.ton.org/languages/func/stdlib#empty-tuple) * [`tpush`](https://docs.ton.org/languages/func/stdlib#tpush) * [TVM Exit codes](https://docs.ton.org/tvm/exit-codes) * [TVM instructions](https://docs.ton.org/tvm/instructions) ### [​](https://docs.ton.org/languages/func/cookbook#basic-operations-with-tuples) Basic operations with tuples ;; tlen determines the length of a tuple int tlen (tuple t) asm "TLEN"; ;; tpop removes the last element in the tuple and ;; returns the mutated tuple and the element. ;; The type of the returned element is arbitrary. forall X -> (tuple, X) ~tpop (tuple t) asm "TPOP"; () main () { ;; creating an empty tuple tuple names = empty_tuple(); ;; push new items ;; Each element is a slice storing an ASCII string names~tpush("Naito"); names~tpush("Shiraki"); names~tpush("Akamatsu"); names~tpush("Takaki"); ;; names is ["Naito", "Shiraki", "Akamatsu", "Takaki"] ;; pop last item, "Takaki" slice last_name = names~tpop(); ;; get first item, "Naito" slice first_name = names.first(); ;; get an item by index, "Akamatsu" ;; First element has index 0 slice best_name = names.at(2); ;; getting the length of the tuple ;; returns 3, because "Takaki" was popped int number_names = names.tlen(); } The `tlen` [assembler function](https://docs.ton.org/languages/func/asm-functions) uses the [TVM instruction `TLEN`](https://docs.ton.org/tvm/instructions#6f88-tlen) to determine the number of elements in the tuple. The `tpop` assembler function uses the [TVM instruction `TPOP`](https://docs.ton.org/tvm/instructions#6f8d-tpop) to detach the last element from the tuple, and it returns the mutated tuple and the detached element. **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [Modifying notation using ~](https://docs.ton.org/languages/func/expressions#modifying-notation) * [Assembler functions](https://docs.ton.org/languages/func/asm-functions) * [Polymorphic functions](https://docs.ton.org/languages/func/functions#forall-declarator) * [`empty_tuple`](https://docs.ton.org/languages/func/stdlib#empty-tuple) * [`tpush`](https://docs.ton.org/languages/func/stdlib#tpush) * [`first`](https://docs.ton.org/languages/func/stdlib#first) * [`at`](https://docs.ton.org/languages/func/built-ins#at) * [TVM instructions](https://docs.ton.org/tvm/instructions) ### [​](https://docs.ton.org/languages/func/cookbook#how-to-iterate-tuples-both-directions) How to iterate tuples (both directions) When working with arrays or stacks in FunC, tuples are essential. The first step is learning how to iterate through tuple values for processing. ;; tlen determines the length of a tuple int tlen (tuple t) asm "TLEN"; ;; Casts any type into a tuple forall X -> tuple to_tuple (X x) asm "NOP"; () main () { ;; Cast the fixed length tuple to an arbitrary length tuple. ;; This is necessary, because in FunC, fixed-length tuples ;; like [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] cannot be assigned ;; directly to arbitrary length tuples. ;; Hence, this does NOT compile: ;; tuple t = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; tuple t = to_tuple([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); int len = t.tlen(); ;; 10 ;; Iterate tuple starting from index 0 ;; up to index 9 int i = 0; while (i < len) { int x = t.at(i); ;; Obtain the i-th element ;; do something with x i = i + 1; } ;; Iterate tuple starting from index 9 ;; down to index 0 i = len - 1; ;; 9 while (i >= 0) { int x = t.at(i); ;; Obtain the i-th element ;; do something with x i = i - 1; } } The `tlen` [assembler function](https://docs.ton.org/languages/func/asm-functions) uses the [TVM instruction `TLEN`](https://docs.ton.org/tvm/instructions#6f88-tlen) to determine the number of elements in the tuple. The `to_tuple` casts **any** type into an arbitrary length tuple, which leads to run-time errors if `to_tuple` is used to cast non-tuple types. Be careful to only cast fixed-length tuples, like `[1, 2]`. The `to_tuple` is essentially a dummy function that does nothing, because it uses the [No operation `NOP`](https://docs.ton.org/tvm/instructions#00-nop) instruction. The only purpose of `to_tuple` is to tell the type-checker to accept the input to `to_tuple` as a `tuple`. **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [Assembler functions](https://docs.ton.org/languages/func/asm-functions) * [Polymorphic functions](https://docs.ton.org/languages/func/functions#forall-declarator) * [`at`](https://docs.ton.org/languages/func/built-ins#at) * [TVM instructions](https://docs.ton.org/tvm/instructions) ### [​](https://docs.ton.org/languages/func/cookbook#iterating-n-nested-tuples) Iterating n-nested tuples Sometimes, while traversing the elements of a tuple, there is the need to iterate through nested tuples. The following example iterates through a tuple starting from the last index, and finds the biggest number, irrespective if there are nested tuples. For example, in the tuple `[[2,6],[1,[3,[3,5]]], 3]`, the example finds `6` as the biggest number. ;; Determines the number of elements in a tuple. int tuple_length (tuple t) asm "TLEN"; ;; Removes the last element in the tuple and ;; returns the mutated tuple and the element. ;; The type of the returned element is arbitrary. forall X -> (tuple, X) ~tpop (tuple t) asm "TPOP"; ;; Checks if the given argument is a tuple forall X -> int is_tuple (X x) asm "ISTUPLE"; ;; Casts the given argument to an arbitrary length tuple. forall X -> tuple to_tuple (X x) asm "NOP"; ;; Casts the given argument to an int. forall X -> int to_int (X x) asm "NOP"; ;; Define a global variable. ;; It will store the biggest number found. global int max_value; () iterate_tuple (tuple t) impure { repeat (t.tuple_length()) { ;; Remove the last element in the tuple. var value = t~tpop(); if (is_tuple(value)) { ;; If the element is a tuple, cast it to a tuple. tuple tuple_value = to_tuple(value); ;; And then, recursively iterate the element. iterate_tuple(tuple_value); } else { ;; The element is not a tuple, so it must be an int. ;; Cast it to an int. int int_value = to_int(value); if (int_value > max_value) { ;; Remember the value in the global variable ;; because it is the biggest so far. max_value = int_value; } } } } () main () { ;; Create an example tuple tuple t = to_tuple([[2,6], [1, [3, [3, 5]]], 3]); ;; Determine the length of the tuple int len = t.tuple_length(); ;; Set the maximum so far to 0 max_value = 0; ;; Find the maximum value in the tuple iterate_tuple(t); ~dump(max_value); ;; 6 } The `tuple_length` [assembler function](https://docs.ton.org/languages/func/asm-functions) uses the [TVM instruction `TLEN`](https://docs.ton.org/tvm/instructions#6f88-tlen) to determine the number of elements in the tuple. The `tpop` assembler function uses the [TVM instruction `TPOP`](https://docs.ton.org/tvm/instructions#6f8d-tpop) to detach the last element from the tuple, and it returns the mutated tuple and the detached element. The `is_tuple` assembler function uses the [TVM instruction `ISTUPLE`](https://docs.ton.org/tvm/instructions#6f8a-istuple) to determine if the argument is a tuple or not. The `to_tuple` and `to_int` cast **any** type into an arbitrary length tuple and integer, respectively. This leads to run-time errors if `to_tuple` and `to_int` are used to cast non-tuple and non-integer types, respectively. The `to_tuple` and `to_int` are essentially dummy functions that do nothing, because they use the [No operation `NOP`](https://docs.ton.org/tvm/instructions#00-nop) instruction. The only purpose of `to_tuple` and `to_int` is to tell the type-checker to accept the input to `to_tuple` as a `tuple`, and the input to `to_int` as an `int`. **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [Modifying notation using ~](https://docs.ton.org/languages/func/expressions#modifying-notation) * [Assembler functions](https://docs.ton.org/languages/func/asm-functions) * [Polymorphic functions](https://docs.ton.org/languages/func/functions#forall-declarator) * [Global Variables](https://docs.ton.org/languages/func/global-variables) * [TVM instructions](https://docs.ton.org/tvm/instructions) ### [​](https://docs.ton.org/languages/func/cookbook#casting-types-in-tuples) Casting types in tuples If a tuple contains various data types `[cell, slice, int, tuple, ...]`, there is the need to check the value and cast it accordingly before processing. The following snippet illustrates this idea. ;; Check if argument is null forall X -> int is_null (X x) asm "ISNULL"; ;; Check if argument is an int forall X -> int is_int (X x) asm "<{ TRY:<{ 0 PUSHINT ADD DROP -1 PUSHINT }>CATCH<{ 2DROP 0 PUSHINT }> }>CONT 1 1 CALLXARGS"; ;; Check if argument is a cell forall X -> int is_cell (X x) asm "<{ TRY:<{ CTOS DROP -1 PUSHINT }>CATCH<{ 2DROP 0 PUSHINT }> }>CONT 1 1 CALLXARGS"; ;; Check if argument is a slice forall X -> int is_slice (X x) asm "<{ TRY:<{ SBITS DROP -1 PUSHINT }>CATCH<{ 2DROP 0 PUSHINT }> }>CONT 1 1 CALLXARGS"; ;; Check if argument is a tuple forall X -> int is_tuple (X x) asm "ISTUPLE"; ;; Cast functions. They do not carry an operation, ;; since they use the "NOP" TVM instruction. ;; Their sole purpose is to tell the type-checker ;; that it should see the argument as having ;; the desired type. forall X -> int cast_to_int (X x) asm "NOP"; forall X -> cell cast_to_cell (X x) asm "NOP"; forall X -> slice cast_to_slice (X x) asm "NOP"; forall X -> tuple cast_to_tuple (X x) asm "NOP"; ;; Removes the last element in the tuple and ;; returns the mutated tuple and the element. ;; The type of the returned element is arbitrary. forall X -> (tuple, X) ~tpop (tuple t) asm "TPOP"; ;; Process value of arbitrary type forall X -> () resolve_type (X value) impure { ;; "value" has an arbitrary type. ;; Check its type and cast it. if (is_null(value)) { ;; Do something with the null. } elseif (is_int(value)) { int valueAsInt = cast_to_int(value); ;; Do something with the int. } elseif (is_slice(value)) { slice valueAsSlice = cast_to_slice(value); ;; Do something with the slice. } elseif (is_cell(value)) { cell valueAsCell = cast_to_cell(value); ;; Do something with the cell. } elseif (is_tuple(value)) { tuple valueAsTuple = cast_to_tuple(value); ;; Do something with the tuple. } } () main () { ;; Create an initially empty tuple. tuple t = empty_tuple(); ;; Add some values of different types to the tuple. t~tpush("Some text"); t~tpush(4); ;; The tuple is ["Some text", 4]. ;; Since the tuple has values of different types, ;; when extracting an element, use the ;; keyword "var". var value = t~tpop(); ;; Process the value. resolve_type(value); } The `is_int` function uses [Fift code](https://docs.ton.org/languages/fift/overview) . Intuitively, the Fift code implements the following FunC-like pseudocode: forall X -> int is_int (X x) { try { ;; Attempt to add 0 to the argument x. ;; If this fails, then x is not an integer. x + 0; return -1; } catch (_, _) { return 0; } } Similarly, the `is_cell` carries out the following FunC-like pseudocode, which makes use of the [CTOS TVM instruction](https://docs.ton.org/tvm/instructions#d0-ctos) : forall X -> int is_cell (X x) { try { ;; Under the assumption that x is a cell, ;; CTOS will attempt to get a slice from cell x. ;; If x turns out to be not a cell, CTOS will fail. CTOS(x); return -1; } catch (_, _) { return 0; } } Finally, the `is_slice` carries out the following FunC-like pseudocode, which makes use of the [SBITS TVM instruction](https://docs.ton.org/tvm/instructions#d749-sbits) : forall X -> int is_slice (X x) { try { ;; Under the assumption that x is a slice, ;; SBITS will attempt to get the number of data bits ;; in the slice. ;; If x turns out to be not a slice, SBITS will fail. SBITS(x); return -1; } catch (_, _) { return 0; } } **References:** * [Modifying notation using ~](https://docs.ton.org/languages/func/expressions#modifying-notation) * [Assembler functions](https://docs.ton.org/languages/func/asm-functions) * [Polymorphic functions](https://docs.ton.org/languages/func/functions#forall-declarator) * [`empty_tuple`](https://docs.ton.org/languages/func/stdlib#empty-tuple) * [`tpush`](https://docs.ton.org/languages/func/stdlib#tpush) * [TVM instructions](https://docs.ton.org/tvm/instructions) ### [​](https://docs.ton.org/languages/func/cookbook#reversing-tuples) Reversing tuples The following example reverses any tuple. For example, given the input `[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]`, the `reverse_tuple` produces the output `[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]`. ;; Determines the number of elements in a tuple. int tuple_length (tuple t) asm "TLEN"; ;; Removes the last element in the tuple and ;; returns the mutated tuple and the element. ;; The type of the returned element is arbitrary. forall X -> (tuple, X) ~tpop (tuple t) asm "TPOP"; ;; Casts the given argument to an arbitrary length tuple. forall X -> tuple to_tuple (X x) asm "NOP"; tuple reverse_tuple (tuple t1) { ;; Create an initially empty tuple. ;; This variable will be the accumulated result. tuple t2 = empty_tuple(); repeat (t1.tuple_length()) { ;; Take the last element in the original tuple. var value = t1~tpop(); ;; And append it to the new tuple. t2~tpush(value); } return t2; } () main () { ;; Create an example tuple. tuple t = to_tuple([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); ;; Reverse the tuple. tuple reversed_t = reverse_tuple(t); ~dump(reversed_t); ;; [10 9 8 7 6 5 4 3 2 1] } The `tuple_length` [assembler function](https://docs.ton.org/languages/func/asm-functions) uses the [TVM instruction `TLEN`](https://docs.ton.org/tvm/instructions#6f88-tlen) to determine the number of elements in the tuple. The `tpop` assembler function uses the [TVM instruction `TPOP`](https://docs.ton.org/tvm/instructions#6f8d-tpop) to detach the last element from the tuple, and it returns the mutated tuple and the detached element. The `to_tuple` casts **any** type into an arbitrary length tuple, which leads to run-time errors if `to_tuple` is used to cast non-tuple types. The `to_tuple` is essentially a dummy function that does nothing, because it uses the [No operation `NOP`](https://docs.ton.org/tvm/instructions#00-nop) instruction. The only purpose of `to_tuple` is to tell the type-checker to accept the input to `to_tuple` as a `tuple`. **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [Modifying notation using ~](https://docs.ton.org/languages/func/expressions#modifying-notation) * [Assembler functions](https://docs.ton.org/languages/func/asm-functions) * [Polymorphic functions](https://docs.ton.org/languages/func/functions#forall-declarator) * [`empty_tuple`](https://docs.ton.org/languages/func/stdlib#empty-tuple) * [`tpush`](https://docs.ton.org/languages/func/stdlib#tpush) * [TVM instructions](https://docs.ton.org/tvm/instructions) ### [​](https://docs.ton.org/languages/func/cookbook#how-to-remove-an-item-with-a-certain-index-from-a-tuple) How to remove an item with a certain index from a tuple ;; Determines the number of elements in a tuple. int tlen (tuple t) asm "TLEN"; (tuple, ()) remove_item (tuple old_tuple, int place) { ;; The result tuple so far. Initially it is empty. tuple new_tuple = empty_tuple(); int i = 0; while (i < old_tuple.tlen()) { int el = old_tuple.at(i); ;; When the place to delete is reached, skip ;; that element by not pushing it to the result tuple. if (i != place) { ;; Since the current index i is not equal to ;; the place to delete, push the element to ;; the end of the result tuple. new_tuple~tpush(el); } i += 1; } return (new_tuple, ()); } () main () { ;; Create an example tuple, intially empty tuple numbers = empty_tuple(); ;; Insert some integers to the tuple numbers~tpush(19); numbers~tpush(999); numbers~tpush(54); ~dump(numbers); ;; [19 999 54] numbers~remove_item(1); ~dump(numbers); ;; [19 54] } The `tlen` [assembler function](https://docs.ton.org/languages/func/asm-functions) uses the [TVM instruction `TLEN`](https://docs.ton.org/tvm/instructions#6f88-tlen) to determine the number of elements in the tuple. **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [Modifying notation using ~](https://docs.ton.org/languages/func/expressions#modifying-notation) * [Assembler functions](https://docs.ton.org/languages/func/asm-functions) * [`empty_tuple`](https://docs.ton.org/languages/func/stdlib#empty-tuple) * [`at`](https://docs.ton.org/languages/func/built-ins#at) * [`tpush`](https://docs.ton.org/languages/func/stdlib#tpush) * [TVM instructions](https://docs.ton.org/tvm/instructions) ### [​](https://docs.ton.org/languages/func/cookbook#determine-if-tuples-are-equal) Determine if tuples are equal The approach involves iterating through both tuples and comparing each value recursively. Since tuples can contain different data types, check types and cast values dynamically. ;; Determines the number of elements in a tuple. int tuple_length (tuple t) asm "TLEN"; ;; Removes the last element in the tuple and ;; returns the mutated tuple and the element. ;; The type of the returned element is arbitrary. forall X -> (tuple, X) ~tpop (tuple t) asm "TPOP"; ;; Cast functions. They do not carry an operation, ;; since they use the "NOP" TVM instruction. ;; Their sole purpose is to tell the type-checker ;; that it should see the argument as having ;; the desired type. forall X -> int cast_to_int (X x) asm "NOP"; forall X -> cell cast_to_cell (X x) asm "NOP"; forall X -> slice cast_to_slice (X x) asm "NOP"; forall X -> tuple cast_to_tuple (X x) asm "NOP"; ;; Check if argument is null. forall X -> int is_null (X x) asm "ISNULL"; ;; Check if argument is an int. forall X -> int is_int (X x) asm "<{ TRY:<{ 0 PUSHINT ADD DROP -1 PUSHINT }>CATCH<{ 2DROP 0 PUSHINT }> }>CONT 1 1 CALLXARGS"; ;; Check if argument is a cell. forall X -> int is_cell (X x) asm "<{ TRY:<{ CTOS DROP -1 PUSHINT }>CATCH<{ 2DROP 0 PUSHINT }> }>CONT 1 1 CALLXARGS"; ;; Check if argument is a slice. forall X -> int is_slice (X x) asm "<{ TRY:<{ SBITS DROP -1 PUSHINT }>CATCH<{ 2DROP 0 PUSHINT }> }>CONT 1 1 CALLXARGS"; ;; Check if argument is a tuple. forall X -> int is_tuple (X x) asm "ISTUPLE"; ;; Determine if two slices are equal, ;; by using the TVM instruction SDEQ. int are_slices_equal? (slice a, slice b) asm "SDEQ"; ;; Determine if two cells are equal by using their hashes. int are_cells_equal? (cell a, cell b) { return a.cell_hash() == b.cell_hash(); } (int) are_tuples_equal? (tuple t1, tuple t2) { int equal? = -1; ;; initial value to true if (t1.tuple_length() != t2.tuple_length()) { ;; if tuples differ in length, they cannot be equal return 0; } ;; At this point, both tuples have the same length int i = t1.tuple_length(); ;; Iterate the tuples back to front, ;; comparing corresponding elements at each iteration. ;; Iterate while there are still elements to check ;; in the tuples, and they remain equal. ;; Recall that the AND boolean operator ;; is emulated using the bitwise AND operator. while (i > 0 & equal?) { ;; Take the last element of both tuples ;; and remove them from the tuples. ;; This updates the tuples implicitly. var v1 = t1~tpop(); var v2 = t2~tpop(); ;; Check the types of both elements. ;; If they have different types, the ;; execution will enter the "else" branch, ;; marking the "equal?" flag to false. ;; However, if they have the same type, ;; check that their values ;; are equal or not. if (is_null(v1) & is_null(v2)) { ;; nulls are always equal } elseif (is_int(v1) & is_int(v2)) { if (cast_to_int(v1) != cast_to_int(v2)) { equal? = 0; } } elseif (is_slice(v1) & is_slice(v2)) { if (~ are_slices_equal?(cast_to_slice(v1), cast_to_slice(v2))) { equal? = 0; } } elseif (is_cell(v1) & is_cell(v2)) { if (~ are_cells_equal?(cast_to_cell(v1), cast_to_cell(v2))) { equal? = 0; } } elseif (is_tuple(v1) & is_tuple(v2)) { ;; recursively determine nested tuples if (~ are_tuples_equal?(cast_to_tuple(v1), cast_to_tuple(v2))) { equal? = 0; } } else { equal? = 0; } ;; Decrease the counter i -= 1; } return equal?; } () main () { ;; Create two equal tuples tuple t1 = cast_to_tuple([[2, 6], [1, [3, [3, 5]]], 3]); tuple t2 = cast_to_tuple([[2, 6], [1, [3, [3, 5]]], 3]); ;; are_tuples_equal? returns -1, i.e., true ~dump(are_tuples_equal?(t1, t2)); } For function `are_slices_equal?` refer to recipe [“Determine if the data bits of slices are equal”](https://docs.ton.org/languages/func/cookbook#determine-if-the-data-bits-of-slices-are-equal) . For function `are_cells_equal?` refer to recipe [“Determine if the cells are equal”](https://docs.ton.org/languages/func/cookbook#determine-if-the-cells-are-equal) . For explanation of the functions that check types, refer to the recipe [“Casting types in tuples”](https://docs.ton.org/languages/func/cookbook#casting-types-in-tuples) . **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [Modifying notation using ~](https://docs.ton.org/languages/func/expressions#modifying-notation) * [Assembler functions](https://docs.ton.org/languages/func/asm-functions) * [Polymorphic functions](https://docs.ton.org/languages/func/functions#forall-declarator) * [`tpush`](https://docs.ton.org/languages/func/stdlib#tpush) * [TVM instructions](https://docs.ton.org/tvm/instructions) ### [​](https://docs.ton.org/languages/func/cookbook#basic-operations-in-lisp-style-lists) Basic operations in lisp-style lists [Lisp-style lists](https://docs.ton.org/languages/func/stdlib#lisp-style-lists) are represented as nested tuples. For example, the list `1, 2, 3` is represented as the nested tuple `[1, [2, [3, null]]]`, where the value `null` acts as a marker for the end of the list. Use the [`cons`](https://docs.ton.org/languages/func/stdlib#cons) function to add an element at the front of the provided list. For example, if `lst` is the list `2, 3`, then `cons(1, lst)` is the list `1, 2, 3`. Internally, `cons(1, lst)` builds the tuple `[1, lst]`, where `lst` is the tuple `[2, [3, null]]`. The [`null?`](https://docs.ton.org/languages/func/built-ins#null%3F) function checks if the provided argument is the `null` value, or equivalently, the empty list. The following snippet illustrates these functions: ;; An initially empty list. ;; "null" represents the empty list. ;; The null value is obtained by calling the null() function. tuple numbers = null(); ;; Attach 100 as first element of the list numbers = cons(100, numbers); ;; Attach 200 as first element of the list, ;; now 100 is the second element of the list numbers = cons(200, numbers); ;; "numbers" is the list: 200, 100. ;; Or equivalently, the tuple: [200, [100, null]] ;; Is the list null or equivalently, empty? if (numbers.null?()) { ;; list-style list is empty } else { ;; list-style list is not empty } **References:** * [Lisp-style lists](https://docs.ton.org/languages/func/stdlib#lisp-style-lists) * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [`cons`](https://docs.ton.org/languages/func/stdlib#cons) * [`null`](https://docs.ton.org/languages/func/stdlib#null) * [`null?`](https://docs.ton.org/languages/func/built-ins#null%3F) ### [​](https://docs.ton.org/languages/func/cookbook#how-to-iterate-through-a-lisp-style-list) How to iterate through a lisp-style list As described in the recipe [“Basic operations in lisp-style lists”](https://docs.ton.org/languages/func/cookbook#basic-operations-in-lisp-style-lists) , [Lisp-style lists](https://docs.ton.org/languages/func/stdlib#lisp-style-lists) are represented as nested tuples. It is possible to iterate a lisp-style list by using the function [`list-next`](https://docs.ton.org/languages/func/stdlib#list-next) , which returns the head of the list and the rest of the list. The following snippet illustrates its usage. () main () { ;; Create an example list. ;; Initially it is empty, indicated ;; by the null value. tuple l = null(); l = cons(1, l); l = cons(2, l); l = cons(3, l); ;; Here, l is the list 3, 2, 1, ;; or [3, [2, [1, null]]] ;; Iterate the list ;; while the list is not empty while (~ l.null?()) { ;; Store the list's head in x ;; and update variable l so that it now ;; contains the rest of the list var x = l~list_next(); ;; Do something with x } } **References:** * [Lisp-style lists](https://docs.ton.org/languages/func/stdlib#lisp-style-lists) * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [Modifying notation using ~](https://docs.ton.org/languages/func/expressions#modifying-notation) * [`cons`](https://docs.ton.org/languages/func/stdlib#cons) * [`null`](https://docs.ton.org/languages/func/stdlib#null) * [`null?`](https://docs.ton.org/languages/func/built-ins#null%3F) * [`list_next`](https://docs.ton.org/languages/func/stdlib#list-next) ### [​](https://docs.ton.org/languages/func/cookbook#how-to-iterate-a-cell-tree) How to iterate a cell tree Each cell can store up to `1023` bits of data and `4` cell references. Therefore, it is possible to represent complex tree structures by linking cells using cell references. Given a tree of cells, use any [tree traversal algorithm](https://en.wikipedia.org/wiki/Tree_traversal) to access each cell in the tree. For example, the snippet below uses the [iterative version of pre-order traversal](https://en.wikipedia.org/wiki/Tree_traversal#Pre-order_implementation) , which makes use of a stack, instead of recursive calls. The stack is implemented using the same technique for [lisp-style lists](https://docs.ton.org/languages/func/stdlib#lisp-style-lists) . The only difference is that the list grows by appending elements to the end of the list, instead of at the front. The last element in the list is the top of the stack. More concretely, if `s` is the current stack, append an element `x` by constructing the tuple `[s, x]`. This tuple `[s, x]` is the new stack, with top element `x`. For example, the stack `1, 2, 3`, where `3` is the top element, is represented using nested tuples as `[[[null, 1], 2], 3]`, where `null` represents the empty stack. ;; Sets "head" to be the new top element of stack "tail". ;; For example, if t is "tail" and x is "head", ;; this function produces the tuple [t, x], ;; which means that x is the new top element of the stack [t, x]. ;; The function returns the new stack and the unit value (), ;; just to be able to use this function using modifying notation. forall X -> (tuple, ()) push_back (tuple tail, X head) asm "CONS"; ;; Removes the last element from the stack, and ;; returns the modified stack and the removed element. ;; For example, if the stack is [t, x], this ;; function returns the stack t, and the element x. forall X -> (tuple, X) pop_back (tuple t) asm "UNCONS"; () main () { ;; An example tree of cells. cell c = begin_cell() .store_uint(1, 16) .store_ref(begin_cell() .store_uint(2, 16) .end_cell()) .store_ref(begin_cell() .store_uint(3, 16) .store_ref(begin_cell() .store_uint(4, 16) .end_cell()) .store_ref(begin_cell() .store_uint(5, 16) .end_cell()) .end_cell()) .end_cell(); ;; Initialize the stack. null plays the roll ;; of the empty stack. tuple stack = null(); ;; Push the root cell into the stack to ;; process it in the loop stack~push_back(c); ;; Iterate while there are cells in the stack while (~ stack.null?()) { ;; Pop a cell from the stack and convert it ;; to a slice to be able to process it. ;; The call stack~pop_back() implicitly ;; modifies the stack. slice s = stack~pop_back().begin_parse(); ;; Do something with the data in s ;; If the current slice has any refs, ;; add them to the stack. ;; slice_refs returns the number of ;; refs in slice s. repeat (s.slice_refs()) { ;; Obtain the cell using s~load_ref(). ;; This implicitly modifies the slice s ;; so that it is ready to read the next ;; cell reference. ;; Then, push the cell to the stack. stack~push_back(s~load_ref()); } } } **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [Modifying notation using ~](https://docs.ton.org/languages/func/expressions#modifying-notation) * [Builder primitives](https://docs.ton.org/languages/func/stdlib#builder-primitives) * [Slice primitives](https://docs.ton.org/languages/func/stdlib#slice-primitives) * [`Lisp-style lists`](https://docs.ton.org/languages/func/stdlib#lisp-style-lists) * [Assembler functions](https://docs.ton.org/languages/func/asm-functions) * [`null`](https://docs.ton.org/languages/func/stdlib#null) * [`null?`](https://docs.ton.org/languages/func/built-ins#null%3F) * [`slice_refs`](https://docs.ton.org/languages/func/stdlib#slice-refs) * [TVM instructions](https://docs.ton.org/tvm/instructions) [​](https://docs.ton.org/languages/func/cookbook#contracts) Contracts ------------------------------------------------------------------------ ### [​](https://docs.ton.org/languages/func/cookbook#how-to-determine-if-the-contract-state-is-empty) How to determine if the contract state is empty Consider a smart contract that keeps a `counter` stored in its state, that tracks the number of internal messages the contract has received. When the contract receives its first message, the contract state is empty, which means that the `counter` has not been initialized yet. It is important to handle all scenarios by checking if the state is empty and initializing the `counter` accordingly. () recv_internal() { ;; "get_data" returns the persistent contract state, as a cell cell contract_data = get_data(); ;; Obtain a slice from the contract data cell, for reading slice cs = contract_data.begin_parse(); ;; Check that the contract state is empty if (cs.slice_empty?()) { ;; Contract data is empty, so create a fresh counter. int counter = 1; ;; To save the counter into the contract state, ;; create a cell containing the counter. ;; The counter is stored as an unsigned 32-bit integer. cell new_data = begin_cell().store_uint(counter, 32).end_cell(); ;; Save the data cell into the contract state by using "set_data". set_data(new_data); } else { ;; Contract data is not empty. ;; Get our counter from the contract state and increase it ;; The counter is an unsigned 32-bit integer. int counter = cs~load_uint(32) + 1; ;; To save the counter into the contract state, ;; create a cell containing the counter. ;; The counter is stored as an unsigned 32-bit integer. cell new_data = begin_cell().store_uint(counter, 32).end_cell(); ;; Save the data cell into the contract state by using "set_data". set_data(new_data); } } **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [Modifying notation using ~](https://docs.ton.org/languages/func/expressions#modifying-notation) * [`recv_internal` method](https://docs.ton.org/languages/func/special-functions#receive-internal) * [`get_data`](https://docs.ton.org/languages/func/stdlib#get-data) * [`begin_parse`](https://docs.ton.org/languages/func/stdlib#begin-parse) * [`slice_empty?`](https://docs.ton.org/languages/func/stdlib#slice-empty%3F) * [`begin_cell`](https://docs.ton.org/languages/func/stdlib#begin-cell) * [`end_cell`](https://docs.ton.org/languages/func/stdlib#end-cell) * [`store_uint`](https://docs.ton.org/languages/func/stdlib#store-uint) * [`load_uint`](https://docs.ton.org/languages/func/stdlib#load-uint) * [`set_data`](https://docs.ton.org/languages/func/stdlib#set-data) ### [​](https://docs.ton.org/languages/func/cookbook#how-to-update-the-smart-contract-logic) How to update the smart contract logic Below is an example of a simple `CounterV1` smart contract that allows the counter to be incremented and includes logic for updating the contract. () recv_internal (slice in_msg_body) { int op = in_msg_body~load_uint(32); if (op == op::increase) { int increase_by = in_msg_body~load_uint(32); ctx_counter += increase_by; save_data(); return (); } if (op == op::upgrade) { cell code = in_msg_body~load_ref(); set_code(code); return (); } } After interacting with the contract, and realizing that the functionality for decrementing the counter is missing. Fix this by copying the code from `CounterV1` and adding a new `decrease` function next to the existing `increase` function. The updated code will look like this: () recv_internal (slice in_msg_body) { int op = in_msg_body~load_uint(32); if (op == op::increase) { int increase_by = in_msg_body~load_uint(32); ctx_counter += increase_by; save_data(); return (); } if (op == op::decrease) { int decrease_by = in_msg_body~load_uint(32); ctx_counter -= decrease_by; save_data(); return (); } if (op == op::upgrade) { cell code = in_msg_body~load_ref(); set_code(code); return (); } } Once the `CounterV2` smart contract is ready, compile it off-chain into a `cell` and send an upgrade message to the `CounterV1` contract: await contractV1.sendUpgrade(provider.sender(), { code: await compile('ContractV2'), value: toNano('0.05'), }); **References:** * [`set_code`](https://docs.ton.org/languages/func/stdlib#set-code) [​](https://docs.ton.org/languages/func/cookbook#messages) Messages ---------------------------------------------------------------------- ### [​](https://docs.ton.org/languages/func/cookbook#how-to-build-an-internal-message-with-default-headers) How to build an internal message with default headers When a smart contract needs to send an internal message, it must first construct the message as a `cell`. This includes specifying technical flags, the recipient’s address, and additional data. The most common case involves sending an internal message that is bounceable, with no `StateInit`, and with message body serialized in the same message cell. The following `build_message` function illustrates this common case. The function receives as parameters the destination address `dest_addr` encoded as a slice, the amount in nanotons to send `amount`, and the requested operation opcode `opcode`: cell build_message(slice dest_addr, int amount, int opcode) { cell msg = begin_cell() ;; Sets 5 headers to their default values. ;; In particular, the bounceable header is true. .store_uint(0x18, 1 + 1 + 1 + 1 + 2) .store_slice(dest_addr) ;; destination address .store_coins(amount) ;; amount to send in nanotons ;; Sets 7 more headers to their default values. ;; Sets default value 0 to all the 7 headers. .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1) ;; Message body starts here. ;; Usually starts with an unsigned 32-bits integer, ;; called "opcode", that identifies the requested operation. .store_uint(op, 32) ;; The next fields depend on the opcode. ;; For example, an opcode representing a lookup operation ;; would need to include the data to lookup ;; ...... .end_cell(); return msg; } The call `store_uint(0x18, 1 + 1 + 1 + 1 + 2)` sets 5 headers to their default values. The sum `1 + 1 + 1 + 1 + 2` represents the number of bits occupied by each header, i.e., the first header occupies 1 bit, the second header 1 bit, and so on until the 5th header which occupies 2 bits. The hexadecimal number `0x18` is a shorthand for the 6 bits `011000`, which represents the default values for each of the headers, i.e., the first header has value `0`, the second header `1`, and so on until the 5th header, which has the two bits `00`. Among these 5 headers, the third one is probably the most interesting for a programmer, because it corresponds to the bounceable flag, which is set to `1` (true) by default. If the flag is required to be `0` (false), use hexadecimal `0x10` instead of `0x18`, because `0x10` corresponds to the 6 bits `010000`. The call `store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)` sets 7 further headers to the default value `0`. The sum `1 + 4 + 4 + 64 + 32 + 1 + 1` represents the number of bits occupied by each header. Among these 7 headers, the last two are probably the most interesting for a programmer, because they correspond to the `StateInit` header and the message body ref header, respectively. In particular, the default headers state that the message has no `StateInit`, and that the message body is not stored as a cell reference, but directly in the cell, together with the headers. Refer to recipes [“How to send a deploy message”](https://docs.ton.org/languages/func/cookbook#how-to-send-a-deploy-message) and [“How to set the message body as a ref in an internal message”](https://docs.ton.org/languages/func/cookbook#how-to-set-the-message-body-as-a-ref-in-an-internal-message) for examples on how to manipulate `StateInit` and the message body ref headers, respectively. For further details on all the headers, see the sending messages page and the [TL-B for messages](https://docs.ton.org/foundations/whitepapers/tblkch#3-1-7-message-layout) . Here is an example on how to use function `build_message` to send a message: ;; Create a slice from a string containing the destination address slice addr = "EQArzP5prfRJtDM5WrMNWyr9yUTAi0c9o6PfR4hkWy9UQXHx"a; ;; The amount to send in nanotons int amount = 1000000000; ;; The opcode for the requested operation int op = 20; ;; Create the message cell cell msg = build_message(addr, amount, op); ;; Send the message, using default sending mode 0 send_raw_message(msg, 0); Refer to the sending messages page for further details on sending modes in the `send_raw_message` function. **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [`begin_cell`](https://docs.ton.org/languages/func/stdlib#begin-cell) * [`store_uint`](https://docs.ton.org/languages/func/stdlib#store-uint) * [`store_slice`](https://docs.ton.org/languages/func/stdlib#store-slice) * [`store_coins`](https://docs.ton.org/languages/func/stdlib#store-coins) * [`end_cell`](https://docs.ton.org/languages/func/stdlib#end-cell) * [TL-B for messages](https://docs.ton.org/foundations/whitepapers/tblkch#3-1-7-message-layout) * Sending messages page * [`"
"a` compile-time builtin](https://docs.ton.org/languages/func/literals#string-with-suffix-a) , where `
` is a string encoding an address. * [`send_raw_message`](https://docs.ton.org/languages/func/stdlib#send-raw-message) ### [​](https://docs.ton.org/languages/func/cookbook#how-to-set-the-message-body-as-a-ref-in-an-internal-message) How to set the message body as a ref in an internal message If there is sufficient space, the message body can be stored in the same `cell` together with the message headers, as shown in the recipe [“How to build an internal message with default headers”](https://docs.ton.org/languages/func/cookbook#how-to-build-an-internal-message-with-default-headers) . If there is not enough space in the message cell, the message body can be stored as a cell reference to the message, as shown in the following function. The function receives the destination address, the amount to send, and the message body as a separate cell. cell build_message(slice dest_addr, int amount, cell message_body) { cell msg = begin_cell() ;; Sets 5 headers to their default values. ;; In particular, the bounceable header is true. .store_uint(0x18, 1 + 1 + 1 + 1 + 2) .store_slice(dest_addr) ;; destination address .store_coins(amount) ;; amount to send in nanotons ;; Sets 6 more headers to their default values. ;; Sets default value 0 to all the 6 headers. .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1) ;; Activate the message body ref header ;; to indicate that the message body is included as a ;; cell reference .store_uint(1, 1) ;; Store the message body as a cell reference .store_ref(message_body) .end_cell(); return msg; } The call `store_uint(0x18, 1 + 1 + 1 + 1 + 2)` sets 5 headers to their default values, as in the recipe [“How to build an internal message with default headers”](https://docs.ton.org/languages/func/cookbook#how-to-build-an-internal-message-with-default-headers) . The call `store_uint(0, 1 + 4 + 4 + 64 + 32 + 1)` sets 6 further headers to the default value `0`, as in the first 6 headers in recipe [“How to build an internal message with default headers”](https://docs.ton.org/languages/func/cookbook#how-to-build-an-internal-message-with-default-headers) . The last header, corresponding to the message body ref header, is set with the call `store_uint(1, 1)`, which indicates that the message body will be included as a cell reference. For further details on all the headers, see the sending messages page and the [TL-B for messages](https://docs.ton.org/foundations/whitepapers/tblkch#3-1-7-message-layout) . Here is an example on how to use function `build_message` to send a message: ;; Create a slice from a string containing the destination address slice addr = "EQArzP5prfRJtDM5WrMNWyr9yUTAi0c9o6PfR4hkWy9UQXHx"a; ;; The amount to send in nanotons int amount = 1000000000; ;; Create a cell storing the message body cell message_body = begin_cell() .store_uint(20, 32) ;; include an opcode .store_slice("❤") ;; include further data required by the opcode .end_cell(); ;; Create the message cell cell msg = build_message(addr, amount, message_body); ;; Send the message, using default sending mode 0 send_raw_message(msg, 0); Refer to the sending messages page for further details on sending modes in the `send_raw_message` function. **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [`begin_cell`](https://docs.ton.org/languages/func/stdlib#begin-cell) * [`store_uint`](https://docs.ton.org/languages/func/stdlib#store-uint) * [`store_slice`](https://docs.ton.org/languages/func/stdlib#store-slice) * [`store_coins`](https://docs.ton.org/languages/func/stdlib#store-coins) * [`end_cell`](https://docs.ton.org/languages/func/stdlib#end-cell) * [TL-B for messages](https://docs.ton.org/foundations/whitepapers/tblkch#3-1-7-message-layout) * Sending messages page * [`"
"a` compile-time builtin](https://docs.ton.org/languages/func/literals#string-with-suffix-a) , where `
` is a string encoding an address. * [`send_raw_message`](https://docs.ton.org/languages/func/stdlib#send-raw-message) ### [​](https://docs.ton.org/languages/func/cookbook#how-to-set-the-message-body-as-a-slice-in-an-internal-message) How to set the message body as a slice in an internal message If the message body needs to be included directly in the message cell, but the message body is already in a separate slice, write the slice into the message cell, as in the following function. The function receives the destination address, the amount to send, and the message body as a slice. cell build_message(slice dest_addr, int amount, slice message_body) { cell msg = begin_cell() ;; Sets 5 headers to their default values. ;; In particular, the bounceable header is true. .store_uint(0x18, 1 + 1 + 1 + 1 + 2) .store_slice(dest_addr) ;; destination address .store_coins(amount) ;; amount to send in nanotons ;; Sets 7 more headers to their default values. ;; Sets default value 0 to all the 7 headers. .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1) ;; Message body starts here. ;; Write the message body slice .store_slice(message_body) .end_cell(); return msg; } The function writes the default values for all the message headers, as in the recipe [“How to build an internal message with default headers”](https://docs.ton.org/languages/func/cookbook#how-to-build-an-internal-message-with-default-headers) . For further details on all the headers, see the sending messages page and the [TL-B for messages](https://docs.ton.org/foundations/whitepapers/tblkch#3-1-7-message-layout) . Here is an example on how to use function `build_message` to send a message: ;; Create a slice from a string containing the destination address slice addr = "EQArzP5prfRJtDM5WrMNWyr9yUTAi0c9o6PfR4hkWy9UQXHx"a; ;; The amount to send in nanotons int amount = 1000000000; ;; Create a slice storing the message body slice message_body = begin_cell() .store_uint(20, 32) ;; include an opcode .store_slice("❤") ;; include further data required by the opcode .end_cell() .begin_parse(); ;; Transform the cell to a slice ;; Create the message cell cell msg = build_message(addr, amount, message_body); ;; Send the message, using default sending mode 0 send_raw_message(msg, 0); Refer to the sending messages page for further details on sending modes in the `send_raw_message` function. **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [`begin_cell`](https://docs.ton.org/languages/func/stdlib#begin-cell) * [`store_uint`](https://docs.ton.org/languages/func/stdlib#store-uint) * [`store_slice`](https://docs.ton.org/languages/func/stdlib#store-slice) * [`store_coins`](https://docs.ton.org/languages/func/stdlib#store-coins) * [`end_cell`](https://docs.ton.org/languages/func/stdlib#end-cell) * [`begin_parse`](https://docs.ton.org/languages/func/stdlib#begin-parse) * [TL-B for messages](https://docs.ton.org/foundations/whitepapers/tblkch#3-1-7-message-layout) * Sending messages page * [`"
"a` compile-time builtin](https://docs.ton.org/languages/func/literals#string-with-suffix-a) , where `
` is a string encoding an address. * [`send_raw_message`](https://docs.ton.org/languages/func/stdlib#send-raw-message) ### [​](https://docs.ton.org/languages/func/cookbook#how-to-send-a-message-containing-a-comment) How to send a message containing a comment A “comment” is an ASCII string encoded as a slice. To send a message with a comment, write a `0` opcode followed by the comment, as done in the following function. The function receives the destination address, the amount to send, and the comment encoded as a slice. cell build_message(slice dest_addr, int amount, slice comment) { cell msg = begin_cell() ;; Sets 5 headers to their default values. ;; In particular, the bounceable header is true. .store_uint(0x18, 1 + 1 + 1 + 1 + 2) .store_slice(dest_addr) ;; destination address .store_coins(amount) ;; amount to send in nanotons ;; Sets 7 more headers to their default values. ;; Sets default value 0 to all the 7 headers. .store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1) ;; Message body starts here. ;; Write a 0 opcode, which means simple ;; message with a comment .store_uint(0, 32) ;; Write the slice containing the comment .store_slice(comment) .end_cell(); return msg; } The function writes the default values for all the message headers, as in the recipe [“How to build an internal message with default headers”](https://docs.ton.org/languages/func/cookbook#how-to-build-an-internal-message-with-default-headers) . For further details on all the headers, see the sending messages page and the [TL-B for messages](https://docs.ton.org/foundations/whitepapers/tblkch#3-1-7-message-layout) . Here is an example on how to use function `build_message` to send a message: ;; Create a slice from a string containing the destination address slice addr = "EQArzP5prfRJtDM5WrMNWyr9yUTAi0c9o6PfR4hkWy9UQXHx"a; ;; The amount to send in nanotons int amount = 1000000000; ;; Create a slice storing the comment slice comment = "Hello from FunC!"; ;; Create the message cell cell msg = build_message(addr, amount, comment); ;; Send the message, using default sending mode 0 send_raw_message(msg, 0); Refer to the sending messages page for further details on sending modes in the `send_raw_message` function. **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [`begin_cell`](https://docs.ton.org/languages/func/stdlib#begin-cell) * [`store_uint`](https://docs.ton.org/languages/func/stdlib#store-uint) * [`store_slice`](https://docs.ton.org/languages/func/stdlib#store-slice) * [`store_coins`](https://docs.ton.org/languages/func/stdlib#store-coins) * [`end_cell`](https://docs.ton.org/languages/func/stdlib#end-cell) * [TL-B for messages](https://docs.ton.org/foundations/whitepapers/tblkch#3-1-7-message-layout) * Sending messages page * [`"
"a` compile-time builtin](https://docs.ton.org/languages/func/literals#string-with-suffix-a) , where `
` is a string encoding an address. * [`""` compile-time builtin](https://docs.ton.org/languages/func/literals#string-without-suffix) , where `` is an ASCII string. * [`send_raw_message`](https://docs.ton.org/languages/func/stdlib#send-raw-message) ### [​](https://docs.ton.org/languages/func/cookbook#how-to-send-a-message-with-a-long-text-comment) How to send a message with a long text comment A `cell` can store up to 1023 bits of data, which means up to 127 8-bit characters. If there is a need to send a message with a really long comment, split the comment into several slices. Each slice should have at most 127 chars. Each slice should have a reference to the next one, forming a snake-like structure. The following example illustrates the idea: ;; Create a slice from a string containing the destination address slice addr = "EQArzP5prfRJtDM5WrMNWyr9yUTAi0c9o6PfR4hkWy9UQXHx"a; ;; The amount to send in nanotons int amount = 1000000000; ;; Create a cell storing the message body ;; It contains a long string, that must be split into several ;; slices, linked by references in a snake-like structure. ;; Each slice has at most 127 chars cell message_body = begin_cell() ;; zero opcode, i.e., message with comment .store_uint(0, 32) ;; The long string starts here .store_slice("long, long, long message...") ;; Create a reference to the next part of the string .store_ref(begin_cell() .store_slice(" store a string of almost any length, ") ;; And another reference to the last part of the string .store_ref(begin_cell() .store_slice(" as long as each slice has at most 127 chars.") .end_cell()) .end_cell()) .end_cell(); ;; Create the message cell cell msg = build_message(addr, amount, message_body); ;; Send the message, using default sending mode 0 send_raw_message(msg, 0); The `build_message` function is exactly the function used in the recipe [How to set the message body as a ref in an internal message](https://docs.ton.org/languages/func/cookbook#how-to-set-the-message-body-as-a-ref-in-an-internal-message) . Refer to the sending messages page for further details on sending modes in the `send_raw_message` function. **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [`begin_cell`](https://docs.ton.org/languages/func/stdlib#begin-cell) * [`store_uint`](https://docs.ton.org/languages/func/stdlib#store-uint) * [`store_slice`](https://docs.ton.org/languages/func/stdlib#store-slice) * [`store_ref`](https://docs.ton.org/languages/func/stdlib#store-ref) * [`end_cell`](https://docs.ton.org/languages/func/stdlib#end-cell) * [`"
"a` compile-time builtin](https://docs.ton.org/languages/func/literals#string-with-suffix-a) , where `
` is a string encoding an address. * [`""` compile-time builtin](https://docs.ton.org/languages/func/literals#string-without-suffix) , where `` is an ASCII string. * [`send_raw_message`](https://docs.ton.org/languages/func/stdlib#send-raw-message) * Sending messages page ### [​](https://docs.ton.org/languages/func/cookbook#how-to-send-a-deploy-message) How to send a deploy message When sending a deploy message, prepare a [`StateInit`](https://docs.ton.org/foundations/messages/deploy) cell, as done in the recipe [How to build a `StateInit` cell](https://docs.ton.org/languages/func/cookbook#how-to-build-a-StateInit-cell) . Once the `StateInit` cell is ready, prepare a message cell in which the message body is included with the headers, or the message body is included as a separate cell. The following function illustrates the case for the message body included in the same cell as the headers. The function receives the destination address, the amount to send, the `StateInit` cell, and the message body as a slice. () deploy(slice dest_addr, int amount, cell state_init, slice message_body) { cell msg = begin_cell() ;; Sets 5 headers to their default values. ;; In particular, the bounceable header is true. .store_uint(0x18, 1 + 1 + 1 + 1 + 2) .store_slice(dest_addr) ;; destination address .store_coins(amount) ;; amount to send in nanotons ;; Sets 5 more headers to their default values. ;; Sets default value 0 to all the 5 headers. .store_uint(0, 1 + 4 + 4 + 64 + 32) ;; Sets the StateInit header to the 2-bit integer 3, ;; which signals that a StateInit cell is included ;; as a separate reference cell. .store_uint(3, 2) ;; Set the message body header to the 1-bit integer 0, ;; which indicates that the message body is ;; included in the same cell. .store_uint(0, 1) ;; Message body starts here. ;; Write the message body slice .store_slice(message_body) ;; Include the StateInit cell as a reference .store_ref(state_init) .end_cell(); ;; Send the deploy message in standard mode send_raw_message(msg, 0); } The function writes the default values for all the message headers, following the same strategy as in the recipe [“How to build an internal message with default headers”](https://docs.ton.org/languages/func/cookbook#how-to-build-an-internal-message-with-default-headers) , with the exception of the last two headers: the `StateInit` header and the message body header. According to the TL-B for internal messages, the `StateInit` header satisfies: init:(Maybe (Either StateInit ^StateInit)) which means that the header needs at most two bits, one for deciding the `Maybe` and, in case the `Maybe` bit is active, another for deciding the `Either`. In the function above, the `StateInit` header was set to the 2-bit integer `3`, which corresponds to the binary `11`. The first bit corresponds to the `Maybe`, and since it is active, it signals that there is a `StateInit` in the message. The second bit corresponds to the `Either`, and since it is active, it signals that the right branch of the `Either` was chosen, i.e., the branch `^StateInit`, which means that the `StateInit` is included as a reference cell in the message. The message body header was set to the 1-bit value `0`, which means that the message body in included in the same cell together with the headers. As a second example, the following function also includes a `StateInit`, but the message body is included as a separate cell. The function receives the destination address, the amount to send, the `StateInit` cell, and the message body as a cell. () deploy_body_cell(slice dest_addr, int amount, cell state_init, cell message_body) { cell msg = begin_cell() ;; Sets 5 headers to their default values. ;; In particular, the bounceable header is true. .store_uint(0x18, 1 + 1 + 1 + 1 + 2) .store_slice(dest_addr) ;; destination address .store_coins(amount) ;; amount to send in nanotons ;; Sets 5 more headers to their default values. ;; Sets default value 0 to all the 5 headers. .store_uint(0, 1 + 4 + 4 + 64 + 32) ;; Sets the StateInit header to the 2-bit integer 3, ;; which signals that a StateInit cell is included ;; as a separate reference cell. .store_uint(3, 2) ;; Set the message body header to the 1-bit integer 1, ;; which indicates that the message body is ;; included as a separate cell .store_uint(1, 1) ;; Include the StateInit cell as a reference .store_ref(state_init) ;; Include the message body as a reference .store_ref(message_body) .end_cell(); ;; Send the deploy message in standard mode send_raw_message(msg, 0); } For further details on all the headers, see the sending messages page and the [TL-B for messages](https://docs.ton.org/foundations/whitepapers/tblkch#3-1-7-message-layout) . Refer to the sending messages page for further details on sending modes in the `send_raw_message` function. **References:** * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [`begin_cell`](https://docs.ton.org/languages/func/stdlib#begin-cell) * [`store_uint`](https://docs.ton.org/languages/func/stdlib#store-uint) * [`store_slice`](https://docs.ton.org/languages/func/stdlib#store-slice) * [`store_coins`](https://docs.ton.org/languages/func/stdlib#store-coins) * [`store_ref`](https://docs.ton.org/languages/func/stdlib#store-ref) * [`end_cell`](https://docs.ton.org/languages/func/stdlib#end-cell) * [`send_raw_message`](https://docs.ton.org/languages/func/stdlib#send-raw-message) * [TL-B for messages](https://docs.ton.org/foundations/whitepapers/tblkch#3-1-7-message-layout) * Sending messages page ### [​](https://docs.ton.org/languages/func/cookbook#how-to-send-a-message-with-the-entire-balance) How to send a message with the entire balance To transfer the entire balance of a smart contract, use [send mode `128`](https://docs.ton.org/foundations/messages/modes) . This is particularly useful for proxy contracts that receive payments and forward them to the main contract. ;; Create a slice from a string containing the destination address slice addr = "EQArzP5prfRJtDM5WrMNWyr9yUTAi0c9o6PfR4hkWy9UQXHx"a; ;; The amount to send in nanotons. ;; In this case, it is irrelevant the sent amount, ;; because, later, the send mode 128 will include ;; all the contract's balance in the message int amount = 0; ;; The comment to send slice comment = "Hello from FunC!"; ;; Create the message cell cell msg = build_message(addr, amount, comment); ;; Send the message, using mode 128 ;; The mode 128 sends the entire contract's balance in the message send_raw_message(msg, 128); The `build_message` function is exactly the function used in the recipe [How to send a message containing a comment](https://docs.ton.org/languages/func/cookbook#how-to-send-a-message-containing-a-comment) . Refer to the sending messages page for further details on sending modes in the `send_raw_message` function. **References:** * [`"
"a` compile-time builtin](https://docs.ton.org/languages/func/literals#string-with-suffix-a) , where `
` is a string encoding an address. * [`""` compile-time builtin](https://docs.ton.org/languages/func/literals#string-without-suffix) , where `` is an ASCII string. * Sending messages page * [`send_raw_message`](https://docs.ton.org/languages/func/stdlib#send-raw-message) ### [​](https://docs.ton.org/languages/func/cookbook#how-to-send-a-message-in-a-proxy-contract) How to send a message in a proxy contract A proxy contract facilitates message exchange between a user and a main contract. The proxy contract redirects messages based on the parameters it receives in the incoming message. For example, this is a simple example of a proxy contract. It expects that the incoming message body `in_msg_body` contains the message mode, destination address, and the slice to send as body. () recv_internal (slice in_msg_body) { ;; In the incoming message body, ;; the first byte contains the message mode ;; for the redirected message int mode = in_msg_body~load_uint(8); ;; Then, the destination address slice addr = in_msg_body~load_msg_addr(); ;; And finally, everything that is left in "in_msg_body" ;; will be the redirected message's body slice body = in_msg_body; ;; The amount to send in nanotons int amount = 1000000000; ;; Create the message cell cell msg = build_message(addr, amount, body); ;; Send the message, using the provided mode. send_raw_message(msg, mode); } The `build_message` function is exactly the function used in the recipe [How to set the message body as a slice in an internal message](https://docs.ton.org/languages/func/cookbook#how-to-set-the-message-body-as-a-slice-in-an-internal-message) . Refer to the sending messages page for further details on sending modes in the `send_raw_message` function. **References:** * [Modifying notation using ~](https://docs.ton.org/languages/func/expressions#modifying-notation) * [load\_uint](https://docs.ton.org/languages/func/stdlib#load-uint) * [`load_msg_addr`](https://docs.ton.org/languages/func/stdlib#load-msg-addr) * Sending messages page * [`send_raw_message`](https://docs.ton.org/languages/func/stdlib#send-raw-message) [​](https://docs.ton.org/languages/func/cookbook#functions) Functions ------------------------------------------------------------------------ ### [​](https://docs.ton.org/languages/func/cookbook#how-to-write-custom-functions-using-asm-keyword) How to write custom functions using asm keyword Many features in FunC come from predefined methods in the [Standard library](https://docs.ton.org/languages/func/stdlib) . However, there are many functionalities that the standard library does not cover, but are available as [TVM instructions](https://docs.ton.org/tvm/instructions) . In such cases, it is possible to define functions that make use of the TVM instructions. For example, while the function [`tpush`](https://docs.ton.org/languages/func/stdlib#tpush) , which adds an element to the end of a tuple, exists in the standard library, there is no `tpop` function, which removes the last element in a tuple and returns the modified tuple and the removed element. But there is a [TVM instruction `TPOP`](https://docs.ton.org/tvm/instructions#6f8d-tpop) that does precisely this. So, define the function `tpop` as an [assembler function](https://docs.ton.org/languages/func/asm-functions) that wraps the `TPOP` instruction: forall X -> (tuple, X) ~tpop (tuple t) asm "TPOP"; The return type `(tuple, X)` indicates that the function produces the modified tuple and the extracted element as a result. The function is [polymorphic](https://docs.ton.org/languages/func/types#polymorphism-with-type-variables) in the sense that the type of the returned element `X` can be any type. The function name uses the symbol `~` to indicate that this function can be called using [modifying notation](https://docs.ton.org/languages/func/expressions#modifying-notation) . For example, if it is certain that tuple `t` has only integer elements, call the function using [modifying notation](https://docs.ton.org/languages/func/expressions#modifying-notation) , like this: int elem = t~tpop(); which will assign the removed element to `elem` and also modify tuple `t` implicitly. As another example, the following function determines the length of a tuple by wrapping the [`TLEN` TVM instruction](https://docs.ton.org/tvm/instructions#6f88-tlen) : int tuple_length (tuple t) asm "TLEN"; Further examples taken from the [Standard library](https://docs.ton.org/languages/func/stdlib) : slice begin_parse(cell c) asm "CTOS"; builder begin_cell() asm "NEWC"; cell end_cell(builder b) asm "ENDC"; **References:** * [Modifying notation using ~](https://docs.ton.org/languages/func/expressions#modifying-notation) * [Standard library](https://docs.ton.org/languages/func/stdlib) * [TVM instructions](https://docs.ton.org/tvm/instructions) * [Assembler functions](https://docs.ton.org/languages/func/asm-functions) ### [​](https://docs.ton.org/languages/func/cookbook#how-to-use-modifying-notation-on-functions) How to use modifying notation on functions To use [modifying notation](https://docs.ton.org/languages/func/expressions#modifying-notation) on a function, define the function so that it has a type of the form `(A, ...) -> (A, B)`, for arbitrary type `B`. Functions of this type usually mutate their first argument and return the mutated argument as their first result. For example, a function `f` of type `(slice, int, slice) -> (slice, cell)`, can be called using modifying notation as `cell result = s~f(0, "hello")`, where `s` is some slice. The modifying notation is a shorthand for the standard function call `(s, cell result) = f(s, 0, "hello")`, where `s` is reassigned after the call to `f`. For a more concrete example, the following defines a function that reads a digit from a slice that stores ASCII digits. The function receives the slice as an argument and produces two results. The first result is the modified slice, so that it is ready to read the next digit. The second result is the loaded digit. (slice, int) load_digit (slice s) { ;; Load 8 bits (one char) from slice. ;; x stores the decimal ASCII code of the char. ;; Since load_uint is called using modifying notation, ;; slice s is implicitly modified, ;; and it is now ready to read the next 8 bits. int x = s~load_uint(8); ;; Char '0' has code 48. Substract it ;; to get the digit as a number. x -= 48; ;; Return the modified slice and the digit. return (s, x); } The function can be called using modifying notation as follows. () main () { ;; Create a slice containing some ASCII digits slice s = "258"; ;; Proceed to read the digits as integers ;; using modifying notation on the function call. ;; This ensures that the slice gets implicitly modified ;; after reading each digit. int c1 = s~load_digit(); int c2 = s~load_digit(); int c3 = s~load_digit(); ;; here s contains no more data, ;; and c1 = 2, c2 = 5, c3 = 8 } Refer to the [modifying notation page](https://docs.ton.org/languages/func/expressions#modifying-notation) for further details. **References:** * [Modifying notation using ~](https://docs.ton.org/languages/func/expressions#modifying-notation) * [`load_uint`](https://docs.ton.org/languages/func/stdlib#load-uint) * [`""` compile-time builtin](https://docs.ton.org/languages/func/literals#string-without-suffix) , where `` is an ASCII string. [​](https://docs.ton.org/languages/func/cookbook#integer-utilities) Integer utilities ---------------------------------------------------------------------------------------- ### [​](https://docs.ton.org/languages/func/cookbook#how-to-get-the-current-time) How to get the current time Use the function `now` to obtain the current UNIX timestamp. int current_time = now(); ;; Is the current time bigger than some timestamp? if (current_time > 1672080143) { ;; do some stuff } **References:** * [now](https://docs.ton.org/languages/func/stdlib#now) ### [​](https://docs.ton.org/languages/func/cookbook#how-to-generate-a-random-number) How to generate a random number ;; do this only once before the first invocation of ;; any of the functions "rand" or "random", to ensure that ;; they will have a different seed every time the contract ;; executes. randomize_lt(); ;; Generate a random number in the range 0..9. int a = rand(10); ;; Generate a random number in the range 0..999999. int b = rand(1000000); ;; Generate an unsigned 256-bit integer. int c = random(); **References:** * [Random Number generator primitives](https://docs.ton.org/languages/func/stdlib#random-number-generator-primitives) ### [​](https://docs.ton.org/languages/func/cookbook#modulo-operations) Modulo operations As an example, let’s say there is a need to perform the following calculation for all 256 numbers: `(xp + zp) * (xp - zp)`. Since these operations are commonly used in cryptography, modulo operator for montgomery curves should be used. **Note:** Variable names like `xp+zp` are valid as long as there are no spaces between the operators. (int) modulo_operations (int xp, int zp) { ;; 2^255 - 19 is a prime number for montgomery curves, meaning all operations should be done against its prime int prime = 57896044618658097711785492504343953926634992332820282019728792003956564819949; ;; muldivmod handles the next two lines itself ;; int xp+zp = (xp + zp) % prime; ;; int xp-zp = (xp - zp + prime) % prime; (_, int xp+zp*xp-zp) = muldivmod(xp + zp, xp - zp, prime); return xp+zp*xp-zp; } **Reference:** [`muldivmod`](https://docs.ton.org/tvm/instructions#A98C) ### [​](https://docs.ton.org/languages/func/cookbook#how-to-raise-a-number-to-a-power) How to raise a number to a power To compute `n^e`, the naive approach multiplies `e - 1` times the number `n` by itself. For example, `n^3` means to multiply by `n` `2` times: `(n * n) * n`. The following code implements such idea. It has a complexity linear on `e`. int pow (int n, int e) { if (e == 0) { return 1; } int i = 0; int value = n; ;; "value" always stores the initial "n" while (i < e - 1) { ;; Repeat e-1 times n *= value; ;; Multiply by the initial "n" ;; and accumulate the result. i += 1; } ;; n stores the accumulated result return n; } There is a more efficient way to compute `n^e` called [binary exponentiation](https://cp-algorithms.com/algebra/binary-exp.html) . It has a complexity base-2 logarithmic on `e`, i.e., `O(log_2 e)`. This is the recursive implementation of the algorithm. Refer to the article for details. int binpow (int n, int e) { if (e == 0) { return 1; } if (e == 1) { return n; } int p = binpow(n, e / 2); p *= p; if ((e % 2) == 1) { p *= n; } return p; } An usage example of `binpow`: () main () { int num = binpow(2, 3); ~dump(num); ;; 8 } **References:** * [Operators](https://docs.ton.org/languages/func/operators) * [Loops](https://docs.ton.org/languages/func/statements#loops) ### [​](https://docs.ton.org/languages/func/cookbook#how-to-convert-the-ascii-digits-in-a-slice-into-an-int) How to convert the ASCII digits in a slice into an int ;; Example slice containing ASCII digits slice string_number = "26052021"; ;; This variable will hold the final number int number = 0; ;; Repeat while there is still data in the slice while (~ string_number.slice_empty?()) { ;; Load 8 bits (one char) from the slice. ;; "x" stores the decimal ASCII code of the char. int x = string_number~load_uint(8); ;; Char '0' has code 48. Substract it ;; to get the digit as a number. x -= 48; ;; Accumulate the result. number = (number * 10) + x; } **References:** * [Modifying notation using ~](https://docs.ton.org/languages/func/expressions#modifying-notation) * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [`load_uint`](https://docs.ton.org/languages/func/stdlib#load-uint) * [`""` compile-time builtin](https://docs.ton.org/languages/func/literals#string-without-suffix) , where `` is an ASCII string. ### [​](https://docs.ton.org/languages/func/cookbook#how-to-convert-an-int-into-ascii-digits-stored-in-a-slice) How to convert an int into ASCII digits stored in a slice ;; Example number to transform int n = 261119911; ;; This will store the partially constructed string builder string = begin_cell(); ;; "chars" will be a lisp-style list, where each element ;; is the decimal ASCII code of a digit. ;; The list will store the ASCII codes of each digit ;; in the number. ;; So, since the number is 261119911, the list will be: ;; ASCII code of 2, ASCII code of 6, ASCII code of 1, ..... ;; Initially, the list has the "null" value, to signal ;; that it is empty. tuple chars = null(); do { ;; Obtain the righmost digit in n ;; and remove it from n int r = n~divmod(10); ;; Transform the digit "r" into its decimal ASCII code ;; and place it as first element in the list. ;; Even tough the digits of n are processed ;; starting from the rigthmost, the list ;; is filled back to front, ensuring that ;; ASCII codes in the list match the order ;; of the digits in the original "n" chars = cons(r + 48, chars); } until (n == 0); ;; Stop until all digits are processed. ;; Now, iterate the list. do { ;; Get the element at the head of the list ;; and remove it from the list int char = chars~list_next(); ;; Store the decimal ASCII code as a binary 8-bit ASCII code string~store_uint(char, 8); } until (null?(chars)); ;; Stop until reaching the end of the list ;; Transform the cell into a slice slice result = string.end_cell().begin_parse(); **References:** * [Modifying notation using ~](https://docs.ton.org/languages/func/expressions#modifying-notation) * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [`begin_cell`](https://docs.ton.org/languages/func/stdlib#begin-cell) * [`end_cell`](https://docs.ton.org/languages/func/stdlib#end-cell) * [`begin_parse`](https://docs.ton.org/languages/func/stdlib#begin-parse) * [`null`](https://docs.ton.org/languages/func/stdlib#null) * [`divmod`](https://docs.ton.org/languages/func/stdlib#divmod) * [`store_uint`](https://docs.ton.org/languages/func/stdlib#store_uint) * [List-style lists](https://docs.ton.org/languages/func/stdlib#lisp-style-lists) [​](https://docs.ton.org/languages/func/cookbook#errors) Errors ------------------------------------------------------------------ ### [​](https://docs.ton.org/languages/func/cookbook#how-to-throw-errors) How to throw errors The following snippet summarizes the main ways of throwing exceptions in FunC, by using functions `throw_if`, `throw_unless` and `throw`. int number = 198; ;; The error 35 is thrown only if the number is greater than 50. ;; In general, throw_if(n, cond) will throw error "n" ;; only if "cond" is true. throw_if(35, number > 50); ;; the error 39 is thrown only if the number is NOT EQUAL to 198. ;; In general, throw_unless(n, cond) will throw error "n" ;; only if "cond" is false. throw_unless(39, number == 198); ;; the error 36 is thrown unconditionally throw(36); **References:** * [TVM exception codes](https://docs.ton.org/tvm/exit-codes) * [`throw_if`](https://docs.ton.org/languages/func/stdlib#throw-if) * [`throw_unless`](https://docs.ton.org/languages/func/stdlib#throw-unless) * [`throw`](https://docs.ton.org/languages/func/stdlib#throw) [​](https://docs.ton.org/languages/func/cookbook#addresses) Addresses ------------------------------------------------------------------------ ### [​](https://docs.ton.org/languages/func/cookbook#generate-an-internal-address) Generate an internal address When deploying a new contract, there is the need to generate its internal address because it is initially unknown. The internal address can be generated from the contract’s `StateInit`, which contains the code and data of the new contract. According to the `MsgAddressInt` TL-B schema, an internal address is composed of the following headers: addr_std$10 anycast:(Maybe Anycast) workchain_id:int8 address:bits256; Therefore, to create an internal address, the above headers must be written in a cell, where `address` header is computed using the hash of the contract’s `StateInit`. The following function creates an internal address that follows these headers, and stores the address in a cell, which finally gets transformed into a slice, as slices tend to be the preferred format for storing internal addresses. slice generate_internal_address (int workchain_id, cell state_init) { return begin_cell() ;; Header addr_std$10, requires the bits 10, ;; i.e., 2 as an unsigned integer .store_uint(2, 2) .store_uint(0, 1) ;; anycast header defaults to nothing ;; workchain_id, 8-bits signed integer .store_int(workchain_id, 8) ;; The address as 256-bit unsigned integer. ;; Use the function cell_hash to compute ;; a hash of the provided state_init. ;; This hash acts as the address. .store_uint(cell_hash(state_init), 256) .end_cell().begin_parse(); } Refer to recipe [“How to build a `StateInit` cell”](https://docs.ton.org/languages/func/cookbook#how-to-build-a-stateinit-cell) . Additionally, refer to recipe [“How to send a deploy message”](https://docs.ton.org/languages/func/cookbook#how-to-send-a-deploy-message) for sending a deploy message. Further information on workchain IDs are found in the [docs](https://docs.ton.org/foundations/addresses/overview#workchain-id) . **References:** * [Modifying notation using ~](https://docs.ton.org/languages/func/expressions#modifying-notation) * [Non-modifying notation using .](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [`begin_cell`](https://docs.ton.org/languages/func/stdlib#begin-cell) * [`end_cell`](https://docs.ton.org/languages/func/stdlib#end-cell) * [`begin_parse`](https://docs.ton.org/languages/func/stdlib#begin-parse) * [`cell_hash()`](https://docs.ton.org/languages/func/stdlib#cell-hash) * [`store_uint`](https://docs.ton.org/languages/func/stdlib#store-uint) * [`store_int`](https://docs.ton.org/languages/func/stdlib#store-int) * [Workchain ID](https://docs.ton.org/foundations/addresses/overview#workchain-id) * [Internal addresses](https://docs.ton.org/foundations/addresses/overview#internal-addresses) ### [​](https://docs.ton.org/languages/func/cookbook#generate-an-external-address) Generate an external address Use the TL-B scheme from [block](https://github.com/ton-blockchain/ton/blob/24dc184a2ea67f9c47042b4104bbb4d82289fac1/crypto/block/block.tlb#L101C1-L101C12) to determine the address format to generate an external address. (int) ubitsize (int a) asm "UBITSIZE"; slice generate_external_address (int address) { ;; addr_extern$01 len:(## 9) external_address:(bits len) = MsgAddressExt; int address_length = ubitsize(address); return begin_cell() .store_uint(1, 2) ;; addr_extern$01 .store_uint(address_length, 9) .store_uint(address, address_length) .end_cell().begin_parse(); } Since there is a need to find the exact number of bits occupied by the address, [declare an asm function](https://docs.ton.org/languages/func/cookbook#how-to-write-custom-functions-using-asm-keyword) with the `UBITSIZE` opcode. This function will return the minimum number of bits required to store a given number. **Reference:** [TVM instructions](https://docs.ton.org/tvm/instructions#B603) Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/languages/func/cookbook.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/languages/func/cookbook) [Previous](https://docs.ton.org/languages/func/overview) [Comments\ \ Next](https://docs.ton.org/languages/func/comments) ⌘I On this page * [Statements](https://docs.ton.org/languages/func/cookbook#statements) * [How to use flags in if statements](https://docs.ton.org/languages/func/cookbook#how-to-use-flags-in-if-statements) * [How to write a repeat loop](https://docs.ton.org/languages/func/cookbook#how-to-write-a-repeat-loop) * [How to write a while loop](https://docs.ton.org/languages/func/cookbook#how-to-write-a-while-loop) * [How to write a do until loop](https://docs.ton.org/languages/func/cookbook#how-to-write-a-do-until-loop) * [Cells and slices](https://docs.ton.org/languages/func/cookbook#cells-and-slices) * [How to determine if a slice is empty](https://docs.ton.org/languages/func/cookbook#how-to-determine-if-a-slice-is-empty) * [How to determine if slice is empty (no bits, but may have refs)](https://docs.ton.org/languages/func/cookbook#how-to-determine-if-slice-is-empty-no-bits-but-may-have-refs) * [How to determine if slice is empty (no refs, but may have bits)](https://docs.ton.org/languages/func/cookbook#how-to-determine-if-slice-is-empty-no-refs-but-may-have-bits) * [How to determine if a cell is empty](https://docs.ton.org/languages/func/cookbook#how-to-determine-if-a-cell-is-empty) * [Determine if the data bits of slices are equal](https://docs.ton.org/languages/func/cookbook#determine-if-the-data-bits-of-slices-are-equal) * [Determine if the cells are equal](https://docs.ton.org/languages/func/cookbook#determine-if-the-cells-are-equal) * [How to get only the data bits from a slice](https://docs.ton.org/languages/func/cookbook#how-to-get-only-the-data-bits-from-a-slice) * [How to build a StateInit cell](https://docs.ton.org/languages/func/cookbook#how-to-build-a-stateinit-cell) * [Data structures](https://docs.ton.org/languages/func/cookbook#data-structures) * [How to determine if a dict is empty](https://docs.ton.org/languages/func/cookbook#how-to-determine-if-a-dict-is-empty) * [How to store and load a dictionary in permanent storage](https://docs.ton.org/languages/func/cookbook#how-to-store-and-load-a-dictionary-in-permanent-storage) * [How to iterate dictionaries](https://docs.ton.org/languages/func/cookbook#how-to-iterate-dictionaries) * [How to delete a value from a dictionary](https://docs.ton.org/languages/func/cookbook#how-to-delete-a-value-from-a-dictionary) * [How to determine if a tuple is empty](https://docs.ton.org/languages/func/cookbook#how-to-determine-if-a-tuple-is-empty) * [Basic operations with tuples](https://docs.ton.org/languages/func/cookbook#basic-operations-with-tuples) * [How to iterate tuples (both directions)](https://docs.ton.org/languages/func/cookbook#how-to-iterate-tuples-both-directions) * [Iterating n-nested tuples](https://docs.ton.org/languages/func/cookbook#iterating-n-nested-tuples) * [Casting types in tuples](https://docs.ton.org/languages/func/cookbook#casting-types-in-tuples) * [Reversing tuples](https://docs.ton.org/languages/func/cookbook#reversing-tuples) * [How to remove an item with a certain index from a tuple](https://docs.ton.org/languages/func/cookbook#how-to-remove-an-item-with-a-certain-index-from-a-tuple) * [Determine if tuples are equal](https://docs.ton.org/languages/func/cookbook#determine-if-tuples-are-equal) * [Basic operations in lisp-style lists](https://docs.ton.org/languages/func/cookbook#basic-operations-in-lisp-style-lists) * [How to iterate through a lisp-style list](https://docs.ton.org/languages/func/cookbook#how-to-iterate-through-a-lisp-style-list) * [How to iterate a cell tree](https://docs.ton.org/languages/func/cookbook#how-to-iterate-a-cell-tree) * [Contracts](https://docs.ton.org/languages/func/cookbook#contracts) * [How to determine if the contract state is empty](https://docs.ton.org/languages/func/cookbook#how-to-determine-if-the-contract-state-is-empty) * [How to update the smart contract logic](https://docs.ton.org/languages/func/cookbook#how-to-update-the-smart-contract-logic) * [Messages](https://docs.ton.org/languages/func/cookbook#messages) * [How to build an internal message with default headers](https://docs.ton.org/languages/func/cookbook#how-to-build-an-internal-message-with-default-headers) * [How to set the message body as a ref in an internal message](https://docs.ton.org/languages/func/cookbook#how-to-set-the-message-body-as-a-ref-in-an-internal-message) * [How to set the message body as a slice in an internal message](https://docs.ton.org/languages/func/cookbook#how-to-set-the-message-body-as-a-slice-in-an-internal-message) * [How to send a message containing a comment](https://docs.ton.org/languages/func/cookbook#how-to-send-a-message-containing-a-comment) * [How to send a message with a long text comment](https://docs.ton.org/languages/func/cookbook#how-to-send-a-message-with-a-long-text-comment) * [How to send a deploy message](https://docs.ton.org/languages/func/cookbook#how-to-send-a-deploy-message) * [How to send a message with the entire balance](https://docs.ton.org/languages/func/cookbook#how-to-send-a-message-with-the-entire-balance) * [How to send a message in a proxy contract](https://docs.ton.org/languages/func/cookbook#how-to-send-a-message-in-a-proxy-contract) * [Functions](https://docs.ton.org/languages/func/cookbook#functions) * [How to write custom functions using asm keyword](https://docs.ton.org/languages/func/cookbook#how-to-write-custom-functions-using-asm-keyword) * [How to use modifying notation on functions](https://docs.ton.org/languages/func/cookbook#how-to-use-modifying-notation-on-functions) * [Integer utilities](https://docs.ton.org/languages/func/cookbook#integer-utilities) * [How to get the current time](https://docs.ton.org/languages/func/cookbook#how-to-get-the-current-time) * [How to generate a random number](https://docs.ton.org/languages/func/cookbook#how-to-generate-a-random-number) * [Modulo operations](https://docs.ton.org/languages/func/cookbook#modulo-operations) * [How to raise a number to a power](https://docs.ton.org/languages/func/cookbook#how-to-raise-a-number-to-a-power) * [How to convert the ASCII digits in a slice into an int](https://docs.ton.org/languages/func/cookbook#how-to-convert-the-ascii-digits-in-a-slice-into-an-int) * [How to convert an int into ASCII digits stored in a slice](https://docs.ton.org/languages/func/cookbook#how-to-convert-an-int-into-ascii-digits-stored-in-a-slice) * [Errors](https://docs.ton.org/languages/func/cookbook#errors) * [How to throw errors](https://docs.ton.org/languages/func/cookbook#how-to-throw-errors) * [Addresses](https://docs.ton.org/languages/func/cookbook#addresses) * [Generate an internal address](https://docs.ton.org/languages/func/cookbook#generate-an-internal-address) * [Generate an external address](https://docs.ton.org/languages/func/cookbook#generate-an-external-address) --- # Other FunC libraries - TON Docs [Skip to main content](https://docs.ton.org/languages/func/libraries#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Libraries Other FunC libraries [​](https://docs.ton.org/languages/func/libraries#standard-libraries) Standard libraries ------------------------------------------------------------------------------------------- * [stdlib](https://github.com/ton-blockchain/ton/blob/master/crypto/smartcont/stdlib.fc/) : the FunC standard library * [mathlib](https://github.com/ton-blockchain/ton/blob/master/crypto/smartcont/mathlib.fc/) : the FunC fixed-point math library [​](https://docs.ton.org/languages/func/libraries#libraries-from-community) Libraries from community ------------------------------------------------------------------------------------------------------- * [`continuation-team/openlib.func`](https://github.com/continuation-team/openlib.func/) : reduces transaction fees in common scenarios. * [`open-contracts/utils`](https://github.com/TonoxDeFi/open-contracts/tree/main/contracts/utils/) : utility library. * [`open-contracts/strings`](https://github.com/TonoxDeFi/open-contracts/tree/main/contracts/strings/) : provides string manipulation functions. * [`open-contracts/math`](https://github.com/TonoxDeFi/open-contracts/tree/main/contracts/math/) : extends FunC arithmetic operations with additional math functions. * [`open-contracts/tuples`](https://github.com/TonoxDeFi/open-contracts/tree/main/contracts/tuples/) : collection of tuple-related functions for FunC. * [`open-contracts/crypto`](https://github.com/TonoxDeFi/open-contracts/tree/main/contracts/crypto/) : provides cryptographic operations for secp256k1 curves. * [`toncli/test-libs`](https://github.com/disintar/toncli/tree/master/src/toncli/lib/test-libs/) : supports TL-B schema operations, including message and type parsing and generation. * [`ston-fi/funcbox`](https://github.com/ston-fi/funcbox/) : collection of FunC snippets and utilities. Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/languages/func/libraries.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/languages/func/libraries) [Previous](https://docs.ton.org/languages/func/stdlib) [Changelog\ \ Next](https://docs.ton.org/languages/func/changelog) ⌘I On this page * [Standard libraries](https://docs.ton.org/languages/func/libraries#standard-libraries) * [Libraries from community](https://docs.ton.org/languages/func/libraries#libraries-from-community) --- # Preprocessed Wallet V2 — specification - TON Docs [Skip to main content](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Preprocessed Wallet V2 Preprocessed Wallet V2 — specification This page provides a complete technical specification for Preprocessed Wallet V2, covering storage structure, message formats, replay protection, limitations, and implementation details. [​](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#objective) Objective ----------------------------------------------------------------------------------------------- Understand the internal architecture, data structures, and operational mechanics of Preprocessed Wallet V2. This reference page explains how the wallet processes batch transactions efficiently with minimal gas consumption. [​](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#what-is-preprocessed-wallet-v2) What is Preprocessed Wallet V2? ------------------------------------------------------------------------------------------------------------------------------------------ Preprocessed Wallet V2 is a wallet smart contract designed for efficiency with minimal code complexity. It provides low transaction costs while maintaining the ability to send up to 255 actions in a single transaction. **Key difference from standard wallets:** Preprocessed V2 enables batch transaction processing with up to 255 actions per message, making it suitable for services that need to send multiple payments efficiently. **Optimization focus:** Preprocessed V2 prioritizes gas efficiency and simplicity, making it suitable for applications that need batch processing with minimal overhead. **Gas consumption:** The wallet consumes 1537 gas units per transaction. [​](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#tl-b-schema) TL-B schema --------------------------------------------------------------------------------------------------- [TL-B (Type Language - Binary)](https://docs.ton.org/languages/tl-b/overview) is a domain-specific language designed to describe data structures in TON. The schemas below define the binary layout of the contract’s storage and external messages. ### [​](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#storage-structure) Storage structure storage$_ pub_key:bits256 seq_no:uint16 = Storage; ### [​](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#external-message-structure) External message structure _ {n:#} valid_until:uint64 seq_no:uint16 actions:^(OutList n) { n <= 255 } = MsgInner n; msg_body$_ {n:#} sign:bits512 ^(MsgInner n) = ExtInMsgBody n; Below, each field is explained in detail. [​](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#storage-structure-2) Storage structure ----------------------------------------------------------------------------------------------------------------- The Preprocessed Wallet V2 contract stores two persistent fields: ### [​](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#pub_key-256-bits) `pub_key` (256 bits) **Purpose:** An Ed25519 public key is used to verify signatures on incoming external messages. **How it works:** When the wallet receives an external message, it verifies that the 512-bit signature was created by the holder of the private key corresponding to this public key. ### [​](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#seq_no-16-bits) `seq_no` (16 bits) **Purpose:** Prevents replay attacks by ensuring each message has a unique sequence number. **How it works:** Each external message must contain the correct `seq_no` that matches the current value stored in the contract. After successful processing, the sequence number is incremented (with modulo 2^16 to prevent overflow). **Range:** 0 to 65535 (wraps from 65535 to 0) **Size optimization:** The sequence number is limited to 16 bits (instead of 32 bits used in other wallets) to minimize storage size and message size, reducing gas costs. **Protection mechanism:** Even if an attacker intercepts an old message, they cannot replay it because the sequence number will no longer match the current value in storage. **Wrap‑around note:** See [Replay protection mechanism](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#replay-protection-mechanism) for guidance on wrap‑around and `valid_until` windows. [​](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#external-message-structure-2) External message structure ----------------------------------------------------------------------------------------------------------------------------------- External messages sent to Preprocessed Wallet V2 have a specific layout. ### [​](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#message-layout) Message layout sign:bits512 ^[ valid_until:uint64\ seq_no:uint16\ actions:^(OutList n) ] **Key point:** The signature is in the root cell (512 bits); all other parameters are in a reference cell (`MsgInner`). * * * ### [​](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#sign-512-bits) `sign` (512 bits) **Type:** Ed25519 signature (512 bits). **What is signed:** The hash of the reference cell (`MsgInner`) containing `valid_until`, `seq_no`, and `actions`. **Validation:** The contract verifies the signature using: check_signature(hash(ref_cell), signature, public_key) **On failure:** Exit code `35`. **Link:** [Ed25519 signature scheme](https://en.wikipedia.org/wiki/EdDSA#Ed25519) * * * ### [​](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#valid_until-64-bits) `valid_until` (64 bits) **Purpose:** Unix timestamp (seconds) when the external message expires. **Validation:** The contract performs a single check: now() > valid_until // Message expired **On failure:** Exit code `34`. **Why it matters:** Prevents replay of expired messages. If `now() > valid_until`, the message is considered expired and rejected. **Recommendation:** Set `valid_until` to 1 minute (60 seconds) from message creation time. * * * ### [​](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#seq_no-16-bits-2) `seq_no` (16 bits) **Purpose:** Expected sequence number for this message. **Validation:** Must match the current `seq_no` stored in contract storage. **On mismatch:** Exit code `33`. ### [​](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#actions-reference-cell) `actions` (reference cell) **Structure:** A serialized `OutList` containing up to 255 actions to execute. **Validation:** No validation. **Supported actions:** All standard TVM actions are supported without restrictions: * `action_send_msg` — Send messages * `action_set_code` — Update contract code * `action_reserve_currency` — Reserve currency * `action_change_library` — Change library **Maximum actions:** 255 (maximum number of out actions in TON) [​](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#replay-protection-mechanism) Replay protection mechanism ----------------------------------------------------------------------------------------------------------------------------------- Preprocessed Wallet V2 uses sequence numbers and time-based expiration to prevent replay attacks. ### [​](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#sequence-number-protection) Sequence number protection **How it works:** 1. Each message must contain the correct `seq_no` 2. After successful processing, `seq_no` is incremented 3. Old messages with incorrect sequence numbers are rejected **Overflow protection:** * Uses modulo 2^16 operation: `(seq_no + 1) % 65536` * Wraps from 65535 to 0 ### [​](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#time-based-expiration) Time-based expiration **How it works:** 1. Each message includes `valid_until` timestamp 2. Messages are rejected if `now() > valid_until` 3. Prevents replay of expired messages **Recommended expiration:** * 1 minute (60 seconds) for most use cases * Shorter for high-frequency operations * Longer for batch operations with network delays ### [​](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#wrap%E2%80%91around-and-validity-window) Wrap‑around and validity window When `seq_no` wraps (65535 → 0), previously sent messages that used the same numeric `seq_no` remain non‑applicable if their `valid_until` has already expired. Safety relies on the dual check: current `seq_no` equality and unexpired `valid_until`. Do not set `valid_until` excessively far in the future. A very long validity window increases the chance that, after wrap‑around, an old message with the same `seq_no` is still valid. Keep the window short (for example, ≤ 60 seconds) unless you have a specific operational reason. ### [​](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#signature-verification) Signature verification **How it works:** 1. All messages must be signed with the wallet’s private key 2. Signature covers the entire message content (hash of `MsgInner`) 3. Prevents unauthorized message creation [​](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#exit-codes) Exit codes ------------------------------------------------------------------------------------------------- | Exit code | Name | Description | How to fix | | --- | --- | --- | --- | | `0` | Success | Message processed successfully | — | | `33` | Incorrect sequence number | The `seq_no` in the message does not match storage | Use the correct `seq_no` from contract storage | | `34` | Message expired | The `valid_until` timestamp has passed | Ensure `valid_until >= now()` when creating the message | | `35` | Invalid signature | Ed25519 signature verification failed | Check that the private key is correct and the message hash is computed properly | [​](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#limitations-and-constraints) Limitations and constraints ----------------------------------------------------------------------------------------------------------------------------------- ### [​](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#maximum-actions-per-transaction) Maximum actions per transaction **Limitation:** Each external message can trigger up to 255 actions. **Why this limitation?** 255 is the maximum number of out actions supported by TON blockchain. This is a fundamental limitation of the TVM execution environment. **Impact:** Suitable for batch operations with up to 255 actions per transaction. [​](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#implementation) Implementation --------------------------------------------------------------------------------------------------------- ### [​](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#source-code) Source code * Repository: - [pyAndr3w/ton-preprocessed-wallet-v2](https://github.com/pyAndr3w/ton-preprocessed-wallet-v2) [​](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#see-also) See also --------------------------------------------------------------------------------------------- * [How to interact with Preprocessed Wallet V2](https://docs.ton.org/standard/wallets/preprocessed-v2/interact) Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/standard/wallets/preprocessed-v2/specification.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/standard/wallets/preprocessed-v2/specification) [Previous](https://docs.ton.org/standard/wallets/lockup) [How to interact with Preprocessed Wallet V2\ \ Next](https://docs.ton.org/standard/wallets/preprocessed-v2/interact) ⌘I On this page * [Objective](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#objective) * [What is Preprocessed Wallet V2?](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#what-is-preprocessed-wallet-v2) * [TL-B schema](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#tl-b-schema) * [Storage structure](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#storage-structure) * [External message structure](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#external-message-structure) * [Storage structure](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#storage-structure-2) * [pub\_key (256 bits)](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#pub_key-256-bits) * [seq\_no (16 bits)](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#seq_no-16-bits) * [External message structure](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#external-message-structure-2) * [Message layout](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#message-layout) * [sign (512 bits)](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#sign-512-bits) * [valid\_until (64 bits)](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#valid_until-64-bits) * [seq\_no (16 bits)](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#seq_no-16-bits-2) * [actions (reference cell)](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#actions-reference-cell) * [Replay protection mechanism](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#replay-protection-mechanism) * [Sequence number protection](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#sequence-number-protection) * [Time-based expiration](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#time-based-expiration) * [Wrap‑around and validity window](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#wrap%E2%80%91around-and-validity-window) * [Signature verification](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#signature-verification) * [Exit codes](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#exit-codes) * [Limitations and constraints](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#limitations-and-constraints) * [Maximum actions per transaction](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#maximum-actions-per-transaction) * [Implementation](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#implementation) * [Source code](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#source-code) * [See also](https://docs.ton.org/standard/wallets/preprocessed-v2/specification#see-also) --- # How to interact with Preprocessed Wallet V2 - TON Docs [Skip to main content](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Preprocessed Wallet V2 How to interact with Preprocessed Wallet V2 This guide shows how to deploy Preprocessed Wallet V2 and send transfers. [​](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#objective) Objective ------------------------------------------------------------------------------------------ By the end of this guide, you will: * Create a Preprocessed Wallet V2 instance from scratch * Deploy the wallet on-chain * Send single and batch transfers [​](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#prerequisites) Prerequisites -------------------------------------------------------------------------------------------------- * Node.js 18+ or TypeScript environment * `@ton/ton`, `@ton/core`, `@ton/crypto` packages installed * Preprocessed Wallet V2 wrapper and compiled contract code This guide uses TypeScript with the official wrapper. The same logic applies to other SDKs (Go/Python): generate or load a mnemonic, derive a keypair, and calculate the address. [​](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#step-1-set-up-dependencies) Step 1: Set up dependencies ----------------------------------------------------------------------------------------------------------------------------- Install required packages: npm install @ton/ton @ton/core @ton/crypto Copy the wrapper and contract code from the [official repository](https://github.com/pyAndr3w/ton-preprocessed-wallet-v2) : # Clone the repository or download this file: # - typescript/wrappers/PreprocessedWalletV2.ts [​](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#step-2-generate-or-load-a-mnemonic) Step 2: Generate or load a mnemonic --------------------------------------------------------------------------------------------------------------------------------------------- A mnemonic is your wallet’s master secret. It derives the private key used to sign all transactions. ### [​](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#generate-a-new-mnemonic) Generate a new mnemonic import { mnemonicNew } from '@ton/crypto'; const mnemonic = await mnemonicNew(24); // Array of 24 words ### [​](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#load-an-existing-mnemonic) Load an existing mnemonic const mnemonic = 'word1 word2 word3 ... word24'.split(' '); [​](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#step-3-derive-the-keypair) Step 3: Derive the keypair --------------------------------------------------------------------------------------------------------------------------- Convert the mnemonic to an Ed25519 keypair: import { mnemonicToPrivateKey } from '@ton/crypto'; const keyPair = await mnemonicToPrivateKey(mnemonic); // keyPair.publicKey — used in contract state // keyPair.secretKey — used to sign external messages [​](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#step-4-create-the-wallet-instance) Step 4: Create the wallet instance ------------------------------------------------------------------------------------------------------------------------------------------- Create a Preprocessed Wallet V2 contract instance: import { TonClient } from '@ton/ton'; import { Cell } from '@ton/core'; import { Wallet, walletCode } from './wrappers/PreprocessedWalletV2'; // Compiled contract code (BoC) const CODE = walletCode; // Already included in the wrapper const client = new TonClient({ endpoint: 'https://testnet.toncenter.com/api/v2/jsonRPC', // This is TESTNET endpoint // apiKey: 'your-api-key' // Optional: get from @tonapibot or @tontestnetapibot }); const wallet = client.open( Wallet.createFromPublicKey(keyPair.publicKey) ); [​](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#step-5-get-the-wallet-address) Step 5: Get the wallet address ----------------------------------------------------------------------------------------------------------------------------------- Calculate the wallet’s address: // Get non-bounceable address for funding const address = wallet.address.toString({ bounceable: false, testOnly: true }); console.log('Wallet address:', address); // Example (truncated): 0Q... (non-bounceable, testnet) This address is deterministic: it depends only on `CODE` and `publicKey`. The same parameters always produce the same address. **Account status: [`nonexist`](https://docs.ton.org/foundations/status#status-variety) ** The calculated address exists only as a deterministic value. No account exists on the blockchain yet — no balance, no code, no data. * * * [​](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#step-6-fund-the-wallet) Step 6: Fund the wallet --------------------------------------------------------------------------------------------------------------------- **Required before deployment:** Send TON to your wallet address (from Step 5) to prepare it for deployment. External messages (which deploy the wallet) require gas to execute. By funding the address, you transition the account from `nonexist` to `uninit` status and provide the balance needed for deployment. See [Account statuses](https://docs.ton.org/foundations/status) for details on how account states work. Send TON using a faucet (testnet) or from another wallet (mainnet). After funding, the account transitions to `uninit` status — it has a balance and can accept external messages, but no code or data yet. * * * [​](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#step-7-send-messages) Step 7: Send messages ----------------------------------------------------------------------------------------------------------------- ### [​](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#send-single-transfers) Send single transfers import { Address, toNano } from '@ton/ton'; import { beginCell } from '@ton/core'; // Get current sequence number const currentSeqno = Number(await wallet.getSeqno()); // Send a single transfer await wallet.sendTransfers(keyPair, [{\ to: Address.parse('EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c'), // Zero address for testing\ value: toNano('0.01'),\ bounce: false\ }], currentSeqno); console.log('Transfer sent'); ### [​](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#send-batch-transfers) Send batch transfers import { Address, toNano, comment } from '@ton/ton'; // Get current sequence number const currentSeqno = Number(await wallet.getSeqno()); // Create multiple transfers with similar structure const transfers = []; for (let i = 0; i < 5; i++) { transfers.push({ to: Address.parse('EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c'), value: toNano('0.01'), body: comment(`#${i}`) }); } // Send batch transfers await wallet.sendTransfers(keyPair, transfers, currentSeqno); console.log('Batch transfers sent'); Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/standard/wallets/preprocessed-v2/interact.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/standard/wallets/preprocessed-v2/interact) [Previous](https://docs.ton.org/standard/wallets/preprocessed-v2/specification) [Restricted wallet\ \ Next](https://docs.ton.org/standard/wallets/restricted) ⌘I On this page * [Objective](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#objective) * [Prerequisites](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#prerequisites) * [Step 1: Set up dependencies](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#step-1-set-up-dependencies) * [Step 2: Generate or load a mnemonic](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#step-2-generate-or-load-a-mnemonic) * [Generate a new mnemonic](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#generate-a-new-mnemonic) * [Load an existing mnemonic](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#load-an-existing-mnemonic) * [Step 3: Derive the keypair](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#step-3-derive-the-keypair) * [Step 4: Create the wallet instance](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#step-4-create-the-wallet-instance) * [Step 5: Get the wallet address](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#step-5-get-the-wallet-address) * [Step 6: Fund the wallet](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#step-6-fund-the-wallet) * [Step 7: Send messages](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#step-7-send-messages) * [Send single transfers](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#send-single-transfers) * [Send batch transfers](https://docs.ton.org/standard/wallets/preprocessed-v2/interact#send-batch-transfers) --- # Highload Wallet v2 — specification - TON Docs [Skip to main content](https://docs.ton.org/standard/wallets/highload/v2/specification#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Highload Wallet v2 Highload Wallet v2 — specification This page provides a complete technical specification for Highload Wallet v2, covering storage structure, message formats, replay protection, and limitations. [​](https://docs.ton.org/standard/wallets/highload/v2/specification#what-is-highload-wallet-v2) What is Highload Wallet v2? ------------------------------------------------------------------------------------------------------------------------------ Highload Wallet v2 is a specialized wallet contract designed for services that need to send many transactions in a short time. It uses dictionary-based replay protection to enable parallel transaction submission. **Key difference from standard wallets:** Unlike seqno-based wallets that require sequential transaction processing, Highload v2 stores processed request identifiers in a dictionary, enabling parallel submissions. **Replaced by:** [Highload Wallet v3](https://docs.ton.org/standard/wallets/highload/v3/specification) [​](https://docs.ton.org/standard/wallets/highload/v2/specification#tl-b-schema) TL-B schema ----------------------------------------------------------------------------------------------- [TL-B (Type Language - Binary)](https://docs.ton.org/languages/tl-b/overview) is a domain-specific language designed to describe data structures in TON. The schemas below define the binary layout of the contract’s storage and external messages. ### [​](https://docs.ton.org/standard/wallets/highload/v2/specification#storage-structure) Storage structure storage$_ subwallet_id:uint32 last_cleaned:uint64 public_key:bits256 queries:(HashmapE 64 Cell) = Storage; ### [​](https://docs.ton.org/standard/wallets/highload/v2/specification#query-id-structure) Query ID structure _ query_id:uint64 = QueryId; ### [​](https://docs.ton.org/standard/wallets/highload/v2/specification#external-message-structure) External message structure _ mode:uint8 message:^Cell = OutListNode; msg_body$_ signature:bits512 subwallet_id:uint32 query_id:uint64 messages:(HashmapE 16 Cell) = ExternalInMsgBody; [​](https://docs.ton.org/standard/wallets/highload/v2/specification#storage-structure-2) Storage structure ------------------------------------------------------------------------------------------------------------- The Highload Wallet v2 contract stores four persistent fields (in this order): ### [​](https://docs.ton.org/standard/wallets/highload/v2/specification#subwallet_id-32-bits) `subwallet_id` (32 bits) **Purpose:** Allows a single keypair to control multiple wallets with different addresses. **How it works:** The `subwallet_id` is part of the contract’s initial state. Changing it produces a different contract address. Each external message must include the correct `subwallet_id`; mismatches result in transaction failure. * * * ### [​](https://docs.ton.org/standard/wallets/highload/v2/specification#last_cleaned-64-bits) `last_cleaned` (64 bits) **Purpose:** Timestamp (in query\_id format) of the oldest query that was kept during the last cleanup. **How it works:** During each transaction, the contract removes queries older than **64 seconds** from the `queries` dictionary. The `last_cleaned` field tracks the last query ID that was removed. **Cleanup logic:** bound -= (64 << 32); // Clean up records expired more than 64 seconds ago Queries with `query_id < (now() - 64) << 32` are removed from storage. * * * ### [​](https://docs.ton.org/standard/wallets/highload/v2/specification#public_key-256-bits) `public_key` (256 bits) **Purpose:** The Ed25519 public key is used to verify signatures on incoming external messages. **How it works:** When the wallet receives an external message, it verifies that the 512-bit signature was created by the holder of the private key corresponding to this public key. * * * ### [​](https://docs.ton.org/standard/wallets/highload/v2/specification#queries-hashmape-64-cell) `queries` (HashmapE 64 Cell) **Purpose:** Stores processed `query_id` values for replay protection. **Structure:** * **Key:** 64-bit `query_id` * **Value:** Cell containing metadata (typically the timestamp when processed) **How it works:** Before processing a message, the contract checks if `query_id` exists in `queries`. If found, the message is rejected (replay attack). If not found, the `query_id` is added to `queries`, and the message is processed. [​](https://docs.ton.org/standard/wallets/highload/v2/specification#external-message-structure-2) External message structure ------------------------------------------------------------------------------------------------------------------------------- ### [​](https://docs.ton.org/standard/wallets/highload/v2/specification#message-layout) Message layout signature:bits512 subwallet_id:uint32 query_id:uint64 messages:(HashmapE 16 Cell) **Key point:** Unlike v3, in v2 the signature is in the **same cell** as the message body, not in a separate reference cell. ### [​](https://docs.ton.org/standard/wallets/highload/v2/specification#signature-512-bits) `signature` (512 bits) **Type:** Ed25519 signature (512 bits). **What is signed:** The hash of the remaining slice after the signature, containing `subwallet_id`, `query_id`, and `messages`. **From source code:** throw_unless(35, check_signature(slice_hash(in_msg), signature, public_key)); The contract uses `slice_hash()` on the message body after loading the signature. * * * ### [​](https://docs.ton.org/standard/wallets/highload/v2/specification#subwallet_id-32-bits-2) `subwallet_id` (32 bits) **Purpose:** Identifies which subwallet this message targets. **Validation:** Must match the `subwallet_id` stored in contract storage. * * * ### [​](https://docs.ton.org/standard/wallets/highload/v2/specification#query_id-64-bits) `query_id` (64 bits) **Purpose:** Unique identifier for replay protection and timestamp validation. **Structure:** The 64-bit value is internally interpreted as a timestamped identifier: * High 32 bits: Unix timestamp (seconds) * Low 32 bits: counter within that second **Validation:** The contract checks `query_id >= now() << 32`, ensuring the query ID is not from the past (based on the current time shifted left by 32 bits). **Total unique IDs:** Approximately **32,000** unique query IDs (limited by the cleanup mechanism and the bitmap structure). * * * ### [​](https://docs.ton.org/standard/wallets/highload/v2/specification#messages-hashmape-16) `messages` (HashmapE 16) **Purpose:** Dictionary of messages to send in this transaction. **Structure:** * **Key:** `uint16` (message index, 0 to 65,535) * **Value:** `mode:uint8` + `^Cell` (reference to internal message) **How it works:** The contract iterates through the dictionary and sends each message with its corresponding [send mode](https://docs.ton.org/foundations/messages/modes) : int i = -1; do { (i, var cs, var f) = dict.idict_get_next?(16, i); if (f) { var mode = cs~load_uint(8); send_raw_message(cs~load_ref(), mode); } } until (~ f); **Max batch size:** Up to **255 messages** (limited by action list size, not dictionary structure). * * * [​](https://docs.ton.org/standard/wallets/highload/v2/specification#replay-protection-mechanism) Replay protection mechanism ------------------------------------------------------------------------------------------------------------------------------- ### [​](https://docs.ton.org/standard/wallets/highload/v2/specification#validation-sequence) Validation sequence 1. **Check query\_id timestamp:** `query_id >= now() << 32` (exit code `35` if too old) 2. **Check replay:** `query_id` must not be in `queries` (exit code `32` if already processed) 3. **Check subwallet:** `subwallet_id == stored_subwallet` (exit code `34` if mismatch) 4. **Verify signature:** Ed25519 signature verification (exit code `35` if invalid) 5. **Mark as processed:** Add `query_id` to `queries` 6. **Send messages:** Iterate through the message dictionary and send each message 7. **Cleanup:** Remove queries older than 64 seconds * * * [​](https://docs.ton.org/standard/wallets/highload/v2/specification#exit-codes) Exit codes --------------------------------------------------------------------------------------------- | Exit code | Name | Description | How to fix | | --- | --- | --- | --- | | `0` | Success | Message processed successfully | — | | `32` | Query already executed | The `query_id` was already processed (found in `queries`) | Use a new, unique `query_id` | | `34` | Subwallet ID mismatch | The `subwallet_id` in the message does not match storage | Verify you are using the correct `subwallet_id` for this wallet | | `35` | Invalid signature or query\_id | Ed25519 signature verification failed, or `query_id` is too old | Check the private key and ensure `query_id >= now() << 32` | * * * [​](https://docs.ton.org/standard/wallets/highload/v2/specification#limitations-and-constraints) Limitations and constraints ------------------------------------------------------------------------------------------------------------------------------- ### [​](https://docs.ton.org/standard/wallets/highload/v2/specification#storage-size-limit) Storage size limit **Limit:** The `queries` dictionary cannot exceed **65,535 cells**. **What happens if exceeded:** An exception is thrown during the action phase, and the transaction fails. The failed transaction may be replayed, potentially locking funds. ### [​](https://docs.ton.org/standard/wallets/highload/v2/specification#gas-limit-for-cleanup) Gas limit for cleanup **Limit:** Transaction gas limit is **1,000,000 gas**. **What happens if exceeded:** Cleanup operations that exceed this limit will fail, preventing the contract from processing new transactions. **Recommended limits:** * Queries within expiration window: ≤ 1,000 * Queries cleaned per transaction: ≤ 100 ### [​](https://docs.ton.org/standard/wallets/highload/v2/specification#query-id-expiration) Query ID expiration **Expiration time:** Queries older than **64 seconds** are removed from storage during cleanup. **Effective limit:** With the 64-second expiration window and recommended limit of ≤1,000 queries per window, the effective query ID space is approximately **32,000** unique IDs before cleanup is required. * * * [​](https://docs.ton.org/standard/wallets/highload/v2/specification#get-methods) Get methods ----------------------------------------------------------------------------------------------- | Method | Returns | Description | | --- | --- | --- | | `processed?(query_id)` | `int` | Returns `-1` if processed, `0` if not processed, `1` if unknown (forgotten after cleanup) | | `get_public_key()` | `int` (256 bits) | Returns the Ed25519 public key | ### [​](https://docs.ton.org/standard/wallets/highload/v2/specification#processed-method-details) `processed?` method details **Returns:** * `-1` (true) — the `query_id` was processed and is still stored in `queries` * `0` (false) — the `query_id` has not been processed yet * `1` (unknown) — the `query_id` is older than `last_cleaned` and was forgotten during cleanup * * * [​](https://docs.ton.org/standard/wallets/highload/v2/specification#implementation) Implementation ----------------------------------------------------------------------------------------------------- **Source code:** [ton-blockchain/ton (highload-wallet-v2-code.fc)](https://github.com/ton-blockchain/ton/blob/4ebd7412c52248360464c2df5f434c8aaa3edfe1/crypto/smartcont/highload-wallet-v2-code.fc) **SDK wrappers:** * **Go:** [`tonutils-go`](https://github.com/xssnick/tonutils-go) — includes Highload v2 wrapper * **Python:** [`pytoniq`](https://github.com/yungwine/pytoniq) — includes Highload v2 wrapper For new projects, consider using [Highload Wallet v3](https://docs.ton.org/standard/wallets/highload/v3/specification) instead. * * * [​](https://docs.ton.org/standard/wallets/highload/v2/specification#see-also) See also ----------------------------------------------------------------------------------------- * [Highload Wallet v3 specification](https://docs.ton.org/standard/wallets/highload/v3/specification) — recommended version * [Version comparison](https://docs.ton.org/standard/wallets/highload/overview#version-comparison) — v1 vs v2 vs v3 Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/standard/wallets/highload/v2/specification.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/standard/wallets/highload/v2/specification) [Previous](https://docs.ton.org/standard/wallets/highload/v3/specification) [Lockup wallet\ \ Next](https://docs.ton.org/standard/wallets/lockup) ⌘I On this page * [What is Highload Wallet v2?](https://docs.ton.org/standard/wallets/highload/v2/specification#what-is-highload-wallet-v2) * [TL-B schema](https://docs.ton.org/standard/wallets/highload/v2/specification#tl-b-schema) * [Storage structure](https://docs.ton.org/standard/wallets/highload/v2/specification#storage-structure) * [Query ID structure](https://docs.ton.org/standard/wallets/highload/v2/specification#query-id-structure) * [External message structure](https://docs.ton.org/standard/wallets/highload/v2/specification#external-message-structure) * [Storage structure](https://docs.ton.org/standard/wallets/highload/v2/specification#storage-structure-2) * [subwallet\_id (32 bits)](https://docs.ton.org/standard/wallets/highload/v2/specification#subwallet_id-32-bits) * [last\_cleaned (64 bits)](https://docs.ton.org/standard/wallets/highload/v2/specification#last_cleaned-64-bits) * [public\_key (256 bits)](https://docs.ton.org/standard/wallets/highload/v2/specification#public_key-256-bits) * [queries (HashmapE 64 Cell)](https://docs.ton.org/standard/wallets/highload/v2/specification#queries-hashmape-64-cell) * [External message structure](https://docs.ton.org/standard/wallets/highload/v2/specification#external-message-structure-2) * [Message layout](https://docs.ton.org/standard/wallets/highload/v2/specification#message-layout) * [signature (512 bits)](https://docs.ton.org/standard/wallets/highload/v2/specification#signature-512-bits) * [subwallet\_id (32 bits)](https://docs.ton.org/standard/wallets/highload/v2/specification#subwallet_id-32-bits-2) * [query\_id (64 bits)](https://docs.ton.org/standard/wallets/highload/v2/specification#query_id-64-bits) * [messages (HashmapE 16)](https://docs.ton.org/standard/wallets/highload/v2/specification#messages-hashmape-16) * [Replay protection mechanism](https://docs.ton.org/standard/wallets/highload/v2/specification#replay-protection-mechanism) * [Validation sequence](https://docs.ton.org/standard/wallets/highload/v2/specification#validation-sequence) * [Exit codes](https://docs.ton.org/standard/wallets/highload/v2/specification#exit-codes) * [Limitations and constraints](https://docs.ton.org/standard/wallets/highload/v2/specification#limitations-and-constraints) * [Storage size limit](https://docs.ton.org/standard/wallets/highload/v2/specification#storage-size-limit) * [Gas limit for cleanup](https://docs.ton.org/standard/wallets/highload/v2/specification#gas-limit-for-cleanup) * [Query ID expiration](https://docs.ton.org/standard/wallets/highload/v2/specification#query-id-expiration) * [Get methods](https://docs.ton.org/standard/wallets/highload/v2/specification#get-methods) * [processed? method details](https://docs.ton.org/standard/wallets/highload/v2/specification#processed-method-details) * [Implementation](https://docs.ton.org/standard/wallets/highload/v2/specification#implementation) * [See also](https://docs.ton.org/standard/wallets/highload/v2/specification#see-also) --- # FunC comments - TON Docs [Skip to main content](https://docs.ton.org/languages/func/comments#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Language FunC comments FunC supports both single-line and multi-line comments. **Single-line** comments start with a double semicolon `;;`. For example: int x = 1; ;; assigns 1 to x **Multi-line** comments begin with an opening curly brace and dash `{-` and end with a dash and closing curly brace `-}`. Unlike other languages, FunC allows **nested multi-line comments**. Example: {- This is a multi-line comment {- This is a comment inside a comment -} -} Single-line comments `;;` can also appear inside multi-line comments. They take precedence over the multi-line comments `{- -}`. For example, in the following snippet, `const a = 10;` is inside a multi-line comment and is effectively commented out: {- Start of the comment ;; This comment’s ending is itself commented out -> -} const a = 10; ;; This comment’s beginning is itself commented out -> {- End of the comment -} Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/languages/func/comments.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/languages/func/comments) [Previous](https://docs.ton.org/languages/func/cookbook) [Types\ \ Next](https://docs.ton.org/languages/func/types) ⌘I --- # FunC global variables - TON Docs [Skip to main content](https://docs.ton.org/languages/func/global-variables#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Program declarations FunC global variables [​](https://docs.ton.org/languages/func/global-variables#definition) Definition ---------------------------------------------------------------------------------- **A global variable** is a variable that can be read and assigned at any function in the entire program, including functions declared in other `.fc` files, as long as those `.fc` files are [imported](https://docs.ton.org/languages/func/compiler-directives#%23include) after the global variable [declaration](https://docs.ton.org/languages/func/global-variables#declaration) . It is possible to use global variables imported from other `.fc` files. Global variables are useful for remembering values across functions, without the need to pass those values as arguments to every single function in the program. Under the hood, global variables in FunC are stored inside the tuple of the [`c7` TVM control register](https://docs.ton.org/foundations/whitepapers/tvm#1-3-2-list-of-control-registers) , with a maximum limit of 31 variables. [​](https://docs.ton.org/languages/func/global-variables#declaration) Declaration ------------------------------------------------------------------------------------ Global variables are declared using the `global` keyword, followed by the variable’s type and name. For example: global ((int, int) -> int) op; This defines global variable `op` of type `(int, int) -> int`. In other words, `op` can store a function that receives two arguments and returns an integer. Here is an example that uses global variable `op`: global ((int, int) -> int) op; int check_commutative(int a, int b) { return op(a, b) == op(b, a); } int add(int a, int b) { return a + b; } int main() { op = add; return check_commutative(2, 3); } The example defines two auxiliary functions: `check_commutative` and `add`, in addition to the program entry point [`main`](https://docs.ton.org/languages/func/special-functions#main) . Function `check_commutative` checks if the operator stored in the global variable `op` satisfies the commutative property for the specified inputs `a` and `b`. Function `add`, adds its two inputs. Function `main` assigns the addition function `add` to the global variable `op`. Then, it verifies the commutativity of addition for the specific values: `2`, `3`. In FunC, you can _omit the type_ of global variables. In this case, the compiler determines the type based on how the variable is used. Equivalently, instead of declaring the type, you can use the `var` keyword as a replacement for the type. For example, in the previous program you can declare the variable `op` as: global op; or as: global var op; FunC allows declaring global variable multiple times, as long as all the declarations have the same type. The declarations can even happen in different `.fc` files. For example, the following does not compile, because the second declaration changes the type of `A` from `int` to `cell`: global int A; int foo() { return 0; } global cell A; ;; DOES NOT COMPILE, cell should be int [​](https://docs.ton.org/languages/func/global-variables#multiple-declarations) Multiple declarations -------------------------------------------------------------------------------------------------------- FunC allows users to declare multiple global variables using a single `global` keyword. The following example: global int A; global cell B; global C; is equivalent to this: global int A, cell B, C; [​](https://docs.ton.org/languages/func/global-variables#restrictions-on-declarations) Restrictions on declarations ---------------------------------------------------------------------------------------------------------------------- A local variable **cannot** have the same name of a previously declared global variable **but only if their types differ**. The following example does not compile, because the local variable `C` of type `int` has the same name as the global variable `C` of type `cell`, and `int` and `cell` are different types. global cell C; int main() { int C = 3; ;; DOES NOT COMPILE return C; } However, if the local variable and the global variable have the same type and the same name, the declaration of the local variable actually means assignment to the global variable. For example, global int C; int main() { int C = 3; return C; } In this case, `int C = 3;` is not declaring a new local variable, but instead assigning value `3` to the global variable `C`. Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/languages/func/global-variables.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/languages/func/global-variables) [Previous](https://docs.ton.org/languages/func/asm-functions) [Compiler directives\ \ Next](https://docs.ton.org/languages/func/compiler-directives) ⌘I On this page * [Definition](https://docs.ton.org/languages/func/global-variables#definition) * [Declaration](https://docs.ton.org/languages/func/global-variables#declaration) * [Multiple declarations](https://docs.ton.org/languages/func/global-variables#multiple-declarations) * [Restrictions on declarations](https://docs.ton.org/languages/func/global-variables#restrictions-on-declarations) --- # FunC assembler functions - TON Docs [Skip to main content](https://docs.ton.org/languages/func/asm-functions#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Program declarations FunC assembler functions [​](https://docs.ton.org/languages/func/asm-functions#assembler-function-definition) Assembler function definition --------------------------------------------------------------------------------------------------------------------- In FunC, functions can be defined directly using assembler code. This is done by declaring the function body using the `asm` keyword, followed by one or more assembler commands written inside double quotes `"`, and finalizing with the symbol `;`. For example, the following function increments an integer and then negates it: int inc_then_negate(int x) asm "INC" "NEGATE"; Calls to `inc_then_negate` are translated to 2 assembler commands `INC` and `NEGATE`. Alternatively, the function can be written as: int inc_then_negate'(int x) asm "INC NEGATE"; Here, `INC NEGATE` is treated as a single assembler command by FunC, but the Fift assembler correctly interprets it as two separate commands. ### [​](https://docs.ton.org/languages/func/asm-functions#multi-line-asms) Multi-line asms Multi-line assembler commands, including Fift code snippets, can be defined using triple-quoted strings `"""`. For instance: slice hello_world() asm """ "Hello" " " "World" $+ $+ $>s PUSHSLICE """; [​](https://docs.ton.org/languages/func/asm-functions#stack-calling-conventions) Stack calling conventions ------------------------------------------------------------------------------------------------------------- The syntax for arguments and returns is the same as for standard functions, but there is one caveat - argument values are pushed onto the stack before the function body is executed, and the return type is what is captured from the stack afterward. ### [​](https://docs.ton.org/languages/func/asm-functions#arguments) Arguments When calling an asm function, the first argument is pushed onto the stack first, the second one second, and so on, so that the first argument is at the bottom of the stack and the last one at the top. builder storeCoins(builder b, int value) asm "STVARUINT16"; ;; | | ;; | Pushed last, sits on top of the stack ;; | ;; Pushed first, sits at the bottom of the stack ;; The instruction "STVARUINT16" stores ;; integer "value" into builder "b", ;; by taking the builder from the bottom of the stack ;; and the integer from the top of the stack, ;; producing a new builder at the top of the stack. ### [​](https://docs.ton.org/languages/func/asm-functions#returns) Returns An assembler function’s return type attempts to grab relevant values from the resulting stack after the function execution and any [result rearrangements](https://docs.ton.org/languages/func/asm-functions#rearranging-stack-entries) . Specifying an [atomic type](https://docs.ton.org/languages/func/types#atomic-types) , such as an `int`, `cell`, or `builder`, will make the assembler function capture the top value from the stack. For example, in the following function: builder storeCoins(builder b, int value) asm "STVARUINT16"; the instruction `STVARUINT16` produces a final builder at the top of the stack, which is returned by the `storeCoins` function. Specifying a [tensor type](https://docs.ton.org/languages/func/types#tensor-types) as a return type, such as `(int, int)`, will cause the assembler function to take as many elements from the stack as the number of components in the tensor type. If the tensor type has nested tensor types, like `((int, int), int)`, it is interpreted as if it was the flattened tensor type `(int, int, int)`. For example, this function duplicates its input, so that if the input is `5`, it returns the tensor `(5, 5)`: (int, int) duplicate(int a) asm "DUP"; ;; ;; DUP reads the value at the top of the stack ;; and pushes a copy. ;; ;; Since the return type is (int, int), ;; the function takes the first two values in the stack ;; and returns them. [​](https://docs.ton.org/languages/func/asm-functions#stack-registers) Stack registers ========================================================================================= The so-called _stack registers_ are a way of referring to the values at the top of the stack. In total, there are 256 stack registers, i.e., values held on the stack at any given time. Register `s0` is the value at the top of the stack, register `s1` is the value immediately after it, and so on, until we reach the bottom of the stack, represented by `s255`, i.e., the 256th stack register. When a value `x` is pushed onto the stack, it becomes the new `s0`. At the same time, the old `s0` becomes the new `s1`, the old `s1` becomes the new `s2`, and so on. int takeSecond(int a, int b) asm "SWAP" "DROP"; ;; ↑ ↑ ;; | Pushed last, sits on top of the stack ;; Pushed first, sits second from the top of the stack ;; SWAP interchanges s0 (top of the stack) with s1 (second-to-top) ;; ;; Before │ After ;; ───────┼─────── ;; s0 = b │ s0 = a ;; s1 = a │ s1 = b ;; Then, DROP pops the value from the top of the stack and throws it away ;; ;; Before │ After ;; ───────┼─────── ;; s0 = a │ s0 = b ;; s1 = b │ s1 is now either some value deeper or just blank ;; At the end, we have only one value on the stack, which is b ;; Thus, it is captured by the return type `int`: int showcase() { return takeSecond(5, 10); ;; 10, i.e., b } [​](https://docs.ton.org/languages/func/asm-functions#rearranging-stack-entries) Rearranging stack entries ------------------------------------------------------------------------------------------------------------- Sometimes, the order in which function arguments are passed may not match the expected order of an assembler command. Similarly, the returned values may need to be arranged differently. While this can be done manually using stack manipulation primitives, FunC has special syntax to handle this. Considering arrangements, the evaluation flow of the assembly function can be thought of in these 5 steps: 1. The function takes arguments in the order specified by the parameters. 2. If an argument arrangement is present, arguments are reordered before being pushed onto the stack. 3. The function body is executed. 4. If a result arrangement is present, resulting values are reordered on the stack. 5. The resulting values are captured (partially or fully) by the return type of the function. The argument arrangement has the syntax `asm(arg2 arg1)`, where `arg1` and `arg2` are some arguments of the function arranged in the order we want to push them onto the stack: `arg1` will be pushed first and placed at the bottom of the stack, while `arg2` will be pushed last and placed at the top of the stack. Arrangements are not limited to two arguments and operate on all parameters of the function: ;; Changing the order of arguments to match the STDICT signature: ;; `c` will be pushed first and placed at the bottom of the stack, ;; while `b` will be pushed last and placed at the top of the stack builder asmStoreDict(builder b, cell c) asm(c b) "STDICT"; The return arrangement has the syntax `asm(-> 1 0)`, where 1 and 0 represent a left-to-right reordering of [stack registers](https://docs.ton.org/languages/func/asm-functions#stack-registers) `s1` and `s0`, respectively. The contents of `s1` will be at the top of the stack, followed by the contents of `s0`. Arrangements are not limited to two return values and operate on captured values: ;; Changing the order of return values of LDVARUINT16 instruction, ;; since originally it would place the modified Slice on top of the stack (slice, int) asmLoadCoins(slice s) asm(-> 1 0) "LDVARUINT16"; ;; ↑ ↑ ;; | Value of the stack register 0, ;; | which is the topmost value on the stack ;; Value of the stack register 1, ;; which is the second-to-top value on the stack Both argument and return arrangement can be combined together and written as follows: `asm(arg2 arg1 -> 1 0)`. ;; Changing the order of return values compared to the stack ;; and switching the order of arguments as well (slice, int) asmLoadInt(int len, slice s) asm(s len -> 1 0) "LDIX"; ;; ↑ ↑ ;; | Value of the stack register 0, ;; | which is the topmost value on the stack ;; Value of the stack register 1, ;; which is the second-to-top value on the stack Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/languages/func/asm-functions.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/languages/func/asm-functions) [Previous](https://docs.ton.org/languages/func/special-functions) [Global variables\ \ Next](https://docs.ton.org/languages/func/global-variables) ⌘I On this page * [Assembler function definition](https://docs.ton.org/languages/func/asm-functions#assembler-function-definition) * [Multi-line asms](https://docs.ton.org/languages/func/asm-functions#multi-line-asms) * [Stack calling conventions](https://docs.ton.org/languages/func/asm-functions#stack-calling-conventions) * [Arguments](https://docs.ton.org/languages/func/asm-functions#arguments) * [Returns](https://docs.ton.org/languages/func/asm-functions#returns) * [Stack registers](https://docs.ton.org/languages/func/asm-functions#stack-registers) * [Rearranging stack entries](https://docs.ton.org/languages/func/asm-functions#rearranging-stack-entries) --- # FunC operators - TON Docs [Skip to main content](https://docs.ton.org/languages/func/operators#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Language FunC operators This page lists all the operators in FunC in decreasing order of their precedence, with examples of usage. [​](https://docs.ton.org/languages/func/operators#table-of-operators) Table of operators ------------------------------------------------------------------------------------------- The following table lists operators in order of decreasing precedence, from highest to lowest. | Brief description | Operators | | --- | --- | | Parentheses | [`(` `)`](https://docs.ton.org/languages/func/operators#parentheses) | | Unary bitwise NOT | [`~`](https://docs.ton.org/languages/func/operators#bitwise-not%2C) | | Multiplicative | [`*`](https://docs.ton.org/languages/func/operators#multiplication%2C)
[`/`](https://docs.ton.org/languages/func/operators#division%2C-%2F)
[`^/`](https://docs.ton.org/languages/func/operators#ceiling-division%2C-%5E%2F)
[`~/`](https://docs.ton.org/languages/func/operators#rounding-division%2C-%2F)
[`%`](https://docs.ton.org/languages/func/operators#modulo%2C-%25)
[`^%`](https://docs.ton.org/languages/func/operators#ceiling-modulo%2C-%5E%25)
[`~%`](https://docs.ton.org/languages/func/operators#rounding-modulo%2C-%25)
[`/%`](https://docs.ton.org/languages/func/operators#division-and-modulo%2C-%2F%25)
[`&`](https://docs.ton.org/languages/func/operators#bitwise-and%2C-%26) | | Unary integer negation | [`-`](https://docs.ton.org/languages/func/operators#negation%2C) | | Additive | [`+`](https://docs.ton.org/languages/func/operators#addition%2C-%2B)
[`-`(integer subtraction)](https://docs.ton.org/languages/func/operators#subtraction%2C)
[`\|`](https://docs.ton.org/languages/func/operators#bitwise-or%2C-%7C)
[`^`](https://docs.ton.org/languages/func/operators#bitwise-xor%2C-%5E) | | Shifts | [`>>`](https://docs.ton.org/languages/func/operators#shift-right%2C-%3E%3E)
[`<<`](https://docs.ton.org/languages/func/operators#shift-left%2C-%3C%3C)
[`^>>`](https://docs.ton.org/languages/func/operators#ceiling-shift-right%2C-%5E%3E%3E)
[`~>>`](https://docs.ton.org/languages/func/operators#rounding-shift-right%2C-%3E%3E) | | Comparison and Equality | [`>`](https://docs.ton.org/languages/func/operators#greater-than%2C-%3E)
[`>=`](https://docs.ton.org/languages/func/operators#greater-than-or-equal%2C-%3E%3D)
[`<`](https://docs.ton.org/languages/func/operators#less-than%2C-%3C)
[`<=`](https://docs.ton.org/languages/func/operators#less-than-or-equal%2C-%3C%3D)
[`<=>`](https://docs.ton.org/languages/func/operators#comparison%2C-%3C%3D%3E)
[`==`](https://docs.ton.org/languages/func/operators#equality%2C-%3D%3D)
[`!=`](https://docs.ton.org/languages/func/operators#inequality%2C-%3D) | | Ternary | [`?:`](https://docs.ton.org/languages/func/operators#ternary%2C-%3F%3A) | | Assignment | [`=`](https://docs.ton.org/languages/func/operators#assignment%2C-%3D)
and all [augmented assignment operators](https://docs.ton.org/languages/func/operators#augmented-assignment-operators) | All [binary operators](https://docs.ton.org/languages/func/operators#binary-operators) are left-associative, with the exception of: * [Assignment operators](https://docs.ton.org/languages/func/operators#assignment%2C-%3D) (i.e., bottom row in the table), which are right-associative. * [Division-modulo operator](https://docs.ton.org/languages/func/operators#division-and-modulo%2C-%2F%25) `/%`, which is neither left associative nor right associative. Also, the [ternary operator](https://docs.ton.org/languages/func/operators#ternary%2C-%3F%3A) `?:` is right-associative. For example: * `1 - 2 + 3` parses as `(1 - 2) + 3`, producing `2` as result. * `a = b += c = 10` parses as `(a = (b += (c = 10)))`, producing the final values `c = 10`, `b = 11`, and `a = 11`, under the assumption that `b` had value `1` initially. * `0 ? a : 1 ? b : c` parses as `0 ? a : (1 ? b : c)`, producing `b` as a result. * `3 /% 5 /% 7` does _not_ compile, neither `(3 /% 5) /% 7` nor `3 /% (5 /% 7)`. [​](https://docs.ton.org/languages/func/operators#precedence) Precedence --------------------------------------------------------------------------- Precedence is used to determine which operator should be considered in a particular situation. Whenever ambiguity arises, FunC prefers operators with higher precedence over those with lower precedence. For example, consider this expression: 10 - 6 * 2 The expression is ambiguous because it could be parsed in two different ways: (10 - 6) * 2 ;; Evaluate first 10 - 6 10 - (6 * 2) ;; Evaluate first 6 * 2 However, since the multiplication operator `*` has higher precedence than the subtraction operator `-`, FunC will prefer to evaluate the multiplication first: 10 - (6 * 2) ;; Evaluate first 6 * 2 [​](https://docs.ton.org/languages/func/operators#parentheses) Parentheses ----------------------------------------------------------------------------- Parentheses (also called round brackets, `()`) are more punctuation symbols than actual operators, but their [precedence](https://docs.ton.org/languages/func/operators#precedence) is higher than the precedence of any other operator. Use parentheses to override the order of operations: 5 * 5 - 2; ;; 23 5 * (5 - 2); ;; 15 [​](https://docs.ton.org/languages/func/operators#unary-operators) Unary operators ------------------------------------------------------------------------------------- Unary here means that they are applied only to one operand of the given expression. All unary operators are prefix operators, i.e., placed before the operand. ### [​](https://docs.ton.org/languages/func/operators#bitwise-not) Bitwise NOT, `~` The tilde (bitwise NOT) operator `~` inverts or flips each bit in the binary representation of the expression, changing each `1` to `0`, and vice versa. int answer = 42; ~ answer; ;; -43 ~ (~ answer); ;; 42 ~ (~ 0); ;; 0 The `~` operator also behaves as expected on `-1` and `0`, which are the [emulated values](https://docs.ton.org/languages/func/types#no-boolean-type) for `true` and `false`: ~ 0; ;; -1, NOT false is true ~ (- 1); ;; 0, NOT true is false Hence, `~` can work as [logical NOT](https://en.wikipedia.org/wiki/Negation) when computing boolean conditions: ~ (1 <= 4); ;; 0, since 1 <= 4 returns true (-1) 1 > 4; ;; 0, logically equivalent to previous ### [​](https://docs.ton.org/languages/func/operators#negation) Negation, `-` The minus sign (negation) operator `-` reverses the sign of the expression. int five = 5; - five; ;; -5 - (- five); ;; 5 - (- 1); ;; 1 [​](https://docs.ton.org/languages/func/operators#binary-operators) Binary operators --------------------------------------------------------------------------------------- Binary here means that they are applied to two operands of the given expression. All binary operators are infix operators, i.e., placed in the middle of the two operands. ### [​](https://docs.ton.org/languages/func/operators#multiplication) Multiplication, `*` The asterisk (multiplication) operator `*` is used for multiplication of two values. Going beyond the range of the integer type will result in an error with [exit code 4](https://docs.ton.org/tvm/exit-codes#4%3A-integer-overflow) : `Integer overflow`. int five = 5; five * 2; ;; 10 five * five; ;; 25 ### [​](https://docs.ton.org/languages/func/operators#division-/) Division, `/` The slash (division) operator `/` is used for integer division of two values, which truncates toward zero if the result is positive and away from zero if the result is negative. This is also called [rounding down](https://en.wikipedia.org/wiki/Rounding#Rounding_down) or rounding toward negative infinity. An attempt to divide by zero results in an error with [exit code 4](https://docs.ton.org/tvm/exit-codes#4%3A-integer-overflow) : `Integer overflow`. (- 1) / 5; ;; -1, rounding down away from 0 (- 1) / (- 5); ;; 0, rounding down toward zero 1 / (- 5); ;; -1, rounding down away from 0 1 / 5; ;; 0, rounding down toward 0 6 / 5; ;; 1, rounding down toward 0 (- 6) / 5; ;; -2, rounding down away from 0 ### [​](https://docs.ton.org/languages/func/operators#ceiling-division-^/) Ceiling division, `^/` The caret-slash (ceiling division) operator `^/` is used for integer division of two values, which truncates away from zero if the result is positive and toward zero if the result is negative. This is also called [rounding up](https://en.wikipedia.org/wiki/Rounding#Rounding_up) or rounding toward positive infinity. An attempt to divide by zero results in an error with [exit code 4](https://docs.ton.org/tvm/exit-codes#4%3A-integer-overflow) : `Integer overflow`. (- 1) ^/ 5; ;; 0, rounding up toward 0 (- 1) ^/ (- 5); ;; 1, rounding up away from zero 1 ^/ (- 5); ;; 0, rounding up toward 0 1 ^/ 5; ;; 1, rounding up away from 0 6 ^/ 5; ;; 2, rounding up away from 0 (- 6) ^/ 5; ;; -1, rounding up toward 0 ### [​](https://docs.ton.org/languages/func/operators#rounding-division-/) Rounding division, `~/` The tilde-slash (rounding division) operator `~/` is used for integer division of two values, which truncates to the nearest integer but using the following tie-breaking rule for half values: if the fractional part is `0.5`, it is truncated away from zero if the result is positive, and truncated toward zero if the result is negative. This is also called [rounding half up](https://en.wikipedia.org/wiki/Rounding#Rounding_half_up) or rounding half toward positive infinity. An attempt to divide by zero results in an error with [exit code 4](https://docs.ton.org/tvm/exit-codes#4%3A-integer-overflow) : `Integer overflow`. (- 6) ~/ 5; ;; -1, rounding -1.2 to nearest integer (- 6) ~/ (- 5); ;; 1, rounding 1.2 to nearest integer 8 ~/ (- 5); ;; -2, rounding -1.6 to nearest integer 8 ~/ 5; ;; 2, rounding 1.6 to nearest integer 3 ~/ 2; ;; 2, rounding half value 1.5 away from 0 (- 3) ~/ 2; ;; -1, rounding half value -1.5 toward 0 ### [​](https://docs.ton.org/languages/func/operators#modulo-%) Modulo, `%` The percent sign (modulo) operator `%` is used for obtaining the modulo of integer division, which is the remainder of dividing the operands with the `/` operator. Concretely, `a % b` is defined as `a - (b * (a / b))`, where `/` is the [division operator](https://docs.ton.org/languages/func/operators#division%2C-%2F) , `*` is the [multiplication operator](https://docs.ton.org/languages/func/operators#multiplication%2C) , and `-` is the [subtraction operator](https://docs.ton.org/languages/func/operators#subtraction%2C) . If `b` in the expression `a % b` is `0`, the result is an error with [exit code 4](https://docs.ton.org/tvm/exit-codes#4%3A-integer-overflow) : `Integer overflow`. (- 6) % 5; ;; 4, result of formula: -6 - (5 * (-6 / 5)) (- 6) % (- 5); ;; -1, result of formula: -6 - (-5 * (-6 / -5)) 8 % (- 5); ;; -2, result of formula: 8 - (-5 * (8 / -5)) 8 % 5; ;; 3, result of formula: 8 - (5 * (8 / 5)) 3 % 2; ;; 1, result of formula: 3 - (2 * (3 / 2)) (- 3) % 2; ;; 1, result of formula: -3 - (2 * (-3 / 2)) The result of `%` always has the same sign as the divisor (i.e., `b` is the divisor in the expression `a % b`). This means that the modulo is not the same as the remainder from [Euclidean division](https://en.wikipedia.org/wiki/Euclidean_division) , because in Euclidean division the remainder is always non-negative, independently of the sign of the divisor. The modulo `%` and the remainder from Euclidean division coincide when both operands are non-negative. If you want to compute remainders as in Euclidean division by using the `%` operator, the best way is to use only unsigned integers. Alternatively, consider using the `abs` function to ensure non-negative values: abs(-3) % abs(-4) ;; 3, same as 3 % 4 ### [​](https://docs.ton.org/languages/func/operators#ceiling-modulo-^%) Ceiling modulo, `^%` The caret-percent sign (ceiling modulo) operator `^%` is used for obtaining the ceiling modulo of integer ceiling division, which is the remainder of dividing the operands with the `^/` operator. Concretely, `a ^% b` is defined as `a - (b * (a ^/ b))`, where `^/` is the [ceiling division operator](https://docs.ton.org/languages/func/operators#ceiling-division%2C-%5E%2F) , `*` is the [multiplication operator](https://docs.ton.org/languages/func/operators#multiplication%2C) , and `-` is the [subtraction operator](https://docs.ton.org/languages/func/operators#subtraction%2C) . If `b` in the expression `a ^% b` is `0`, the result is an error with [exit code 4](https://docs.ton.org/tvm/exit-codes#4%3A-integer-overflow) : `Integer overflow`. (- 6) ^% 5; ;; -1, result of formula: -6 - (5 * (-6 ^/ 5)) (- 6) ^% (- 5); ;; 4, result of formula: -6 - (-5 * (-6 ^/ -5)) 8 ^% (- 5); ;; 3, result of formula: 8 - (-5 * (8 ^/ -5)) 8 ^% 5; ;; -2, result of formula: 8 - (5 * (8 ^/ 5)) 3 ^% 2; ;; -1, result of formula: 3 - (2 * (3 ^/ 2)) (- 3) ^% 2; ;; -1, result of formula: -3 - (2 * (-3 ^/ 2)) The result of `^%` always has the opposite sign of the divisor (i.e., `b` is the divisor in the expression `a ^% b`). ### [​](https://docs.ton.org/languages/func/operators#rounding-modulo-%) Rounding modulo, `~%` The tilde-percent sign (rounding modulo) operator `~%` is used for obtaining the rounding modulo of integer rounding division, which is the remainder of dividing the operands with the `~/` operator. Concretely, `a ~% b` is defined as `a - (b * (a ~/ b))`, where `~/` is the [rounding division operator](https://docs.ton.org/languages/func/operators#rounding-division%2C-%2F) , `*` is the [multiplication operator](https://docs.ton.org/languages/func/operators#multiplication%2C) , and `-` is the [subtraction operator](https://docs.ton.org/languages/func/operators#subtraction%2C) . If `b` in the expression `a ~% b` is `0`, the result is an error with [exit code 4](https://docs.ton.org/tvm/exit-codes#4%3A-integer-overflow) : `Integer overflow`. (- 6) ~% 5; ;; -1, result of formula: -6 - (5 * (-6 ~/ 5)) (- 6) ~% (- 5); ;; -1, result of formula: -6 - (-5 * (-6 ~/ -5)) 8 ~% (- 5); ;; -2, result of formula: 8 - (-5 * (8 ~/ -5)) 8 ~% 5; ;; -2, result of formula: 8 - (5 * (8 ~/ 5)) 3 ~% 2; ;; -1, result of formula: 3 - (2 * (3 ~/ 2)) (- 3) ~% 2; ;; -1, result of formula: -3 - (2 * (-3 ~/ 2)) ### [​](https://docs.ton.org/languages/func/operators#division-and-modulo-/%) Division and modulo, `/%` The slash-percent sign (division and modulo) operator `/%` returns a two element [tensor](https://docs.ton.org/languages/func/types#tensor-types) , where the first element is the result of applying the [division operator](https://docs.ton.org/languages/func/operators#division%2C-%2F) `/` on the operands, and the second element is the result of applying the [modulo operator](https://docs.ton.org/languages/func/operators#modulo%2C-%25) on the operands. If `b` in the expression `a /% b` is `0`, the result is an error with [exit code 4](https://docs.ton.org/tvm/exit-codes#4%3A-integer-overflow) : `Integer overflow`. (- 6) /% 5; ;; (-2, 4), which is: (-6 / 5, -6 % 5) (- 6) /% (- 5); ;; (1, -1), which is: (-6 / -5, -6 % -5) 8 /% (- 5); ;; (-2, -2), which is: (8 / -5, 8 % -5) 8 /% 5; ;; (1, 3), which is: (8 / 5, 8 % 5) 3 /% 2; ;; (1, 1), which is: (3 / 2, 3 % 2) (- 3) /% 2; ;; (-2, 1), which is: (-3 / 2, -3 % 2) `/%` is the only binary operator that does not associate to the right or to the left: 10 /% 2 /% 3; ;; Does NOT compile (10 /% 2) /% 3; ;; Does NOT compile 10 /% (2 /% 3); ;; Does NOT compile The reason for this non-associativity of `/%` is that it returns a 2-element tensor. This means that you must decompose the tensor before using the values. See more about decomposition notation in the [variable declaration](https://docs.ton.org/languages/func/expressions#variable-declaration) section. (int x, int y) = 10 /% 2; ;; x stores 5, y stores 0 (int z, int w) = x /% 3; ;; z stores 1, w stores 2 ### [​](https://docs.ton.org/languages/func/operators#bitwise-and-&) Bitwise AND, `&` The ampersand (bitwise AND) operator `&` applies a [bitwise AND](https://en.wikipedia.org/wiki/Bitwise_operation#AND) , which performs the logical AND operation on each pair of corresponding bits of the operands. This is useful when we want to clear selected bits of a number, where each bit represents an individual flag or a boolean state. This makes it possible to “store” up to 257 boolean values per integer, as all integers in FunC are 257-bit signed. 2 & 1; ;; 0, since 2 and 1 has no bits in common 4 & 1; ;; 0, since 4 and 1 has no bits in common 3 & 1; ;; 1, since 3 and 1 has in common only the lowest degree bit 1 & 1; ;; 1, & is idempotent, as expected of logical AND The `&` operator also behaves as expected on `-1` and `0`, which are the [emulated values](https://docs.ton.org/languages/func/types#no-boolean-type) for `true` and `false`: 0 & 0; ;; 0, false AND false is false 0 & (- 1); ;; 0, false AND true is false (- 1) & 0; ;; 0, true AND false is false (- 1) & (- 1); ;; -1, true AND true is true Hence, `&` can work as logical AND when computing boolean conditions: (1 <= 4) & (2 < 3); ;; -1, since (1 <= 4) and (2 < 3) both return -1 ### [​](https://docs.ton.org/languages/func/operators#addition-+) Addition, `+` The plus (addition) operator `+` is used for adding numbers together. Going beyond the range of the integer type will result in an error with [exit code 4](https://docs.ton.org/tvm/exit-codes#4%3A-integer-overflow) : `Integer overflow`. 2 + 2; ;; 4 - 1 + 1; ;; 0 ### [​](https://docs.ton.org/languages/func/operators#subtraction) Subtraction, `-` The minus (subtraction) operator `-` is used for subtracting numbers from each other. Going beyond the range of the integer type will result in an error with [exit code 4](https://docs.ton.org/tvm/exit-codes#4%3A-integer-overflow) : `Integer overflow`. 2 - 2; ;; 0 - 1 - 1; ;; -2 ### [​](https://docs.ton.org/languages/func/operators#bitwise-or-|) Bitwise OR, `|` The bar (bitwise OR) operator `|` applies a [bitwise OR](https://en.wikipedia.org/wiki/Bitwise_operation#OR) , which performs the logical OR operation on each pair of corresponding bits of the operands. This is useful when we want to apply a specific [bitmask](https://en.wikipedia.org/wiki/Mask_(computing)) . 2 & 1; ;; 3, 4 & 1; ;; 5, 3 & 1; ;; 3, 1 & 1; ;; 1, | is idempotent, as expected of logical OR The `|` operator also behaves as expected on `-1` and `0`, which are the [emulated values](https://docs.ton.org/languages/func/types#no-boolean-type) for `true` and `false`: 0 | 0; ;; 0, false OR false is false 0 | (- 1); ;; -1, false OR true is true (- 1) | 0; ;; -1, true OR false is true (- 1) | (- 1); ;; -1, true OR true is true Hence, `|` can work as logical OR when computing boolean conditions: (1 <= 4) | (3 < 2); ;; -1, since (1 <= 4) returns -1 ### [​](https://docs.ton.org/languages/func/operators#bitwise-xor-^) Bitwise XOR, `^` The caret (bitwise XOR) operator `^` applies a [bitwise XOR](https://en.wikipedia.org/wiki/Bitwise_operation#XOR) , performing the [logical exclusive OR](https://en.wikipedia.org/wiki/Exclusive_or) operation on each pair of corresponding bits of the operands. The result in each position is `1` if exactly one of the bits is `1`, or `0` if both bits are `0` or both bits are `1`. Thus, it compares two bits, yielding `1` if the bits are different and `0` if they are the same. It is useful for inverting selected bits of an operand (also called toggling or flipping), as any bit can be toggled by “XORing” it with `1`. 6 ^ 2; ;; 4, 4 ^ 2; ;; 6, 3 ^ 1; ;; 2, 1 ^ 1; ;; 0, The `^` operator also behaves as expected on `-1` and `0`, which are the [emulated values](https://docs.ton.org/languages/func/types#no-boolean-type) for `true` and `false`: 0 ^ 0; ;; 0, false XOR false is false 0 ^ (- 1); ;; -1, false XOR true is true (- 1) ^ 0; ;; -1, true XOR false is true (- 1) ^ (- 1); ;; 0, true XOR true is false ### [​](https://docs.ton.org/languages/func/operators#shift-right-%3E%3E) Shift right, `>>` The double greater than (shift right) operator `>>` returns an integer whose binary representation is the left operand value shifted by the right operand number of bits to the right. Excess bits shifted off to the right are discarded, and copies of the leftmost bit are shifted in from the left. This operation is also called “sign-propagating right shift” or “arithmetic right shift” because the sign of the resulting number is the same as the sign of the left operand. `x >> n` is a more efficient way to divide `x` by `2^n`, where the division truncation is done by flooring. In other words, `x >> n` is equivalent to `floor(x / 2^n)`, where `floor` is the [floor function](https://en.wikipedia.org/wiki/Floor_and_ceiling_functions) , `2^n` is exponentiation of `2` by `n`, and `/` is standard [arithmetical division](https://en.wikipedia.org/wiki/Division_(mathematics)) . 2 >> 1; ;; 1, since floor(2 / 2^1) = 1 (- 2) >> 1; ;; -1, because >> preserves the sign of the left operand, ;; or equivalently floor(-2 / 2^1) = -1 8 >> 2; ;; 2, since floor(8 / 2^2) = 2 5 >> 1; ;; 2, since floor(5 / 2^1) = 2 (- 14) >> 2; ;; -4 since floor(-14 / 2^2) = -4 ### [​](https://docs.ton.org/languages/func/operators#shift-left-%3C%3C) Shift left, `<<` The double less-than (shift left) operator `<<` returns an integer whose binary representation is the left operand value shifted to the left by the number of bits specified by the right operand. Excess bits shifted off from the left are discarded, and zero bits are shifted in from the right. `x << n` is a more efficient way to multiply `x` by `2^n`. In other words, `x << n` is equivalent to `x * 2^n`, where `2^n` is exponentiation of `2` by `n` and `*` is standard arithmetical multiplication. Exceeding the range of the integer type will result in an error with [exit code 4](https://docs.ton.org/tvm/exit-codes#4%3A-integer-overflow) : `Integer overflow`. 2 << 1; ;; 4, since 2 * 2^1 = 4 1 << 5; ;; 32, since 1 * 2^5 = 32 2 << 5; ;; 64, since 2 * 2^5 = 64 ### [​](https://docs.ton.org/languages/func/operators#ceiling-shift-right-^%3E%3E) Ceiling shift right, `^>>` The caret-double greater than (ceiling shift right) operator computes an efficient way to divide the left operand by `2^n`, where `n` is the right operand and the division truncation is done by ceiling. In other words, `x ^>> n` is equivalent to `ceil(x / 2^n)`, where `ceil` is the [ceil function](https://en.wikipedia.org/wiki/Floor_and_ceiling_functions) , `2^n` is exponentiation of `2` by `n`, and `/` is standard [arithmetical division](https://en.wikipedia.org/wiki/Division_(mathematics)) . 2 ^>> 1; ;; 1, since ceil(2 / 2^1) = 1 (- 2) ^>> 1; ;; -1, since ceil(-2 / 2^1) = -1 8 ^>> 2; ;; 2, since ceil(8 / 2^2) = 2 5 ^>> 1; ;; 3, since ceil(5 / 2^1) = 3 (- 14) ^>> 2; ;; -3 since ceil(-14 / 2^2) = -3 ### [​](https://docs.ton.org/languages/func/operators#rounding-shift-right-%3E%3E) Rounding shift right, `~>>` The tilde-double greater than (rounding shift right) operator computes an efficient way to divide the left operand by `2^n`, where `n` is the right operand and the division truncation is done by [rounding half up](https://en.wikipedia.org/wiki/Rounding#Rounding_half_up) . In other words, `x ~>> n` is equivalent to `floor(x / 2^n + 0.5)`, where `floor` is the [floor function](https://en.wikipedia.org/wiki/Floor_and_ceiling_functions) , `2^n` is exponentiation of `2` by `n`, `/` is standard [arithmetical division](https://en.wikipedia.org/wiki/Division_(mathematics)) , and `+` is standard arithmetical addition. 15 ~>> 3; ;; 2, since floor(15 / 2^3 + 0.5) = 2 12 ~>> 3; ;; 2, since floor(12 / 2^3 + 0.5) = 2 11 ~>> 3; ;; 1, since floor(11 / 2^3 + 0.5) = 1 (- 14) ~>> 3; ;; -2, since floor(-14 / 2^3 + 0.5) = -2 (- 12) ~>> 3; ;; -1 since floor(-12 / 2^3 + 0.5) = -1 ### [​](https://docs.ton.org/languages/func/operators#greater-than-%3E) Greater than, `>` The greater than operator `>` returns `-1` if the left operand is greater than the right operand and `0` otherwise. 2 > 2; ;; 0 (- 1) > (- 3); ;; -1 ### [​](https://docs.ton.org/languages/func/operators#greater-than-or-equal-%3E=) Greater than or equal, `>=` The greater than or equal to operator `>=` returns `-1` if the left operand is greater than or equal to the right operand and `0` otherwise. 2 >= 2; ;; -1 (- 3) >= (- 1); ;; 0 ### [​](https://docs.ton.org/languages/func/operators#less-than-%3C) Less than, `<` The less than operator `<` returns `-1` if the left operand is less than the right operand and `0` otherwise. 2 < 2; ;; 0 (- 3) < (- 1); ;; -1 ### [​](https://docs.ton.org/languages/func/operators#less-than-or-equal-%3C=) Less than or equal, `<=` The less than or equal to operator `<=` returns `-1` if the left operand is less than or equal to the right operand and `0` otherwise. 2 <= 2; ;; -1 (- 1) <= (- 3); ;; 0 ### [​](https://docs.ton.org/languages/func/operators#comparison-%3C=%3E) Comparison, `<=>` The less than or equal or greater than (comparison) operator `<=>`, returns `-1` if the left operand is less than the right operand, `0` if the left and right operands are equal, or `1` if the left operand is greater than the right operand. 1 <=> 2; ;; -1 (- 2) <=> (- 2); ;; 0 2 <=> (- 1) ;; 1 ### [​](https://docs.ton.org/languages/func/operators#equality-==) Equality, `==` The equality operator `==` checks whether its two operands are equal, returning `-1` if they are and `0` otherwise. The `==` can only compare integers. 1 == 2; ;; 0 (- 2) == (- 2); ;; -1 ### [​](https://docs.ton.org/languages/func/operators#inequality-=) Inequality, `!=` The inequality operator `!=` checks whether its two operands are different, returning `-1` if they are and `0` otherwise. The `!=` can only compare integers. 1 != 2; ;; -1 (- 2) != (- 2); ;; 0 ### [​](https://docs.ton.org/languages/func/operators#ternary-) Ternary, `?:` The conditional (ternary) operator `?:` is the only operator that takes three operands: a condition followed by a question mark (`?`), then an [expression](https://docs.ton.org/languages/func/expressions) to execute (the “consequent” expression) if the condition evaluates to an integer different from `0`, followed by a colon (`:`), and finally the expression to execute (the “alternative” expression) if the condition evaluates to `0`. This operator is frequently used as an alternative to an `if...else` statement. ? : Both the consequent and alternative expressions must have the same type. The condition must have the type integer. 2 ? 3 : 4; ;; 3, since the condition evaluates to an integer different from 0 0 ? 3 : 4; ;; 4, since the condition evaluates to 0 1 < 2 ? 3 : 4; ;; 3, since the condition evaluates to -1 1 != 4 ? begin_cell() : 5; ;; DOES NOT COMPILE: consequent and alternative do not have the same type ### [​](https://docs.ton.org/languages/func/operators#assignment-=) Assignment, `=` The assignment operator `=` is used to assign the result of an [expression](https://docs.ton.org/languages/func/expressions) to a variable. After execution, the `=` operator returns the value assigned to the variable. a = 5; ;; Assigns 5 to variable a, and returns 5 b = 5 + a; ;; Assigns 10 to variable b, and returns 10 Since the assignment operator returns the assigned value, it can be used in expressions: (a = 5) + 10; ;; Assign 5 to a, and the expression evaluates to 15 (a = 5) + a; ;; Assigns 5 to a, and the expression evaluates to 10, ;; since a = 5 evaluates to 5, and 5 + a is 10. The operator `=` is right associative: (b = a = 5) + b; ;; Parses as (b = (a = 5)) + b. ;; So, it does the following: ;; (1) a = 5 assigns 5 to a, and returns 5. ;; (2) b = (a = 5) assigns 5 to b, and returns 5. ;; (3) (b = (a = 5)) + b, evaluates to 10, since b has value 5. ;; From here onwards, a and b have value 5. The assignment operator can also occur in [variable declarations](https://docs.ton.org/languages/func/expressions#variable-declaration) , which are also expressions: int x = 5; ;; Declares integer variable x with value 5, and returns 5. a = (int y = 5); ;; Declares integer variable y with value 5, then assigns 5 to a, and returns 5. ;; From here onwards, a has value 5 and y is also available with value 5. (int z = 5) + z; ;; Declares integer variable z with value 5, and the expression evaluates to 10, ;; since after the declaration, z has value 5. ;; From here onwards, z is available with value 5. ### [​](https://docs.ton.org/languages/func/operators#augmented-assignment-operators) Augmented assignment operators Augmented (or compound) assignment operators such as `+=` combine an operation with an assignment. Augmented assignments are semantically equivalent to regular assignments `=` but include an operation: a += 5; ;; is equivalent to: a = a + 5; After execution, the augmented operator returns the final value assigned to the variable: int a = 0; int b = 2; a += 4; ;; returns 4 and assigns 4 to a, equivalent to a = a + 4. b *= 10; ;; returns 20 and assigns 20 to b, equivalent to b = b * 10. (b /= 2) + 1; ;; returns 11 and assigns 10 to b, equivalent to (b = b / 2) + 1. List of augmented assignment operators: * `*=`, which uses the [multiplication operator](https://docs.ton.org/languages/func/operators#multiplication%2C) `*`. * `/=`, which uses the [division operator](https://docs.ton.org/languages/func/operators#division%2C-%2F) `/`. * `^/=`, which uses the [ceiling division operator](https://docs.ton.org/languages/func/operators#ceiling-division%2C-%5E%2F) `^/`. * `~/=`, which uses the [rounding division operator](https://docs.ton.org/languages/func/operators#rounding-division%2C-%2F) `~/`. * `%=`, which uses the [modulo operator](https://docs.ton.org/languages/func/operators#modulo%2C-%25) `%`. * `^%=`, which uses the [ceiling modulo operator](https://docs.ton.org/languages/func/operators#ceiling-modulo%2C-%5E%25) `^%`. * `~%=`, which uses the [rounding modulo operator](https://docs.ton.org/languages/func/operators#rounding-modulo%2C-%25) `~%`. * `&=`, which uses the [bitwise AND operator](https://docs.ton.org/languages/func/operators#bitwise-and%2C-%26) `&`. * `+=`, which uses the [addition operator](https://docs.ton.org/languages/func/operators#addition%2C-%2B) `+`. * `-=`, which uses the [subtraction operator](https://docs.ton.org/languages/func/operators#subtraction%2C) `-`. * `|=`, which uses the [bitwise OR operator](https://docs.ton.org/languages/func/operators#bitwise-or%2C-%7C) `|`. * `^=`, which uses the [bitwise XOR operator](https://docs.ton.org/languages/func/operators#bitwise-xor%2C-%5E) `^`. * `>>=`, which uses the [shift right operator](https://docs.ton.org/languages/func/operators#shift-right%2C-%3E%3E) `>>`. * `<<=`, which uses the [shift left operator](https://docs.ton.org/languages/func/operators#shift-left%2C-%3C%3C) `<<`. * `^>>=`, which uses the [ceiling shift right operator](https://docs.ton.org/languages/func/operators#ceiling-shift-right%2C-%5E%3E%3E) `^>>`. * `~>>=`, which uses the [rounding shift right operator](https://docs.ton.org/languages/func/operators#rounding-shift-right%2C-%3E%3E) `~>>`. Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/languages/func/operators.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/languages/func/operators) [Previous](https://docs.ton.org/languages/func/literals) [Expressions\ \ Next](https://docs.ton.org/languages/func/expressions) ⌘I On this page * [Table of operators](https://docs.ton.org/languages/func/operators#table-of-operators) * [Precedence](https://docs.ton.org/languages/func/operators#precedence) * [Parentheses](https://docs.ton.org/languages/func/operators#parentheses) * [Unary operators](https://docs.ton.org/languages/func/operators#unary-operators) * [Bitwise NOT, ~](https://docs.ton.org/languages/func/operators#bitwise-not) * [Negation, -](https://docs.ton.org/languages/func/operators#negation) * [Binary operators](https://docs.ton.org/languages/func/operators#binary-operators) * [Multiplication, \*](https://docs.ton.org/languages/func/operators#multiplication) * [Division, /](https://docs.ton.org/languages/func/operators#division-%2F) * [Ceiling division, ^/](https://docs.ton.org/languages/func/operators#ceiling-division-%5E%2F) * [Rounding division, ~/](https://docs.ton.org/languages/func/operators#rounding-division-%2F) * [Modulo, %](https://docs.ton.org/languages/func/operators#modulo-%25) * [Ceiling modulo, ^%](https://docs.ton.org/languages/func/operators#ceiling-modulo-%5E%25) * [Rounding modulo, ~%](https://docs.ton.org/languages/func/operators#rounding-modulo-%25) * [Division and modulo, /%](https://docs.ton.org/languages/func/operators#division-and-modulo-%2F%25) * [Bitwise AND, &](https://docs.ton.org/languages/func/operators#bitwise-and-%26) * [Addition, +](https://docs.ton.org/languages/func/operators#addition-%2B) * [Subtraction, -](https://docs.ton.org/languages/func/operators#subtraction) * [Bitwise OR, |](https://docs.ton.org/languages/func/operators#bitwise-or-%7C) * [Bitwise XOR, ^](https://docs.ton.org/languages/func/operators#bitwise-xor-%5E) * [Shift right, >>](https://docs.ton.org/languages/func/operators#shift-right-%3E%3E) * [Shift left, <<](https://docs.ton.org/languages/func/operators#shift-left-%3C%3C) * [Ceiling shift right, ^>>](https://docs.ton.org/languages/func/operators#ceiling-shift-right-%5E%3E%3E) * [Rounding shift right, ~>>](https://docs.ton.org/languages/func/operators#rounding-shift-right-%3E%3E) * [Greater than, >](https://docs.ton.org/languages/func/operators#greater-than-%3E) * [Greater than or equal, >=](https://docs.ton.org/languages/func/operators#greater-than-or-equal-%3E%3D) * [Less than, <](https://docs.ton.org/languages/func/operators#less-than-%3C) * [Less than or equal, <=](https://docs.ton.org/languages/func/operators#less-than-or-equal-%3C%3D) * [Comparison, <=>](https://docs.ton.org/languages/func/operators#comparison-%3C%3D%3E) * [Equality, ==](https://docs.ton.org/languages/func/operators#equality-%3D%3D) * [Inequality, !=](https://docs.ton.org/languages/func/operators#inequality-%3D) * [Ternary, ?:](https://docs.ton.org/languages/func/operators#ternary-) * [Assignment, =](https://docs.ton.org/languages/func/operators#assignment-%3D) * [Augmented assignment operators](https://docs.ton.org/languages/func/operators#augmented-assignment-operators) --- # Standard library of FunC - TON Docs [Skip to main content](https://docs.ton.org/languages/func/stdlib#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Libraries Standard library of FunC The FunC standard library serves as a wrapper around the most commonly used TVM assembly commands that aren’t built-in. For detailed descriptions of these commands, refer to the [TVM documentation](https://docs.ton.org/tvm) . Some explanations in this document adapted from there. Some functions in the library are commented out, meaning they have already been optimized and integrated as built-in operations. However, their type signatures and behaviors remain unchanged. Additionally, some less frequently used TVM commands are not yet included in the standard library. These may be added in future updates. [​](https://docs.ton.org/languages/func/stdlib#tuple-manipulation-primitives) Tuple manipulation primitives -------------------------------------------------------------------------------------------------------------- Most function names and types in this section are self-explanatory. For more details on polymorphic functions, refer to the [Polymorphism with forall](https://docs.ton.org/languages/func/functions#polymorphism-with-forall) section. **Note:** Currently, values of atomic type `tuple` cannot be converted into composite tuple types (e.g.,`[int, cell]`) and vice versa. ### [​](https://docs.ton.org/languages/func/stdlib#lisp-style-lists) Lisp-style lists Lists can be represented as nested 2-element tuples. Empty list is conventionally represented as TVM `null` value (it can be obtained by calling `null()`). For example, the tuple `(1, (2, (3, null)))` represents the list `[1, 2, 3]`. Elements of a list can be of different types. Lists in FunC are represented as nested two-element tuples. An empty list is conventionally represented by the TVM `null` value, which can be obtained using `null()`. For example, the tuple `(1, (2, (3, null)))` corresponds to the list `[1, 2, 3]`. Lists in FunC can contain elements of different types. #### [​](https://docs.ton.org/languages/func/stdlib#cons) `cons` forall X -> tuple cons(X head, tuple tail) asm "CONS"; Adds an element to the beginning of a lisp-style list. #### [​](https://docs.ton.org/languages/func/stdlib#uncons) `uncons` forall X -> (X, tuple) uncons(tuple list) asm "UNCONS"; Extracts the head and tail of a lisp-style list. #### [​](https://docs.ton.org/languages/func/stdlib#list_next) `list_next` forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS"; Extracts the head and tail of a lisp-style list. It can be used as a [(non-)modifying method](https://docs.ton.org/languages/func/statements#methods-calls) . **Example** () foo(tuple xs) { (_, int x) = xs.list_next(); ;; get the first element, `_` means do not use tail list int y = xs~list_next(); ;; pop the first element int z = xs~list_next(); ;; pop the second element } #### [​](https://docs.ton.org/languages/func/stdlib#car) `car` forall X -> X car(tuple list) asm "CAR"; Returns the head of a lisp-style list. #### [​](https://docs.ton.org/languages/func/stdlib#cdr) `cdr` tuple cdr(tuple list) asm "CDR"; Returns the tail of a lisp-style list. ### [​](https://docs.ton.org/languages/func/stdlib#other-tuple-primitives) Other tuple primitives #### [​](https://docs.ton.org/languages/func/stdlib#empty_tuple) `empty_tuple` tuple empty_tuple() asm "NIL"; Creates an empty tuple (0 elements). #### [​](https://docs.ton.org/languages/func/stdlib#tpush) `tpush` forall X -> tuple tpush(tuple t, X value) asm "TPUSH"; forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH"; Appends a value to the tuple `(x1, ..., xn)`, forming `(x1, ..., xn, x)`. The resulting tuple must not exceed 255 elements, or a type check exception is thrown. #### [​](https://docs.ton.org/languages/func/stdlib#single) `single` forall X -> [X] single(X x) asm "SINGLE"; Creates a tuple with a single element — singleton #### [​](https://docs.ton.org/languages/func/stdlib#unsingle) `unsingle` forall X -> X unsingle([X] t) asm "UNSINGLE"; Unpacks a singleton. #### [​](https://docs.ton.org/languages/func/stdlib#pair) `pair` forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR"; Creates a two-element tuple (pair). #### [​](https://docs.ton.org/languages/func/stdlib#unpair) `unpair` forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR"; Unpacks a pair into two separate values. #### [​](https://docs.ton.org/languages/func/stdlib#triple) `triple` forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE"; Creates a three-element tuple (triple). #### [​](https://docs.ton.org/languages/func/stdlib#untriple) `untriple` forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE"; Unpacks a triple into three separate values. #### [​](https://docs.ton.org/languages/func/stdlib#tuple4) `tuple4` forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE"; Creates a four-element tuple. #### [​](https://docs.ton.org/languages/func/stdlib#untuple4) `untuple4` forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE"; Unpacks a four-element tuple into four separate values. ### [​](https://docs.ton.org/languages/func/stdlib#tuple-element-access) Tuple element access #### [​](https://docs.ton.org/languages/func/stdlib#first) `first` forall X -> X first(tuple t) asm "FIRST"; Returns the first element of a tuple. #### [​](https://docs.ton.org/languages/func/stdlib#second) `second` forall X -> X second(tuple t) asm "SECOND"; Returns the second element of a tuple. #### [​](https://docs.ton.org/languages/func/stdlib#third) `third` forall X -> X third(tuple t) asm "THIRD"; Returns the third element of a tuple. #### [​](https://docs.ton.org/languages/func/stdlib#fourth) `fourth` forall X -> X fourth(tuple t) asm "3 INDEX"; Returns the fourth element of a tuple. ### [​](https://docs.ton.org/languages/func/stdlib#pair-and-triple-element-access) Pair and triple element access #### [​](https://docs.ton.org/languages/func/stdlib#pair_first) `pair_first` forall X, Y -> X pair_first([X, Y] p) asm "FIRST"; Returns the first element of a pair. #### [​](https://docs.ton.org/languages/func/stdlib#pair_second) `pair_second` forall X, Y -> Y pair_second([X, Y] p) asm "SECOND"; Returns the second element of a pair. #### [​](https://docs.ton.org/languages/func/stdlib#triple_first) `triple_first` forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST"; Returns the first element of a triple. #### [​](https://docs.ton.org/languages/func/stdlib#triple_second) `triple_second` forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND"; Returns the second element of a triple. #### [​](https://docs.ton.org/languages/func/stdlib#triple_third) `triple_third` forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD"; Returns the third element of a triple. [​](https://docs.ton.org/languages/func/stdlib#domain-specific-primitives) Domain specific primitives -------------------------------------------------------------------------------------------------------- ### [​](https://docs.ton.org/languages/func/stdlib#extracting-info-from-c7) Extracting info from c7 The [c7 special register](https://docs.ton.org/tvm/overview) holds useful data about smart contract execution. The following primitives facilitate easy retrieval of this information: #### [​](https://docs.ton.org/languages/func/stdlib#now) `now` int now() asm "NOW"; Returns the current Unix timestamp as an integer. #### [​](https://docs.ton.org/languages/func/stdlib#my_address) `my_address` slice my_address() asm "MYADDR"; Retrieves the smart contract’s internal address as a Slice containing `MsgAddressInt`. If needed, it can be further processed using functions like `parse_std_addr`. #### [​](https://docs.ton.org/languages/func/stdlib#get_balance) `get_balance` [int, cell] get_balance() asm "BALANCE"; Returns the smart contract’s balance as a `tuple`: * `int`: The remaining balance in nanotoncoins. * `cell`: A dictionary (with 32-bit keys) containing balances of extra currencies. Since this is retrieved during the compute phase, the balance reflects the incoming message `value`, with `storage_fee` and `import_fee` already subtracted. #### [​](https://docs.ton.org/languages/func/stdlib#cur_lt) `cur_lt` int cur_lt() asm "LTIME"; Returns the logical time of the current transaction. #### [​](https://docs.ton.org/languages/func/stdlib#block_lt) `block_lt` int block_lt() asm "BLOCKLT"; Returns the logical time at the beginning of the current block. #### [​](https://docs.ton.org/languages/func/stdlib#config_param) `config_param` cell config_param(int x) asm "CONFIGOPTPARAM"; Returns the value of the global configuration parameter with integer index `i` as `cell` or `null` value. #### [​](https://docs.ton.org/languages/func/stdlib#my_code) `my_code` cell my_code() asm "MYCODE"; Retrieves the smart contract’s code from `c7`. ### [​](https://docs.ton.org/languages/func/stdlib#hashes) Hashes #### [​](https://docs.ton.org/languages/func/stdlib#cell_hash) `cell_hash` int cell_hash(cell c) asm "HASHCU"; Calculates the representation hash of the given `cell c` and returns it as a 256-bit unsigned integer `x`. This function is handy for signing and verifying signatures of arbitrary entities structured as a tree of cells. #### [​](https://docs.ton.org/languages/func/stdlib#slice_hash) `slice_hash` int slice_hash(slice s) asm "HASHSU"; Computes the hash of the given `slice s` and returns it as a 256-bit unsigned integer `x`. The result is equivalent to creating a standard cell containing only the data and references from `s` and then computing its hash using `cell_hash`. #### [​](https://docs.ton.org/languages/func/stdlib#string_hash) `string_hash` int string_hash(slice s) asm "SHA256U"; Calculates the SHA-256 hash of the data bits in the given `slice s`. A cell underflow exception is thrown if the bit length of `s` is not a multiple of eight. The hash is returned as a 256-bit unsigned integer `x`. ### [​](https://docs.ton.org/languages/func/stdlib#signature-checks) Signature checks #### [​](https://docs.ton.org/languages/func/stdlib#check_signature) `check_signature` int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU"; Checks whether the given `signature` is a valid Ed25519 signature of the provided `hash` using the specified `public key`. The `hash` and `public key` are both 256-bit unsigned integers. The `signature` must be at least 512 bits long, and only the first 512 bits are used. If the signature is valid, the function returns `-1`; otherwise, it returns `0`. Remember that `CHKSIGNU` converts the hash into a 256-bit slice and then calls `CHKSIGNS`. This means that if the `hash` was initially generated from some data, that data gets hashed _twice_ — the first time when creating the hash and the second time within `CHKSIGNS`. #### [​](https://docs.ton.org/languages/func/stdlib#check_data_signature) `check_data_signature` int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS"; Verifies whether the given `signature` is a valid Ed25519 signature for the data contained in the `slice data`, using the specified `public key`, just like `check_signature`. A cell underflow exception is thrown if the data bit length is not a multiple of eight. The verification follows the standard Ed25519 process, where SHA-256 is used to derive a 256-bit number from `data`, which is then signed. ### [​](https://docs.ton.org/languages/func/stdlib#computation-of-boc-size) Computation of BoC size The following functions help calculate storage fees for user-provided data. #### [​](https://docs.ton.org/languages/func/stdlib#compute_data_size) `compute_data_size?` (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)`. It recursively calculates the number of unique cells `x`, data bits `y`, and cell references `z` in the **directed acyclic graph (DAG)** at `cell c`. This provides the total storage used by the DAG while recognizing identical cells. The computation uses a depth-first traversal with a hash table to track visited cells, preventing redundant visits. If the total amount of visited cells `x` exceeds `max_cells`, the process stops before visiting the `(max_cells + 1)` -th cell, and the function returns `0` to indicate failure. If `c` is `null`, the function returns `x = y = z = 0`. #### [​](https://docs.ton.org/languages/func/stdlib#slice_compute_data_size) `slice_compute_data_size?` (int, int, int, int) slice_compute_data_size?(slice s, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT"; It works similarly to `compute_data_size?` but takes a `slice s` instead of a `cell`. The result `x` does not include the cell that contains the slice `s`, but `y` and `z` account for the data bits and cell references inside `s`. #### [​](https://docs.ton.org/languages/func/stdlib#compute_data_size) `compute_data_size` (int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE"; A strict version of `compute_data_size?` that throws a cell overflow exception (8) if the computation fails. #### [​](https://docs.ton.org/languages/func/stdlib#slice_compute_data_size) `slice_compute_data_size` (int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE"; A strict version of `slice_compute_data_size?` that throws a cell overflow exception (8) if the computation fails. ### [​](https://docs.ton.org/languages/func/stdlib#persistent-storage-save-and-load) Persistent storage save and load #### [​](https://docs.ton.org/languages/func/stdlib#get_data) `get_data` cell get_data() asm "c4 PUSH"; Returns the persistent contract storage cell, which can be later parsed or modified using slice and builder functions. #### [​](https://docs.ton.org/languages/func/stdlib#set_data) `set_data` () set_data(cell c) impure asm "c4 POP"; Sets cell `c` as persistent contract data. You can update the persistent contract storage with this primitive. ### [​](https://docs.ton.org/languages/func/stdlib#continuation-primitives) Continuation primitives #### [​](https://docs.ton.org/languages/func/stdlib#get_c3) `get_c3` cont get_c3() impure asm "c3 PUSH"; The `c3` register typically holds a continuation set up by the contract code. It is used for function calls. The primitive returns the current value of `c3`. #### [​](https://docs.ton.org/languages/func/stdlib#set_c3) `set_c3` () set_c3(cont c) impure asm "c3 POP"; Updates the `c3` value to modify the contract’s execution code at runtime. The current code and function call stack remain unchanged, but future function calls use the updated code. #### [​](https://docs.ton.org/languages/func/stdlib#bless) `bless` cont bless(slice s) impure asm "BLESS"; Converts a `slice s` into a basic continuation `c`, where `c.code = s`, an empty stack and a savelist. ### [​](https://docs.ton.org/languages/func/stdlib#gas-related-primitives) Gas related primitives #### [​](https://docs.ton.org/languages/func/stdlib#accept_message) `accept_message` () accept_message() impure asm "ACCEPT"; This function sets the current gas limit `gl` to its maximum possible value `gm` and resets the gas credit `gc` to zero. At the same time, it deducts the previous gas credit `gc` from the remaining gas reserve `gr`. Simply put, the smart contract agrees to purchase gas to complete the transaction. This function is required when processing external messages that do not carry any value and do not provide gas. #### [​](https://docs.ton.org/languages/func/stdlib#set_gas_limit) `set_gas_limit` () set_gas_limit(int limit) impure asm "SETGASLIMIT"; This function sets the gas limit `gl` to the smaller of two values: the provided `limit` or the maximum allowed gas `gm`. It also resets the gas credit `gc` to zero. If the contract already uses more gas than this new limit `gl`, including the current instruction, an out-of-gas exception is triggered before the new limit is applied. Remember that if the `limit` is `2^63 − 1` or higher, calling `set_gas_limit` works the same as calling `accept_message`. #### [​](https://docs.ton.org/languages/func/stdlib#commit) `commit` () commit() impure asm "COMMIT"; Saves the current state of persistent storage `c4` and action registers `c5`, ensuring execution succeeds with these stored values, even if an exception occurs later. #### [​](https://docs.ton.org/languages/func/stdlib#buy_gas) `buy_gas` () buy_gas(int gram) impure asm "BUYGAS"; This function calculates how much gas can be purchased for the `gram` nanotoncoins and updates the gas limit `gl` accordingly, similar to `set_gas_limit`. ### [​](https://docs.ton.org/languages/func/stdlib#actions-primitives) Actions primitives #### [​](https://docs.ton.org/languages/func/stdlib#raw_reserve) `raw_reserve` () raw_reserve(int amount, int mode) impure asm "RAWRESERVE"; The `raw_reserve` function creates an output action that reserves a specific amount of nanotoncoins from the account’s remaining balance. The behavior depends on the `mode` parameter: * If `mode = 0`, exactly the `amount` of nanotoncoins is reserved. * If `mode = 2`, up to the `amount` of nanotoncoins is reserved. * If `mode = 1` or `mode = 3`, all but the `amount` of nanotoncoins is reserved. This process is equivalent to generating an outbound message that transfers the `amount` of nanotoncoins or `b − amount` nanotoncoins, where `b` represents the remaining balance, to the sender. This ensures that subsequent output actions cannot exceed the remaining funds. **Mode Flags** * **Bit +2** in `mode`: prevents failure if the specified `amount` cannot be reserved. Instead, the entire remaining balance is reserved. * **Bit +8** in `mode`: negates `amount` (`amount <- -amount`) before executing further actions. * **Bit +4** in `mode`: increases `amount` by the original balance of the current account before the compute phase, including all extra currencies, before performing any other checks and actions. **Constraints** * The `amount` must be a non-negative integer. * `mode` must be within the range `0..15`. #### [​](https://docs.ton.org/languages/func/stdlib#raw_reserve_extra) `raw_reserve_extra` () raw_reserve_extra(int amount, cell extra_amount, int mode) impure asm "RAWRESERVEX"; Similar to `raw_reserve`, but it also supports an `extra_amount` dictionary. This dictionary, given as a `cell` or `null`, allows reserving currencies other than Toncoin. #### [​](https://docs.ton.org/languages/func/stdlib#send_raw_message) `send_raw_message` () send_raw_message(cell msg, int mode) impure asm "SENDRAWMSG"; This function sends a raw message stored in `msg`. This message must contain a properly serialized `Message X` object, with a few exceptions. The source address can have a dummy value `addr_none`, which the current smart contract address will automatically replace. The fields `ihr_fee`, `fwd_fee`, `created_lt`, and `created_at` can hold arbitrary values, as they will be updated with the correct ones during the action phase of the transaction. The integer parameter `mode` specifies the flags. Currently, there are **3 modes** and **4 flags** available for messages. A single mode can be combined with multiple flags or none to form the desired `mode`. The combination is achieved by **summing** their values. The table below provides descriptions of the available modes and flags. | Mode | Description | | --- | --- | | `0` | Sends an ordinary message. | | `64` | Transfers the full remaining value of the inbound message and the initially specified amount. | | `128` | Transfers the entire remaining balance of the current smart contract instead of the initially specified amount. | | Flag | Description | | --- | --- | | `+1` | Pays transfer fees separately from the message value. | | `+2` | Ignores certain errors that occur while processing the message during the action phase (see note below). | | `+16` | Bounces the transaction if the action fails. Has no effect if `+2` is used. | | `+32` | Destroys the current account if its resulting balance is zero (commonly used with `mode = 128`). | #### [​](https://docs.ton.org/languages/func/stdlib#set_code) `set_code` () set_code(cell new_code) impure asm "SETCODE"; Generates an output action to update the smart contract’s code to the one provided in the `new_code` cell. This change occurs only after the smart contract completes its current execution. See also [set\_c3](https://docs.ton.org/languages/func/stdlib#set_c3) . ### [​](https://docs.ton.org/languages/func/stdlib#random-number-generator-primitives) Random number generator primitives The pseudo-random number generator relies on a random seed, a 256-bit unsigned integer, and sometimes additional data stored in [c7](https://docs.ton.org/tvm/overview) . Before a smart contract executes in the TON Blockchain, its initial random seed is derived from a hash of the smart contract address and the global block random seed. If the same smart contract runs multiple times within a block, each run will use the same random seed. This can be adjusted by calling `randomize_ltbefore` using the pseudo-random number generator for the first time. #### [​](https://docs.ton.org/languages/func/stdlib#random) `random` int random() impure asm "RANDU256"; Generates a new pseudo-random 256-bit unsigned integer `x`. The process works as follows: * Let `r` be the previous random seed, a 32-byte array constructed from the big-endian representation of a 256-bit unsigned integer. * Compute `sha512(r)`. * The first 32 bytes of the hash become the new seed `r'`. * The remaining 32 bytes are returned as the new random value `x`. #### [​](https://docs.ton.org/languages/func/stdlib#rand) `rand` 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. Produces a pseudo-random integer `z` within the range `0..range−1` (or `range..−1` if `range < 0`). * First, an unsigned random value `x` is generated using `random()`. * Then, `z := x * range / 2^256` is calculated. #### [​](https://docs.ton.org/languages/func/stdlib#get_seed) `get_seed` int get_seed() impure asm "RANDSEED"; Returns the current random seed as a 256-bit unsigned integer. #### [​](https://docs.ton.org/languages/func/stdlib#set_seed) `set_seed` int set_seed(int seed) impure asm "SETRAND"; Sets the random seed to a specified 256-bit unsigned integer `seed`. #### [​](https://docs.ton.org/languages/func/stdlib#randomize) `randomize` () randomize(int x) impure asm "ADDRAND"; Mixes an unsigned 256-bit integer `x` into a random seed `r` by setting the random seed to sha256 of the concatenation of two 32-byte strings: the first with a big-endian representation of the old seed `r`, and the second with a big-endian representation of `x`. Mixes a 256-bit unsigned integer `x` into the random seed `r` by updating`r` to `sha256(r || x)`, where: * `r` is the previous seed, represented as a 32-byte big-endian array. * `x` is also converted into a 32-byte big-endian array. T- he new seed is the SHA-256 hash of their concatenation. #### [​](https://docs.ton.org/languages/func/stdlib#randomize_lt) `randomize_lt` () randomize_lt() impure asm "LTIME" "ADDRAND"; Equivalent to calling `randomize(cur_lt());`. ### [​](https://docs.ton.org/languages/func/stdlib#address-manipulation-primitives) Address manipulation primitives The functions below handle the serialization and deserialization of values based on the following TL-B scheme. 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; * `addr_none` is represented by `t = (0)`, i.e., a tuple containing exactly one integer that equals 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 `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` A deserialized `MsgAddress`cis represented as a tuple `t` with the following structure: * `addr_none` is represented as `t = (0)`, a single-element tuple where the integer is zero. * `addr_extern` is represented as `t = (1, s)`, where `s` is a slice containing `external_address`. In other words, `t` is a pair with the first element being `1` and the second being `s`. * `addr_std` is represented as `t = (2, u, x, s)`, where: * `u` is `null` if `anycast` is absent or a slice `s'` containing `rewrite_pfx` if `anycast` is present. * `x` is the `workchain_id`. * `s` is a slice containing the address. * `addr_var` is represented as `t = (3, u, x, s)`, where `u`, `x,` and `s` follow the same structure as `addr_std`. #### [​](https://docs.ton.org/languages/func/stdlib#load_msg_addr) `load_msg_addr` (slice, slice) load_msg_addr(slice s) asm( -> 1 0) "LDMSGADDR"; Extracts a valid `MsgAddress` prefix from `slice s` and returns the extracted prefix `s'` and the remaining part `s''`. #### [​](https://docs.ton.org/languages/func/stdlib#parse_addr) `parse_addr` tuple parse_addr(slice s) asm "PARSEMSGADDR"; Splits `slice s`, which holds a valid `MsgAddress`, into tuple `t`, separating its fields. If `s` is invalid, a cell deserialization exception is raised. #### [​](https://docs.ton.org/languages/func/stdlib#parse_std_addr) `parse_std_addr` (int, int) parse_std_addr(slice s) asm "REWRITESTDADDR"; Extracts a valid `MsgAddressInt`, typically `msg_addr_std`, from `slice s`, modifies the address prefix if `anycast` is present, and returns the workchain and 256-bit address as integers. A cell `deserialization` exception is triggered if the address isn’t 256-bit or `s` isn’t a valid `MsgAddressInt` serialization. #### [​](https://docs.ton.org/languages/func/stdlib#parse_var_addr) `parse_var_addr` (int, slice) parse_var_addr(slice s) asm "REWRITEVARADDR"; A modified version of `parse_std_addr` that returns the modified address as `slice s`, even if its length is not exactly 256 bits, as in `msg_addr_var`. ### [​](https://docs.ton.org/languages/func/stdlib#debug-primitives) Debug primitives Debug primitives help inspect the state of various variables while running tests or executing console scripts. #### [​](https://docs.ton.org/languages/func/stdlib#dump) `~dump` forall X -> () ~dump(X value) impure asm "s0 DUMP"; Prints the given value. Multiple values can be output as a tuple, e.g.,`~dump([v1, v2, v3])`. #### [​](https://docs.ton.org/languages/func/stdlib#strdump) `~strdump` () ~strdump(slice str) impure asm "STRDUMP"; Prints a string. The bit length of the slice parameter must be a multiple of 8. #### [​](https://docs.ton.org/languages/func/stdlib#dump_stack) `dump_stack` () dump_stack() impure asm "DUMPSTK"; Prints the current stack up to the top 255 values and displays the total stack depth. ### [​](https://docs.ton.org/languages/func/stdlib#slice-primitives) Slice primitives A primitive _loads_ data when it returns both the extracted data and the remainder of the slice. It can be used as a [modifying method](https://docs.ton.org/languages/func/statements#modifying-methods) . A primitive _preloads_ data when it returns only the extracted data, leaving the original slice unchanged. It can be used as a [non-modifying method](https://docs.ton.org/languages/func/statements#non-modifying-methods) . Unless specified otherwise, loading and preloading primitives read data from the beginning of the slice. #### [​](https://docs.ton.org/languages/func/stdlib#begin_parse) `begin_parse` slice begin_parse(cell c) asm "CTOS"; Converts a `cell` into a `slice`. The input `c` must be either an ordinary or exotic cell. See [TVM.pdf](https://ton.org/tvm.pdf) , 3.1.2. If `c` is exotic, it is automatically converted into an ordinary cell `c'` before being transformed into a `slice`. #### [​](https://docs.ton.org/languages/func/stdlib#end_parse) `end_parse` () end_parse(slice s) impure asm "ENDS"; Checks if the `slice s` is empty. It throws an exception if it is not. #### [​](https://docs.ton.org/languages/func/stdlib#load_ref) `load_ref` (slice, cell) load_ref(slice s) asm( -> 1 0) "LDREF"; Loads the first reference from a slice. #### [​](https://docs.ton.org/languages/func/stdlib#preload_ref) `preload_ref` cell preload_ref(slice s) asm "PLDREF"; Preloads the first reference from a slice. #### [​](https://docs.ton.org/languages/func/stdlib#load_int) `load_int` ;; (slice, int) ~load_int(slice s, int len) asm(s len -> 1 0) "LDIX"; Loads a signed `len`\-bit integer from a slice. #### [​](https://docs.ton.org/languages/func/stdlib#load_uint) `load_uint` ;; (slice, int) ~load_uint(slice s, int len) asm( -> 1 0) "LDUX"; Loads an unsigned `len`\-bit integer from a slice. #### [​](https://docs.ton.org/languages/func/stdlib#preload_int) `preload_int` ;; int preload_int(slice s, int len) asm "PLDIX"; Preloads a signed `len`\-bit integer from a slice. #### [​](https://docs.ton.org/languages/func/stdlib#preload_uint) `preload_uint` ;; int preload_uint(slice s, int len) asm "PLDUX"; Preloads an unsigned `len`\-bit integer from a slice. #### [​](https://docs.ton.org/languages/func/stdlib#load_bits) `load_bits` ;; (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 new slice `s''`. #### [​](https://docs.ton.org/languages/func/stdlib#preload_bits) `preload_bits` ;; slice preload_bits(slice s, int len) asm "PLDSLICEX"; Preloads the first `0 ≤ len ≤ 1023` bits from `slice s` into a new slice `s''`. #### [​](https://docs.ton.org/languages/func/stdlib#load_coins) `load_coins` (slice, int) load_coins(slice s) asm( -> 1 0) "LDGRAMS"; Loads serialized amount of Toncoin, which is an unsigned integer up to `2^120 - 1`. #### [​](https://docs.ton.org/languages/func/stdlib#skip_bits) `skip_bits` slice skip_bits(slice s, int len) asm "SDSKIPFIRST"; (slice, ()) ~skip_bits(slice s, int len) asm "SDSKIPFIRST"; Returns all bits of `s` except for the first `len` bits, where `0 ≤ len ≤ 1023`. #### [​](https://docs.ton.org/languages/func/stdlib#first_bits) `first_bits` slice first_bits(slice s, int len) asm "SDCUTFIRST"; Returns the first `len` bits of `s`, where `0 ≤ len ≤ 1023`. #### [​](https://docs.ton.org/languages/func/stdlib#skip_last_bits) `skip_last_bits` slice skip_last_bits(slice s, int len) asm "SDSKIPLAST"; (slice, ()) ~skip_last_bits(slice s, int len) asm "SDSKIPLAST"; Returns all bits of `s` except for the last `len` bits, where `0 ≤ len ≤ 1023`. #### [​](https://docs.ton.org/languages/func/stdlib#slice_last) `slice_last` slice slice_last(slice s, int len) asm "SDCUTLAST"; Returns the last `len` bits of `s`, where `0 ≤ len ≤ 1023`. #### [​](https://docs.ton.org/languages/func/stdlib#load_dict) `load_dict` (slice, cell) load_dict(slice s) asm( -> 1 0) "LDDICT"; Loads a dictionary `D` from slice `s`. It can be used for dictionaries or to values of arbitrary `Maybe ^Y` types (returns `null` if the `nothing` constructor is used). #### [​](https://docs.ton.org/languages/func/stdlib#preload_dict) `preload_dict` cell preload_dict(slice s) asm "PLDDICT"; Preloads a dictionary `D` from slice `s`. #### [​](https://docs.ton.org/languages/func/stdlib#skip_dict) `skip_dict` slice skip_dict(slice s) asm "SKIPDICT"; Loads a dictionary as `load_dict` but returns only the remainder of the slice. ### [​](https://docs.ton.org/languages/func/stdlib#slice-size-primitives) Slice size primitives #### [​](https://docs.ton.org/languages/func/stdlib#slice_refs) `slice_refs` int slice_refs(slice s) asm "SREFS"; Returns the number of references in slice `s`. #### [​](https://docs.ton.org/languages/func/stdlib#slice_bits) `slice_bits` int slice_bits(slice s) asm "SBITS"; Returns the number of data bits in slice `s`. #### [​](https://docs.ton.org/languages/func/stdlib#slice_bits_refs) `slice_bits_refs` (int, int) slice_bits_refs(slice s) asm "SBITREFS"; Returns both the number of data bits and the number of references in `s`. #### [​](https://docs.ton.org/languages/func/stdlib#slice_empty) `slice_empty?` int slice_empty?(slice s) asm "SEMPTY"; Checks whether slice `s` is empty (i.e., contains no bits of data and no cell references). #### [​](https://docs.ton.org/languages/func/stdlib#slice_data_empty) `slice_data_empty?` int slice_data_empty?(slice s) asm "SDEMPTY"; Checks whether slice `s` has no bits of data. #### [​](https://docs.ton.org/languages/func/stdlib#slice_refs_empty) `slice_refs_empty?` int slice_refs_empty?(slice s) asm "SREMPTY"; Checks whether slice `s` has no references. #### [​](https://docs.ton.org/languages/func/stdlib#slice_depth) `slice_depth` int slice_depth(slice s) asm "SDEPTH"; Returns the depth of slice `s`. If `s` has no references, it returns `0`; otherwise, the returned value is one plus the maximum depths of cells referred to from `s`. ### [​](https://docs.ton.org/languages/func/stdlib#builder-primitives) Builder primitives A primitive _stores_ a value `x` in a builder `b` by returning a modified version `b'` with `x` added at the end. It can also be used as a [non-modifying method](https://docs.ton.org/languages/func/statements#non-modifying-methods) . Each of the following primitives first checks for enough space in the `builder` and then verifies the range of the serialized value. #### [​](https://docs.ton.org/languages/func/stdlib#begin_cell) `begin_cell` builder begin_cell() asm "NEWC"; Creates a new empty `builder`. #### [​](https://docs.ton.org/languages/func/stdlib#end_cell) `end_cell` cell end_cell(builder b) asm "ENDC"; Converts a `builder` into a standard `cell`. #### [​](https://docs.ton.org/languages/func/stdlib#store_ref) `store_ref` builder store_ref(builder b, cell c) asm(c b) "STREF"; Stores a reference to cell `c` in builder `b`. #### [​](https://docs.ton.org/languages/func/stdlib#store_uint) `store_uint` builder store_uint(builder b, int x, int len) asm(x b len) "STUX"; Stores an unsigned `len`\-bit integer `x` in `b`, where `0 ≤ len ≤ 256`. #### [​](https://docs.ton.org/languages/func/stdlib#store_int) `store_int` builder store_int(builder b, int x, int len) asm(x b len) "STIX"; Stores a signed `len`\-bit integer `x` in `b`, where `0 ≤ len ≤ 257`. #### [​](https://docs.ton.org/languages/func/stdlib#store_slice) `store_slice` builder store_slice(builder b, slice s) asm "STSLICER"; Stores slice `s` in builder `b`. #### [​](https://docs.ton.org/languages/func/stdlib#store_grams) `store_grams` builder store_grams(builder b, int x) asm "STGRAMS"; #### [​](https://docs.ton.org/languages/func/stdlib#store_coins) `store_coins` builder store_coins(builder b, int x) asm "STGRAMS"; Serializes an integer `x` in the range `0..2^120 − 1` into builder `b`. The serialization consists of: * A 4-bit unsigned big-endian integer `l`, the smallest `l ≥ 0` such that `x < 2^8l`. * An `8l`\-bit unsigned big-endian representation of `x`. A range check exception is thrown if `x` is outside the supported range. This is the standard way of storing Toncoin. #### [​](https://docs.ton.org/languages/func/stdlib#store_dict) `store_dict` builder store_dict(builder b, cell c) asm(c b) "STDICT"; Stores a dictionary `D` represented by cell `c` or `null` into builder `b`. Stores a 1-bit and a reference to `c` if `c` is not `null`; otherwise, stores a 0-bit. #### [​](https://docs.ton.org/languages/func/stdlib#store_maybe_ref) `store_maybe_ref` builder store_maybe_ref(builder b, cell c) asm(c b) "STOPTREF"; The same as `store_dict`. ### [​](https://docs.ton.org/languages/func/stdlib#builder-size-primitives) Builder size primitives #### [​](https://docs.ton.org/languages/func/stdlib#builder_refs) `builder_refs` int builder_refs(builder b) asm "BREFS"; Returns the number of cell references currently stored in builder `b`. #### [​](https://docs.ton.org/languages/func/stdlib#builder_bits) `builder_bits` int builder_bits(builder b) asm "BBITS"; Returns the number of data bits currently stored in builder `b`. #### [​](https://docs.ton.org/languages/func/stdlib#builder_depth) `builder_depth` int builder_depth(builder b) asm "BDEPTH"; Returns the depth of builder `b`. If `b` contains no cell references, it returns `0`. Otherwise, it returns `1` plus the maximum depth among the referenced cells. ### [​](https://docs.ton.org/languages/func/stdlib#cell-primitives) Cell primitives #### [​](https://docs.ton.org/languages/func/stdlib#cell_depth) `cell_depth` int cell_depth(cell c) asm "CDEPTH"; Returns the depth of the given `cell c`. If `c` has no references, the function returns `0`. Otherwise, it returns `1` plus the maximum depth among all cells referenced by `c`. If `c` is `null` instead of a cell, the function returns `0`. #### [​](https://docs.ton.org/languages/func/stdlib#cell_null) `cell_null?` int cell_null?(cell c) asm "ISNULL"; Checks whether the given `cell c` is `null`. In most cases, a `null` cell represents an empty dictionary. FunC also includes a polymorphic `null?` built-in function. See [built-in](https://docs.ton.org/languages/func/built-ins#other-primitives) for more details. [​](https://docs.ton.org/languages/func/stdlib#dictionaries-primitives) Dictionaries primitives -------------------------------------------------------------------------------------------------- As stated in [TVM.pdf](https://ton.org/tvm.pdf) : > Dictionaries can be represented in two different ways as TVM stack values: > > 1. **As a slice `s`** containing the serialized TL-B value of type `HashmapE(n, X)`. In simpler terms, `s` consists either of a single `0` bit if the dictionary is empty or a `1` bit followed by a reference to a cell containing the binary tree’s root — essentially, a serialized value of type `Hashmap(n, X)`. > 2. **As a `Maybe cell (c^?)`**, which is either a cell that contains a serialized `Hashmap(n, X)` same as above or `null`, indicating an empty dictionary. See [null values](https://docs.ton.org/languages/func/types#null-values) > for details. When using this format, the dictionary is typically referred to as `D`. > > Most dictionary-related operations use the second format because it is easier to manipulate on the stack. However, when dictionaries are serialized within larger TL-B objects, they follow the first representation. In FunC, dictionaries are also represented as `cells` with the implicit assumption that they can be `null`. There are no separate types for dictionaries with different key lengths or value types — after all, this is FunC, not FunC++. ### [​](https://docs.ton.org/languages/func/stdlib#taxonomy-note) Taxonomy note A dictionary primitive interprets dictionary keys in one of three ways: 1. Unsigned `l`\-bit integers (denoted by **u**); 2. Signed `l`\-bit integers (denoted by **i**); 3. `l`\-bit slices (**no prefix**). The naming convention of dictionary primitives reflects these distinctions. For example: * `udict_set` is a set-by-key function for dictionaries with unsigned integer keys. * `idict_set` is the equivalent function for signed integer keys. * `dict_set` applies to dictionaries with slice keys. In function titles, an **empty prefix** indicates slice keys. Additionally, some primitives have counterparts prefixed with `~`, enabling them to be used as [modifying methods](https://docs.ton.org/languages/func/statements#modifying-methods) . ### [​](https://docs.ton.org/languages/func/stdlib#dictionary-values) Dictionary values Values in a dictionary can be stored in two ways: 1. As a **subslice** within an inner dictionary cell. 2. As a **reference** to a separate cell. In the first case, even if a value is small enough to fit within a cell, it may not fit within the dictionary. This is because a segment of the corresponding key may already occupy part of the inner cell’s space. The second method, while ensuring storage, is less efficient regarding gas consumption. Storing a value this way is functionally equivalent to inserting a slice with no data bits and a single reference to the value, as in the first method. #### [​](https://docs.ton.org/languages/func/stdlib#dict_set) `dict_set` 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"; This function updates the dictionary `dict` by setting the value corresponding to the `key_len`\-bit key `index` to `value`, a slice, and returns the updated dictionary. #### [​](https://docs.ton.org/languages/func/stdlib#dict_set_ref) `dict_set_ref` 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"; This is similar to `dict_set`, but it sets the value to a reference of cell `value`. #### [​](https://docs.ton.org/languages/func/stdlib#dict_get) `dict_get?` (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"; Searches for the key `index` in the `dict` dictionary with `key_len`\-bit keys. It retrieves the associated value as a `slice` and returns a success flag of `-1` if found. If not found, it returns `(null, 0)`. #### [​](https://docs.ton.org/languages/func/stdlib#dict_get_ref) `dict_get_ref?` (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 it returns the first reference of the found value. #### [​](https://docs.ton.org/languages/func/stdlib#dict_get_ref) `dict_get_ref` cell idict_get_ref(cell dict, int key_len, int index) asm(index dict key_len) "DICTIGETOPTREF"; This variant of `dict_get_ref?` returns `null` if the key `index` is absent in the dictionary `dict`. #### [​](https://docs.ton.org/languages/func/stdlib#dict_set_get_ref) `dict_set_get_ref` (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"; This function sets the value associated with the `index` to `value`. If the `value` is `null`, the key is deleted. It then returns the old value or `null` if it wasn’t present. #### [​](https://docs.ton.org/languages/func/stdlib#dict_delete) `dict_delete?` (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"; This function deletes the `key_len`\-bit key `index` from the dictionary `dict`. It returns the modified dictionary and a success flag of `-1` if successful. If the key is not found, it returns the original dictionary and `0`. #### [​](https://docs.ton.org/languages/func/stdlib#dict_delete_get) `dict_delete_get?` (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 the `key_len`\-bit key `index` from the dictionary `dict`. If the key is found, it returns the modified dictionary, the original value associated with the key as a Slice, and the success flag `-1`. If the key is not found, it returns `(dict, null, 0)`. #### [​](https://docs.ton.org/languages/func/stdlib#dict_add) `dict_add?` (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"; This `add` operation is similar to `dict_set` but only sets the value if the key `index` does not already exist in the dictionary `dict`. It returns the modified dictionary and a success flag of `-1` or `(dict, 0)`. #### [​](https://docs.ton.org/languages/func/stdlib#dict_replace) `dict_replace?` (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"; This `replace` operation works like `dict_set`, but it only updates the value for the `index` if the key is already present in the dictionary `dict`. It returns the modified dictionary and a success flag of `-1` or `(dict, 0)`. ### [​](https://docs.ton.org/languages/func/stdlib#builder-counterparts) Builder counterparts The following primitives accept a builder as the new value instead of a slice, making them more convenient when the value needs to be serialized from multiple components computed on the stack. Functionally, this is equivalent to converting the builder into a slice and executing the corresponding primitive listed above. #### [​](https://docs.ton.org/languages/func/stdlib#dict_set_builder) `dict_set_builder` 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"; It works similarly to `dict_set` but takes a builder as input. #### [​](https://docs.ton.org/languages/func/stdlib#dict_add_builder) `dict_add_builder?` (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 uses a builder. #### [​](https://docs.ton.org/languages/func/stdlib#dict_replace_builder) `dict_replace_builder?` (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 uses a builder. #### [​](https://docs.ton.org/languages/func/stdlib#dict_delete_get_min) `dict_delete_get_min` (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"; Finds the smallest key `k` in the dictionary `dict`, removes it, and returns `(dict', k, x, -1)`, where `dict'` is the updated dictionary and `x` is the value associated with `k`. If the dictionary is empty, it returns `(dict, null, null, 0)`. Note: The key returned by `idict_delete_get_min` may differ from that returned by `dict_delete_get_min` and `udict_delete_get_min`. #### [​](https://docs.ton.org/languages/func/stdlib#dict_delete_get_max) `dict_delete_get_max` (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"; Finds the largest key `k` in the dictionary `dict`, removes it, and returns `(dict', k, x, -1)`, where `dict'` is the updated dictionary and `x` is the value associated with `k`. If the dictionary is empty, it returns `(dict, null, null, 0)`. #### [​](https://docs.ton.org/languages/func/stdlib#dict_get_min) `dict_get_min?` (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"; Finds the smallest key `k` in the dictionary `dict` and returns `(k, x, -1)`, where `x` is the value associated with `k`. If the dictionary is empty, it returns `(null, null, 0)`. #### [​](https://docs.ton.org/languages/func/stdlib#dict_get_max) `dict_get_max?` (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"; Finds the largest key `k` in the dictionary `dict` and returns `(k, x, -1)`, where `x` is the value associated with `k`. If the dictionary is empty, it returns `(null, null, 0)`. #### [​](https://docs.ton.org/languages/func/stdlib#dict_get_min_ref) `dict_get_min_ref?` (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"; Same as `dict_get_min?` but it returns a reference. #### [​](https://docs.ton.org/languages/func/stdlib#dict_get_max_ref) `dict_get_max_ref?` (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"; Same as `dict_get_max?` but it returns a reference. #### [​](https://docs.ton.org/languages/func/stdlib#dict_get_next) `dict_get_next?` (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"; Finds the smallest key `k` in `dict` that is greater than the `pivot`. Returns `k`, associated value, and a success flag. If the dictionary is empty, it returns `(null, null, 0)`. #### [​](https://docs.ton.org/languages/func/stdlib#dict_get_nexteq) `dict_get_nexteq?` (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 instead finds the smallest key `k` that is greater than or equal to the `pivot`. #### [​](https://docs.ton.org/languages/func/stdlib#dict_get_prev) `dict_get_prev?` (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 instead finds the largest key `k` that is less than the `pivot`. #### [​](https://docs.ton.org/languages/func/stdlib#dict_get_preveq) `dict_get_preveq?` (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 instead finds the largest key `k` that is less than or equal to the `pivot`. #### [​](https://docs.ton.org/languages/func/stdlib#new_dict) `new_dict` cell new_dict() asm "NEWDICT"; Creates an empty dictionary, which is represented as a `null` value — a special case of `null()`. #### [​](https://docs.ton.org/languages/func/stdlib#dict_empty) `dict_empty?` int dict_empty?(cell c) asm "DICTEMPTY"; Checks whether a dictionary is empty. Equivalent to `cell_null?`. ### [​](https://docs.ton.org/languages/func/stdlib#prefix-dictionaries-primitives) Prefix dictionaries primitives TVM supports dictionaries with non-fixed length keys that follow a prefix code structure, meaning no key is a prefix of another key. Learn more in the [TVM instruction](https://docs.ton.org/tvm/instructions) section. #### [​](https://docs.ton.org/languages/func/stdlib#pfxdict_get) `pfxdict_get?` (slice, slice, slice, int) pfxdict_get?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTGETQ" "NULLSWAPIFNOT2"; Searches for the unique prefix of a slice `key` in the prefix code dictionary `dict`. If found, returns `(s', x, s'', -1)`, where: * `s'` is the matching prefix of `s`, * `x` is the corresponding value (a slice), * `s''` is the remaining part of `s`, * `-1` indicates success. If no matching prefix is found, returns `(null, null, s, 0)`, where `s` remains unchanged and `0` indicates failure. #### [​](https://docs.ton.org/languages/func/stdlib#pfxdict_set) `pfxdict_set?` (cell, int) pfxdict_set?(cell dict, int key_len, slice key, slice value) asm(value key dict key_len) "PFXDICTSET"; Works like `dict_set` but fails if the given key is a prefix of an existing key in dict. Returns a flag indicating success. #### [​](https://docs.ton.org/languages/func/stdlib#pfxdict_delete) `pfxdict_delete?` (cell, int) pfxdict_delete?(cell dict, int key_len, slice key) asm(key dict key_len) "PFXDICTDEL"; Similar to `dict_delete?`. [​](https://docs.ton.org/languages/func/stdlib#special-primitives) Special primitives ---------------------------------------------------------------------------------------- ### [​](https://docs.ton.org/languages/func/stdlib#null) `null` forall X -> X null() asm "PUSHNULL"; In TVM, the `Null` type in FunC represents the absence of a value for any atomic type, meaning `null` can take on any atomic type. [​](https://docs.ton.org/languages/func/stdlib#impure_touch) `~impure_touch` ------------------------------------------------------------------------------- forall X -> (X, ()) ~impure_touch(X x) impure asm "NOP"; Marks a variable as used, ensuring the code generated isn’t removed during optimization, even if it’s not impure. See [Impure specifier](https://docs.ton.org/languages/func/functions#impure-specifier) section. [​](https://docs.ton.org/languages/func/stdlib#other-primitives) Other primitives ------------------------------------------------------------------------------------ ### [​](https://docs.ton.org/languages/func/stdlib#min) `min` int min(int x, int y) asm "MIN"; Computes the minimum of two integers `x` and `y`. ### [​](https://docs.ton.org/languages/func/stdlib#max) `max` int max(int x, int y) asm "MAX"; Computes the maximum of two integers `x` and `y`. ### [​](https://docs.ton.org/languages/func/stdlib#minmax) `minmax` (int, int) minmax(int x, int y) asm "MINMAX"; Returns `(min(x, y), max(x, y))`, sorting two integers. ### [​](https://docs.ton.org/languages/func/stdlib#abs) `abs` int abs(int x) asm "ABS"; Computes the absolute value of `x`. Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/languages/func/stdlib.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/languages/func/stdlib) [Previous](https://docs.ton.org/languages/func/dictionaries) [Other libraries\ \ Next](https://docs.ton.org/languages/func/libraries) ⌘I On this page * [Tuple manipulation primitives](https://docs.ton.org/languages/func/stdlib#tuple-manipulation-primitives) * [Lisp-style lists](https://docs.ton.org/languages/func/stdlib#lisp-style-lists) * [cons](https://docs.ton.org/languages/func/stdlib#cons) * [uncons](https://docs.ton.org/languages/func/stdlib#uncons) * [list\_next](https://docs.ton.org/languages/func/stdlib#list_next) * [car](https://docs.ton.org/languages/func/stdlib#car) * [cdr](https://docs.ton.org/languages/func/stdlib#cdr) * [Other tuple primitives](https://docs.ton.org/languages/func/stdlib#other-tuple-primitives) * [empty\_tuple](https://docs.ton.org/languages/func/stdlib#empty_tuple) * [tpush](https://docs.ton.org/languages/func/stdlib#tpush) * [single](https://docs.ton.org/languages/func/stdlib#single) * [unsingle](https://docs.ton.org/languages/func/stdlib#unsingle) * [pair](https://docs.ton.org/languages/func/stdlib#pair) * [unpair](https://docs.ton.org/languages/func/stdlib#unpair) * [triple](https://docs.ton.org/languages/func/stdlib#triple) * [untriple](https://docs.ton.org/languages/func/stdlib#untriple) * [tuple4](https://docs.ton.org/languages/func/stdlib#tuple4) * [untuple4](https://docs.ton.org/languages/func/stdlib#untuple4) * [Tuple element access](https://docs.ton.org/languages/func/stdlib#tuple-element-access) * [first](https://docs.ton.org/languages/func/stdlib#first) * [second](https://docs.ton.org/languages/func/stdlib#second) * [third](https://docs.ton.org/languages/func/stdlib#third) * [fourth](https://docs.ton.org/languages/func/stdlib#fourth) * [Pair and triple element access](https://docs.ton.org/languages/func/stdlib#pair-and-triple-element-access) * [pair\_first](https://docs.ton.org/languages/func/stdlib#pair_first) * [pair\_second](https://docs.ton.org/languages/func/stdlib#pair_second) * [triple\_first](https://docs.ton.org/languages/func/stdlib#triple_first) * [triple\_second](https://docs.ton.org/languages/func/stdlib#triple_second) * [triple\_third](https://docs.ton.org/languages/func/stdlib#triple_third) * [Domain specific primitives](https://docs.ton.org/languages/func/stdlib#domain-specific-primitives) * [Extracting info from c7](https://docs.ton.org/languages/func/stdlib#extracting-info-from-c7) * [now](https://docs.ton.org/languages/func/stdlib#now) * [my\_address](https://docs.ton.org/languages/func/stdlib#my_address) * [get\_balance](https://docs.ton.org/languages/func/stdlib#get_balance) * [cur\_lt](https://docs.ton.org/languages/func/stdlib#cur_lt) * [block\_lt](https://docs.ton.org/languages/func/stdlib#block_lt) * [config\_param](https://docs.ton.org/languages/func/stdlib#config_param) * [my\_code](https://docs.ton.org/languages/func/stdlib#my_code) * [Hashes](https://docs.ton.org/languages/func/stdlib#hashes) * [cell\_hash](https://docs.ton.org/languages/func/stdlib#cell_hash) * [slice\_hash](https://docs.ton.org/languages/func/stdlib#slice_hash) * [string\_hash](https://docs.ton.org/languages/func/stdlib#string_hash) * [Signature checks](https://docs.ton.org/languages/func/stdlib#signature-checks) * [check\_signature](https://docs.ton.org/languages/func/stdlib#check_signature) * [check\_data\_signature](https://docs.ton.org/languages/func/stdlib#check_data_signature) * [Computation of BoC size](https://docs.ton.org/languages/func/stdlib#computation-of-boc-size) * [compute\_data\_size?](https://docs.ton.org/languages/func/stdlib#compute_data_size) * [slice\_compute\_data\_size?](https://docs.ton.org/languages/func/stdlib#slice_compute_data_size) * [compute\_data\_size](https://docs.ton.org/languages/func/stdlib#compute_data_size) * [slice\_compute\_data\_size](https://docs.ton.org/languages/func/stdlib#slice_compute_data_size) * [Persistent storage save and load](https://docs.ton.org/languages/func/stdlib#persistent-storage-save-and-load) * [get\_data](https://docs.ton.org/languages/func/stdlib#get_data) * [set\_data](https://docs.ton.org/languages/func/stdlib#set_data) * [Continuation primitives](https://docs.ton.org/languages/func/stdlib#continuation-primitives) * [get\_c3](https://docs.ton.org/languages/func/stdlib#get_c3) * [set\_c3](https://docs.ton.org/languages/func/stdlib#set_c3) * [bless](https://docs.ton.org/languages/func/stdlib#bless) * [Gas related primitives](https://docs.ton.org/languages/func/stdlib#gas-related-primitives) * [accept\_message](https://docs.ton.org/languages/func/stdlib#accept_message) * [set\_gas\_limit](https://docs.ton.org/languages/func/stdlib#set_gas_limit) * [commit](https://docs.ton.org/languages/func/stdlib#commit) * [buy\_gas](https://docs.ton.org/languages/func/stdlib#buy_gas) * [Actions primitives](https://docs.ton.org/languages/func/stdlib#actions-primitives) * [raw\_reserve](https://docs.ton.org/languages/func/stdlib#raw_reserve) * [raw\_reserve\_extra](https://docs.ton.org/languages/func/stdlib#raw_reserve_extra) * [send\_raw\_message](https://docs.ton.org/languages/func/stdlib#send_raw_message) * [set\_code](https://docs.ton.org/languages/func/stdlib#set_code) * [Random number generator primitives](https://docs.ton.org/languages/func/stdlib#random-number-generator-primitives) * [random](https://docs.ton.org/languages/func/stdlib#random) * [rand](https://docs.ton.org/languages/func/stdlib#rand) * [get\_seed](https://docs.ton.org/languages/func/stdlib#get_seed) * [set\_seed](https://docs.ton.org/languages/func/stdlib#set_seed) * [randomize](https://docs.ton.org/languages/func/stdlib#randomize) * [randomize\_lt](https://docs.ton.org/languages/func/stdlib#randomize_lt) * [Address manipulation primitives](https://docs.ton.org/languages/func/stdlib#address-manipulation-primitives) * [load\_msg\_addr](https://docs.ton.org/languages/func/stdlib#load_msg_addr) * [parse\_addr](https://docs.ton.org/languages/func/stdlib#parse_addr) * [parse\_std\_addr](https://docs.ton.org/languages/func/stdlib#parse_std_addr) * [parse\_var\_addr](https://docs.ton.org/languages/func/stdlib#parse_var_addr) * [Debug primitives](https://docs.ton.org/languages/func/stdlib#debug-primitives) * [~dump](https://docs.ton.org/languages/func/stdlib#dump) * [~strdump](https://docs.ton.org/languages/func/stdlib#strdump) * [dump\_stack](https://docs.ton.org/languages/func/stdlib#dump_stack) * [Slice primitives](https://docs.ton.org/languages/func/stdlib#slice-primitives) * [begin\_parse](https://docs.ton.org/languages/func/stdlib#begin_parse) * [end\_parse](https://docs.ton.org/languages/func/stdlib#end_parse) * [load\_ref](https://docs.ton.org/languages/func/stdlib#load_ref) * [preload\_ref](https://docs.ton.org/languages/func/stdlib#preload_ref) * [load\_int](https://docs.ton.org/languages/func/stdlib#load_int) * [load\_uint](https://docs.ton.org/languages/func/stdlib#load_uint) * [preload\_int](https://docs.ton.org/languages/func/stdlib#preload_int) * [preload\_uint](https://docs.ton.org/languages/func/stdlib#preload_uint) * [load\_bits](https://docs.ton.org/languages/func/stdlib#load_bits) * [preload\_bits](https://docs.ton.org/languages/func/stdlib#preload_bits) * [load\_coins](https://docs.ton.org/languages/func/stdlib#load_coins) * [skip\_bits](https://docs.ton.org/languages/func/stdlib#skip_bits) * [first\_bits](https://docs.ton.org/languages/func/stdlib#first_bits) * [skip\_last\_bits](https://docs.ton.org/languages/func/stdlib#skip_last_bits) * [slice\_last](https://docs.ton.org/languages/func/stdlib#slice_last) * [load\_dict](https://docs.ton.org/languages/func/stdlib#load_dict) * [preload\_dict](https://docs.ton.org/languages/func/stdlib#preload_dict) * [skip\_dict](https://docs.ton.org/languages/func/stdlib#skip_dict) * [Slice size primitives](https://docs.ton.org/languages/func/stdlib#slice-size-primitives) * [slice\_refs](https://docs.ton.org/languages/func/stdlib#slice_refs) * [slice\_bits](https://docs.ton.org/languages/func/stdlib#slice_bits) * [slice\_bits\_refs](https://docs.ton.org/languages/func/stdlib#slice_bits_refs) * [slice\_empty?](https://docs.ton.org/languages/func/stdlib#slice_empty) * [slice\_data\_empty?](https://docs.ton.org/languages/func/stdlib#slice_data_empty) * [slice\_refs\_empty?](https://docs.ton.org/languages/func/stdlib#slice_refs_empty) * [slice\_depth](https://docs.ton.org/languages/func/stdlib#slice_depth) * [Builder primitives](https://docs.ton.org/languages/func/stdlib#builder-primitives) * [begin\_cell](https://docs.ton.org/languages/func/stdlib#begin_cell) * [end\_cell](https://docs.ton.org/languages/func/stdlib#end_cell) * [store\_ref](https://docs.ton.org/languages/func/stdlib#store_ref) * [store\_uint](https://docs.ton.org/languages/func/stdlib#store_uint) * [store\_int](https://docs.ton.org/languages/func/stdlib#store_int) * [store\_slice](https://docs.ton.org/languages/func/stdlib#store_slice) * [store\_grams](https://docs.ton.org/languages/func/stdlib#store_grams) * [store\_coins](https://docs.ton.org/languages/func/stdlib#store_coins) * [store\_dict](https://docs.ton.org/languages/func/stdlib#store_dict) * [store\_maybe\_ref](https://docs.ton.org/languages/func/stdlib#store_maybe_ref) * [Builder size primitives](https://docs.ton.org/languages/func/stdlib#builder-size-primitives) * [builder\_refs](https://docs.ton.org/languages/func/stdlib#builder_refs) * [builder\_bits](https://docs.ton.org/languages/func/stdlib#builder_bits) * [builder\_depth](https://docs.ton.org/languages/func/stdlib#builder_depth) * [Cell primitives](https://docs.ton.org/languages/func/stdlib#cell-primitives) * [cell\_depth](https://docs.ton.org/languages/func/stdlib#cell_depth) * [cell\_null?](https://docs.ton.org/languages/func/stdlib#cell_null) * [Dictionaries primitives](https://docs.ton.org/languages/func/stdlib#dictionaries-primitives) * [Taxonomy note](https://docs.ton.org/languages/func/stdlib#taxonomy-note) * [Dictionary values](https://docs.ton.org/languages/func/stdlib#dictionary-values) * [dict\_set](https://docs.ton.org/languages/func/stdlib#dict_set) * [dict\_set\_ref](https://docs.ton.org/languages/func/stdlib#dict_set_ref) * [dict\_get?](https://docs.ton.org/languages/func/stdlib#dict_get) * [dict\_get\_ref?](https://docs.ton.org/languages/func/stdlib#dict_get_ref) * [dict\_get\_ref](https://docs.ton.org/languages/func/stdlib#dict_get_ref) * [dict\_set\_get\_ref](https://docs.ton.org/languages/func/stdlib#dict_set_get_ref) * [dict\_delete?](https://docs.ton.org/languages/func/stdlib#dict_delete) * [dict\_delete\_get?](https://docs.ton.org/languages/func/stdlib#dict_delete_get) * [dict\_add?](https://docs.ton.org/languages/func/stdlib#dict_add) * [dict\_replace?](https://docs.ton.org/languages/func/stdlib#dict_replace) * [Builder counterparts](https://docs.ton.org/languages/func/stdlib#builder-counterparts) * [dict\_set\_builder](https://docs.ton.org/languages/func/stdlib#dict_set_builder) * [dict\_add\_builder?](https://docs.ton.org/languages/func/stdlib#dict_add_builder) * [dict\_replace\_builder?](https://docs.ton.org/languages/func/stdlib#dict_replace_builder) * [dict\_delete\_get\_min](https://docs.ton.org/languages/func/stdlib#dict_delete_get_min) * [dict\_delete\_get\_max](https://docs.ton.org/languages/func/stdlib#dict_delete_get_max) * [dict\_get\_min?](https://docs.ton.org/languages/func/stdlib#dict_get_min) * [dict\_get\_max?](https://docs.ton.org/languages/func/stdlib#dict_get_max) * [dict\_get\_min\_ref?](https://docs.ton.org/languages/func/stdlib#dict_get_min_ref) * [dict\_get\_max\_ref?](https://docs.ton.org/languages/func/stdlib#dict_get_max_ref) * [dict\_get\_next?](https://docs.ton.org/languages/func/stdlib#dict_get_next) * [dict\_get\_nexteq?](https://docs.ton.org/languages/func/stdlib#dict_get_nexteq) * [dict\_get\_prev?](https://docs.ton.org/languages/func/stdlib#dict_get_prev) * [dict\_get\_preveq?](https://docs.ton.org/languages/func/stdlib#dict_get_preveq) * [new\_dict](https://docs.ton.org/languages/func/stdlib#new_dict) * [dict\_empty?](https://docs.ton.org/languages/func/stdlib#dict_empty) * [Prefix dictionaries primitives](https://docs.ton.org/languages/func/stdlib#prefix-dictionaries-primitives) * [pfxdict\_get?](https://docs.ton.org/languages/func/stdlib#pfxdict_get) * [pfxdict\_set?](https://docs.ton.org/languages/func/stdlib#pfxdict_set) * [pfxdict\_delete?](https://docs.ton.org/languages/func/stdlib#pfxdict_delete) * [Special primitives](https://docs.ton.org/languages/func/stdlib#special-primitives) * [null](https://docs.ton.org/languages/func/stdlib#null) * [~impure\_touch](https://docs.ton.org/languages/func/stdlib#impure_touch) * [Other primitives](https://docs.ton.org/languages/func/stdlib#other-primitives) * [min](https://docs.ton.org/languages/func/stdlib#min) * [max](https://docs.ton.org/languages/func/stdlib#max) * [minmax](https://docs.ton.org/languages/func/stdlib#minmax) * [abs](https://docs.ton.org/languages/func/stdlib#abs) --- # Highload Wallet v3 — specification - TON Docs [Skip to main content](https://docs.ton.org/standard/wallets/highload/v3/specification#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Highload Wallet v3 Highload Wallet v3 — specification This page provides a complete technical specification for Highload Wallet v3, covering storage structure, message formats, replay protection, limitations, and security mechanisms. [​](https://docs.ton.org/standard/wallets/highload/v3/specification#objective) Objective ------------------------------------------------------------------------------------------- Understand the internal architecture, data structures, and operational mechanics of Highload Wallet v3. This reference page explains how the wallet processes high-throughput transaction flows securely. [​](https://docs.ton.org/standard/wallets/highload/v3/specification#what-is-highload-wallet-v3) What is Highload Wallet v3? ------------------------------------------------------------------------------------------------------------------------------ Highload Wallet v3 is a specialized wallet smart contract designed for services that need to send many transactions in a short time (e.g., cryptocurrency exchanges, payment processors). **Key difference from standard wallets:** Unlike seqno-based wallets (v3, v4, v5) that require sequential transaction processing, Highload v3 stores processed request identifiers in a dictionary, enabling **parallel transaction submission** without blocking. **Compared to Highload v2:** v3 solves architectural issues that could lock funds in v2 and consumes less gas during operations. * * * [​](https://docs.ton.org/standard/wallets/highload/v3/specification#tl-b-schema) TL-B schema ----------------------------------------------------------------------------------------------- [TL-B (Type Language - Binary)](https://docs.ton.org/languages/tl-b/overview) is a domain-specific language designed to describe data structures in TON. The schemas below define the binary layout of the contract’s storage, external messages, and internal messages. ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#storage-structure) Storage structure storage$_ public_key:bits256 subwallet_id:uint32 old_queries:(HashmapE 13 ^Cell) queries:(HashmapE 13 ^Cell) last_clean_time:uint64 timeout:uint22 = Storage; ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#query-id-structure) Query ID structure _ shift:uint13 bit_number:(## 10) { bit_number >= 0 } { bit_number < 1023 } = QueryId; ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#external-message-structure) External message structure _ {n:#} subwallet_id:uint32 message_to_send:^Cell send_mode:uint8 query_id:QueryId created_at:uint64 timeout:uint22 = MsgInner; msg_body$_ {n:#} signature:bits512 ^(MsgInner) = ExternalInMsgBody; ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#internal-message-structure-for-batch-transfers) Internal message structure (for batch transfers) internal_transfer#ae42e5a4 {n:#} query_id:uint64 actions:^(OutList n) = InternalMsgBody n; Below, each field is explained in detail. * * * [​](https://docs.ton.org/standard/wallets/highload/v3/specification#storage-structure-2) Storage structure ------------------------------------------------------------------------------------------------------------- The Highload Wallet v3 contract stores six persistent fields: ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#public_key-256-bits) `public_key` (256 bits) **Purpose:** An Ed25519 public key is used to verify signatures on incoming external messages. **How it works:** When the wallet receives an external message, it verifies that the 512-bit signature was created by the holder of the private key corresponding to this public key. * * * ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#subwallet_id-32-bits) `subwallet_id` (32 bits) **Purpose:** Allows a single keypair to control multiple wallets with different addresses. **How it works:** The `subwallet_id` is part of the contract’s initial state. Changing it produces a different contract address (because the address is a hash of code + data). Each external message must include the correct `subwallet_id`; mismatches result in exit code `34`. **Common use case:** One private key manages multiple “virtual” wallets for organizational or accounting purposes. **Recommendation:** Use `subwallet_id: 0x10ad` (4269) to avoid conflicts with other wallet types (standard wallets or vesting wallets) derived from the same keypair. See [How to create Highload Wallet v3](https://docs.ton.org/standard/wallets/highload/v3/create) for details. * * * ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#old_queries-hashmape-13-^cell) `old_queries` (HashmapE 13 ^Cell) **Purpose:** Stores previously processed `query_id` values during rotation cycles. **Structure:** Hashmap with 13-bit keys, where each key holds a bitmap of processed query IDs. **Usage:** Provides a second layer of replay protection. During cleanup, `queries` → `old_queries`, creating a double timeout window. **Details:** See [Replay protection mechanism](https://docs.ton.org/standard/wallets/highload/v3/specification#replay-protection-mechanism) . * * * ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#queries-hashmape-13-^cell) `queries` (HashmapE 13 ^Cell) **Purpose:** Stores recently processed `query_id` values to prevent replay attacks. **Structure:** Hashmap with 13-bit keys, where each key holds a bitmap of processed query IDs. **Usage:** When a message arrives, the contract checks if its `query_id` is already marked in `queries` or `old_queries`. If found, the message is rejected as a replay attempt. **Details:** See [Replay protection mechanism](https://docs.ton.org/standard/wallets/highload/v3/specification#replay-protection-mechanism) . * * * ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#last_clean_time-64-bits) `last_clean_time` (64 bits) **Purpose:** Unix timestamp (in seconds) of the last cleanup operation. **Usage:** Tracks when the contract last rotated `queries` → `old_queries`. Cleanup triggers when `current_time >= last_clean_time + timeout`. **Details:** See [Replay protection mechanism](https://docs.ton.org/standard/wallets/highload/v3/specification#replay-protection-mechanism) . * * * ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#timeout-22-bits) `timeout` (22 bits) **Purpose:** Defines the validity window (in seconds) for external messages. **Usage:** Messages are valid if `created_at > now() - timeout` and `created_at <= now()`. If expired or from the future, the contract rejects them with exit code `35`. **Details:** * [Replay protection mechanism](https://docs.ton.org/standard/wallets/highload/v3/specification#replay-protection-mechanism) — how timeout is used * [Timeout constraints](https://docs.ton.org/standard/wallets/highload/v3/specification#timeout-constraints) — choosing the right value * * * [​](https://docs.ton.org/standard/wallets/highload/v3/specification#replay-protection-mechanism) Replay protection mechanism ------------------------------------------------------------------------------------------------------------------------------- Highload v3 uses a dual-hashmap system (`queries` and `old_queries`) combined with timestamps to prevent replay attacks. ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#storage-structure-for-replay-protection) Storage structure for replay protection The contract stores processed `query_id` values in two hashmaps: **`old_queries` (HashmapE 13 ^Cell):** * Hashmap with 13-bit keys * Each key corresponds to `shift` (13 bits from query\_id) * Each value is a cell containing a bitmap of processed `bit_number` values * Stores previously processed query IDs from the last rotation cycle * Provides extended protection during rotation **`queries` (HashmapE 13 ^Cell):** * Same structure as `old_queries` — hashmap with 13-bit keys * Each key corresponds to `shift = query_id >> 10` * Each value is a cell containing a bitmap of processed `bit_number` values * Stores recently processed query IDs ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#how-query_id-is-checked) How query\_id is checked When an external message arrives, the contract: 1. Extracts `query_id` from the message 2. Splits it into components: * `shift = query_id >> 10` (13 bits, range 0–8191) * `bit_number = query_id & 1023` (10 bits, range 0–1022) 3. Checks if bit `bit_number` is set in `queries[shift]`: * If found → reject with exit code `36` 4. Checks if bit `bit_number` is set in `old_queries[shift]`: * If found → reject with exit code `36` 5. If not found in either → mark the bit in `queries[shift]` and proceed **Why a hashmap structure?** Enables [parallel transaction submission](https://docs.ton.org/standard/wallets/highload/v3/specification#what-is-highload-wallet-v3) — multiple messages can be sent simultaneously without waiting for sequential confirmation. ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#rotation-mechanism) Rotation mechanism When `current_time >= last_clean_time + timeout`, the contract performs cleanup: 1. `old_queries := queries` — move current queries to old 2. `queries := {}` — clear current queries hashmap 3. `last_clean_time := current_time` — update timestamp **Additional cleanup:** If `current_time >= last_clean_time + (2 × timeout)` (i.e., no cleanup for twice the timeout period), the contract also clears `old_queries` completely to prevent unbounded storage growth. **Why two hashmaps?** This provides a **double timeout window** for replay protection: * A `query_id` is protected for at least `timeout` seconds in `queries` * After rotation, it remains in `old_queries` for another `timeout` period before deletion * Total protection window: between `timeout` and `2 × timeout` **Benefit:** Prevents replay attacks even if messages arrive near the rotation boundary. ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#timestamp-validation) Timestamp validation The `created_at` timestamp combined with `timeout` ensures that even very old messages (beyond the rotation window) are rejected. This creates a time-based boundary for message validity: The message is valid if: created_at > now() - timeout // Not too old created_at <= now() // Not from future Otherwise: reject with exit code 35 ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#uniqueness-guarantee) Uniqueness guarantee ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#why-internal-messages-to-self) Why internal messages to self? Highload v3 uses a unique **internal message to self** pattern for a critical security reason related to TON’s transaction phases. **The problem with standard external message wallets:** In TON, transaction processing includes several phases. Two phases are critical for understanding this problem: 1. **Compute phase** — executes smart contract code, updates storage 2. **Action phase** — performs actions (sends messages) If the action phase fails (e.g., insufficient funds for outgoing messages), the **entire transaction is rolled back**, including all storage changes made in the compute phase. For standard wallets that process external messages and send outgoing messages directly, this creates a problem: if you mark a message as “processed” in the compute phase but the action phase then fails (e.g., due to insufficient balance or invalid message), the rollback will **undo the replay protection**. Since the message was never marked as processed, lite-servers will keep retrying the same external message again and again, **burning gas on each attempt** for a long time or until the wallet runs out of funds. **Highload v3’s solution:** Highload v3 uses a two-step approach with **internal messages**: 1. **Transaction 1 (external message):** Only marks `query_id` as processed and sends an **internal message to itself** 2. **Transaction 2 (internal message):** Processes the internal message and sends actual outgoing transfers Even if Transaction 2 fails in the action phase, Transaction 1 has already succeeded, and its storage changes (replay protection) cannot be rolled back. The `query_id` remains marked as processed, preventing replay attacks. This architecture solves a fundamental problem present in all standard external message wallets, including seqno-based wallets and earlier highload designs. * * * [​](https://docs.ton.org/standard/wallets/highload/v3/specification#external-message-structure-2) External message structure ------------------------------------------------------------------------------------------------------------------------------- External messages sent to Highload v3 have a specific layout. ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#message-layout) Message layout signature:bits512 ^[ subwallet_id:uint32\ message_to_send:^Cell\ send_mode:uint8\ query_id:QueryId\ created_at:uint64\ timeout:uint22 ] **Key point:** The signature is in the **root cell** (512 bits); all other parameters are in a **reference cell** (`MsgInner`). * * * ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#signature-512-bits) `signature` (512 bits) **Type:** Ed25519 signature (512 bits). **What is signed:** The hash of the reference cell (`MsgInner`) containing `subwallet_id`, `message_to_send`, `send_mode`, `query_id`, `created_at`, and `timeout`. **Validation:** The contract verifies the signature using: check_signature(hash(ref_cell), signature, public_key) **On failure:** Exit code `33`. **Link:** [Ed25519 signature scheme](https://en.wikipedia.org/wiki/EdDSA#Ed25519) * * * ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#subwallet_id-32-bits-2) `subwallet_id` (32 bits) **Purpose:** Identifies which subwallet this message targets. **Validation:** Must match the `subwallet_id` stored in contract storage. **On mismatch:** Exit code `34`. * * * ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#query_id-composite-structure) `query_id` (composite structure) The `query_id` follows the `QueryId` TL-B structure and is split into two parts: * **`shift`** (uint13, 13 bits): high-order bits (range 0 to 8191) * **`bit_number`** (## 10): low-order bits with constraints `{ bit_number >= 0 } { bit_number < 1023 }` (range 0 to 1022) **Total range:** `2^13 × 1023 = 8,380,416` possible unique query IDs. **How it maps to the hashmap:** hashmap_key = shift (13 bits) bit_index = bit_number (10 bits) The contract checks if bit `bit_number` is set in the cell stored at `hashmap[shift]`. **Recommendation:** Increment `query_id` sequentially using a counter-based strategy. * * * ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#created_at-64-bits) `created_at` (64 bits) **Purpose:** Unix timestamp (seconds) when the external message was created. **Validation:** The contract performs two checks: created_at > now() - timeout // Message not too old created_at <= now() // Message not from future **On failure:** Exit code `35`. **Why it matters:** Prevents replay of expired messages. Even if a `query_id` is eventually forgotten, stale messages are rejected based on `created_at`. See [Timestamp validation](https://docs.ton.org/standard/wallets/highload/v3/specification#timestamp-validation) for important time lag considerations. * * * ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#timeout-22-bits-2) `timeout` (22 bits) **Purpose:** Defines the message validity window (in seconds). **Validation:** Must match the `timeout` value stored in contract storage. **On mismatch:** Exit code `38`. * * * ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#send_mode-8-bits) `send_mode` (8 bits) **Purpose:** Specifies the [send mode](https://docs.ton.org/foundations/messages/modes) for the internal message. **Link:** [send\_raw\_message modes](https://docs.ton.org/languages/func/stdlib#send-raw-message) * * * ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#message_to_send-reference-cell) `message_to_send` (reference cell) **Structure:** A serialized internal message stored in a reference cell. **Validation (exit code 37):** The contract validates `message_to_send` **after committing storage** to prevent action phase errors. The following checks are performed: 1. **Must be internal message:** First bit must be `0` (`int_msg_info$0`, not `ext_msg_info$10`) 2. **Source address must be none:** The `src` field must be `addr_none` (empty address) 3. **State-init must not be present:** State-init validation is too expensive in gas and is rarely needed. For contract deployment, use the [batch transfer pattern](https://docs.ton.org/standard/wallets/highload/v3/send-batch-transfers) with an action list 4. **Bounced messages are ignored:** If the `bounced` flag is set, the message is silently ignored (no error) **Critical limitation:** Highload v3 can send **only ONE internal message** per external message. For batch transfers, use the [internal\_transfer pattern](https://docs.ton.org/standard/wallets/highload/v3/specification#single-message-per-external) with an action list (up to 254 messages). * * * [​](https://docs.ton.org/standard/wallets/highload/v3/specification#message-sending-flow) Message sending flow ----------------------------------------------------------------------------------------------------------------- Highload v3 uses a two-transaction pattern to safely send messages: See [Single message per external](https://docs.ton.org/standard/wallets/highload/v3/specification#single-message-per-external) for details on this limitation and the batch transfer workaround. * * * [​](https://docs.ton.org/standard/wallets/highload/v3/specification#exit-codes) Exit codes --------------------------------------------------------------------------------------------- | Exit code | Name | Description | How to fix | | --- | --- | --- | --- | | `0` | Success | Message processed successfully | — | | `33` | Invalid signature | Ed25519 signature verification failed | Check that the private key is correct and the message hash is computed properly | | `34` | Subwallet ID mismatch | The `subwallet_id` in the message does not match storage | Verify you are using the correct `subwallet_id` for this wallet | | `35` | Invalid created\_at | Message timestamp is invalid (too old or from the future) | Ensure `created_at > now() - timeout` and `created_at <= now()` | | `36` | Query already executed | The `query_id` was already processed (found in `queries` or `old_queries`) | Use a new, unique `query_id` | | `37` | Invalid message | The `message_to_send` structure is invalid or cannot be processed | Verify the message cell structure and contents | | `38` | Invalid timeout | The `timeout` in the message does not match storage timeout | Verify you are using the correct `timeout` value for this wallet | * * * [​](https://docs.ton.org/standard/wallets/highload/v3/specification#limitations-and-constraints) Limitations and constraints ------------------------------------------------------------------------------------------------------------------------------- ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#single-message-per-external) Single message per external **Limitation:** Each external message can trigger **only one** outgoing internal message directly. **Why this limitation?** Manually validating message structure is expensive in gas costs. The contract validates only the single `message_to_send` reference to keep gas consumption predictable and low. **Why no state-init support?** State-init validation is complex and gas-intensive, while deploying contracts from a highload wallet is rarely needed. The feature was intentionally excluded to reduce gas costs. **Workaround for batch transfers:** Send an internal message to the wallet itself with opcode `0xae42e5a4` (`internal_transfer`) and an action list containing up to **254 outgoing messages** (not 255, because one action slot is reserved for [`set_code` protection](https://docs.ton.org/standard/wallets/highload/v3/specification#protection-against-set-code) ). **How to implement:** [Send batch transfers](https://docs.ton.org/standard/wallets/highload/v3/send-batch-transfers) * * * ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#query-id-space-limitations) Query ID space limitations Highload v3 supports up to **8,380,416 unique query IDs** (see [`query_id` structure](https://docs.ton.org/standard/wallets/highload/v3/specification#query-id-composite-structure) for details). **Impact on throughput:** If you send messages faster than `timeout`, you may exhaust available query IDs. After `timeout`, old IDs can be reused. **Recommended strategy:** Use a counter-based approach, incrementing `query_id` for each message. * * * ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#timeout-constraints) Timeout constraints The `timeout` value affects message validity, storage costs, and operational behavior: **Message validity:** Messages are valid for `timeout` seconds after `created_at`. Expired messages are rejected with exit code 35. **Storage costs:** Processed `query_id` values remain in storage for up to `2 × timeout` (across `queries` and `old_queries` hashmaps). Longer timeouts increase storage size and costs. **Operational impact:** * Short timeout (seconds/minutes): Fast expiration certainty, but messages may expire during network congestion * Long timeout (hours): Messages survive congestion, but slow failure detection and higher storage costs * * * ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#gas-consumption) Gas consumption Gas costs vary depending on the number of outgoing messages sent: | Operation | Transaction 1 (external) | Transaction 2 (internal) | Total | | --- | --- | --- | --- | | 1 message | TBD | TBD | TBD | | 10 messages | TBD | TBD | TBD | | 254 messages | TBD | TBD | TBD | **What affects gas costs:** Gas consumption depends **only** on the number of entries in `queries` and `old_queries` hashmaps. Cleanup/rotation operations are highly optimized and add minimal overhead (unlike Highload v2). **Forward fees:** The two-transaction pattern means forward fees are spent **twice**: first when sending the external message (outside → external), then when the wallet sends an internal message to itself (external → internal). This makes Highload v3 approximately **2× more expensive in forward fees** compared to single-transaction wallets like v5. Forward fees scale with: * Number of outgoing messages * Size and complexity of message content * * * [​](https://docs.ton.org/standard/wallets/highload/v3/specification#get-methods) Get methods ----------------------------------------------------------------------------------------------- Highload Wallet v3 provides several read-only methods for monitoring and verification. | Method | Returns | Description | | --- | --- | --- | | `get_public_key()` | `int` (256 bits) | Returns the stored public key | | `get_subwallet_id()` | `int` (32 bits) | Returns the subwallet ID | | `get_timeout()` | `int` | Returns the current timeout value (stored as uint22) | | `get_last_clean_time()` | `int` (64 bits) | Returns the Unix timestamp of the last cleanup | | `processed?(query_id, need_clean)` | `(int, int)` | Checks if `query_id` was processed; optionally indicates if cleanup is needed | ### [​](https://docs.ton.org/standard/wallets/highload/v3/specification#processed-method-details) `processed?` method details **Parameters:** * `query_id` (int): The query ID to check. * `need_clean` (int): If non-zero, also return whether cleanup is due. **Returns:** * First int: `-1` if processed, `0` if not. * Second int: `-1` if cleanup is needed, `0` otherwise. **Use case:** Before sending a message, check if a `query_id` was already used to avoid replay errors. **Link:** [How to verify if a message is processed](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed) * * * [​](https://docs.ton.org/standard/wallets/highload/v3/specification#protection-against-set_code) Protection against `set_code` --------------------------------------------------------------------------------------------------------------------------------- **Why this protection is needed:** The contract uses `set_actions(actions)` to execute arbitrary actions from the internal message (this allows sending batch transfers). However, leaving the ability to execute `set_code` actions would be unsafe — it creates a risk of **accidentally changing the contract code**. **How the protection works:** In `recv_internal` (Transaction 2), after extracting the action list from the internal message, the contract executes: cell old_code = my_code(); set_actions(actions); // Apply action list from message set_code(old_code); // Immediately restore original code This pattern **prevents any `set_code` action in the action list from taking effect**. Even if an action list accidentally contains a `set_code` instruction, the final `set_code(old_code)` call overwrites it, ensuring the contract code remains unchanged. **Action list limitation:** Because the contract calls `set_code(old_code)` as a protection mechanism, one action slot is consumed. This is why the maximum number of outgoing messages in a batch is **254** (not 255) — one slot is reserved for the `set_code` protection. * * * [​](https://docs.ton.org/standard/wallets/highload/v3/specification#implementation) Implementation ----------------------------------------------------------------------------------------------------- **Source code:** [`ton-blockchain/highload-wallet-contract-v3`](https://github.com/ton-blockchain/highload-wallet-contract-v3) **SDK wrappers:** * **Go:** [`tonutils-go`](https://github.com/xssnick/tonutils-go) — includes Highload v3 wrapper * **Python:** [`pytoniq`](https://github.com/yungwine/pytoniq) — includes Highload v3 wrapper * **TypeScript/JavaScript:** Copy wrappers from the [official repository](https://github.com/ton-blockchain/highload-wallet-contract-v3/tree/main/wrappers) **Tests and examples:** See the [tests/](https://github.com/ton-blockchain/highload-wallet-contract-v3/tree/main/tests) directory in the repository for reference implementation and usage patterns. **Link:** [How-to guides](https://docs.ton.org/standard/wallets/highload/v3/create) * * * [​](https://docs.ton.org/standard/wallets/highload/v3/specification#see-also) See also ----------------------------------------------------------------------------------------- * [How to create Highload Wallet v3](https://docs.ton.org/standard/wallets/highload/v3/create) * [How to send single transfer](https://docs.ton.org/standard/wallets/highload/v3/send-single-transfer) * [How to send batch transfers](https://docs.ton.org/standard/wallets/highload/v3/send-batch-transfers) * [How to verify if a message is processed](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed) Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/standard/wallets/highload/v3/specification.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/standard/wallets/highload/v3/specification) [Previous](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed) [Specification\ \ Next](https://docs.ton.org/standard/wallets/highload/v2/specification) ⌘I On this page * [Objective](https://docs.ton.org/standard/wallets/highload/v3/specification#objective) * [What is Highload Wallet v3?](https://docs.ton.org/standard/wallets/highload/v3/specification#what-is-highload-wallet-v3) * [TL-B schema](https://docs.ton.org/standard/wallets/highload/v3/specification#tl-b-schema) * [Storage structure](https://docs.ton.org/standard/wallets/highload/v3/specification#storage-structure) * [Query ID structure](https://docs.ton.org/standard/wallets/highload/v3/specification#query-id-structure) * [External message structure](https://docs.ton.org/standard/wallets/highload/v3/specification#external-message-structure) * [Internal message structure (for batch transfers)](https://docs.ton.org/standard/wallets/highload/v3/specification#internal-message-structure-for-batch-transfers) * [Storage structure](https://docs.ton.org/standard/wallets/highload/v3/specification#storage-structure-2) * [public\_key (256 bits)](https://docs.ton.org/standard/wallets/highload/v3/specification#public_key-256-bits) * [subwallet\_id (32 bits)](https://docs.ton.org/standard/wallets/highload/v3/specification#subwallet_id-32-bits) * [old\_queries (HashmapE 13 ^Cell)](https://docs.ton.org/standard/wallets/highload/v3/specification#old_queries-hashmape-13-%5Ecell) * [queries (HashmapE 13 ^Cell)](https://docs.ton.org/standard/wallets/highload/v3/specification#queries-hashmape-13-%5Ecell) * [last\_clean\_time (64 bits)](https://docs.ton.org/standard/wallets/highload/v3/specification#last_clean_time-64-bits) * [timeout (22 bits)](https://docs.ton.org/standard/wallets/highload/v3/specification#timeout-22-bits) * [Replay protection mechanism](https://docs.ton.org/standard/wallets/highload/v3/specification#replay-protection-mechanism) * [Storage structure for replay protection](https://docs.ton.org/standard/wallets/highload/v3/specification#storage-structure-for-replay-protection) * [How query\_id is checked](https://docs.ton.org/standard/wallets/highload/v3/specification#how-query_id-is-checked) * [Rotation mechanism](https://docs.ton.org/standard/wallets/highload/v3/specification#rotation-mechanism) * [Timestamp validation](https://docs.ton.org/standard/wallets/highload/v3/specification#timestamp-validation) * [Uniqueness guarantee](https://docs.ton.org/standard/wallets/highload/v3/specification#uniqueness-guarantee) * [Why internal messages to self?](https://docs.ton.org/standard/wallets/highload/v3/specification#why-internal-messages-to-self) * [External message structure](https://docs.ton.org/standard/wallets/highload/v3/specification#external-message-structure-2) * [Message layout](https://docs.ton.org/standard/wallets/highload/v3/specification#message-layout) * [signature (512 bits)](https://docs.ton.org/standard/wallets/highload/v3/specification#signature-512-bits) * [subwallet\_id (32 bits)](https://docs.ton.org/standard/wallets/highload/v3/specification#subwallet_id-32-bits-2) * [query\_id (composite structure)](https://docs.ton.org/standard/wallets/highload/v3/specification#query_id-composite-structure) * [created\_at (64 bits)](https://docs.ton.org/standard/wallets/highload/v3/specification#created_at-64-bits) * [timeout (22 bits)](https://docs.ton.org/standard/wallets/highload/v3/specification#timeout-22-bits-2) * [send\_mode (8 bits)](https://docs.ton.org/standard/wallets/highload/v3/specification#send_mode-8-bits) * [message\_to\_send (reference cell)](https://docs.ton.org/standard/wallets/highload/v3/specification#message_to_send-reference-cell) * [Message sending flow](https://docs.ton.org/standard/wallets/highload/v3/specification#message-sending-flow) * [Exit codes](https://docs.ton.org/standard/wallets/highload/v3/specification#exit-codes) * [Limitations and constraints](https://docs.ton.org/standard/wallets/highload/v3/specification#limitations-and-constraints) * [Single message per external](https://docs.ton.org/standard/wallets/highload/v3/specification#single-message-per-external) * [Query ID space limitations](https://docs.ton.org/standard/wallets/highload/v3/specification#query-id-space-limitations) * [Timeout constraints](https://docs.ton.org/standard/wallets/highload/v3/specification#timeout-constraints) * [Gas consumption](https://docs.ton.org/standard/wallets/highload/v3/specification#gas-consumption) * [Get methods](https://docs.ton.org/standard/wallets/highload/v3/specification#get-methods) * [processed? method details](https://docs.ton.org/standard/wallets/highload/v3/specification#processed-method-details) * [Protection against set\_code](https://docs.ton.org/standard/wallets/highload/v3/specification#protection-against-set_code) * [Implementation](https://docs.ton.org/standard/wallets/highload/v3/specification#implementation) * [See also](https://docs.ton.org/standard/wallets/highload/v3/specification#see-also) --- # FunC types - TON Docs [Skip to main content](https://docs.ton.org/languages/func/types#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Language FunC types FunC offers a range of built-in types covering all the types the TVM has. On the other hand, FunC has no custom user-defined types like records or classes. [​](https://docs.ton.org/languages/func/types#atomic-types) Atomic types --------------------------------------------------------------------------- Each of these types occupies a single entry on the [TVM stack](https://docs.ton.org/tvm/overview#tvm-state) . | | | | --- | --- | | `int` | a 257-bit signed integer type. Overflow checks are enabled by default and trigger an exception. | | `cell` | a [TVM cell type](https://docs.ton.org/foundations/serialization/cells)
for persistent data storage on TON Blockchain. Data is organized in a [bag of cells](https://docs.ton.org/foundations/serialization/boc)
, with each cell containing up to 1023 bits of arbitrary data and up to four references to other cells. | | `slice` | a read-only view of a cell that allows sequential access to its data and references. A cell can be converted into a slice, extracting stored bits and references without modifying the original cell. | | `builder` | a mutable structure used to construct cells by adding data and references before finalizing them into a new cell. | | `tuple` | an ordered collection of up to 255 elements, each capable of holding a value of any type. | | `cont` | a [TVM continuation](https://docs.ton.org/tvm/continuations)
employed for execution flow management in [TVM instructions](https://docs.ton.org/tvm/instructions)
. | ### [​](https://docs.ton.org/languages/func/types#special-null-value) Special null value Any atomic type allows the special value `null` which represents the absence of an actual value of that type. For example, a function that searches the position of an integer in a list may return `null` to signify that it could not find the integer. The `null` value can be obtained by calling the function [`null()`](https://docs.ton.org/languages/func/stdlib#null) . For example, in this snippet, an integer variable is declared and initialized with `null`: int a = null(); ;; a has value null Since `null` is a valid value for any atomic type, keep the following in mind when working with functions: * Functions that return an atomic type may return `null`. * Functions that expect an atomic type as input could also accept `null`. * For [library functions](https://docs.ton.org/languages/func/stdlib) specifications explicitly indicate when `null` is acceptable as a valid input or output. Example: [`cell_depth(cell c)`](https://docs.ton.org/languages/func/stdlib#cell-depth) receives a `cell` as input, and its specification states that if the input cell is `null`, the function returns `0`. ### [​](https://docs.ton.org/languages/func/types#no-boolean-type) No boolean type FunC does not have a boolean type. Instead, booleans are represented as integers: * `false` is `0`, `true` is `-1`, a 257-bit integer with all bits set to `1`. * Logical operations are performed using [bitwise operations](https://docs.ton.org/languages/func/operators) . * In [conditional statements](https://docs.ton.org/languages/func/statements#conditional-statements) , [loops](https://docs.ton.org/languages/func/statements#loops) , and [conditional expressions](https://docs.ton.org/languages/func/operators#ternary%2C-%3F%3A) any nonzero integer is regarded as `true`. [​](https://docs.ton.org/languages/func/types#typed-holes) Typed holes ------------------------------------------------------------------------- FunC supports type inference through the type holes: `_` and `var` serve as placeholders resolved during type checking; `_` is for functions, and `var` is for variables. Example: var x = 2; The type checker determines that `x` is of type `int` since `2` is an `int`. As another example, in the following function declaration: _ someFunction(int a) { return a + 1; } the type checker infers that `_` has type `int`, as the return expression `a + 1` is of type `int`. See [Function declarations](https://docs.ton.org/languages/func/functions#function-declaration) for more details. [​](https://docs.ton.org/languages/func/types#composite-types) Composite types --------------------------------------------------------------------------------- To represent non-atomic, composite types, simpler types can be combined with the following three operations. ### [​](https://docs.ton.org/languages/func/types#function-type) Function type A functional type is written in the form `A -> B`, where: * `A` is the input type, which is called domain. * `B` is the output type, which is called codomain. For example, the type `int -> cell` represents a function that: * Takes an integer as input. * Returns a cell as output. Like in functional programming, it is possible to declare function types which have in their domain and codomain other function types. For example, `(int -> int) -> int` is a function with domain `int -> int` and codomain `int`. Similarly, `cell -> (slice -> slice)` is a function with domain `cell` and codomain `slice -> slice` ### [​](https://docs.ton.org/languages/func/types#tuple-type) Tuple type Tuple types in FunC are written in the form `[A, B, ...]` and represent TVM tuples with fixed length and known component types at compile time. A tuple occupies one entry on the TVM stack, even if it is a zero-length tuple. For example, `[int, cell]` defines a tuple with exactly two elements: * The first element is an integer. * The second element is a cell. The type `[]` represents an empty tuple. There is only one value of this type, the empty tuple, which is also written as `[]`. ### [​](https://docs.ton.org/languages/func/types#tensor-type) Tensor type Tensor types represent ordered collections of values and are written in the form `(A, B, ...)`. These types occupy multiple TVM stack entries, unlike atomic types, which use a single entry. **Example:** A function `foo` of type `int -> (int, int)` takes one integer as input and returns two integers as output, each one occupying a stack entry. Example call: (int a, int b) = foo(42); Internally, the function consumes one stack entry and produces two. **Type representation:** Values `(2, (3, 9))` of type `(int, (int, int))` and `(2, 3, 9)` of type `(int, int, int)` are stored identically as three stack entries containing the values `2`, `3`, and `9`, respectively. However, FunC treats `(int, (int, int))` and `(int, int, int)` as distinct types. The following code **will not compile**: (int a, int b, int c) = (2, (3, 9)); However, this code will compile correctly: (int a, (int b, int c)) = (2, (3, 9)); FunC enforces strict type consistency, so only matching tensor structures are allowed. **Special case: unit type`()`** The unit type `()` is used to indicate that: * A function does not return a value, or * A function takes no arguments The unit type `()` has a single value, also written as `()`, occupying **zero** stack entries. **Examples** * `print_int` has the type `int -> ()`, meaning it takes an integer but returns nothing. * `random` has the type `() -> int`, meaning it takes no arguments but returns an integer. [​](https://docs.ton.org/languages/func/types#polymorphism-with-type-variables) Polymorphism with type variables ------------------------------------------------------------------------------------------------------------------- FunC supports [polymorphic functions](https://en.wikipedia.org/wiki/Parametric_polymorphism) . Example: forall X -> (X, X) duplicate(X value) { return (value, value); } Here, `X` is a type variable that allows the function to operate on values of any type. Type variables are declared between `forall` and `->`. The function receives a value of type `X`, and duplicates this value to return a value of type `(X, X)`. For example, * Calling `duplicate(6)` produces `(6, 6)`. * Calling `duplicate([])` produces two copies of an empty tuple: `([], [])`. For more details, see the [Polymorphism with forall](https://docs.ton.org/languages/func/functions#polymorphism-with-forall) section. [​](https://docs.ton.org/languages/func/types#user-defined-types) User-defined types --------------------------------------------------------------------------------------- FunC does not support defining custom types beyond the type constructions described above. [​](https://docs.ton.org/languages/func/types#type-width) Type width ----------------------------------------------------------------------- Every value in FunC occupies a certain number of stack entries. If this number is consistent for all values of a given type, it is called the **type width**. For example, all [atomic types](https://docs.ton.org/languages/func/types#atomic-types) have a type width of 1, because all their values occupy a single stack entry. The tensor type `(int, int)` has type width 2, because all its values occupy 2 stack entries. Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/languages/func/types.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/languages/func/types) [Previous](https://docs.ton.org/languages/func/comments) [Literals\ \ Next](https://docs.ton.org/languages/func/literals) ⌘I On this page * [Atomic types](https://docs.ton.org/languages/func/types#atomic-types) * [Special null value](https://docs.ton.org/languages/func/types#special-null-value) * [No boolean type](https://docs.ton.org/languages/func/types#no-boolean-type) * [Typed holes](https://docs.ton.org/languages/func/types#typed-holes) * [Composite types](https://docs.ton.org/languages/func/types#composite-types) * [Function type](https://docs.ton.org/languages/func/types#function-type) * [Tuple type](https://docs.ton.org/languages/func/types#tuple-type) * [Tensor type](https://docs.ton.org/languages/func/types#tensor-type) * [Polymorphism with type variables](https://docs.ton.org/languages/func/types#polymorphism-with-type-variables) * [User-defined types](https://docs.ton.org/languages/func/types#user-defined-types) * [Type width](https://docs.ton.org/languages/func/types#type-width) --- # FunC literals - TON Docs [Skip to main content](https://docs.ton.org/languages/func/literals#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Language FunC literals [​](https://docs.ton.org/languages/func/literals#number-literals) Number literals ------------------------------------------------------------------------------------ FunC supports decimal and hexadecimal integer literals, including those with leading zeros: * Examples of valid integer literals: `0`, `123`, `-17`, `00987`, and `-0`. * Examples of valid hexadecimal literals: `0xef`, `0xEF`, `0x0`, `-0xfFAb`, `0x0001`, and `-0x0`. [​](https://docs.ton.org/languages/func/literals#identifiers) Identifiers ---------------------------------------------------------------------------- FunC allows a broad range of identifiers for functions and variable names. Any single-line string that meets the following conditions qualifies as a valid identifier: * It **does not** contain special symbols: `;`, `,`, `(`, `)`, `[`, `]`, spaces including tabs, `~`, and `.`. * It **does not** start as a [comment](https://docs.ton.org/languages/func/comments) or a [string literal](https://docs.ton.org/languages/func/literals#string-literals) (i.e., with `"` at the beginning). * It is **not** a [number literal](https://docs.ton.org/languages/func/literals#number-literals) . * It is **not** an underscore `_`. * It is **not** a [reserved keyword](https://docs.ton.org/languages/func/built-ins#reserved-keywords) . * It is **not** the name of a [built-in](https://docs.ton.org/languages/func/built-ins#built-ins) . Additionally, **function** names in function definitions can start with `.` or `~`. **Examples of valid identifiers:** * `query`, `query'`, `query''` * `elem0`, `elem1`, `elem2` * `CHECK` * `_internal_value` * `message_found?` * `get_pubkeys&signatures` * `dict::udict_set_builder` * `fatal!` **Examples of less common, but still valid identifiers:** * `123validname` * `2+2=2*2` * `-alsovalidname` * `0xefefefhahaha` * `{hehehe}` * ``pa{--}in"`aaa`"`` **Examples of valid function names:** * `fun_a` * `~fun_a?` * `._how123` **Examples of invalid identifiers:** * `take(first)Entry` - contains parentheses `(` and `)` * `"not_a_string` - starts with a `"`, like a string literal * `msg.sender` - includes a `.` * `send_message,then_terminate` - contains a `,` * `_` - just an underscore, which is not valid on its own * ``pa;;in"`aaa`"`` - contains `;` * `{-aaa-}` - it is a comment * `aa(bb` - contains an opening parenthesis * `123` - a number literal * `_+_` - it is a reserved builtin name **Special identifiers in backticks:** FunC allows identifiers enclosed in backticks `` ` ``. These identifiers can contain any characters except: * Newline characters `\n` * Backticks `` ` `` themselves, except the opening and closing ones. **Examples of valid backtick identifiers:** * `` `I'm a variable identifier too` `` * `` `any symbols ; ~ () are allowed here...` `` [​](https://docs.ton.org/languages/func/literals#constants) Constants ------------------------------------------------------------------------ FunC allows defining **compile-time constants** that are substituted and pre-computed during compilation. **Syntax:** const optional-type identifier = value-or-expression; * `optional-type` (e.g., `int` or `slice`) is optional but improves readability and ensures type correctness. * `value-or-expression`can be a literal or an expression involving literals and previously defined constants. Multiple constants can be defined in the same `const` declaration by separating them with `,`. **Example usage:** const int101 = 101; ;; Numeric constant const str1 = "const1", str2 = "aabbcc"s; ;; Multiple string constants separated with , const int int240 = (int101 * 10) << 3; ;; Constant computed from an expression const slice str2r = str2; ;; Constant referencing another constant [​](https://docs.ton.org/languages/func/literals#compile-time-built-ins) Compile-time built-ins -------------------------------------------------------------------------------------------------- FunC has a special syntax for compile-time operations that compute slices and integer hashes out of ASCII strings. These compile-time operations are invoked by enclosing the ASCII string in double quotes `"`, followed by a suffix representing the compile-time operation to apply on the string, like: "this is a string"u where the suffix `u` represents the compile-time operation to invoke on the ASCII string. These built-ins are evaluated during compilation time, which means that the FunC compiler replaces the built-in call anywhere it occurs with the result of the call. In particular, it is possible to use these compile-time built-ins while declaring constants: const c = "some string"s; We now describe the possible string suffixes. ### [​](https://docs.ton.org/languages/func/literals#string-without-suffix) String without suffix If no suffix is provided, the compiler computes a slice from the ASCII string, such that the contents of the slice is the binary code of the ASCII string. const c = "hello"; ;; c has the slice x{68656c6c6f}, where 68656c6c6f ;; is the slice contents in hexadecimal, representing ;; the ASCII code of the string. ### [​](https://docs.ton.org/languages/func/literals#string-with-suffixs) String with suffix `s` Suffix `s` interprets the string as an hexadecimal number and produces a slice having the binary representation of the hexadecimal number. If the string is not an hexadecimal number, the compiler signals an error. const c = "abcdef"s; ;; c has the slice x{abcdef}, where abcdef is the ;; slice contents in hexadecimal. ;; Note that abcdef is a valid hexadecimal number. ### [​](https://docs.ton.org/languages/func/literals#string-with-suffix-a) String with suffix `a` Suffix `a` interprets the string as an address and creates a slice containing a [`MsgAddressInt` structure](https://docs.ton.org/foundations/addresses/overview#internal-addresses) from the address. ;; c has slice x{9FE6666666666666666666666666666666666666666666666666666666666666667_} ;; The slice contents represent the MsgAddressInt structure: ;; addr_std$10 anycast:none$0 workchain_id:int8=0xFF address:bits256=0x33...33 const c = "Ef8zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzM0vF"a; ### [​](https://docs.ton.org/languages/func/literals#string-with-suffix-u) String with suffix `u` Suffix `u` produces the decimal representation of the binary code of the ASCII string. const c = "NstK"u; ;; c has the integer 1316189259 ;; which is the decimal representation of the ;; ASCII code of the string ### [​](https://docs.ton.org/languages/func/literals#string-with-suffix-h) String with suffix `h` Suffix `h` generates an integer from the first 32 bits of the string’s SHA-256 hash. const c = "transfer(slice, int)"h; ;; c has the integer 2053302440 ### [​](https://docs.ton.org/languages/func/literals#string-with-suffix-h-2) String with suffix `H` Suffix `H` generates an integer from the full 256-bit SHA-256 hash of the string. ;; c has the integer ;; 55356924298749527416066000120313684523410504308849542670649639903159354505593 const c = "transfer(slice, int)"H ### [​](https://docs.ton.org/languages/func/literals#string-with-suffix-c) String with suffix `c` Suffix `c` generates an integer from the `crc32` value of the string. const c = "transfer(slice, int)"c ;; c has the integer 2235694568 ### [​](https://docs.ton.org/languages/func/literals#string-with-multiple-lines) String with multiple lines Special characters like `\n` are not supported in strings, but you can create multi-line strings by writing the text across multiple lines, all surrounded by triple quotes `"""`. The triple quotes syntax also supports the previously described suffixes. For example: int a = """ hash me baby one more time .... Oh, baby, baby """h; ;; a has value 876244482 Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/languages/func/literals.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/languages/func/literals) [Previous](https://docs.ton.org/languages/func/types) [Operators\ \ Next](https://docs.ton.org/languages/func/operators) ⌘I On this page * [Number literals](https://docs.ton.org/languages/func/literals#number-literals) * [Identifiers](https://docs.ton.org/languages/func/literals#identifiers) * [Constants](https://docs.ton.org/languages/func/literals#constants) * [Compile-time built-ins](https://docs.ton.org/languages/func/literals#compile-time-built-ins) * [String without suffix](https://docs.ton.org/languages/func/literals#string-without-suffix) * [String with suffix s](https://docs.ton.org/languages/func/literals#string-with-suffixs) * [String with suffix a](https://docs.ton.org/languages/func/literals#string-with-suffix-a) * [String with suffix u](https://docs.ton.org/languages/func/literals#string-with-suffix-u) * [String with suffix h](https://docs.ton.org/languages/func/literals#string-with-suffix-h) * [String with suffix H](https://docs.ton.org/languages/func/literals#string-with-suffix-h-2) * [String with suffix c](https://docs.ton.org/languages/func/literals#string-with-suffix-c) * [String with multiple lines](https://docs.ton.org/languages/func/literals#string-with-multiple-lines) --- # FunC expressions - TON Docs [Skip to main content](https://docs.ton.org/languages/func/expressions#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Language FunC expressions Expressions in FunC combine literals, variables, operators, and function calls to produce a value when evaluated. An expression in FunC can be: * A [number literal](https://docs.ton.org/languages/func/literals#number-literals) * An [identifier](https://docs.ton.org/languages/func/literals#identifiers) * A [compile-time builtin](https://docs.ton.org/languages/func/literals#compile-time-built-ins) * An [operator](https://docs.ton.org/languages/func/operators) * A [variable declaration](https://docs.ton.org/languages/func/expressions#variable-declaration) * A [function call](https://docs.ton.org/languages/func/expressions#function-call) We focus on variable declarations and function calls, since the other kind of expressions are explained in their respective articles. As a general rule, all sub-expressions inside an expression are evaluated from left to right, except in cases where [asm stack rearrangement](https://docs.ton.org/languages/func/functions#rearranging-stack-entries) explicitly defines the order. [​](https://docs.ton.org/languages/func/expressions#variable-declaration) Variable declaration ------------------------------------------------------------------------------------------------- Local variables must be initialized at the time of declaration. Since variable declarations are expressions, the result of evaluating a declaration like: type iden = expr returns the value produced by `expr`, in addition to defining variable `iden` with value `expr`. For instance: `(int x = 3) + x;` declares `x` and assigns to it the value `3`. The result of the expression `(int x = 3)` is therefore `3`, which means that `(int x = 3) + x` evaluates to `6`, since `x` has value `3` after the declaration. Here are further examples of variable declarations, where each line is independent from the other ones. It is possible to use the keyword `var` to let the type checker infer the type, see [hole types](https://docs.ton.org/languages/func/types#hole-type) . int x = 2; var x = 2; ;; Equivalent to previous, but with type inference (int, int) p = (1, 2); (int, var) p = (1, 2); ;; Equivalent to previous, but with type inference [int, var, int] t = [1, 2, 3]; In the previous examples, `p` and `t` store the entire tensor and tuple, respectively. But it is possible to deconstruct tensors and tuples and assign each component to different variables. Here are some examples that showcase different ways of deconstructing tensors and tuples: (int x, int y, int z) = (1, 2, 3); ;; Assign each tensor component to x, y, and z. (int, int, int) (x, y, z) = (1, 2, 3); ;; Equivalent to previous var (x, y, z) = (1, 2, 3); ;; Equivalent to previous, but with type inference (int x = 1, int y = 2, int z = 3); ;; Assigning each component directly [int x, int y, int z] = [1, 2, 3]; ;; Assign each tuple component to x, y, and z [int, int, int] [x, y, z] = [1, 2, 3]; ;; Equivalent to previous var [x, y, z] = [1, 2, 3]; ;; Equivalent to previous, but with type inference A variable can be redeclared in the same scope. For example, the following code is valid: int x = 2; int y = x + 1; int x = 3; In this example, the second occurrence of `int x` is not a new declaration but a compile-time check ensuring that `x` has type `int`. The third line is equivalent to `x = 3;`. The following example, which redeclares `x` with type `(int, int)` at the third line, is also valid: int x = 2; int y = x + 1; (int, int) x = (y, y + 1); After the third line, variable `x` has type `(int, int)`. ### [​](https://docs.ton.org/languages/func/expressions#variable-redeclaration-in-nested-scopes) Variable redeclaration in nested scopes In nested scopes, a new variable with the same name can be declared, just like in C: 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 refers to the original variable of type int declared above However, global variables **cannot** be redeclared. See [Global variables](https://docs.ton.org/languages/func/global-variables) . ### [​](https://docs.ton.org/languages/func/expressions#underscore) Underscore The underscore `_` is used when a value is not needed. For example, if `foo` is a function of type `int -> (int, int, int)`, you can retrieve only the first return value while ignoring the rest: (int fst, _, _) = foo(42); [​](https://docs.ton.org/languages/func/expressions#function-call) Function call ----------------------------------------------------------------------------------- A function call in FunC follows a conventional syntax: the function name is followed by its arguments, separated by commas. However, unlike many conventional languages, FunC also treats functions as taking a single tensor argument. For example, suppose `foo` is a function of type `(int, int, int) -> int`. The following two lines are equivalent ways of calling `foo`: int x = foo(1, 2, 3); ;; Three arguments separated by , int x = foo((1, 2, 3)); ;; The tensor (1, 2, 3) passed as a single argument Equivalently, we could also assign tensor `(1, 2, 3)` to a variable, and then call `foo`: (int, int, int) t = (1, 2, 3); int x = foo(t); ;; Pass the tensor as a single argument ### [​](https://docs.ton.org/languages/func/expressions#function-composition) Function composition To illustrate how function composition works in FunC, suppose that together with the previous `foo` function, there is also a `bar` function of type `int -> (int, int, int)`. Since `foo` expects a single tensor argument, you can pass the entire result of `bar(42)` directly into `foo`: int x = foo(bar(42)); This is equivalent to the longer form, which decomposes the result tensor of `bar(42)` and then calls `foo` by passing all arguments separated by commas: (int a, int b, int c) = bar(42); int x = foo(a, b, c); ### [​](https://docs.ton.org/languages/func/expressions#functions-as-first-class-objects) Functions as first-class objects In FunC, functions are first-class objects: they can be assigned to variables, passed as arguments to other functions, and returned from functions. For example, the following function `apply`, receives a function `f` of type `int -> int`, and a value `v` of type `int` as arguments. Function `apply` invokes `f` with argument `v` and returns the result of the application, i.e., `apply` computes the expression `f(v)`. int apply(int -> int f, int v) { return f(v); } Let us suppose we have an increment function: int inc(int x) { return x + 1; } We can then invoke `apply` by passing the increment function: apply(inc, 2); ;; produces 3, or equivalently, inc(2) It is also possible to assign the increment function to variables: var f = inc; or return it from functions: int -> int return_inc() { return inc; } ### [​](https://docs.ton.org/languages/func/expressions#special-function-call-notation) Special function call notation In addition to the standard syntax for calling a function, FunC supports two function call notations for specific situations, the [non-modifying notation](https://docs.ton.org/languages/func/expressions#non-modifying-notation) , and the [modifying notation](https://docs.ton.org/languages/func/expressions#modifying-notation) , which are explained next. #### [​](https://docs.ton.org/languages/func/expressions#non-modifying-notation) Non-modifying notation In FunC, a function with at least one argument can be called using the dot `.` notation, also called _non-modifying notation_. For example, the function `store_uint`, which stores an unsigned integer into a cell builder and returns the modified builder, has type `(builder, int, int) -> builder`, where: * The first argument is the builder object. * The second argument is the value to store. * The third argument is the unsigned integer bit length. The following way of calling `store_uint`: builder b = begin_cell(); b = store_uint(b, 239, 8); is equivalent to: builder b = begin_cell(); b = b.store_uint(239, 8); ;; Uses non-modifying notation The dot `.` notation allows the first argument of a function to be placed before the function name, simplifying the code further: builder b = begin_cell().store_uint(239, 8); which is equivalent to the standard syntax for calling a function: builder b = store_uint(begin_cell(), 239, 8); Using the `.` notation it is possible to chain many function calls together: builder b = begin_cell().store_uint(239, 8) .store_int(-1, 16) .store_uint(0xff, 10); which is equivalent to the longer form: builder b = begin_cell(); b = b.store_uint(239, 8); b = b.store_int(-1, 16); b = b.store_uint(0xff, 10); or to the more difficult to read form, which nests all the calls: builder b = store_uint( store_int( store_uint( begin_cell(), 239, 8), -1, 16), 0xff, 10 ); #### [​](https://docs.ton.org/languages/func/expressions#modifying-notation) Modifying notation If a function’s first argument is of type `A` and its return type follows the structure `(A, B)`, where `B` is an arbitrary type, the function can be called using the `~` notation, also called _modifying notation_. The primary purpose of the `~` notation is to automatically update the first argument in a function call. More concretely, suppose `foo` is a function of type `(builder, int, int) -> (builder, int)`, then the call `v = b~foo(2, 3)`, which uses the `~` notation, is equivalent to the standard call `(b, v) = foo(b, 2, 3)`. The statement `(b, v) = foo(b, 2, 3)` reassigns (or updates) the first argument `b` after the call to `foo` finishes. The `~` notation serves as a shortcut to express this reassignment of the first argument. One possible application of the `~` notation is for working with cell slices. For example, consider a cell slice `cs` and the function `load_uint`, which has type: `(slice, int) -> (slice, int)`. The function `load_uint` takes a cell slice and a number of bits to load, returning the remaining slice and the loaded unsigned integer value. The following three calls are equivalent: (cs, int x) = load_uint(cs, 8); ;; Standard function call (cs, int x) = cs.load_uint(8); ;; Call using non-modifying notation (i.e., `.`) int x = cs~load_uint(8); ;; Call using modifying notation (i.e., `~`) #### [​](https://docs.ton.org/languages/func/expressions#adapting-functions-to-use) Adapting functions to use `~` When a function type is of the form `(A, ...) -> A`, it is possible to adapt the function so that the `~` notation can be used on such a function. This can be achieved using unit types, by redefining the function type to `(A, ...) -> (A, ())`. For example, consider an increment function `inc` of type `int -> int`: int inc(int x) { return x + 1; } To increment a variable `y` using `inc`, the function should be used as follows: y = inc(y); Attempting to use the `~` notation on `inc` would fail: y~inc(); ;; DOES NOT COMPILE because `inc` does not have a return type of the form `(int, B)`, where `B` is some type. To use the `~` notation on `inc`, first redefine the function so that it now has type `int -> (int, ())` as follows: (int, ()) inc(int x) { return (x + 1, ()); } Now, the following code increments `y`: y~inc(); #### [​](https://docs.ton.org/languages/func/expressions#and-in-function-names) `.` and `~` in function names Previously, we redefined `inc` to have type `int -> (int, ())` so that it was possible to use the `~` notation on it. However, it would be bothersome to use `inc` in cases where we do not want to increment a variable, but we just want to store the increment in a different variable: (int y, _) = inc(x); In other words, we would _also_ like to use `inc` as if it was the original function with type `int -> int`: int y = inc(x); In FunC, it is possible to _also_ keep the original `inc` of type `int -> int` so that we can use `inc` in different ways, like: x~inc(); ;; Increments x, using modifying notation int y = inc(x); ;; Doesn't modify x, but stores the increment in y int z = x.inc(); ;; Equivalent to previous, but using non-modifying notation This is achieved by declaring a function `~inc` alongside the original `inc`: int inc(int x) { ;; Original inc function return x + 1; } (int, ()) ~inc(int x) { ;; inc version to be able to use ~ notation return (x + 1, ()); } This is possible because of the way FunC resolves function calls: * If a function is called with `.`, e.g., `x.foo()`, the compiler looks for a `.foo` definition. * If a function is called with `~`, e.g., `x~foo()`, the compiler looks for a `~foo` definition. * If neither `.foo` nor `~foo` is defined, the compiler falls back to the regular `foo` definition. Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/languages/func/expressions.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/languages/func/expressions) [Previous](https://docs.ton.org/languages/func/operators) [Statements\ \ Next](https://docs.ton.org/languages/func/statements) ⌘I On this page * [Variable declaration](https://docs.ton.org/languages/func/expressions#variable-declaration) * [Variable redeclaration in nested scopes](https://docs.ton.org/languages/func/expressions#variable-redeclaration-in-nested-scopes) * [Underscore](https://docs.ton.org/languages/func/expressions#underscore) * [Function call](https://docs.ton.org/languages/func/expressions#function-call) * [Function composition](https://docs.ton.org/languages/func/expressions#function-composition) * [Functions as first-class objects](https://docs.ton.org/languages/func/expressions#functions-as-first-class-objects) * [Special function call notation](https://docs.ton.org/languages/func/expressions#special-function-call-notation) * [Non-modifying notation](https://docs.ton.org/languages/func/expressions#non-modifying-notation) * [Modifying notation](https://docs.ton.org/languages/func/expressions#modifying-notation) * [Adapting functions to use ~](https://docs.ton.org/languages/func/expressions#adapting-functions-to-use) * [. and ~ in function names](https://docs.ton.org/languages/func/expressions#and-in-function-names) --- # FunC program declarations - TON Docs [Skip to main content](https://docs.ton.org/languages/func/declarations-overview#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Program declarations FunC program declarations A FunC program is a list of: * [Function declarations and definitions](https://docs.ton.org/languages/func/functions) * [Global variable declarations](https://docs.ton.org/languages/func/global-variables) * [Compiler directives](https://docs.ton.org/languages/func/compiler-directives) Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/languages/func/declarations-overview.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/languages/func/declarations-overview) [Previous](https://docs.ton.org/languages/func/statements) [Functions\ \ Next](https://docs.ton.org/languages/func/functions) ⌘I --- # FunC statements - TON Docs [Skip to main content](https://docs.ton.org/languages/func/statements#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Language FunC statements FunC statements can occur anywhere inside function bodies. [​](https://docs.ton.org/languages/func/statements#expression-statements) Expression statements -------------------------------------------------------------------------------------------------- The most common type of statement is the expression statement—an expression followed by `;`. See the [FunC expressions](https://docs.ton.org/languages/func/expressions) article for details on the allowed expressions. [​](https://docs.ton.org/languages/func/statements#return-statement) `return` statement ------------------------------------------------------------------------------------------ The `return` statement ends function execution and specifies a value to be returned to the function caller. Any statement after the `return` statement is not executed. In this example, the `return` statement instructs the function to halt execution and produce `x + 1` as a result. int inc(int x) { return x + 1; } In this example, only the first `return` executes: int inc(int x) { return x + 1; return x; } [​](https://docs.ton.org/languages/func/statements#block-statement) Block statement -------------------------------------------------------------------------------------- A block statement is used to group zero or more statements. The block is delimited by a pair of curly braces `{ ... }`. A block statement also defines a scope, in which variables defined in the block are accessible only in the block or in nested blocks. For example: int x = 1; int y = 2; { ;; x and y are accessible in this block. int z = x + y; { ;; x, y, and z are accessible in this block. int w = z; ;; The block declares w, ;; which is only accessible in this block. } ;; w is no longer accessible here. ;; x, y, and z are still accessible here. } ;; z is no longer accessible here, but x and y are. [​](https://docs.ton.org/languages/func/statements#conditional-statements) Conditional statements ---------------------------------------------------------------------------------------------------- These statements control the flow of the code based on a condition. ### [​](https://docs.ton.org/languages/func/statements#if-else-statement) `if...else` statement When executing an `if...else` statement, first, the specified condition is evaluated. If the condition evaluates to an integer different from `0`, see [absence of boolean type](https://docs.ton.org/languages/func/types#no-boolean-type) , the block after the condition is executed. Otherwise, if the condition evaluates to `0`, the optional `else` block is executed. If the `else` block is missing, nothing happens, and execution continues further. Examples: ;; The condition evaluates to -1, so the block executes if (1 < 10) { do_something(); } ;; The condition evaluates to 0, so the block does not execute if (11 < 10) { do_something(); } ;; No else is provided. So, execution continues here, after the block. ;; The condition evaluates to 0, so the block does not execute if (11 < 10) { do_something(); } else { ;; else is provided. So, the else block executes. handle_else(); } Curly brackets `{}` are required in each block of an `if...else` statement. For example, the following code will not compile: if (1 < 10) { do_something(); } else if (2 > 1) { ;; else block must have curly brackets do_something2(); } That is because the `else` block must have curly brackets: if (1 < 10) { do_something(); } else { ;; else block now has curly brackets if (2 > 1) { do_something2(); } } The above example can be written in a simpler form by using the `elseif` keyword, to avoid the need to write several nested curly brackets in the `else` case: if (1 < 10) { do_something(); } elseif (2 > 1) { do_something2(); } In general, the `elseif` keyword is useful for stating several alternative cases: if (cond) { do_1(); } elseif (cond2) { do_2(); } elseif (cond23) { do_3(); } else { do_4(); } The alternative cases can also include the `elseifnot` keyword, which allows the inclusion of [`ifnot` statements](https://docs.ton.org/languages/func/statements#ifnot%E2%80%A6else-statement) in the alternatives: if (cond) { do_1(); } elseif (cond2) { ;; if in else case do_2(); } elseifnot (cond23) { ;; ifnot in else case do_3(); } else { do_4(); } ### [​](https://docs.ton.org/languages/func/statements#ifnot-else-statement) `ifnot...else` statement The `ifnot...else` statement is equivalent to the [`if...else` statement](https://docs.ton.org/languages/func/statements#if%E2%80%A6else-statement) but with the condition negated using the [bitwise `~` operator](https://docs.ton.org/languages/func/operators#bitwise-not%2C) . More specifically: ifnot (cond) { do_something(); } else { handle_else(); } is equivalent to: if (~ cond) { ;; Standard if..else, with condition negated using ~ do_something(); } else { handle_else(); } In other words, if the condition in the `ifnot` evaluates to `0`, see [absence of boolean type](https://docs.ton.org/languages/func/types#no-boolean-type) , the block after the condition is executed. Otherwise, if the condition evaluates to an integer different from `0`, the optional `else` block is executed. If the `else` block is missing, nothing happens, and execution continues further. Examples: ifnot (1 > 10) { ;; The condition evaluates to 0, the block executes do_something(); } ifnot (11 > 10) { ;; The condition evaluates to -1, the block does not execute do_something(); } ;; No else is provided. Execution continues here, after the block. ifnot (11 > 10) { ;; The condition evaluates to -1, the block does not execute do_something(); } else { ;; else is provided. The else block executes. handle_else(); } Similarly to the `if...else`, it is possible to use the keyword `elseifnot` to add several alternative cases: ifnot (cond) { do_1(); } elseifnot (cond2) { do_2(); } elseifnot (cond23) { do_3(); } else { do_4(); } The alternative cases can also include the `elseif` keyword, which allows the inclusion of standard [`if` statements](https://docs.ton.org/languages/func/statements#if%E2%80%A6else-statement) in the alternatives: ifnot (cond) { ;; ifnot do_1(); } elseif (cond2) { ;; if in else case do_2(); } elseifnot (cond23) { ;; ifnot in else case do_3(); } else { do_4(); } [​](https://docs.ton.org/languages/func/statements#loops) Loops ------------------------------------------------------------------ FunC supports `repeat`, `while`, and `do { ... } until` loops. The `for` loop is not supported. ### [​](https://docs.ton.org/languages/func/statements#repeat-loop) `repeat` loop The `repeat` loop executes a block of code a specified number of times. The number of repetitions should be given as a positive 32-bit integer in the inclusive range from `1` to `2^31 - 1`, i.e., `2,147,483,647`. If the value is greater, an error with [exit code 5](https://docs.ton.org/tvm/exit-codes#5%3A-integer-out-of-expected-range) , `Integer out of expected range`, will be thrown. int x = 1; repeat(10) { ;; Repeats the block 10 times. x *= 2; ;; Each iteration multiplies x by 2. } ;; x has value 1024 int x = 1; int y = 10; repeat(y + 6) { ;; Repeats the block 16 times. x *= 2; ;; Each iteration multiplies x by 2. } ;; x has value 65536 If the specified number of repetitions is equal to `0` or any negative number in the inclusive range from `-2^256` to `-1`, it is ignored, and the code block is not executed at all. int x = 1; repeat(-1) { ;; Block does not execute. x *= 2; } ;; x has value 1 ### [​](https://docs.ton.org/languages/func/statements#while-loop) `while` loop The `while` loop continues executing the block of code as long as the given condition evaluates to an integer different from `0`, see [absence of boolean type](https://docs.ton.org/languages/func/types#no-boolean-type) . int x = 5; while (x < 10) { ;; Executes the block 5 times. ;; Each iteration increases x by 1. ;; The loop stops when x becomes 10. x += 1; } ;; x has value 10 ### [​](https://docs.ton.org/languages/func/statements#do-until-loop) `do...until` loop The `do...until` loop is a post-test loop that executes the block of code at least once and then continues to execute it until the given condition evaluates to an integer different from `0`, see [absence of boolean type](https://docs.ton.org/languages/func/types#no-boolean-type) . int x = 0; do { ;; The block always executes at least once x += 3; } until (x % 9 == 0); ;; Executes the block 3 times. ;; Each iteration increases x by 3. ;; The loop stops when x becomes divisible by 9. ;; x has value 9 [​](https://docs.ton.org/languages/func/statements#try-catch-statement) `try...catch` statement -------------------------------------------------------------------------------------------------- _Available in FunC since v0.4.0_ The `try...catch` statement consists of a `try` block and a `catch` block. The code in the `try` block is executed first, and if it fails, all changes made within the `try` block are rolled back, and the `catch` block is executed instead. The `catch` block has two arguments, which are local to the `catch` block: * The exception parameter, which can be of any type. Used to provide extra information about the error. * The error code, an integer, which identifies the kind of error. try { do_something(); } catch (x, n) { ;; x is the exception parameter ;; n is the error code handle_exception(); } Unlike many other languages, in FunC, all changes are **undone** if an error occurs inside the `try` block. These modifications include updates to local and global variables and changes to [control registers](https://docs.ton.org/foundations/whitepapers/tvm#1-3-2-list-of-control-registers) . For example, `c4` for storage, `c5`for action/messages, `c7` for context, etc. Any contract storage updates and outgoing messages are also reverted. However, certain [TVM state components](https://docs.ton.org/foundations/whitepapers/tvm#1-4-total-state-of-tvm-scccg) are **not** rolled back, such as: * Codepage settings * Gas counters As a result, all gas consumed within the `try` block is still accounted for, and any modifications carried out by operations that change gas limits (e.g., [`accept_message`](https://docs.ton.org/languages/func/stdlib#accept-message) or [`set_gas_limit`](https://docs.ton.org/languages/func/stdlib#set-gas-limit) ) will remain in effect. In this example: int x = 0; try { x += 1; ;; x now has value 1 throw(100); } catch (arg, e) { ;; x is rolled back to value 0. x += 2; } ;; Here, x has value 2. although `x` is incremented to `1` inside the `try` block, the modification is **rolled back** due to the exception produced by the [`throw`](https://docs.ton.org/languages/func/built-ins#throw) function. Hence, `x` has value `0` at the moment the `catch` block starts execution. However, the gas consumed inside the `try` block is **not** rolled back when the `catch` block starts execution. Here is an example which illustrates how to generate and use the exception parameter: int x = 10; try { throw_arg(-1, 100); ;; throw an exception with error code 100 ;; and exception parameter -1 } catch (arg, e) { if (e == 100) { ;; Handle exceptions with error code 100 arg.cast_to_int(); ;; Tell the type checker that the ;; exception parameter is an integer ;; arg = -1, e = 100 x = arg + 1; } } ;; x has value 0 In the above example, [`throw_arg(-1, 100)`](https://docs.ton.org/languages/func/built-ins#throw-arg) produces an exception with error code `100` and exception parameter `-1`. However, since the exception parameter can be of any type, which may vary depending on the exception, FunC cannot determine its type at compile time in the `catch` block. This requires the developer to manually cast the exception parameter. In the example, casting of the exception parameter is achieved with the [assembler](https://docs.ton.org/languages/func/functions#assembler-function-body-definition) and [polymorphic](https://docs.ton.org/languages/func/functions#polymorphism-with-forall) function `cast_to_int`, which receives an argument of any type and returns the same argument as an integer by wrapping the [`NOP` (no operation) TVM instruction](https://docs.ton.org/tvm/instructions#00-nop) : forall X -> int cast_to_int(X x) asm "NOP"; Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/languages/func/statements.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/languages/func/statements) [Previous](https://docs.ton.org/languages/func/expressions) [Overview\ \ Next](https://docs.ton.org/languages/func/declarations-overview) ⌘I On this page * [Expression statements](https://docs.ton.org/languages/func/statements#expression-statements) * [return statement](https://docs.ton.org/languages/func/statements#return-statement) * [Block statement](https://docs.ton.org/languages/func/statements#block-statement) * [Conditional statements](https://docs.ton.org/languages/func/statements#conditional-statements) * [if...else statement](https://docs.ton.org/languages/func/statements#if-else-statement) * [ifnot...else statement](https://docs.ton.org/languages/func/statements#ifnot-else-statement) * [Loops](https://docs.ton.org/languages/func/statements#loops) * [repeat loop](https://docs.ton.org/languages/func/statements#repeat-loop) * [while loop](https://docs.ton.org/languages/func/statements#while-loop) * [do...until loop](https://docs.ton.org/languages/func/statements#do-until-loop) * [try...catch statement](https://docs.ton.org/languages/func/statements#try-catch-statement) --- # FunC reserved words and built-ins - TON Docs [Skip to main content](https://docs.ton.org/languages/func/built-ins#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Language FunC reserved words and built-ins [​](https://docs.ton.org/languages/func/built-ins#reserved-keywords) Reserved keywords ----------------------------------------------------------------------------------------- FunC reserves the following symbols and words. These cannot be used as identifiers. ### [​](https://docs.ton.org/languages/func/built-ins#symbols) Symbols `+`   `-`   `*`   `/` `%`   `?`   `:`   `,` `;`   `(`   `)`   `[` `]`   `{`   `}`   `=` `_`   `<`   `>`   `&` `|`   `^`   `~`   `==` `!=`   `<=`   `>=`   `<=>` `<<`   `>>`   `~>>`   `^>>` `~/`   `^/`   `~%`   `^%` `/%`   `+=`   `-=`   `*=` `/=`   `~/=`   `^/=`   `%=` `~%=`   `^%=`   `<<=`   `>>=` `~>>=`   `^>>=`   `&=`   `|=` `^=`   `->` ### [​](https://docs.ton.org/languages/func/built-ins#words) Words `return`   `var`   `repeat`   `do` `while`   `until`   `try`   `catch` `if`   `ifnot`   `then`   `else` `elseif`   `elseifnot`   `int`   `cell` `slice`   `builder`   `cont`   `tuple` `type`   `forall`   `extern`   `global` `asm`   `impure`   `inline`   `inline_ref` `auto_apply`   `method_id`   `operator`   `infix` `infixl`   `infixr`   `const`   `#pragma` `#include` [​](https://docs.ton.org/languages/func/built-ins#built-ins) Built-ins ------------------------------------------------------------------------- This section covers extra language constructs that are not part of the core but are still important for functionality. Although they could be implemented in [stdlib.fc](https://docs.ton.org/languages/func/stdlib) , keeping them as built-in features allows the FunC optimizer to work more efficiently. In addition, FunC does not allow the built-in names in this section to be used as identifiers. However, there is an exception: [built-ins with non-symbolic names](https://docs.ton.org/languages/func/built-ins#built-ins-with-non-symbolic-names) _can_ be used as identifiers for local variables. ### [​](https://docs.ton.org/languages/func/built-ins#built-ins-with-symbolic-names) Built-ins with symbolic names `_+_`   `_-_`   `-_`   `_*_` `_/_`   `_~/_`   `_^/_`   `_%_` `_~%_`   `_^%_`   `_/%_`   `_<<_` `_>>_`   `_~>>_`   `_^>>_`   `_&_` `_|_`   `_^_`   `~_`   `^_+=_` `^_-=_`   `^_*=_`   `^_/=_`   `^_~/=_` `^_^/=_`   `^_%=_`   `^_~%=_`   `^_^%=_` `^_<<=_`   `^_>>=_`   `^_~>>=_`   `^_^>>=_` `^_&=_`   `^_|=_`   `^_^=_`   `_==_` `_!=_`   `_<_`   `_>_`   `_<=_` `_>=_`   `_<=>_` Each one of the above names is a function wrapping the corresponding operator. For example, `_+_` can be understood as wrapping the [`+` operator](https://docs.ton.org/languages/func/operators#addition%2C-%2B) : int _+_(int a, int b) { return a + b; } These functions are useful when operators need to be passed as arguments to functions, or assigned to variables. For example, in the following snippet, function `apply` receives as argument a function `f` of type `(int, int) -> int` and applies it on the arguments `2` and `3`: int apply(((int, int) -> int) f) { return f(2, 3); } Then, it is possible to invoke `apply` by passing `_+_`: apply(_+_); ;; Returns 5 Attempting to pass the operator `+` directly does not compile: apply(+); ;; DOES NOT COMPILE ### [​](https://docs.ton.org/languages/func/built-ins#built-ins-with-non-symbolic-names) Built-ins with non-symbolic names [`divmod`](https://docs.ton.org/languages/func/built-ins#divmod)   [`~divmod`](https://docs.ton.org/languages/func/built-ins#divmod-2)   [`moddiv`](https://docs.ton.org/languages/func/built-ins#moddiv)   [`~moddiv`](https://docs.ton.org/languages/func/built-ins#moddiv-2) [`muldiv`](https://docs.ton.org/languages/func/built-ins#muldiv)   [`muldivr`](https://docs.ton.org/languages/func/built-ins#muldivr)   [`muldivc`](https://docs.ton.org/languages/func/built-ins#muldivc)   [`muldivmod`](https://docs.ton.org/languages/func/built-ins#muldivmod) [`true`](https://docs.ton.org/languages/func/built-ins#true)   [`false`](https://docs.ton.org/languages/func/built-ins#false)   [`nil`](https://docs.ton.org/languages/func/built-ins#nil)   [`Nil`](https://docs.ton.org/languages/func/built-ins#nil-2) [`null?`](https://docs.ton.org/languages/func/built-ins#null%3F)   [`throw`](https://docs.ton.org/languages/func/built-ins#throw)   [`throw_if`](https://docs.ton.org/languages/func/built-ins#throw-if)   [`throw_unless`](https://docs.ton.org/languages/func/built-ins#throw-unless) [`throw_arg`](https://docs.ton.org/languages/func/built-ins#throw-arg)   [`throw_arg_if`](https://docs.ton.org/languages/func/built-ins#throw-arg-if)   [`throw_arg_unless`](https://docs.ton.org/languages/func/built-ins#throw-arg-unless)   [`load_int`](https://docs.ton.org/languages/func/built-ins#load-int) [`load_uint`](https://docs.ton.org/languages/func/built-ins#load-uint)   [`preload_int`](https://docs.ton.org/languages/func/built-ins#preload-int)   [`preload_uint`](https://docs.ton.org/languages/func/built-ins#preload-uint)   [`store_int`](https://docs.ton.org/languages/func/built-ins#store-int) [`store_uint`](https://docs.ton.org/languages/func/built-ins#store-uint)   [`~store_int`](https://docs.ton.org/languages/func/built-ins#store-int-2)   [`~store_uint`](https://docs.ton.org/languages/func/built-ins#store-uint-2)   [`load_bits`](https://docs.ton.org/languages/func/built-ins#load-bits) [`preload_bits`](https://docs.ton.org/languages/func/built-ins#preload-bits)   [`int_at`](https://docs.ton.org/languages/func/built-ins#int-at)   [`cell_at`](https://docs.ton.org/languages/func/built-ins#cell-at)   [`slice_at`](https://docs.ton.org/languages/func/built-ins#slice-at) [`tuple_at`](https://docs.ton.org/languages/func/built-ins#tuple-at)   [`at`](https://docs.ton.org/languages/func/built-ins#at)   [`touch`](https://docs.ton.org/languages/func/built-ins#touch)   [`~touch`](https://docs.ton.org/languages/func/built-ins#touch-2) [`touch2`](https://docs.ton.org/languages/func/built-ins#touch2)   [`~touch2`](https://docs.ton.org/languages/func/built-ins#touch2-2)   [`~dump`](https://docs.ton.org/languages/func/built-ins#dump)   [`~strdump`](https://docs.ton.org/languages/func/built-ins#strdump) [`run_method0`](https://docs.ton.org/languages/func/built-ins#run-method0)   [`run_method1`](https://docs.ton.org/languages/func/built-ins#run-method1)   [`run_method2`](https://docs.ton.org/languages/func/built-ins#run-method2)   [`run_method3`](https://docs.ton.org/languages/func/built-ins#run-method3) #### [​](https://docs.ton.org/languages/func/built-ins#divmod) `divmod` (int, int) divmod(int dividend, int divisor) `divmod` takes two integers as input and returns the quotient and remainder of their division `dividend / divisor`. #### [​](https://docs.ton.org/languages/func/built-ins#divmod-2) `~divmod` Same as [`divmod`](https://docs.ton.org/languages/func/built-ins#divmod) , but allows using [modifying notation](https://docs.ton.org/languages/func/expressions#modifying-notation) . Example: int a = 10; int b = 2; ;; "mod" stores the modulo 10 % 2 ;; and "a" gets updated with the quotient of 10 / 2 int mod = a~divmod(b); ;; Here, a has value 5 ;; mod has value 0 ;; b has value 2 #### [​](https://docs.ton.org/languages/func/built-ins#moddiv) `moddiv` (int, int) moddiv(int dividend, int divisor) `moddiv` takes two integers as input and returns the remainder and quotient of their division `dividend / divisor`. #### [​](https://docs.ton.org/languages/func/built-ins#moddiv-2) `~moddiv` Same as [`moddiv`](https://docs.ton.org/languages/func/built-ins#moddiv) , but allows using [modifying notation](https://docs.ton.org/languages/func/expressions#modifying-notation) . Example: int a = 10; int b = 2; ;; "div" stores the quotient of 10 / 2 ;; and "a" gets updated with the modulo 10 % 2 int div = a~moddiv(b); ;; Here, a has value 0 ;; div has value 5 ;; b has value 2 #### [​](https://docs.ton.org/languages/func/built-ins#muldiv) `muldiv` int muldiv(int factor1, int factor2, int divisor) `muldiv` performs a multiply-then-divide operation `(factor1 * factor2) / divisor`, where `/` is the [division operator](https://docs.ton.org/languages/func/operators#division%2C-%2F) . It uses a 513-bit intermediate result to prevent overflow if the final result fits within 257 bits. #### [​](https://docs.ton.org/languages/func/built-ins#muldivr) `muldivr` int muldivr(int factor1, int factor2, int divisor) `muldivr` performs a multiply-then-divide operation `(factor1 * factor2) ~/ divisor`, where `~/` is the [rounding division operator](https://docs.ton.org/languages/func/operators#rounding-division%2C-%2F) . It uses a 513-bit intermediate result to prevent overflow if the final result fits within 257 bits. #### [​](https://docs.ton.org/languages/func/built-ins#muldivc) `muldivc` int muldivc(int factor1, int factor2, int divisor) `muldivc` performs a multiply-then-divide operation `(factor1 * factor2) ^/ divisor`, where `^/` is the [ceiling division operator](https://docs.ton.org/languages/func/operators#ceiling-division%2C-%5E%2F) . It uses a 513-bit intermediate result to prevent overflow if the final result fits within 257 bits. #### [​](https://docs.ton.org/languages/func/built-ins#muldivmod) `muldivmod` (int, int) muldivmod(int factor1, int factor2, int divisor) `muldivmod` performs a multiply-then-divide operation `(factor1 * factor2) / divisor`, where `/` is the [division operator](https://docs.ton.org/languages/func/operators#division%2C-%2F) , and returns the quotient and remainder of such division. It uses a 513-bit intermediate result to prevent overflow if the final result fits within 257 bits. #### [​](https://docs.ton.org/languages/func/built-ins#true) `true` `true` is an alias for `-1`. #### [​](https://docs.ton.org/languages/func/built-ins#false) `false` `false` is an alias for `0`. #### [​](https://docs.ton.org/languages/func/built-ins#nil) `nil` `nil` is an alias for the `null` value. #### [​](https://docs.ton.org/languages/func/built-ins#nil-2) `Nil` `Nil` is an alias for the empty tuple `[]`. #### [​](https://docs.ton.org/languages/func/built-ins#null) `null?` forall X -> int null?(X val) `null?` checks if the given argument is `null`. Returns `0` if the argument is not `null`, and `-1` otherwise. For more info, see [null values](https://docs.ton.org/languages/func/types#null-values) . #### [​](https://docs.ton.org/languages/func/built-ins#throw) `throw` () throw(int error) Triggers an exception, which interrupts the execution flow. `throw` takes only one argument, the error code. See [TVM error codes](https://docs.ton.org/tvm/exit-codes) for details about error codes. #### [​](https://docs.ton.org/languages/func/built-ins#throw_if) `throw_if` () throw_if(int error, int condition) Triggers an exception only if the provided condition is true, i.e., if the condition is `-1`. It receives two arguments: the error code, which defines the exception type, and the condition. See [TVM error codes](https://docs.ton.org/tvm/exit-codes) for details about error codes. #### [​](https://docs.ton.org/languages/func/built-ins#throw_unless) `throw_unless` () throw_unless(int error, int condition) Triggers an exception only if the provided condition is false, i.e., if the condition is `0`. It receives two arguments: the error code, which defines the exception type, and the condition. See [TVM error codes](https://docs.ton.org/tvm/exit-codes) for details about error codes. #### [​](https://docs.ton.org/languages/func/built-ins#throw_arg) `throw_arg` forall X -> () throw_arg(X arg, int error) Triggers an exception, which interrupts the execution flow. The first argument can be of any type, and it is used to pass extra information about the error. This extra information can be processed in [`try..catch` statements](https://docs.ton.org/languages/func/statements#try-catch-statement) . Refer to the `try..catch` statement page for an example on how to use the first argument. The second argument is the error code. See [TVM error codes](https://docs.ton.org/tvm/exit-codes) for details about error codes. #### [​](https://docs.ton.org/languages/func/built-ins#throw_arg_if) `throw_arg_if` forall X -> () throw_arg_if(X arg, int error, int condition) Triggers an exception only if the provided condition is true, i.e., if the condition is `-1`. Similarly to [`throw_arg`](https://docs.ton.org/languages/func/built-ins#throw-arg) , the first argument can be of any type, and it is used to pass extra information about the error. This extra information can be processed in [`try..catch` statements](https://docs.ton.org/languages/func/statements#try-catch-statement) , in the same way as with [`throw_arg`](https://docs.ton.org/languages/func/built-ins#throw-arg) . The second argument is the error code. See [TVM error codes](https://docs.ton.org/tvm/exit-codes) for details about error codes. The third argument is the condition to check. #### [​](https://docs.ton.org/languages/func/built-ins#throw_arg_unless) `throw_arg_unless` forall X -> () throw_arg_unless(X arg, int error, int condition) Triggers an exception only if the provided condition is false, i.e., if the condition is `0`. Similarly to [`throw_arg`](https://docs.ton.org/languages/func/built-ins#throw-arg) , the first argument can be of any type, and it is used to pass extra information about the error. This extra information can be processed in [`try..catch` statements](https://docs.ton.org/languages/func/statements#try-catch-statement) , in the same way as with [`throw_arg`](https://docs.ton.org/languages/func/built-ins#throw-arg) . The second argument is the error code. See [TVM error codes](https://docs.ton.org/tvm/exit-codes) for details about error codes. The third argument is the condition to check. #### [​](https://docs.ton.org/languages/func/built-ins#load_int) `load_int` (slice, int) load_int(slice s, int len) Reads a signed `len`\-bit integer from slice `s`. Returns the modified slice and the obtained integer. #### [​](https://docs.ton.org/languages/func/built-ins#load_uint) `load_uint` (slice, int) load_uint(slice s, int len) Reads an unsigned `len`\-bit integer from slice `s`. Returns the modified slice and the obtained unsigned integer. #### [​](https://docs.ton.org/languages/func/built-ins#preload_int) `preload_int` int preload_int(slice s, int len) Reads a signed `len`\-bit integer from slice `s`. Returns the obtained integer. This method does not modify slice `s`. #### [​](https://docs.ton.org/languages/func/built-ins#preload_uint) `preload_uint` int preload_uint(slice s, int len) Reads an unsigned `len`\-bit integer from slice `s`. Returns the obtained unsigned integer. This method does not modify slice `s`. #### [​](https://docs.ton.org/languages/func/built-ins#store_int) `store_int` builder store_int(builder b, int x, int len) Stores a signed `len`\-bit integer `x` in builder `b`. Returns the modified builder. #### [​](https://docs.ton.org/languages/func/built-ins#store_uint) `store_uint` builder store_uint(builder b, int x, int len) Stores an unsigned `len`\-bit integer `x` in builder `b`. Returns the modified builder. #### [​](https://docs.ton.org/languages/func/built-ins#store_int-2) `~store_int` (builder, ()) ~store_int(builder b, int x, int len) Same as [`store_int`](https://docs.ton.org/languages/func/built-ins#store-int) , but adapted to use [modifying notation](https://docs.ton.org/languages/func/expressions#modifying-notation) . #### [​](https://docs.ton.org/languages/func/built-ins#store_uint-2) `~store_uint` (builder, ()) ~store_uint(builder b, int x, int len) Same as [`store_uint`](https://docs.ton.org/languages/func/built-ins#store-uint) , but adapted to use [modifying notation](https://docs.ton.org/languages/func/expressions#modifying-notation) . #### [​](https://docs.ton.org/languages/func/built-ins#load_bits) `load_bits` (slice, slice) load_bits(slice s, int len) Loads the first `len` bits from slice `s`. It returns the modified slice and a slice containing the loaded bits. #### [​](https://docs.ton.org/languages/func/built-ins#preload_bits) `preload_bits` slice preload_bits(slice s, int len) Loads the first `len` bits from slice `s`. It returns a slice containing the loaded bits. This method does not modify slice `s`. #### [​](https://docs.ton.org/languages/func/built-ins#int_at) `int_at` int int_at(tuple t, int index) Returns the element at index `index` in tuple `t`, casted as an integer. #### [​](https://docs.ton.org/languages/func/built-ins#cell_at) `cell_at` cell cell_at(tuple t, int index) Returns the element at index `index` in tuple `t`, casted as a cell. #### [​](https://docs.ton.org/languages/func/built-ins#slice_at) `slice_at` slice slice_at(tuple t, int index) Returns the element at index `index` in tuple `t`, casted as a slice. #### [​](https://docs.ton.org/languages/func/built-ins#tuple_at) `tuple_at` tuple tuple_at(tuple t, int index) Returns the element at index `index` in tuple `t`, casted as a tuple. #### [​](https://docs.ton.org/languages/func/built-ins#at) `at` forall X -> X at(tuple t, int index) Returns the element at index `index` in tuple `t`. The returned element can be of any type. #### [​](https://docs.ton.org/languages/func/built-ins#touch) `touch` forall X -> X touch(X v) Moves `v` to the top of the stack. It returns the argument `v`. #### [​](https://docs.ton.org/languages/func/built-ins#touch-2) `~touch` forall X -> (X, ()) ~touch(X v) `~touch` is identical to [`touch`](https://docs.ton.org/languages/func/built-ins#touch) , but adapted to use [modifying notation](https://docs.ton.org/languages/func/expressions#modifying-notation) . #### [​](https://docs.ton.org/languages/func/built-ins#touch2) `touch2` forall X, Y -> (X, Y) touch2((X, Y) t) Moves the components of the tensor `t` to the top of the stack; first component with type `X` and then component with type `Y`. It returns the argument tensor `t`. #### [​](https://docs.ton.org/languages/func/built-ins#touch2-2) `~touch2` forall X, Y -> ((X, Y), ()) ~touch2((X, Y) t) `~touch2` is identical to [`touch2`](https://docs.ton.org/languages/func/built-ins#touch2) , but adapted to use [modifying notation](https://docs.ton.org/languages/func/expressions#modifying-notation) . #### [​](https://docs.ton.org/languages/func/built-ins#dump) `~dump` forall X -> (X, ()) ~dump(X value) Outputs value `value` to the debug log. It returns the argument `value` and the unit value `()`. [Modifying notation](https://docs.ton.org/languages/func/expressions#modifying-notation) can be used on this function. In case `value` is a slice containing ASCII characters, it is preferable to use [`~strdump`](https://docs.ton.org/languages/func/built-ins#strdump) if the intention is to print the ASCII string in the debug log. Otherwise, `~dump` will print the slice’s contents as bits. #### [​](https://docs.ton.org/languages/func/built-ins#strdump) `~strdump` forall X -> (X, ()) ~strdump(X s) Outputs to the debug log the ASCII string encoded in slice `s`. It returns the argument `s` and the unit value `()`. [Modifying notation](https://docs.ton.org/languages/func/expressions#modifying-notation) can be used on this function. If the argument `s` is not a slice containing ASCII characters, the debug log will show an error. #### [​](https://docs.ton.org/languages/func/built-ins#run_method0) `run_method0` () run_method0 (int method_id) Executes the 0 argument function with [ID](https://docs.ton.org/languages/func/functions#method-id-specifier) `method_id`. The function with ID `method_id` must have a signature of the form: () some_function() which receives 0 arguments and returns nothing. The `run_method0` is useful for dynamically executing methods at run-time. For example, receiving the method ID to execute in the incoming internal message. #### [​](https://docs.ton.org/languages/func/built-ins#run_method1) `run_method1` forall X -> () run_method1 (int method_id, X arg1) Executes the 1 argument function with [ID](https://docs.ton.org/languages/func/functions#method-id-specifier) `method_id`, and passes `arg1` as argument to the function. The function with ID `method_id` must have a signature of the form: () some_function(T a1) which receives 1 argument and returns nothing. Type `T` must coincide with the type of the argument `arg1` provided in `run_method1`. For example, under the assumption that `1234` is the ID of function `test`, invoking: ;; The argument "a" is a slice containing the ASCII character 'a' run_method1(1234, "a"); requires that `test` has the signature: () test(slice s) As with [`run_method0`](https://docs.ton.org/languages/func/built-ins#run-method0) , function `run_method1` is useful for dynamically executing 1 argument methods at run-time. #### [​](https://docs.ton.org/languages/func/built-ins#run_method2) `run_method2` forall X, Y -> () run_method2 (int method_id, X arg1, Y arg2) Executes the 2 argument function with [ID](https://docs.ton.org/languages/func/functions#method-id-specifier) `method_id`. The function with ID `method_id` must have a signature of the form: () some_function(T1 a1, T2 a2) which receives 2 arguments and returns nothing. Type `T1` must coincide with the type of the argument `arg1` provided in `run_method2`, and similarly for type `T2`. The same observations and warnings apply as with [`run_method1`](https://docs.ton.org/languages/func/built-ins#run-method1) . #### [​](https://docs.ton.org/languages/func/built-ins#run_method3) `run_method3` forall X, Y, Z -> () run_method3 (int method_id, X arg1, Y arg2, Z arg3) Executes the 3 argument function with [ID](https://docs.ton.org/languages/func/functions#method-id-specifier) `method_id`. The function with ID `method_id` must have a signature of the form: () some_function(T1 a1, T2 a2, T3 a3) which receives 3 arguments and returns nothing. Type `T1` must coincide with the type of the argument `arg1` provided in `run_method3`, and similarly for types `T2` and `T3`. The same observations and warnings apply as with [`run_method1`](https://docs.ton.org/languages/func/built-ins#run-method1) . Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/languages/func/built-ins.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/languages/func/built-ins) [Previous](https://docs.ton.org/languages/func/compiler-directives) [Dictionaries\ \ Next](https://docs.ton.org/languages/func/dictionaries) ⌘I On this page * [Reserved keywords](https://docs.ton.org/languages/func/built-ins#reserved-keywords) * [Symbols](https://docs.ton.org/languages/func/built-ins#symbols) * [Words](https://docs.ton.org/languages/func/built-ins#words) * [Built-ins](https://docs.ton.org/languages/func/built-ins#built-ins) * [Built-ins with symbolic names](https://docs.ton.org/languages/func/built-ins#built-ins-with-symbolic-names) * [Built-ins with non-symbolic names](https://docs.ton.org/languages/func/built-ins#built-ins-with-non-symbolic-names) * [divmod](https://docs.ton.org/languages/func/built-ins#divmod) * [~divmod](https://docs.ton.org/languages/func/built-ins#divmod-2) * [moddiv](https://docs.ton.org/languages/func/built-ins#moddiv) * [~moddiv](https://docs.ton.org/languages/func/built-ins#moddiv-2) * [muldiv](https://docs.ton.org/languages/func/built-ins#muldiv) * [muldivr](https://docs.ton.org/languages/func/built-ins#muldivr) * [muldivc](https://docs.ton.org/languages/func/built-ins#muldivc) * [muldivmod](https://docs.ton.org/languages/func/built-ins#muldivmod) * [true](https://docs.ton.org/languages/func/built-ins#true) * [false](https://docs.ton.org/languages/func/built-ins#false) * [nil](https://docs.ton.org/languages/func/built-ins#nil) * [Nil](https://docs.ton.org/languages/func/built-ins#nil-2) * [null?](https://docs.ton.org/languages/func/built-ins#null) * [throw](https://docs.ton.org/languages/func/built-ins#throw) * [throw\_if](https://docs.ton.org/languages/func/built-ins#throw_if) * [throw\_unless](https://docs.ton.org/languages/func/built-ins#throw_unless) * [throw\_arg](https://docs.ton.org/languages/func/built-ins#throw_arg) * [throw\_arg\_if](https://docs.ton.org/languages/func/built-ins#throw_arg_if) * [throw\_arg\_unless](https://docs.ton.org/languages/func/built-ins#throw_arg_unless) * [load\_int](https://docs.ton.org/languages/func/built-ins#load_int) * [load\_uint](https://docs.ton.org/languages/func/built-ins#load_uint) * [preload\_int](https://docs.ton.org/languages/func/built-ins#preload_int) * [preload\_uint](https://docs.ton.org/languages/func/built-ins#preload_uint) * [store\_int](https://docs.ton.org/languages/func/built-ins#store_int) * [store\_uint](https://docs.ton.org/languages/func/built-ins#store_uint) * [~store\_int](https://docs.ton.org/languages/func/built-ins#store_int-2) * [~store\_uint](https://docs.ton.org/languages/func/built-ins#store_uint-2) * [load\_bits](https://docs.ton.org/languages/func/built-ins#load_bits) * [preload\_bits](https://docs.ton.org/languages/func/built-ins#preload_bits) * [int\_at](https://docs.ton.org/languages/func/built-ins#int_at) * [cell\_at](https://docs.ton.org/languages/func/built-ins#cell_at) * [slice\_at](https://docs.ton.org/languages/func/built-ins#slice_at) * [tuple\_at](https://docs.ton.org/languages/func/built-ins#tuple_at) * [at](https://docs.ton.org/languages/func/built-ins#at) * [touch](https://docs.ton.org/languages/func/built-ins#touch) * [~touch](https://docs.ton.org/languages/func/built-ins#touch-2) * [touch2](https://docs.ton.org/languages/func/built-ins#touch2) * [~touch2](https://docs.ton.org/languages/func/built-ins#touch2-2) * [~dump](https://docs.ton.org/languages/func/built-ins#dump) * [~strdump](https://docs.ton.org/languages/func/built-ins#strdump) * [run\_method0](https://docs.ton.org/languages/func/built-ins#run_method0) * [run\_method1](https://docs.ton.org/languages/func/built-ins#run_method1) * [run\_method2](https://docs.ton.org/languages/func/built-ins#run_method2) * [run\_method3](https://docs.ton.org/languages/func/built-ins#run_method3) --- # FunC dictionaries - TON Docs [Skip to main content](https://docs.ton.org/languages/func/dictionaries#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Language FunC dictionaries Smart contracts in TON can utilize dictionaries structured as ordered key-value mappings. Internally, these dictionaries are represented as tree-like structures composed of cells. [​](https://docs.ton.org/languages/func/dictionaries#dictionary-kinds) Dictionary kinds ------------------------------------------------------------------------------------------ ### [​](https://docs.ton.org/languages/func/dictionaries#%E2%80%9Dhash%E2%80%9D-map) ”Hash” map Hashmaps are the most widely used dictionary type in TON. They have a dedicated set of TVM opcodes for manipulation and are commonly used in smart contracts (see [TVM instructions](https://docs.ton.org/tvm/instructions) - Dictionary manipulation). Hashmaps map fixed-length keys, which are defined as an argument to all functions, to value slices. Despite the “hash” in its name, entries are ordered and allow efficient access to elements by key and retrieval of the previous or next key-value pair. Since values share space with internal node tags and possibly key fragments within the same cell, they cannot utilize the full 1023 bits. In such cases, the `~udict_set_ref` function often helps. An empty hashmap is represented as `null` in TVM, meaning it is not stored as a cell. A single bit is first saved to store a dictionary in a cell (0 for empty, 1 otherwise), followed by a reference if the hashmap is not empty. This makes `store_maybe_ref` and `store_dict` interchangeable. Some smart contract developers use `load_dict` to load a `Maybe ^Cell` from an incoming message or storage. **Available hashmap operations:** * Load from a slice, store to a builder; * Get/Set/Delete a value by key; * Replace a value (update an existing key) or add a new value (if the key is absent); * Move to the next/previous key-value pair (entries are ordered by keys, enabling [iteration](https://docs.ton.org/languages/func/cookbook#how-to-iterate-dictionaries) if gas constraints allow); * Retrieve the minimal or maximal key with its value; * Fetch and execute a function (continuation) by key. To prevent gas exhaustion, smart contracts should limit the number of dictionary updates per transaction. If a contract’s balance is used to maintain the hashmap under specific conditions, it can send itself a message to continue processing in another transaction. #### [​](https://docs.ton.org/languages/func/dictionaries#hashmap-examples) Hashmap examples To illustrate, let’s examine a hashmap that maps 257-bit integer keys to empty value slices. This type of hashmap serves as a presence indicator, storing only the existence of elements. You can quickly check this by running the following Python script. If needed, you can use a different SDK instead of `pytoniq`: import pytoniq k = pytoniq.HashMap(257) em = pytoniq.begin_cell().to_slice() k.set(5, em) k.set(7, em) k.set(5 - 2**256, em) k.set(6 - 2**256, em) print(str(pytoniq.begin_cell().store_maybe_ref(k.serialize()).end_cell())) This structure forms a binary tree, which appears balanced except for the root cell: 1[80] -> { 2[00] -> { 265[9FC00000000000000000000000000000000000000000000000000000000000000080] -> { 4[50], 4[50] }, 266[9FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40] -> { 2[00], 2[00] } } } For further [examples of hashmap parsing](https://docs.ton.org/languages/tl-b/overview#hashmap-parsing-example) , refer to the official documentation. ### [​](https://docs.ton.org/languages/func/dictionaries#augmented-maps) Augmented maps Augmented maps with additional data in each node are used internally by TON validators to calculate the total balance of all contracts in a shard. By storing the total subtree balance in each node, validators can quickly validate updates. There are no TVM primitives for working with these maps. ### [​](https://docs.ton.org/languages/func/dictionaries#prefix-dictionary) Prefix dictionary Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/languages/func/dictionaries.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/languages/func/dictionaries) [Previous](https://docs.ton.org/languages/func/built-ins) [Standard library\ \ Next](https://docs.ton.org/languages/func/stdlib) ⌘I On this page * [Dictionary kinds](https://docs.ton.org/languages/func/dictionaries#dictionary-kinds) * [”Hash” map](https://docs.ton.org/languages/func/dictionaries#%E2%80%9Dhash%E2%80%9D-map) * [Hashmap examples](https://docs.ton.org/languages/func/dictionaries#hashmap-examples) * [Augmented maps](https://docs.ton.org/languages/func/dictionaries#augmented-maps) * [Prefix dictionary](https://docs.ton.org/languages/func/dictionaries#prefix-dictionary) --- # FunC functions - TON Docs [Skip to main content](https://docs.ton.org/languages/func/functions#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Program declarations FunC functions Every function declaration or definition follows a common pattern. The general form is: [] () where `[ ... ]` represents an optional entry. Here, * `` is the [`forall` declarator](https://docs.ton.org/languages/func/functions#forall-declarator) , which declares that the function is [polymorphic](https://en.wikipedia.org/wiki/Parametric_polymorphism) . This is optional. * `` is the [return type](https://docs.ton.org/languages/func/functions#return-type) of the function. * `` is the [function name](https://docs.ton.org/languages/func/functions#function-name) . * `` is a comma separated list of [function arguments](https://docs.ton.org/languages/func/functions#function-arguments) , each argument consisting on a type and the argument’s name. * `` are [specifiers](https://docs.ton.org/languages/func/functions#specifiers) that instruct the compiler on how to process the function. * `` is the actual [function body](https://docs.ton.org/languages/func/functions#function-body) , which can be of three kinds: an [empty body](https://docs.ton.org/languages/func/functions#empty-body) , an [assembler body](https://docs.ton.org/languages/func/functions#assembler-body) , or a [standard body](https://docs.ton.org/languages/func/functions#standard-body) . [​](https://docs.ton.org/languages/func/functions#return-type) Return type ----------------------------------------------------------------------------- The return type can be any atomic or composite type, as described in the [Types](https://docs.ton.org/languages/func/types) section. For example, the following functions are valid: int foo() { return 0; } (int, int) foo'() { return (0, 0); } [int, int] foo''() { return [0, 0]; } (() -> int) foo'''() { return foo; } () foo''''() { return (); } FunC also supports **type inference** with the use of underscore `_` as the return type. For example: _ divAndMod(int m, int n) { return (m /% n); } There, the function `divAndMod` has the inferred type `(int, int) -> (int, int)`. The function computes the division and modulo of the parameters `m` and `n` by using the [division and modulo](https://docs.ton.org/languages/func/operators#division-and-modulo%2C-%2F%25) operator `/%`, which always returns a two-element tensor `(int, int)`. [​](https://docs.ton.org/languages/func/functions#function-name) Function name --------------------------------------------------------------------------------- A function name can be any valid [identifier](https://docs.ton.org/languages/func/literals#identifiers) . Additionally, it may start with the symbols `.` or `~`, which have specific meanings explained in the [special function call notation](https://docs.ton.org/languages/func/expressions#special-function-call-notation) section. Specifically, refer to this [section](https://docs.ton.org/languages/func/expressions#and-in-function-names) to understand how the symbols `.` or `~` affect the function name. For example, `udict_add_builder?`, `dict_set`, and `~dict_set` are all valid function names, and each is distinct. These functions are defined in [stdlib.fc](https://docs.ton.org/languages/func/stdlib) . FunC reserves several function names. See the [reserved functions](https://docs.ton.org/languages/func/special-functions) article for more details. [​](https://docs.ton.org/languages/func/functions#function-arguments) Function arguments ------------------------------------------------------------------------------------------- A function can receive zero or more argument declarations, each declaration separated by a comma. The following kinds of argument declarations are allowed: * Ordinary declaration: an argument is declared using **its type** followed by **its name**. Example: int foo(int x) { return x + 2; } Here, `int x` declares an argument named `x` of type `int` in function `foo`. An example that declares multiple arguments: int foo(int x, int y) { return x + y; } An example that declares no arguments: int foo() { return 0; } * Unused argument declaration: only its type needs to be specified. Example: int first(int x, int) { return x; } This is a valid function of type `(int, int) -> int`, but the function does not use its second argument. * Argument with inferred type declaration: If an argument’s type is not explicitly declared, it is inferred by the type-checker. For example, int inc(x) { return x + 1; } This defines a function `inc` with the inferred type `int -> int`, meaning `x` is automatically recognized as an `int`. [​](https://docs.ton.org/languages/func/functions#specifiers) Specifiers --------------------------------------------------------------------------- In FunC, function specifiers modify the behavior of functions. There are three types: 1. `impure` 2. Either `inline` or `inline_ref`, but not both 3. `method_id` One, multiple, or none can be used in a function declaration. However, they must appear in the order of the above list, e.g., `impure` must come before `inline` and `method_id`, `inline_ref` must come before `method_id`, etc. ### [​](https://docs.ton.org/languages/func/functions#impure-specifier) `impure` specifier The `impure` specifier indicates that a function has side effects, such as modifying contract storage, sending messages, or throwing exceptions. If a function is not marked as `impure` and its result is unused, the FunC compiler may delete the function call for optimization. For example, the [stdlib.fc](https://docs.ton.org/languages/func/stdlib) function [`random`](https://docs.ton.org/languages/func/stdlib#random) changes the internal state of the random number generator: int random() impure asm "RANDU256"; The `impure` keyword prevents the compiler from removing calls to this function: var n = 0; random(); ;; Even though the result of random is not used, ;; the compiler will not remove this call ;; because random has the impure specifier. ### [​](https://docs.ton.org/languages/func/functions#inline-specifier) Inline specifier A function marked as `inline` is directly substituted into the code wherever it is called, eliminating the function call overhead. Recursive calls are not allowed for inline functions. For example: (int) add(int a, int b) inline { return a + b; } Since the `add` function is marked with the `inline` specifier, the compiler substitutes `add(a, b)` with `a + b` directly in the code. For instance, the compiler will replace the following code: var a = 1; var b = 2; var n = add(a, b); with this code: var a = 1; var b = 2; var n = a + b; ### [​](https://docs.ton.org/languages/func/functions#inline_ref-specifier) `inline_ref` specifier When a function is marked with the `inline_ref` specifier, its code is stored in a separate cell. Each time the function is called, the TVM executes a `CALLREF` command, which loads the code stored in the referenced cell and executes the function code. To give you a very high level idea on how to visualize this, think how programs are stored in the blockchain. Anything in the blockchain is a cell. A program is a [directed acyclic graph (DAG)](https://docs.ton.org/foundations/whitepapers/tblkch#1-1-1-tvm-cells) of cells. Each cell stores TVM instructions, and can have up to 4 references to other cells. Each one of those references represent code that the TVM can jump to. So, you can picture a program like this: Cell 1 instruction 1 instruction 2 ..... call reference A ..... instruction n ---------------------------------------- Reference to cell A | Reference to cell B | where `Reference to cell A`, and `Reference to cell B` are references to other cells containing further code of the program. When the TVM executes the instruction `call reference A`, the TVM loads the cell referenced by `Reference to cell A` and executes the cell. When a function is marked as `inline_ref`, its code is placed in a separate cell, name it `C`. Then, everywhere the function is called in the original program, it is replaced with a `call reference C`. Then, the reference to `C` is added to the original program as a cell reference. More concretely, imagine the following program: int foo() inline_ref { return 1; } int main() { return (foo() + foo()); } Then, this would create two cells, one storing the code of the `main` function, call it cell `M`; and another cell storing the code of the `foo` function, because it is marked as `inline_ref`, call it cell `F`. The two calls to `foo` inside `main` will be replaced by reference calls to `F`. And the reference to `F` is added as a reference in cell `M`: Cell M call reference to F call reference to F ADD ---------------------------------------- Reference to F | Cell F 1 PUSHINT When `call reference to F` executes, the TVM loads the cell for `F` and executes it. As the example suggests, contrary to the `inline` specifier, the code for `foo` is not duplicated, because the two calls for `foo` are loading the same cell. As such, `inline_ref` is generally more efficient regarding code size. The only case where `inline` might be preferable is if the function is called just once, because loading cell references costs gas. However, recursive calls to `inline_ref` functions remain impossible, as TVM cells do not support cyclic references. ### [​](https://docs.ton.org/languages/func/functions#method_id-specifier) `method_id` specifier In a TVM program, every function has an internal integer ID that identifies it uniquely. These IDs are necessary because of the way the TVM calls functions within a program: it uses a dictionary where each key is a function ID that maps to the corresponding function code. When the TVM needs to invoke a particular function, the TVM looks up the ID in the dictionary and executes the corresponding code. By default, functions are assigned sequential numbers starting from `1`. If a function has the `method_id` specifier, the compiler will compute an ID using the formula `(crc16() & 0xffff) | 0x10000` instead. Additionally, such function becomes a get-method (or getter method), which are functions that can be invoked by its name in lite client or TON explorer. The `method_id` specifier has the variant `method_id()`, which allows you to set a function’s ID to a specific number manually. For example, this defines a function whose ID is computed by the compiler and the function is available as a get-method in TON blockchain explorers: int get_counter() method_id { load_data(); return ctx_counter; ;; Some global variable } This other example defines the same function, but this time it sets the specific ID `65536`. Again, the function is available as a get-method in TON explorers. int get_counter() method_id(65536) { load_data(); return ctx_counter; ;; Some global variable } [​](https://docs.ton.org/languages/func/functions#function-body) Function body --------------------------------------------------------------------------------- ### [​](https://docs.ton.org/languages/func/functions#empty-body) Empty body An empty body, marked with a single semicolon `;` indicates that the function is declared but not yet defined. Its definition must appear later in the same file or a different file processed before the current one by the FunC compiler. A function with an empty body is also called a _function declaration_. For example: int add(int x, int y); This declares a function named `add` with type `(int, int) -> int` but does not define it. In FunC, all functions must be defined or declared before using them in other functions, which explains the need for function declarations. For example, the following code calls function `foo` inside the `main` function, but `foo` is defined _after_ `main`. Hence, the compiler rejects the code: () main() { var a = foo(); ;; DOES NOT COMPILE ;; foo is not declared nor ;; defined before main } int foo() { return 0; } To fix the error, either declare `foo` before `main`: int foo(); ;; foo declared before main, ;; but defined after main () main() { var a = foo(); } int foo() { return 0; } Or move the definition of `foo` before main: int foo() { return 0; } () main() { var a = foo(); } ### [​](https://docs.ton.org/languages/func/functions#assembler-body) Assembler body An assembler body defines the function using low-level TVM primitives for use in a FunC program. The body consists on the keyword `asm`, followed a list of TVM instructions, and ending with symbol `;`. For example: int add(int x, int y) asm "ADD"; This defines the function `add` of type `(int, int) -> int`, using the TVM instruction `ADD`. Refer to the [assembler functions](https://docs.ton.org/languages/func/asm-functions) article for more details. ### [​](https://docs.ton.org/languages/func/functions#standard-body) Standard body A standard body uses a [block statement](https://docs.ton.org/languages/func/statements#block-statement) , i.e., the body of the function is defined inside curly braces `{ }`. For example: int add(int x, int y) { return x + y; } This defines a function that adds its two arguments and returns the result of the addition. [​](https://docs.ton.org/languages/func/functions#forall-declarator) `forall` declarator ------------------------------------------------------------------------------------------- The `forall` declarator has the following syntax: forall -> The declarator starts with the `forall` keyword and finishes with the symbol `->`. Each element in the comma separated list must be a type variable name. A type variable name can be any [identifier](https://docs.ton.org/languages/func/literals#identifiers) , but capital letters are commonly used. The `forall` declarator makes the function a [polymorphic function](https://en.wikipedia.org/wiki/Parametric_polymorphism) , meaning that when the function is called, the type variables get replaced with actual types. For example: forall X, Y -> [Y, X] pair_swap([X, Y] pair) { [X p1, Y p2] = pair; return [p2, p1]; } This function declares two type variables `X` and `Y`. The function uses these two type variables to declare an argument `pair` of type `[X, Y]`, i.e., a [tuple](https://docs.ton.org/languages/func/types#tuple-types) where the first component is of type `X` and the second component of type `Y`. The function then swaps the components of the tuple and returns a tuple of type `[Y, X]`. That `pair_swap` is polymorphic means that it can be called with tuples of type `[int, int]`, `[int, cell]`, `[cell, slice]`, `[[int, int], cell]`, etc. For instance: * `pair_swap([2, 3])` returns `[3, 2]`. In this case, both type variables `X` and `Y` get substituted with `int`. * `pair_swap([1, [2, 3, 4]])` returns `[[2, 3, 4], 1]`. In this case, type variable `X` gets substituted with `int`, and `Y` with `[int, int, int]`. Even though the function is polymorphic, the compiled assembly code remains the same for any substitution of the type variables. This is possible due to the polymorphic nature of stack manipulation operations. However, other forms of polymorphism, such as [`ad-hoc` polymorphism](https://en.wikipedia.org/wiki/Ad_hoc_polymorphism) with type classes, are not supported. Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/languages/func/functions.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/languages/func/functions) [Previous](https://docs.ton.org/languages/func/declarations-overview) [Reserved functions\ \ Next](https://docs.ton.org/languages/func/special-functions) ⌘I On this page * [Return type](https://docs.ton.org/languages/func/functions#return-type) * [Function name](https://docs.ton.org/languages/func/functions#function-name) * [Function arguments](https://docs.ton.org/languages/func/functions#function-arguments) * [Specifiers](https://docs.ton.org/languages/func/functions#specifiers) * [impure specifier](https://docs.ton.org/languages/func/functions#impure-specifier) * [Inline specifier](https://docs.ton.org/languages/func/functions#inline-specifier) * [inline\_ref specifier](https://docs.ton.org/languages/func/functions#inline_ref-specifier) * [method\_id specifier](https://docs.ton.org/languages/func/functions#method_id-specifier) * [Function body](https://docs.ton.org/languages/func/functions#function-body) * [Empty body](https://docs.ton.org/languages/func/functions#empty-body) * [Assembler body](https://docs.ton.org/languages/func/functions#assembler-body) * [Standard body](https://docs.ton.org/languages/func/functions#standard-body) * [forall declarator](https://docs.ton.org/languages/func/functions#forall-declarator) --- # FunC compiler directives - TON Docs [Skip to main content](https://docs.ton.org/languages/func/compiler-directives#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Program declarations FunC compiler directives Compiler directives are keywords that begin with `#`, instructing the compiler to perform specific actions, enforce checks, or modify parameters. These directives can only be used at the outermost level of a source file and cannot be placed inside function definitions. [​](https://docs.ton.org/languages/func/compiler-directives##include) `#include` ----------------------------------------------------------------------------------- The `#include` directive enables the inclusion of another FunC source file parsed in place of the directive. **Syntax:** #include ""; where `` is the path to the FunC source file to include. Files are automatically checked for multiple inclusions. By default, the compiler will ignore redundant inclusions if the same file is included more than once. This also applies to inclusions along a path of nested inclusions. A warning will be issued if the verbosity level is 2 or higher. For example, suppose that `main.fc` contains the `main` function. Suppose also that `main.fc` includes a file `A.fc`, which in turn includes a file `B.fc`, which in turn includes `main.fc`. When `main.fc` is compiled, the inclusion of `main.fc` in `B.fc` will be ignored. If an error occurs while parsing an included file, the compiler displays an inclusion stack, showing the locations of each file in the inclusion chain. [​](https://docs.ton.org/languages/func/compiler-directives##pragma) `#pragma` --------------------------------------------------------------------------------- The `#pragma` directive provides additional information to the compiler beyond what the language conveys. ### [​](https://docs.ton.org/languages/func/compiler-directives##pragma-version) `#pragma` version The `#pragma` version directive enforces using a specific FunC compiler version when compiling the file. **Syntax:** #pragma version ; where `` is an optional [version operator](https://docs.ton.org/languages/func/compiler-directives#operators) that allows to specify a constraint, and `` is specified in [**semantic versioning (semver)** format](https://en.wikipedia.org/wiki/Software_versioning) : _a.b.c_, where: * _a_ is the major version * _b_ is the minor version * _c_ is the patch version Example: #pragma version 2.3.4; #pragma version >2.3.4; The first example does not use an operator and it means that the compiler must have exactly version `2.3.4`. The second uses the greater than operator `>`, and it means that the compiler must have a version greater than `2.3.4` (see [precedence](https://docs.ton.org/languages/func/compiler-directives#equality-and-precedence) and [operators](https://docs.ton.org/languages/func/compiler-directives#operators) below for details). #### [​](https://docs.ton.org/languages/func/compiler-directives#equality-and-precedence) Equality and precedence Two versions are **equal** if their respective major, minor, and patch numbers are equal. Two versions are **not equal** if at least one of those numbers differ. Example: * _1.2.3_ is equal to _1.2.3_ * _3.4.5_ is not equal to _3.1.5_ **Precedence** of two versions _a.b.c_ and _d.e.f_ is determined the following way: * If _a_ is smaller than _d_, then _a.b.c_ precedes _d.e.f_ * If _a_ is equal to _d_, and _b_ is smaller than _e_, then _a.b.c_ precedes _d.e.f_ * If _a_ is equal to _d_, and _b_ is equal to _e_, and _c_ is smaller than _f_, then _a.b.c_ precedes _d.e.f_ If _a.b.c_ precedes _d.e.f_, then it is said that _a.b.c_ is smaller than _d.e.f_, or equivalently, that _d.e.f_ is greater than _a.b.c_. Example: * _1.0.0_ precedes _2.0.0_. Equivalently: _1.0.0_ is smaller than _2.0.0_ or _2.0.0_ is greater than _1.0.0_. * _2.0.0_ precedes _2.1.0_. Equivalently: _2.0.0_ is smaller than _2.1.0_ or _2.1.0_ is greater than _2.0.0_. * _2.1.0_ precedes _2.1.1_. Equivalently: _2.1.0_ is smaller than _2.1.1_ or _2.1.1_ is greater than _2.1.0_. #### [​](https://docs.ton.org/languages/func/compiler-directives#operators) Operators Developers can specify version constraints using the following operators: * _a.b.c_ or _\=a.b.c_ - Requires **exactly** version _a.b.c_ of the compiler * _\>a.b.c_ - Requires the compiler version to be **greater** than _a.b.c._ * _\>=a.b.c_ - Requires the compiler version to be **greater** than or **equal** to _a.b.c_ * __, _\>=_, _<_, _<=_, omitted parts default to zero. For example: * _\>a.b_ is equivalent to _\>a.b.0_ * _<=a_ is equivalent to _<=a.0.0_ For the operator ^, omitted parts do **not** default to zero. For example: * _^a.b_ is not equivalent to _^a.b.0_ * _^a_ is not equivalent to _^a.0.0_ Here are some examples of constraints: * _^5.1.2_ matches compiler version _5.1.3_ because patch `3` is no lower than patch `2`. * _^5.1.2_ does not match compiler version _5.2.3_ because minor `2` does not equal minor `1`. * _^5.1.2_ does not match compiler version _5.1.1_ because patch `1` is lower than patch `2`. * _^5.1_ matches compiler version _5.1.3_ because minor `1` is no lower than minor `1`. * _^5.1_ matches compiler version _5.2.3_ because minor `2` is no lower than minor `1`. * _^5.1_ matches compiler version _5.1.0_ because minor `1` is no lower than minor `1`. * _^5.1_ does not match compiler version _5.0.2_ because minor `0` is lower than minor `1`. * _^5_ matches compiler version _5.1.0_ because major `5` is no lower than major `5`. * _^5_ does not match compiler version _4.1.0_ because major `4` is lower than major `5`. * _\>5.1.2_ matches compiler version _5.1.3_ because patch `3` is bigger than patch `2`. * _\>5.1.2_ matches compiler version _5.2.0_ because minor `2` is bigger than minor `1`. * _\>5.1.2_ matches compiler version _6.0.0_ because major `6` is bigger than major `5`. * _\=5.1.2_ does not match compiler version _5.2.2_ because minor `2` is not equal to minor `1`. ### [​](https://docs.ton.org/languages/func/compiler-directives##pragma-not-version) `#pragma not-version` The `#pragma not-version` is similar to `#pragma version`, but it fails if the specified condition is met. **Syntax:** #pragma not-version ; where `` is an optional [version operator](https://docs.ton.org/languages/func/compiler-directives#operators) that allows to specify a constraint, and `` is identical as in [`#pragma version`](https://docs.ton.org/languages/func/compiler-directives#%23pragma-version) . This directive is useful for blocking specific compiler versions known to have issues. Here are some examples: #pragma not-version >2.1.3; #pragma not-version ^3.4; #pragma not-version 1.2.3; In the first example, `not-version >2.1.3` matches any compiler version that is _not_ bigger than _2.1.3_, like _2.1.2_, _2.0.5_ and even _2.1.3_ itself. In the second example, `not-version ^3.4` matches any compiler version that does _not_ match _^3.4_, like _3.3.1_, _4.4.0_, and _3.3.9_ In the third example, `not-version 1.2.3` matches any compiler version different from _1.2.3_. ### [​](https://docs.ton.org/languages/func/compiler-directives##pragma-allow-post-modification) `#pragma allow-post-modification` _Introduced in FunC v0.4.1_ In Func, using a variable before it is modified within the same [expression](https://docs.ton.org/languages/func/expressions) is prohibited by default. For example, the following code will **not** compile, because `ds` is used before it is modified in `ds~load_uint(8)`. See [modifying notation](https://docs.ton.org/languages/func/expressions#modifying-notation) for more details on using symbol `~`. (x, y) = (ds, ds~load_uint(8)); However, this version is **valid**, since `ds` is used after it is modified: (x, y) = (ds~load_uint(8), ds) To override this restriction, use `#pragma allow-post-modification`. This allows variables to be modified after usage in mass assignments and function calls while sub-expressions are still computed **left to right**. In the following example, `x` will contain the initial value of `ds`, while `y` the modified value of `ds`: #pragma allow-post-modification (x, y) = (ds, ds~load_bits(8)); ### [​](https://docs.ton.org/languages/func/compiler-directives##pragma-compute-asm-ltr) `#pragma compute-asm-ltr` _Introduced in FunC v0.4.1_ `asm` declarations can override the order of argument evaluation. For example, in the following expression: idict_set_ref(ds~load_dict(), ds~load_uint(8), ds~load_uint(256), ds~load_ref()) The evaluation order of the call arguments is: 1. `load_ref()` 2. `load_uint(256)` 3. `load_dict()` 4. `load_uint(8)` This happens due to the corresponding `asm` declaration: cell idict_set_ref(cell dict, int key_len, int index, cell value) asm(value index dict key_len) "DICTISETREF"; Here, the `asm(value index dict key_len)` notation dictates a [rearrangement of arguments](https://docs.ton.org/languages/func/asm-functions#rearranging-stack-entries) . To ensure strict left-to-right computation order of the arguments, use `#pragma compute-asm-ltr`. With this directive enabled, the same function call: #pragma compute-asm-ltr ;; ... idict_set_ref(ds~load_dict(), ds~load_uint(8), ds~load_uint(256), ds~load_ref()); will evaluate its arguments in the following order: 1. `load_dict()` 2. `load_uint(8)` 3. `load_uint(256)` 4. `load_ref()` and only _after_ the evaluation of all these arguments, the `asm` rearrangement will occur. Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/languages/func/compiler-directives.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/languages/func/compiler-directives) [Previous](https://docs.ton.org/languages/func/global-variables) [Reserved words and built-ins\ \ Next](https://docs.ton.org/languages/func/built-ins) ⌘I On this page * [#include](https://docs.ton.org/languages/func/compiler-directives#%23include) * [#pragma](https://docs.ton.org/languages/func/compiler-directives#%23pragma) * [#pragma version](https://docs.ton.org/languages/func/compiler-directives#%23pragma-version) * [Equality and precedence](https://docs.ton.org/languages/func/compiler-directives#equality-and-precedence) * [Operators](https://docs.ton.org/languages/func/compiler-directives#operators) * [#pragma not-version](https://docs.ton.org/languages/func/compiler-directives#%23pragma-not-version) * [#pragma allow-post-modification](https://docs.ton.org/languages/func/compiler-directives#%23pragma-allow-post-modification) * [#pragma compute-asm-ltr](https://docs.ton.org/languages/func/compiler-directives#%23pragma-compute-asm-ltr) --- # Reserved functions of FunC - TON Docs [Skip to main content](https://docs.ton.org/languages/func/special-functions#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Program declarations Reserved functions of FunC FunC, or more specifically, the Fift assembler, reserves several function names with predefined [IDs](https://docs.ton.org/languages/func/functions#method-id-specifier) : * [`recv_internal`](https://docs.ton.org/languages/func/special-functions#receive-internal) and [`main`](https://docs.ton.org/languages/func/special-functions#main) have `id = 0` * [`recv_external`](https://docs.ton.org/languages/func/special-functions#receive-external) has `id = -1` * [`run_ticktock`](https://docs.ton.org/languages/func/special-functions#run-ticktock) has `id = -2` * [`split_prepare`](https://docs.ton.org/languages/func/special-functions#split-prepare) has `id = -3` * [`split_install`](https://docs.ton.org/languages/func/special-functions#split-install) has `id = -4` Every program must include a function with `id = 0`, meaning it must define either `recv_internal` or `main`, but **not** both. #### [​](https://docs.ton.org/languages/func/special-functions#receive-internal) Receive internal The `recv_internal` function is invoked when a smart contract receives an inbound [internal message](https://docs.ton.org/foundations/messages/internal) . Any of the following `recv_internal` declarations can be used: () recv_internal(int balance, int msg_value, cell in_msg_cell, slice in_msg_body) () recv_internal(int msg_value, cell in_msg_cell, slice in_msg_body) () recv_internal(cell in_msg_cell, slice in_msg_body) () recv_internal(slice in_msg_body) () recv_internal() There, * `balance` is the smart contract balance in nanotons after adding the amount `msg_value` in the inbound message. It is an integer. * `msg_value` is the amount in nanotons included in the inbound message. It is an integer. * `in_msg_cell` is the inbound message, given as a cell. * `in_msg_body` is the inbound message body, equal to the body field in `in_msg_cell`. The body is given as a cell slice. #### [​](https://docs.ton.org/languages/func/special-functions#main) Main `main` is an alias for [`recv_internal`](https://docs.ton.org/languages/func/special-functions#receive-internal) . If the intention of the code is to handle inbound internal messages, it is preferable to use `recv_internal` over `main`, since `recv_internal` states more clearly the intention of the code. #### [​](https://docs.ton.org/languages/func/special-functions#receive-external) Receive external The `recv_external` function handles inbound [external messages](https://docs.ton.org/foundations/messages/external-in) . It allows declarations similar to those for [`recv_internal`](https://docs.ton.org/languages/func/special-functions#receive-internal) : () recv_external(int balance, int msg_value, cell in_msg_cell, slice in_msg_body) () recv_external(int msg_value, cell in_msg_cell, slice in_msg_body) () recv_external(cell in_msg_cell, slice in_msg_body) () recv_external(slice in_msg_body) () recv_external() The only difference is that `msg_value` is always `0`, since external messages cannot carry coins, as they are created outside the blockchain. The behavior of the stack is identical to the behavior described for [`recv_internal`](https://docs.ton.org/languages/func/special-functions#receive-internal) . #### [​](https://docs.ton.org/languages/func/special-functions#run-ticktock) Run ticktock The `run_ticktock` triggers at inbound tick and tock messages. It allows the following possible declarations: () run_ticktock(int balance, int address, int is_tock) () run_ticktock(int address, int is_tock) () run_ticktock(int is_tock) () run_ticktock() There: * `balance` is the smart contract balance in nanotons. It is an integer. * `address` is the address of the current account inside the masterchain. It is an unsigned 256-bit integer. * `is_tock` a flag that indicates if it is a tock message (`-1`) or a tick message (`0`). The behavior of the stack is identical to the behavior described for [`recv_internal`](https://docs.ton.org/languages/func/special-functions#receive-internal) . ### [​](https://docs.ton.org/languages/func/special-functions#split-prepare) Split prepare The `split_prepare` triggers for inbound split prepare messages. Even though the `split_prepare` name is currently reserved, split prepare messages are currently not in use. ### [​](https://docs.ton.org/languages/func/special-functions#split-install) Split install The `split_install` triggers for inbound split install messages. Even though the `split_install` name is currently reserved, split install messages are currently unavailable. Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/languages/func/special-functions.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/languages/func/special-functions) [Previous](https://docs.ton.org/languages/func/functions) [Assembler functions\ \ Next](https://docs.ton.org/languages/func/asm-functions) ⌘I On this page * [Receive internal](https://docs.ton.org/languages/func/special-functions#receive-internal) * [Main](https://docs.ton.org/languages/func/special-functions#main) * [Receive external](https://docs.ton.org/languages/func/special-functions#receive-external) * [Run ticktock](https://docs.ton.org/languages/func/special-functions#run-ticktock) * [Split prepare](https://docs.ton.org/languages/func/special-functions#split-prepare) * [Split install](https://docs.ton.org/languages/func/special-functions#split-install) --- # How to create Highload Wallet v3 - TON Docs [Skip to main content](https://docs.ton.org/standard/wallets/highload/v3/create#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Highload Wallet v3 How to create Highload Wallet v3 This guide shows how to create a Highload Wallet v3 instance from scratch: choose configuration parameters, generate a mnemonic, and calculate the wallet address. [​](https://docs.ton.org/standard/wallets/highload/v3/create#objective) Objective ------------------------------------------------------------------------------------ By the end of this guide, you will have: * A 24-word mnemonic phrase (seed phrase) for your wallet * A calculated wallet address (but not yet deployed on-chain) * Configuration parameters: `subwalletId` and `timeout` [​](https://docs.ton.org/standard/wallets/highload/v3/create#prerequisites) Prerequisites -------------------------------------------------------------------------------------------- * Node.js 18+ or TypeScript environment * `@ton/ton`, `@ton/core`, `@ton/crypto` packages installed * Highload Wallet v3 wrapper and compiled contract code This guide uses TypeScript with the official wrapper. The same logic applies to other SDKs (Go/Python): generate or load a mnemonic, derive a keypair, choose parameters, and calculate the address. [​](https://docs.ton.org/standard/wallets/highload/v3/create#step-1-set-up-dependencies) Step 1: Set up dependencies ----------------------------------------------------------------------------------------------------------------------- Install required packages: npm install @ton/ton @ton/core @ton/crypto Copy the wrapper and contract code from the [official repository](https://github.com/ton-blockchain/highload-wallet-contract-v3) : # Clone the repository or download these files: # - wrappers/HighloadWalletV3.ts # - wrappers/HighloadQueryId.ts # - Compiled contract BoC (from build/ or inline hex) [​](https://docs.ton.org/standard/wallets/highload/v3/create#step-2-choose-configuration-parameters) Step 2: Choose configuration parameters ----------------------------------------------------------------------------------------------------------------------------------------------- Highload Wallet v3 requires two configuration parameters at creation time: ### [​](https://docs.ton.org/standard/wallets/highload/v3/create#timeout) `timeout` **Type:** `uint22` (0 to 4,194,303 seconds) **Purpose:** Validity window for external messages and cleanup cycle duration The `timeout` determines: * How long a signed external message remains valid: `created_at` must be within `[now - timeout, now]` * When old processed messages rotate to `old_queries`: every `timeout` seconds * When `old_queries` is cleared: after `2 × timeout` **Choosing a value:** | Range | Use case | | --- | --- | | Short (60–300s) | Fast certainty if message expires; lower storage costs; requires tight synchronization | | Medium (1–6 hours) | Balanced; suitable for most production use | | Long (24+ hours) | High tolerance for blockchain congestion; higher storage costs; slower certainty on expiration | See [Timeout constraints](https://docs.ton.org/standard/wallets/highload/v3/specification#timeout-constraints) in the specification for details. ### [​](https://docs.ton.org/standard/wallets/highload/v3/create#subwalletid) `subwalletId` **Type:** `uint32` (0 to 4,294,967,295) **Purpose:** Isolate multiple wallets derived from the same keypair A single mnemonic can generate multiple independent wallet addresses by varying `subwalletId`. Each wallet has its own balance, state, and transaction history. **Why this matters:** If you use the same `subwalletId` across different wallet types (e.g., Highload v3 and standard wallet v5), they might share the same address, causing conflicts. Using `0x10ad` ensures isolation from standard wallets. See [Storage structure](https://docs.ton.org/standard/wallets/highload/v3/specification#storage-structure) in the specification for details. [​](https://docs.ton.org/standard/wallets/highload/v3/create#step-3-generate-or-load-a-mnemonic) Step 3: Generate or load a mnemonic --------------------------------------------------------------------------------------------------------------------------------------- A mnemonic is your wallet’s master secret. It derives the private key used to sign all transactions. ### [​](https://docs.ton.org/standard/wallets/highload/v3/create#generate-a-new-mnemonic) Generate a new mnemonic import { mnemonicNew } from '@ton/crypto'; const mnemonic = await mnemonicNew(24); // Array of 24 words ### [​](https://docs.ton.org/standard/wallets/highload/v3/create#load-an-existing-mnemonic) Load an existing mnemonic const mnemonic = 'word1 word2 word3 ... word24'.split(' '); [​](https://docs.ton.org/standard/wallets/highload/v3/create#step-4-derive-the-keypair) Step 4: Derive the keypair --------------------------------------------------------------------------------------------------------------------- Convert the mnemonic to an Ed25519 keypair: import { mnemonicToPrivateKey } from '@ton/crypto'; const keyPair = await mnemonicToPrivateKey(mnemonic); // keyPair.publicKey — used in contract state // keyPair.secretKey — used to sign external messages [​](https://docs.ton.org/standard/wallets/highload/v3/create#step-5-create-the-wallet-instance) Step 5: Create the wallet instance ------------------------------------------------------------------------------------------------------------------------------------- Create a Highload Wallet v3 contract instance with your chosen parameters: import { TonClient } from '@ton/ton'; import { Cell } from '@ton/core'; import { HighloadWalletV3 } from './wrappers/HighloadWalletV3'; // Configuration const SUBWALLET_ID = 0x10ad; // Recommended for Highload Wallets const TIMEOUT = 60 * 60 * 24; // 24 hours // Compiled contract code (BoC) const CODE = Cell.fromBoc( Buffer.from( 'b5ee9c7241021001000228000114ff00f4a413f4bcf2c80b01020120020d02014803040078d020d74bc00101c060b0915be101d0d3030171b0915be0fa4030f828c705b39130e0d31f018210ae42e5a4ba9d8040d721d74cf82a01ed55fb04e030020120050a02027306070011adce76a2686b85ffc00201200809001aabb6ed44d0810122d721d70b3f0018aa3bed44d08307d721d70b1f0201200b0c001bb9a6eed44d0810162d721d70b15800e5b8bf2eda2edfb21ab09028409b0ed44d0810120d721f404f404d33fd315d1058e1bf82325a15210b99f326df82305aa0015a112b992306dde923033e2923033e25230800df40f6fa19ed021d721d70a00955f037fdb31e09130e259800df40f6fa19cd001d721d70a00937fdb31e0915be270801f6f2d48308d718d121f900ed44d0d3ffd31ff404f404d33fd315d1f82321a15220b98e12336df82324aa00a112b9926d32de58f82301de541675f910f2a106d0d31fd4d307d30cd309d33fd315d15168baf2a2515abaf2a6f8232aa15250bcf2a304f823bbf2a35304800df40f6fa199d024d721d70a00f2649130e20e01fe5309800df40f6fa18e13d05004d718d20001f264c858cf16cf8301cf168e1030c824cf40cf8384095005a1a514cf40e2f800c94039800df41704c8cbff13cb1ff40012f40012cb3f12cb15c9ed54f80f21d0d30001f265d3020171b0925f03e0fa4001d70b01c000f2a5fa4031fa0031f401fa0031fa00318060d721d300010f0020f265d2000193d431d19130e272b1fb00b585bf03', 'hex' ) )[0]; const client = new TonClient({ endpoint: 'https://testnet.toncenter.com/api/v2/jsonRPC', // This is TESTNET endpoint // apiKey: 'your-api-key' // Optional: get from @tonapibot or @tontestnetapibot }); const wallet = client.open( HighloadWalletV3.createFromConfig( { publicKey: keyPair.publicKey, subwalletId: SUBWALLET_ID, timeout: TIMEOUT, }, CODE ) ); [​](https://docs.ton.org/standard/wallets/highload/v3/create#step-6-get-the-wallet-address) Step 6: Get the wallet address ----------------------------------------------------------------------------------------------------------------------------- Calculate the wallet’s address: // Get non-bounceable address for funding const address = wallet.address.toString({ bounceable: false, testOnly: true }); console.log('Wallet address:', address); // Example (truncated): 0Q... (non-bounceable, testnet) This address is deterministic: it depends only on `CODE`, `publicKey`, `subwalletId`, and `timeout`. The same parameters always produce the same address. **Account status: [`nonexist`](https://docs.ton.org/foundations/status#status-variety) ** The calculated address exists only as a deterministic value. No account exists on the blockchain yet — no balance, no code, no data. [​](https://docs.ton.org/standard/wallets/highload/v3/create#step-7-fund-the-wallet) Step 7: Fund the wallet --------------------------------------------------------------------------------------------------------------- **Required before deployment:** Send TON to your wallet address (from Step 6) to prepare it for deployment. External messages (which deploy the wallet) require gas to execute. By funding the address, you transition the account from `nonexist` to `uninit` status and provide the balance needed for deployment. See [Account status](https://docs.ton.org/foundations/status) for details on how account states work. Send TON using a faucet (testnet) or from another wallet (mainnet). After funding, the account transitions to `uninit` status — it has a balance and can accept external messages, but no code or data yet. [​](https://docs.ton.org/standard/wallets/highload/v3/create#saving-wallet-data) Saving wallet data ------------------------------------------------------------------------------------------------------ For convenience, save your wallet configuration to reuse later: import * as fs from 'fs'; const walletData = { mnemonic: mnemonic.join(' '), address: address, // From Step 6 subwalletId: SUBWALLET_ID, timeout: TIMEOUT, }; fs.writeFileSync('.wallet.json', JSON.stringify(walletData, null, 2)); console.log('Wallet saved to .wallet.json'); [​](https://docs.ton.org/standard/wallets/highload/v3/create#next-steps) Next steps -------------------------------------------------------------------------------------- Your wallet is ready for deployment. The wallet will auto-deploy on the first external message. Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/standard/wallets/highload/v3/create.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/standard/wallets/highload/v3/create) [Previous](https://docs.ton.org/standard/wallets/highload/overview) [How to send a single transfer\ \ Next](https://docs.ton.org/standard/wallets/highload/v3/send-single-transfer) ⌘I On this page * [Objective](https://docs.ton.org/standard/wallets/highload/v3/create#objective) * [Prerequisites](https://docs.ton.org/standard/wallets/highload/v3/create#prerequisites) * [Step 1: Set up dependencies](https://docs.ton.org/standard/wallets/highload/v3/create#step-1-set-up-dependencies) * [Step 2: Choose configuration parameters](https://docs.ton.org/standard/wallets/highload/v3/create#step-2-choose-configuration-parameters) * [timeout](https://docs.ton.org/standard/wallets/highload/v3/create#timeout) * [subwalletId](https://docs.ton.org/standard/wallets/highload/v3/create#subwalletid) * [Step 3: Generate or load a mnemonic](https://docs.ton.org/standard/wallets/highload/v3/create#step-3-generate-or-load-a-mnemonic) * [Generate a new mnemonic](https://docs.ton.org/standard/wallets/highload/v3/create#generate-a-new-mnemonic) * [Load an existing mnemonic](https://docs.ton.org/standard/wallets/highload/v3/create#load-an-existing-mnemonic) * [Step 4: Derive the keypair](https://docs.ton.org/standard/wallets/highload/v3/create#step-4-derive-the-keypair) * [Step 5: Create the wallet instance](https://docs.ton.org/standard/wallets/highload/v3/create#step-5-create-the-wallet-instance) * [Step 6: Get the wallet address](https://docs.ton.org/standard/wallets/highload/v3/create#step-6-get-the-wallet-address) * [Step 7: Fund the wallet](https://docs.ton.org/standard/wallets/highload/v3/create#step-7-fund-the-wallet) * [Saving wallet data](https://docs.ton.org/standard/wallets/highload/v3/create#saving-wallet-data) * [Next steps](https://docs.ton.org/standard/wallets/highload/v3/create#next-steps) --- # How to send a single transfer - TON Docs [Skip to main content](https://docs.ton.org/standard/wallets/highload/v3/send-single-transfer#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Highload Wallet v3 How to send a single transfer This guide shows how to send a single transfer from your Highload Wallet v3. [​](https://docs.ton.org/standard/wallets/highload/v3/send-single-transfer#objective) Objective -------------------------------------------------------------------------------------------------- By the end of this guide, you will: * Send a single TON transfer from your Highload Wallet v3 * Understand how `query_id`, `created_at`, and [send modes](https://docs.ton.org/foundations/messages/modes) work [​](https://docs.ton.org/standard/wallets/highload/v3/send-single-transfer#prerequisites) Prerequisites ---------------------------------------------------------------------------------------------------------- * Completed [wallet creation](https://docs.ton.org/standard/wallets/highload/v3/create) with funded balance and saved configuration in `.wallet.json` [​](https://docs.ton.org/standard/wallets/highload/v3/send-single-transfer#step-1-load-wallet-configuration) Step 1: Load wallet configuration ------------------------------------------------------------------------------------------------------------------------------------------------- Load the wallet data and create the wallet instance: import { TonClient, internal, toNano } from '@ton/ton'; import { mnemonicToPrivateKey } from '@ton/crypto'; import { Cell, SendMode } from '@ton/core'; import { HighloadWalletV3 } from './wrappers/HighloadWalletV3'; import { HighloadQueryId } from './wrappers/HighloadQueryId'; import * as fs from 'fs'; // Load wallet data const walletData = JSON.parse(fs.readFileSync('.wallet.json', 'utf-8')); const mnemonic = walletData.mnemonic.split(' '); const keyPair = await mnemonicToPrivateKey(mnemonic); const CODE = Cell.fromBoc(Buffer.from('b5ee9c7241021001000228000114ff00f4a413f4bcf2c80b01020120020d02014803040078d020d74bc00101c060b0915be101d0d3030171b0915be0fa4030f828c705b39130e0d31f018210ae42e5a4ba9d8040d721d74cf82a01ed55fb04e030020120050a02027306070011adce76a2686b85ffc00201200809001aabb6ed44d0810122d721d70b3f0018aa3bed44d08307d721d70b1f0201200b0c001bb9a6eed44d0810162d721d70b15800e5b8bf2eda2edfb21ab09028409b0ed44d0810120d721f404f404d33fd315d1058e1bf82325a15210b99f326df82305aa0015a112b992306dde923033e2923033e25230800df40f6fa19ed021d721d70a00955f037fdb31e09130e259800df40f6fa19cd001d721d70a00937fdb31e0915be270801f6f2d48308d718d121f900ed44d0d3ffd31ff404f404d33fd315d1f82321a15220b98e12336df82324aa00a112b9926d32de58f82301de541675f910f2a106d0d31fd4d307d30cd309d33fd315d15168baf2a2515abaf2a6f8232aa15250bcf2a304f823bbf2a35304800df40f6fa199d024d721d70a00f2649130e20e01fe5309800df40f6fa18e13d05004d718d20001f264c858cf16cf8301cf168e1030c824cf40cf8384095005a1a514cf40e2f800c94039800df41704c8cbff13cb1ff40012f40012cb3f12cb15c9ed54f80f21d0d30001f265d3020171b0925f03e0fa4001d70b01c000f2a5fa4031fa0031f401fa0031fa00318060d721d300010f0020f265d2000193d431d19130e272b1fb00b585bf03', 'hex'))[0]; const client = new TonClient({ endpoint: 'https://testnet.toncenter.com/api/v2/jsonRPC', // This is TESTNET endpoint // apiKey: 'your-api-key' // Optional: get from @tonapibot or @tontestnetapibot }); const wallet = client.open( HighloadWalletV3.createFromConfig( { publicKey: keyPair.publicKey, subwalletId: walletData.subwalletId, timeout: walletData.timeout, }, CODE ) ); [​](https://docs.ton.org/standard/wallets/highload/v3/send-single-transfer#step-2-prepare-the-transfer-message) Step 2: Prepare the transfer message ------------------------------------------------------------------------------------------------------------------------------------------------------- Create an internal message with the transfer details: const internalMessage = internal({ to: 'EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c', // Zero address (for testing) value: toNano('0.01'), bounce: false, }); This example uses the zero address for testing. Replace it with your actual destination address. [​](https://docs.ton.org/standard/wallets/highload/v3/send-single-transfer#step-3-send-the-transfer) Step 3: Send the transfer --------------------------------------------------------------------------------------------------------------------------------- Send the transfer using the `sendExternalMessage` method: const createdAt = Math.floor(Date.now() / 1000) - 30; // 30 seconds ago const queryId = new HighloadQueryId(); // Represents query_id as a seqno await wallet.sendExternalMessage(keyPair.secretKey, { message: internalMessage, mode: SendMode.PAY_GAS_SEPARATELY, query_id: queryId, createdAt: createdAt, subwalletId: walletData.subwalletId, timeout: walletData.timeout, }); console.log('Transfer sent'); ### [​](https://docs.ton.org/standard/wallets/highload/v3/send-single-transfer#parameter-explanation) Parameter explanation **`query_id`** — Unique identifier for replay protection: * Each `query_id` can only be processed once within the protection window * `HighloadQueryId` is a wrapper class that represents the composite `query_id` as a sequential counter * Provides `getNext()` method to increment to the next unique ID * Total range: 8,380,416 unique IDs * See [Query ID structure](https://docs.ton.org/standard/wallets/highload/v3/specification#query-id-structure) for details **`createdAt`** — Message timestamp for expiration: * Set to 30 seconds **before** current time: `Math.floor(Date.now() / 1000) - 30` * Compensates for blockchain time lag (lite-servers use last block time, not current time) * See [Timestamp validation](https://docs.ton.org/standard/wallets/highload/v3/specification#timestamp-validation) for why this is necessary [​](https://docs.ton.org/standard/wallets/highload/v3/send-single-transfer#next-steps) Next steps ---------------------------------------------------------------------------------------------------- Your wallet is fully operational. You can send multiple transfers in parallel or batch multiple messages in one transaction. To verify that your message, see [How to verify message is processed](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed) . Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/standard/wallets/highload/v3/send-single-transfer.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/standard/wallets/highload/v3/send-single-transfer) [Previous](https://docs.ton.org/standard/wallets/highload/v3/create) [How to send a batch of transfers\ \ Next](https://docs.ton.org/standard/wallets/highload/v3/send-batch-transfers) ⌘I On this page * [Objective](https://docs.ton.org/standard/wallets/highload/v3/send-single-transfer#objective) * [Prerequisites](https://docs.ton.org/standard/wallets/highload/v3/send-single-transfer#prerequisites) * [Step 1: Load wallet configuration](https://docs.ton.org/standard/wallets/highload/v3/send-single-transfer#step-1-load-wallet-configuration) * [Step 2: Prepare the transfer message](https://docs.ton.org/standard/wallets/highload/v3/send-single-transfer#step-2-prepare-the-transfer-message) * [Step 3: Send the transfer](https://docs.ton.org/standard/wallets/highload/v3/send-single-transfer#step-3-send-the-transfer) * [Parameter explanation](https://docs.ton.org/standard/wallets/highload/v3/send-single-transfer#parameter-explanation) * [Next steps](https://docs.ton.org/standard/wallets/highload/v3/send-single-transfer#next-steps) --- # How to send a batch of transfers - TON Docs [Skip to main content](https://docs.ton.org/standard/wallets/highload/v3/send-batch-transfers#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Highload Wallet v3 How to send a batch of transfers This guide shows how to send multiple transfers in a single transaction using Highload Wallet v3. This is the main feature of the wallet, enabling up to 254 messages per transaction. [​](https://docs.ton.org/standard/wallets/highload/v3/send-batch-transfers#objective) Objective -------------------------------------------------------------------------------------------------- By the end of this guide, you will: * Send multiple transfers (up to 254) in a single transaction * Understand the two-transaction flow for batch transfers * Know how to calculate the compute fees for the internal transaction [​](https://docs.ton.org/standard/wallets/highload/v3/send-batch-transfers#prerequisites) Prerequisites ---------------------------------------------------------------------------------------------------------- * Completed [wallet creation](https://docs.ton.org/standard/wallets/highload/v3/create) with funded balance and saved configuration in `.wallet.json` [​](https://docs.ton.org/standard/wallets/highload/v3/send-batch-transfers#step-1-load-wallet-configuration) Step 1: Load wallet configuration ------------------------------------------------------------------------------------------------------------------------------------------------- Load the wallet data and create the wallet instance: import { TonClient, internal, toNano, comment } from '@ton/ton'; import { mnemonicToPrivateKey } from '@ton/crypto'; import { Cell, SendMode } from '@ton/core'; import { HighloadWalletV3 } from './wrappers/HighloadWalletV3'; import { HighloadQueryId } from './wrappers/HighloadQueryId'; import * as fs from 'fs'; // Load wallet data const walletData = JSON.parse(fs.readFileSync('.wallet.json', 'utf-8')); const mnemonic = walletData.mnemonic.split(' '); const keyPair = await mnemonicToPrivateKey(mnemonic); const CODE = Cell.fromBoc(Buffer.from('b5ee9c7241021001000228000114ff00f4a413f4bcf2c80b01020120020d02014803040078d020d74bc00101c060b0915be101d0d3030171b0915be0fa4030f828c705b39130e0d31f018210ae42e5a4ba9d8040d721d74cf82a01ed55fb04e030020120050a02027306070011adce76a2686b85ffc00201200809001aabb6ed44d0810122d721d70b3f0018aa3bed44d08307d721d70b1f0201200b0c001bb9a6eed44d0810162d721d70b15800e5b8bf2eda2edfb21ab09028409b0ed44d0810120d721f404f404d33fd315d1058e1bf82325a15210b99f326df82305aa0015a112b992306dde923033e2923033e25230800df40f6fa19ed021d721d70a00955f037fdb31e09130e259800df40f6fa19cd001d721d70a00937fdb31e0915be270801f6f2d48308d718d121f900ed44d0d3ffd31ff404f404d33fd315d1f82321a15220b98e12336df82324aa00a112b9926d32de58f82301de541675f910f2a106d0d31fd4d307d30cd309d33fd315d15168baf2a2515abaf2a6f8232aa15250bcf2a304f823bbf2a35304800df40f6fa199d024d721d70a00f2649130e20e01fe5309800df40f6fa18e13d05004d718d20001f264c858cf16cf8301cf168e1030c824cf40cf8384095005a1a514cf40e2f800c94039800df41704c8cbff13cb1ff40012f40012cb3f12cb15c9ed54f80f21d0d30001f265d3020171b0925f03e0fa4001d70b01c000f2a5fa4031fa0031f401fa0031fa00318060d721d300010f0020f265d2000193d431d19130e272b1fb00b585bf03', 'hex'))[0]; const client = new TonClient({ endpoint: 'https://testnet.toncenter.com/api/v2/jsonRPC', // This is TESTNET endpoint // apiKey: 'your-api-key' // Optional: get from @tonapibot or @tontestnetapibot }); const wallet = client.open( HighloadWalletV3.createFromConfig( { publicKey: keyPair.publicKey, subwalletId: walletData.subwalletId, timeout: walletData.timeout, }, CODE ) ); [​](https://docs.ton.org/standard/wallets/highload/v3/send-batch-transfers#step-2-prepare-the-message-batch) Step 2: Prepare the message batch ------------------------------------------------------------------------------------------------------------------------------------------------- Create an array of messages to send: const messages = []; for (let i = 1; i <= 10; i++) { messages.push({ type: 'sendMsg' as const, mode: SendMode.PAY_GAS_SEPARATELY, outMsg: internal({ to: 'EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c', // Zero address (for testing) value: toNano('0.001'), body: comment(`#${i}`), bounce: false, }), }); } Each message in the batch: * **`type: 'sendMsg'`** — specifies that this is an outgoing message action * **`mode`** — [send mode](https://docs.ton.org/foundations/messages/modes) for each individual message * **`outMsg`** — the internal message to send [​](https://docs.ton.org/standard/wallets/highload/v3/send-batch-transfers#step-3-send-the-batch) Step 3: Send the batch --------------------------------------------------------------------------------------------------------------------------- Send the batch using the `sendBatch` method: const queryId = HighloadQueryId.fromSeqno(17n); // Use a specific seqno const createdAt = Math.floor(Date.now() / 1000) - 30; // 30 seconds ago const value = toNano('0.0007024'); // Compute fee for internal receiver await wallet.sendBatch( keyPair.secretKey, messages, walletData.subwalletId, queryId, walletData.timeout, createdAt, value ); console.log('Batch sent: 10 transfers'); console.log(`Query ID: ${queryId.toSeqno()}`); console.log(`Created At: ${createdAt}`); ### [​](https://docs.ton.org/standard/wallets/highload/v3/send-batch-transfers#parameter-explanation) Parameter explanation **`queryId`** — Unique identifier for replay protection: * Each `query_id` can only be processed once within the protection window * `HighloadQueryId` is a wrapper class that represents the composite `query_id` as a sequential counter * Use `HighloadQueryId.fromSeqno(n)` to create a specific query ID * Provides `getNext()` method to increment to the next unique ID * Total range: 8,380,416 unique IDs * See [Query ID structure](https://docs.ton.org/standard/wallets/highload/v3/specification#query-id-structure) for details **`createdAt`** — Message timestamp for expiration: * Set to 30 seconds **before** current time: `Math.floor(Date.now() / 1000) - 30` * Compensates for blockchain time lag (lite-servers use last block time, not current time) * See [Timestamp validation](https://docs.ton.org/standard/wallets/highload/v3/specification#timestamp-validation) for why this is necessary **`value`** — Compute fee for the internal transaction: * The internal receiver (Transaction 2) consumes a fixed **1,756 gas** to process the action list * At current gas prices, this equals ~0.0007024 TON * This fee is sent to the wallet itself to cover internal message processing * If insufficient, the internal transaction may fail (but replay protection remains intact) [​](https://docs.ton.org/standard/wallets/highload/v3/send-batch-transfers#how-it-works) How it works -------------------------------------------------------------------------------------------------------- Batch transfers use a two-transaction pattern: the external message marks the `query_id` as processed and sends an internal message to itself with the action list, then the internal transaction processes the actions and sends all outgoing messages. See [Message sending flow](https://docs.ton.org/standard/wallets/highload/v3/specification#message-sending-flow) for the complete validation sequence. [​](https://docs.ton.org/standard/wallets/highload/v3/send-batch-transfers#next-steps) Next steps ---------------------------------------------------------------------------------------------------- You can send multiple batches in parallel, each with a unique `query_id`. To verify that your batch was fully processed, see [How to verify message is processed](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed) . Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/standard/wallets/highload/v3/send-batch-transfers.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/standard/wallets/highload/v3/send-batch-transfers) [Previous](https://docs.ton.org/standard/wallets/highload/v3/send-single-transfer) [How to verify message is processed\ \ Next](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed) ⌘I On this page * [Objective](https://docs.ton.org/standard/wallets/highload/v3/send-batch-transfers#objective) * [Prerequisites](https://docs.ton.org/standard/wallets/highload/v3/send-batch-transfers#prerequisites) * [Step 1: Load wallet configuration](https://docs.ton.org/standard/wallets/highload/v3/send-batch-transfers#step-1-load-wallet-configuration) * [Step 2: Prepare the message batch](https://docs.ton.org/standard/wallets/highload/v3/send-batch-transfers#step-2-prepare-the-message-batch) * [Step 3: Send the batch](https://docs.ton.org/standard/wallets/highload/v3/send-batch-transfers#step-3-send-the-batch) * [Parameter explanation](https://docs.ton.org/standard/wallets/highload/v3/send-batch-transfers#parameter-explanation) * [How it works](https://docs.ton.org/standard/wallets/highload/v3/send-batch-transfers#how-it-works) * [Next steps](https://docs.ton.org/standard/wallets/highload/v3/send-batch-transfers#next-steps) --- # How to verify message is processed - TON Docs [Skip to main content](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#content-area) [TON Docs home page![light logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/light.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=f92139f656fab8b0a6085d039b1c5242)![dark logo](https://mintcdn.com/companyname-a7d5b98e/hToXJqpfpFUyET7E/resources/logo/dark.svg?fit=max&auto=format&n=hToXJqpfpFUyET7E&q=85&s=95ecae495638ab04f45c2d9e69178fab)](https://docs.ton.org/) Search... ⌘K Search... Navigation Highload Wallet v3 How to verify message is processed This guide shows how to verify that a transfer (single or batch) was fully processed across both transactions. [​](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#objective) Objective ------------------------------------------------------------------------------------------------- By the end of this guide, you will: * Verify that both transactions (external and internal) succeeded * Calculate how many messages were successfully sent * Detect partial failures in batch transfers [​](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#prerequisites) Prerequisites --------------------------------------------------------------------------------------------------------- * Completed [wallet creation](https://docs.ton.org/standard/wallets/highload/v3/create) with funded balance * Sent at least one transfer (single or batch) * Know the `query_id` and `created_at` values used in the transfer [​](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#verification-overview) Verification overview ------------------------------------------------------------------------------------------------------------------------- Highload Wallet v3 uses a two-transaction pattern. To verify full processing, you need to check both transactions: 1. **External transaction (Transaction 1):** Validates the message and marks `query_id` as processed 2. **Internal transaction (Transaction 2):** Processes the action list and sends outgoing messages Even if `processed?` returns `true`, the internal transaction may have failed. Full verification requires checking both transactions. See [Message sending flow](https://docs.ton.org/standard/wallets/highload/v3/specification#message-sending-flow) for the complete two-transaction pattern. [​](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#helper-functions) Helper functions --------------------------------------------------------------------------------------------------------------- Create helper functions for transaction search and parsing: import { TonClient } from '@ton/ton'; import { Cell, Transaction, Address } from '@ton/core'; // Retry helper for network requests async function retry(fn: () => Promise, options: { retries: number; delay: number }): Promise { let lastError: Error | undefined; for (let i = 0; i < options.retries; i++) { try { return await fn(); } catch (e) { if (e instanceof Error) lastError = e; await new Promise((resolve) => setTimeout(resolve, options.delay)); } } throw lastError; } // Parse external message to extract query_id and created_at function parseExternalMessageBody(body: Cell) { try { const inner = body.refs[0]!.beginParse(); inner.skip(32 + 8); // Skip subwalletId and mode const queryId = inner.loadUintBig(23); const createdAt = inner.loadUint(64); return { queryId, createdAt }; } catch (e) { return null; } } // Generic transaction finder with pagination async function findTransaction( client: TonClient, address: Address, predicate: (tx: Transaction) => boolean ): Promise { let lt: string | undefined = undefined; let hash: string | undefined = undefined; while (true) { const transactions = await retry( () => client.getTransactions(address, { hash, lt, limit: 20, archival: true, }), { delay: 1000, retries: 3 } ); if (transactions.length === 0) return null; const found = transactions.find(predicate); if (found) return found; const last = transactions.at(-1)!; lt = last.lt.toString(); hash = last.hash().toString('base64'); } } [​](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#step-1-set-up-and-check-if-processed) Step 1: Set up and check if processed -------------------------------------------------------------------------------------------------------------------------------------------------------- Load wallet configuration and check if the `query_id` was marked as processed: import { mnemonicToPrivateKey } from '@ton/crypto'; import { HighloadWalletV3 } from './wrappers/HighloadWalletV3'; import { HighloadQueryId } from './wrappers/HighloadQueryId'; import * as fs from 'fs'; // Load wallet data const walletData = JSON.parse(fs.readFileSync('.wallet.json', 'utf-8')); const keyPair = await mnemonicToPrivateKey(walletData.mnemonic.split(' ')); const CODE = Cell.fromBoc(Buffer.from('b5ee9c7241021001000228000114ff00f4a413f4bcf2c80b01020120020d02014803040078d020d74bc00101c060b0915be101d0d3030171b0915be0fa4030f828c705b39130e0d31f018210ae42e5a4ba9d8040d721d74cf82a01ed55fb04e030020120050a02027306070011adce76a2686b85ffc00201200809001aabb6ed44d0810122d721d70b3f0018aa3bed44d08307d721d70b1f0201200b0c001bb9a6eed44d0810162d721d70b15800e5b8bf2eda2edfb21ab09028409b0ed44d0810120d721f404f404d33fd315d1058e1bf82325a15210b99f326df82305aa0015a112b992306dde923033e2923033e25230800df40f6fa19ed021d721d70a00955f037fdb31e09130e259800df40f6fa19cd001d721d70a00937fdb31e0915be270801f6f2d48308d718d121f900ed44d0d3ffd31ff404f404d33fd315d1f82321a15220b98e12336df82324aa00a112b9926d32de58f82301de541675f910f2a106d0d31fd4d307d30cd309d33fd315d15168baf2a2515abaf2a6f8232aa15250bcf2a304f823bbf2a35304800df40f6fa199d024d721d70a00f2649130e20e01fe5309800df40f6fa18e13d05004d718d20001f264c858cf16cf8301cf168e1030c824cf40cf8384095005a1a514cf40e2f800c94039800df41704c8cbff13cb1ff40012f40012cb3f12cb15c9ed54f80f21d0d30001f265d3020171b0925f03e0fa4001d70b01c000f2a5fa4031fa0031f401fa0031fa00318060d721d300010f0020f265d2000193d431d19130e272b1fb00b585bf03', 'hex'))[0]; const client = new TonClient({ endpoint: 'https://testnet.toncenter.com/api/v2/jsonRPC', // This is TESTNET endpoint // apiKey: 'your-api-key' // Optional: get from @tonapibot or @tontestnetapibot }); const highloadWallet = HighloadWalletV3.createFromConfig( { publicKey: keyPair.publicKey, subwalletId: walletData.subwalletId, timeout: walletData.timeout, }, CODE ); const wallet = client.open(highloadWallet); // The query_id and created_at from your transfer const queryId = HighloadQueryId.fromSeqno(17n); const createdAt = 1759878156; // Your actual created_at timestamp // Check if processed const isProcessed = await wallet.getProcessed(queryId); if (!isProcessed) { console.log('❌ Query not processed'); return; } console.log('✓ Query marked as processed'); [​](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#step-2-find-and-verify-external-transaction) Step 2: Find and verify external transaction ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Search transaction history to find the external transaction by `query_id` and `created_at`: // Find external transaction by query_id + created_at async function findHighloadExternalTransaction( client: TonClient, walletAddress: Address, queryId: HighloadQueryId, createdAt: number ): Promise { const targetQueryId = queryId.getQueryId(); return findTransaction(client, walletAddress, (tx) => { if (tx.inMessage?.info.type !== 'external-in') return false; if (!tx.inMessage.body) return false; const parsed = parseExternalMessageBody(tx.inMessage.body); if (!parsed) return false; return parsed.queryId === targetQueryId && parsed.createdAt === createdAt; }); } const externalTx = await findHighloadExternalTransaction( client, highloadWallet.address, queryId, createdAt ); if (!externalTx) { console.log('❌ External transaction not found'); return; } // Verify external transaction compute phase if (externalTx.description.type !== 'generic') { console.log('❌ Invalid transaction'); return; } const externalCompute = externalTx.description.computePhase; if (!externalCompute.success || externalCompute.exitCode !== 0) { console.log(`❌ External transaction failed: exit code ${externalCompute.exitCode}`); return; } console.log('✓ External transaction succeeded'); If the external transaction failed, see [Exit codes](https://docs.ton.org/standard/wallets/highload/v3/specification#exit-codes) for troubleshooting. [​](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#step-3-find-and-verify-internal-transaction) Step 3: Find and verify internal transaction ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- Follow the transaction chain to find and verify Transaction 2: // Find internal transaction by prevTransactionLt async function findHighloadInternalTransaction( client: TonClient, walletAddress: Address, externalLt: string ): Promise { return findTransaction(client, walletAddress, (tx) => tx.prevTransactionLt.toString() === externalLt ); } // Check for outgoing messages if (externalTx.outMessagesCount === 0) { console.log('❌ No outgoing messages from external transaction'); return; } // Find the internal transaction const internalTx = await findHighloadInternalTransaction( client, highloadWallet.address, externalTx.lt.toString() ); if (!internalTx || internalTx.description.type !== 'generic') { console.log('❌ Internal transaction not found'); return; } // Verify compute phase if (internalTx.description.computePhase.type !== 'vm') { console.log('❌ Compute phase skipped'); return; } const internalCompute = internalTx.description.computePhase; if (!internalCompute.success || internalCompute.exitCode !== 0) { console.log(`❌ Internal transaction failed: exit code ${internalCompute.exitCode}`); return; } // Verify action phase if (!internalTx.description.actionPhase) { console.log('❌ No action phase in internal transaction'); return; } const action = internalTx.description.actionPhase; if (!action.success) { console.log(`❌ Action phase failed: result code ${action.resultCode}`); return; } console.log('✓ Internal transaction succeeded'); [​](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#step-4-calculate-sent-messages) Step 4: Calculate sent messages -------------------------------------------------------------------------------------------------------------------------------------------- Calculate how many messages were successfully sent: // Calculate messages sent (total actions - 1 for set_code) const messageActions = action.totalActions - 1; const messagesSent = action.messagesCreated; const messagesFailed = action.skippedActions; if (messagesFailed > 0) { console.log(`✅ Sent ${messagesSent}/${messageActions} messages (${messagesFailed} failed)`); } else { console.log(`✅ Sent ${messagesSent}/${messageActions} messages`); } [​](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#expected-outputs) Expected outputs --------------------------------------------------------------------------------------------------------------- ### [​](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#full-success) Full success ✓ Query marked as processed ✓ External transaction succeeded ✓ Internal transaction succeeded ✅ Sent 10/10 messages ### [​](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#partial-success) Partial success ✓ Query marked as processed ✓ External transaction succeeded ✓ Internal transaction succeeded ✅ Sent 8/10 messages (2 failed) ### [​](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#external-transaction-failure) External transaction failure ✓ Query marked as processed ❌ External transaction failed: exit code 35 The `query_id` is marked as processed, but the transaction failed during validation. See [Exit codes](https://docs.ton.org/standard/wallets/highload/v3/specification#exit-codes) for troubleshooting. ### [​](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#internal-transaction-failure) Internal transaction failure ✓ Query marked as processed ✓ External transaction succeeded ❌ Internal transaction failed: exit code 9 Transaction 1 succeeded (replay protection applied), but Transaction 2 failed. The `query_id` cannot be reused. ### [​](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#action-phase-failure) Action phase failure ✓ Query marked as processed ✓ External transaction succeeded ❌ Action phase failed: result code 37 Both transactions were executed, but the action phase failed to send messages. [​](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#next-steps) Next steps --------------------------------------------------------------------------------------------------- You can now verify any transfer to ensure it was fully processed. This is especially important for batch transfers where partial failures can occur. Was this page helpful? YesNo [Suggest edits](https://github.com/ton-org/docs/edit/main/standard/wallets/highload/v3/verify-is-processed.mdx) [Raise issue](https://github.com/ton-org/docs/issues/new?title=Issue%20on%20docs&body=Path:%20/standard/wallets/highload/v3/verify-is-processed) [Previous](https://docs.ton.org/standard/wallets/highload/v3/send-batch-transfers) [Specification\ \ Next](https://docs.ton.org/standard/wallets/highload/v3/specification) ⌘I On this page * [Objective](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#objective) * [Prerequisites](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#prerequisites) * [Verification overview](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#verification-overview) * [Helper functions](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#helper-functions) * [Step 1: Set up and check if processed](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#step-1-set-up-and-check-if-processed) * [Step 2: Find and verify external transaction](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#step-2-find-and-verify-external-transaction) * [Step 3: Find and verify internal transaction](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#step-3-find-and-verify-internal-transaction) * [Step 4: Calculate sent messages](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#step-4-calculate-sent-messages) * [Expected outputs](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#expected-outputs) * [Full success](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#full-success) * [Partial success](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#partial-success) * [External transaction failure](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#external-transaction-failure) * [Internal transaction failure](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#internal-transaction-failure) * [Action phase failure](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#action-phase-failure) * [Next steps](https://docs.ton.org/standard/wallets/highload/v3/verify-is-processed#next-steps) ---