Обновление TVM 2023.07
Эта страница переведена сообществом на русский язык, но нуждается в улучшениях. Если вы хотите принять участие в переводе свяжитесь с @alexgton.
Это обновление запущено в основной сети с декабря 2023 года.
c7
c7 — это регистр, в котором хранится локальная контекстная информация, необходимая для выполнения контракта (например, время, lt, конфигурации сети и т. д.).
c7 кортеж расширен с 10 до 14 элементов:
- 10:
cell
с кодом самого смарт-контракта. - 11:
[integer, maybe_dict]
: значение ТON входящего сообщения, дополнительные валюты. - 12:
integer
, сборы, собранные на этапе хранения. - 13:
tuple
с информацией о предыдущих блоках.
10 В настоящее время код смарт-контракта представлен на уровне TVM только как исполняемое продолжение и не может быть преобразован в ячейку. Этот код часто используется для авторизации соседнего контракта того же типа, например jetton-wallet авторизует jetton-wallet. На данный момент нам нужно явно хранить ячейку кода в хранилище, что делает хранилище и init_wrapper более громоздкими, чем они могли бы быть. Использование 10 для кода совместимо с обновлением Everscale tvm.
11 В настоящее время значение входящего сообщения представлено в стеке после инициализации TVM, поэтому при необходимости во время выполнения
нужно либо сохранить его в глобальной переменной, либо передать через локальные переменные
(на уровне funC это выглядит как дополнительный аргумент msg_value
во всех функциях).
Поместив его в элемент 11, мы повторим поведение баланса контракта: он представлен как в стеке, так и в c7.
12 В настоящее время единственный способ рассчитать плату за хранение — это сохранить баланс в предыдущей транзакции, как-то рассчитать потребление газа в предыдущей транзакции, а затем сравнить с текущим балансом за вычетом значения сообщения. Между тем, часто требуется учитывать плату за хранение.
13 В настоящее время нет способа извлечь данные о предыдущих блоках. Одной из ключевых особенностей TON является то, что каждый структура представляет собой дружественный к доказательству Меркла пакет (дерево) ячеек, более того, TVM также дружественна к ячейкам и доказательсву Меркла. Таким образом, если мы включим информацию о блоках в контекст TVM, станет возможным реализовать множество не требующих доверия сценариев: контракт A может проверять транзакции по контракту B (без сотрудничества с B), можно восстановить разорванные цепочки сообщений (когда recovery-contract получает и проверяет доказательства того, что некоторая транзакция произошла, но была отменена), также требуется знание хэшей блоков мастерчейна для выполнения некоторых функций проверки onchain.
Идентификаторы блоков представлены в следующем формате:
[ wc:Integer shard:Integer seqno:Integer root_hash:Integer file_hash:Integer ] = BlockId;
[ last_mc_blocks:[BlockId0, BlockId1, ..., BlockId15]
prev_key_block:BlockId ] : PrevBlocksInfo
Включены идентификаторы последних 16 блоков мастерчейна (или меньше, если seqno мастерчейна меньше 16), а также последний ключевой блок. Включение данных о шардблоках может вызвать некоторые проблемы с доступностью данных (из-за событий слияния/разделения), это не обязательно требуется (так как любое событие/данные могут быть подтверждены с помощью блоков мастерчейна), поэтому мы решили не включать их.
Новые коды операций
Основное правило при выборе стоимости газа для новых кодов операций заключается в том, что она не должна быть меньше обычной (рассчитанной по длине кода операции) и должна заним ать не более 20 нс на единицу газа.
Коды операций для работы с новыми значениями c7
26 газа для каждого, за исключением PREVMCBLOCKS
и PREVKEYBLOCK
(34 газа).
Синтаксис Fift | Стек | Описание |
---|---|---|
MYCODE | - c | Извлекает код смарт-контракта из c7 |
INCOMINGVALUE | - t | Извлекает значение входящего сообщения из c7 |
STORAGEFEES | - i | Извлекает значение платы за фазу хранения из c7 |
PREVBLOCKSINFOTUPLE | - t | Извлекает PrevBlocksInfo: [last_mc_blocks, prev_key_block] из c7 |
PREVMCBLOCKS | - t | Извлекает только last_mc_blocks |
PREVKEYBLOCK | - t | Извлекает только prev_key_block |
GLOBALID | - i | Извлекает global_id из 19 конфигурации сети |
Газ
Синтаксис Fift | Стек | Описание |
---|---|---|
GASCONSUMED | - g_c | Возвращает газ, потребленный виртуальной машиной на данный момент (включая эту инструкцию). 26 газа |
Арифметика
Добавлены новые варианты кода операции деления (A9mscdf
):
d=0
берет одно дополнительное целое число из стека и добавляет его к промежуточному значению перед делением/rshift. Э ти операции возвращают как частное, так и остаток (как d=3
).
Также доступны тихие варианты (например, QMULADDDIVMOD
или QUIET MULADDDIVMOD
).
Если возвращаемые значения не вписываются в 257-разрядные целые числа или делитель равен нулю, при выполнении операции без прерывания возникает исключение переполнения целого числа. Операции без прерывания возвращают значение NaN
вместо значения, которое не помещается (два NaN
, если делитель равен нулю).
Стоимость газа равна 10 плюс длина опкода: 26 для большинства кодов операции, +8 для LSHIFT#
/RSHIFT#
, +8 для тихого режима.
Синтаксис Fift | Стек |
---|---|
MULADDDIVMOD | x y w z - q=floor((xy+w)/z) r=(xy+w)-zq |
MULADDDIVMODR | x y w z - q=round((xy+w)/z) r=(xy+w)-zq |
MULADDDIVMODC | x y w z - q=ceil((xy+w)/z) r=(xy+w)-zq |
ADDDIVMOD | x w z - q=floor((x+w)/z) r=(x+w)-zq |
ADDDIVMODR | x w z - q=round((x+w)/z) r=(x+w)-zq |
ADDDIVMODC | x w y - q=ceil((x+w)/z) r=(x+w)-zq |
ADDRSHIFTMOD | x w z - q=floor((x+w)/2^z) r=(x+w)-q*2^z |
ADDRSHIFTMODR | x w z - q=round((x+w)/2^z) r=(x+w)-q*2^z |
ADDRSHIFTMODC | x w z - q=ceil((x+w)/2^z) r=(x+w)-q*2^z |
z ADDRSHIFT#MOD | x w - q=floor((x+w)/2^z) r=(x+w)-q*2^z |
z ADDRSHIFTR#MOD | x w - q=round((x+w)/2^z) r=(x+w)-q*2^z |
z ADDRSHIFTC#MOD | x w - q=ceil((x+w)/2^z) r=(x+w)-q*2^z |
MULADDRSHIFTMOD | x y w z - q=floor((xy+w)/2^z) r=(xy+w)-q*2^z |
MULADDRSHIFTRMOD | x y w z - q=round((xy+w)/2^z) r=(xy+w)-q*2^z |
MULADDRSHIFTCMOD | x y w z - q=ceil((xy+w)/2^z) r=(xy+w)-q*2^z |
z MULADDRSHIFT#MOD | x y w - q=floor((xy+w)/2^z) r=(xy+w)-q*2^z |
z MULADDRSHIFTR#MOD | x y w - q=round((xy+w)/2^z) r=(xy+w)-q*2^z |
z MULADDRSHIFTC#MOD | x y w - q=ceil((xy+w)/2^z) r=(xy+w)-q*2^z |
LSHIFTADDDIVMOD | x w z y - q=floor((x*2^y+w)/z) r=(x*2^y+w)-zq |
LSHIFTADDDIVMODR | x w z y - q=round((x*2^y+w)/z) r=(x*2^y+w)-zq |
LSHIFTADDDIVMODC | x w z y - q=ceil((x*2^y+w)/z) r=(x*2^y+w)-zq |
y LSHIFT#ADDDIVMOD | x w z - q=floor((x*2^y+w)/z) r=(x*2^y+w)-zq |
y LSHIFT#ADDDIVMODR | x w z - q=round((x*2^y+w)/z) r=(x*2^y+w)-zq |
y LSHIFT#ADDDIVMODC | x w z - q=ceil((x*2^y+w)/z) r=(x*2^y+w)-zq |
Операции со стеком
В настоящее время аргументы всех операций со стеком ограничены 256.
Это означает, что если стек становится глубже 256, становится трудно управлять глубокими элементами стека.
В большинстве случаев нет никаких причин для безопасности для этого ограничения, т. е. аргументы не ограничиваются, чтобы предотвратить слишком дорогие операции.
Для некоторых массовых операций со стеком, таких как ROLLREV
(где время вычисления линейно зависит от значения аргумента), стоимость газа также линейно зависит от значения аргумента.
- Аргументы
PICK
,ROLL
,ROLLREV
,BLKSWX
,REVX
,DROPX
,XCHGX
,CHKDEPTH
,ONLYTOPX
,ONLYX
теперь не ограничены. ROLL
,ROLLREV
,REVX
,ONLYTOPX
потребляют больше газа, когда аргументы большие: дополнительная стоимость газа составляетmax(arg-255,0)
(для аргумента меньше 256 потребление газа постоянно и соответствует текущему режиму)- Для
BLKSWX
дополнительная стоимость составляетmax(arg1+arg2-255,0)
(это не соответствует текущему режиму, так как в настоящее время иarg1
, иarg2
ограничены 255).
Хэши
В настоящее время в TVM доступны только две операции хэширования: вычисление хэша представления ячейки/среза и sha256 данных, но только до 127 байт (только столько данных помещается в одну ячейку).
Добавлено семейство операций HASHEXT[A][R]_(HASH)
:
Синтаксис Fift | Стек | Описание |
---|---|---|
HASHEXT_(HASH) | s_1 ... s_n n - h | Вычисляет и возвращает хэш объединения срезов (или сборщиков) s_1...s_n . |
HASHEXTR_(HASH) | s_n ... s_1 n - h | То же самое, но аргументы приводятся в обратном порядке. |
HASHEXTA_(HASH) | b s_1 ... s_n n - b' | Добавляет полученный хэш к строителю b вместо того, чтобы помещать его в стек. |
HASHEXTAR_(HASH) | b s_n ... s_1 n - b' | Аргументы задаются в обратном порядке, добавляя хэш к строителю. |
Используются только биты из корневых ячеек s_i
.
Каждый фрагмент s_i
может содержать нецелое число байтов. Однако сумма битов всех фрагментов должна делиться на 8.
Обратите внимание, что TON использует порядок старших битов, поэтому при объединении двух фрагментов с нецелым числом байтов биты из первого фрагмента становятся старшими битами.
Расход газа зависит от количества хэшированных байтов и выбранного алгоритма. На каждый фрагмент потребляется дополнительно 1 единица газа.
Если параметр [A]
не включен, результат хэширования будет возвращен в виде целого числа без знака, если оно соответствует 256 битам, или целого ряда целых чисел в противном случае.
Доступны следующие алгоритмы:
SHA256
- реализация openssl, 1/33 газа на байт, хеш составляет 256 бит.SHA512
- реализация openssl, 1/16 газа на байт, хеш составляет 512 бит.BLAKE2B
- реализация openssl, 1/19 газа на байт, хеш составляет 512 бит.KECCAK256
- реализация, совместимая с ethereum, 1/11 газа на байт, хеш составляет 256 бит.KECCAK512
- совместимая с ethereum реализация, 1/6 газа на байт, хэш составляет 512 бит.
Использование газа округляется в меньшую сторону.
Крипто
В настоящее время доступен только один криптографический алгоритм - CHKSIGN
: проверьте подпись Ed25519 хеша h
для открытого ключа k
.
- Для совместимости с блокчейнами предыдущего поколения, такими как Bitcoin и Ethereum, нам также необходимо проверить подписи
secp256k1
. - Для современных криптографических алгоритмов абсолютный минимум - это сложение и умножение кривых.
- Для совместимости с Ethereum 2.0 PoS и некоторыми другими современными криптографическими алгоритмами нам нужна схема BLS-подписи на кривой bls12-381.
- Для некоторого защищенного оборудования требуется secp256r1 == P256 == prime256v1.
secp256k1
Подписи Bitcoin/Ethereum. Использует реализацию libsecp256k1.
Синтаксис Fift | Стек | Описание |
---|---|---|
ECRECOVER | hash v r s - 0 или h x1 x2 -1 | Восстанавливает открытый ключ из подписи, идентично операциям Bitcoin/Ethereum. Принимает 32-байтовый хэш как uint256 hash ; 65-байтовая подпись как uint8 v и uint256 r , s .Возвращает 0 в случае неудачи, открытый ключ и -1 в случае успеха.65-байтовый открытый ключ возвращается как uint8 h , uint256 x1 , x2 .1526 газа |
secp256r1
Использует реализацию OpenSSL. Интерфейс похож на CHKSIGNS
/CHKSIGNU
. Совместимо с Apple Secure Enclave.
Синтаксис Fift | Стек | Описание |
---|---|---|
P256_CHKSIGNS | d sig k - ? | Проверяет seck256r1-подпись sig части данных среза d и открытый ключ k . Возвращает -1 в случае успеха, 0 в случае неудачи.Открытый ключ представляет собой 33-байтовый срез (закодированный в соответствии с разделом 2.3.4, пункт 2 SECG SEC 1). Подпись sig представляет собой 64-байтовый срез (два 256-битных беззнаковых целых числа r и s ).3526 газа |
P256_CHKSIGNU | h sig k - ? | То же самое, но подписанные данные представляют собой 32-байтовую кодировку 256-битного беззнакового целого числа h .3526 газа |
Ристретто
Расширенная документация доступна здесь. Проще говоря, Curve25519 был разработан с учетом производительности, однако из-за симметрии некоторые элементы группы имеют несколько представлений. Более простые протоколы, такие как подписи Шнорра или Диффи-Хеллмана, применяют приемы на уровне протокола для смягчения некоторых проблем, но нарушают схемы вывода ключей и маскировки ключей. И эти приемы не масштабируются до более сложных протоколов, таких как Bulletproofs. Ристретто представляет собой арифметическое абстракцию поверх Curve25519 таким образом, что каждый элемент группы соответствует уникальной точке, что является требованием для большинства криптографических протоколов. Ристретто по сути является протоколом сжатия/распаковки для Curve25519, который предлагает необходимую арифметическую абстракцию. В результате криптопротоколы легко писать правильно, при этом извлекая выгоду из высокой производительности Curve25519.
Операции Ристретто позволяют вычислять операции кривой на Curve25519 (в обратном порядке это не так), таким образом мы можем считать, что добавляем как Ристретто, так и операции по кривой Curve25519 за один шаг.
Используется реализация libsodium.
Все точки ristretto-255 представлены в TVM как 256-битные целые числа без знака.
При некорректных операциях генерируется range_chk
, если аргументы не являются допустимыми закодированными точками.
Нулевая точка представлена в виде целого числа 0
.
Синтаксис Fift | Стек | Описание |
---|---|---|
RIST255_FROMHASH | h1 h2 - x | Детерминированно генерирует допустимую точку x из 512-битного хеша (заданного как два 256-битных целых числа).626 газа |
RIST255_VALIDATE | x - | Проверяет, что целое число x является допустимым представлением некоторой точки кривой. Выдает range_chk при ошибке.226 газа |
RIST255_ADD | x y - x+y | Сложение двух точек на кривой. 626 газа |
RIST255_SUB | x y - x-y | Вычитание двух точек на кривой. 626 газа |
RIST255_MUL | x n - x*n | Умножает точку x на скаляр n .Допустимо любое n , включая отрицательное.2026 газа |
RIST255_MULBASE | n - g*n | Умножает точку генератора g на скаляр n .Допустимо любое n , включая отрицательное.776 газа |
RIST255_PUSHL | - l | Выводит целое число l=2^252+27742317777372353535851937790883648493 , которое соответствует порядку в группе.26 газа |
RIST255_QVALIDATE | x - 0 или -1 | Тихая версия RIST255_VALIDATE .234 газа |
RIST255_QADD | x y - 0 или x+y -1 | Тихая версия RIST255_ADD . 634 газа |
RIST255_QSUB | x y - 0 или x-y -1 | Тихая версия RIST255_SUB .634 газа |
RIST255_QMUL | x n - 0 или x*n -1 | Тихая версия RIST255_MUL .2034 газа |
RIST255_QMULBASE | n - 0 или g*n -1 | Тихая версия RIST255_MULBASE .784 газа |
BLS12-381
Операции на кривой BLS12-381, удобной для сопряжения. Используется реализация BLST. Также, операции для схемы подписи BLS, которая основана на этой кривой.
Значения BLS представлены в TVM следующим образом:
- G1-точки и открытые ключи: 48-байтовый срез.
- G2-точки и подписи: 96-байтовый срез.
- Элементы поля FP: 48-байтовый срез.
- Элементы поля FP2: 96-байтовый срез.
- Сообщения: срез. Количество бит должно делиться на 8.
Когда входное значение является точкой или элементом поля, срез может иметь более 48/96 байт. В этом случае берутся только первые 48/96 байт. Если в срезе меньше байтов (или если размер сообщения не делится на 8), выдается исключение переполнения ячейки.
Высокоуровневые операции
Это высокоуровневые операции для проверки подписей BLS.
Синтаксис Fift | Стек | Описание |
---|---|---|
BLS_VERIFY | pk msg sgn - bool | Проверяет подпись BLS, возвращает true в случае успеха, в противном случае false. 61034 газа |
BLS_AGGREGATE | sig_1 ... sig_n n - sig | Агрегирует подписи. n>0 . Выдает исключение, если n=0 или если какой-либо sig_i не является допустимой подписью.gas=n*4350-2616 |
BLS_FASTAGGREGATEVERIFY - | pk_1 ... pk_n n msg sig - bool | Проверяет агрегированную подпись BLS для ключей pk_1...pk_n и сообщения msg . Возвращает true в случае успеха, в противном случае false. Возвращает false, если n=0 .gas=58034+n*3000 |
BLS_AGGREGATEVERIFY | pk_1 msg_1 ... pk_n msg_n n sgn - bool | Проверяет агрегированную подпись BLS для пар ключ-сообщение pk_1 msg_1...pk_n msg_n . Возвращает true в случае успеха, в противном случае false. Верните false, если n=0 .gas=38534+n*22500 |
Инструкции VERIFY
не выбрасывают исключения при недействительных подписях и открытых ключах (за исключением исключений, связанных с переполнением ячеек), вместо этого они возвращают false.
Низкоуровневые операции
Это арифметические операции над элементами группы.
Синтаксис Fift | Стек | Описание |
---|---|---|
BLS_G1_ADD | x y - x+y | Сложение на G1. 3934 газа |
BLS_G1_SUB | x y - x-y | Вычитание на G1. 3934 газа |
BLS_G1_NEG | x - -x | Отрицание на G1. 784 газа |
BLS_G1_MUL | x s - x*s | Умножает точку G1 x на скаляр s .Допустим любой s , включая отрицательный.5234 газа |
BLS_G1_MULTIEXP | x_1 s_1 ... x_n s_n n - x_1*s_1+...+x_n*s_n | Вычисляет x_1*s_1+...+x_n*s_n для точек G1 x_i и скаляров s_i . Возвращает нулевую точку, если n=0 .Любое s_i допустимо, включая отрицательное.gas=11409+n*630+n/floor(max(log2(n),4))*8820 |
BLS_G1_ZERO | - zero | Помещает нулевую точку в G1. 34 газа |
BLS_MAP_TO_G1 | f - x | Преобразует элемент FP f в точку G1.2384 газа |
BLS_G1_INGROUP | x - bool | Проверяет, что срез x представляет допустимый элемент G1.2984 газа |
BLS_G1_ISZERO | x - bool | Проверяет, что точка G1 x равна нулю.34 газа |
BLS_G2_ADD | x y - x+y | Сложение на G2. 6134 газа |
BLS_G2_SUB | x y - x-y | Вычитание на G2. 6134 газа |
BLS_G2_NEG | x - -x | Отрицание на G2. 1584 газа |
BLS_G2_MUL | x s - x*s | Умножает точку G2 x на скаляр s .Любое s допустимо, включая отрицательное.10584 газа |
BLS_G2_MULTIEXP | x_1 s_1 ... x_n s_n n - x_1*s_1+...+x_n*s_n | Вычисляет x_1*s_1+...+x_n*s_n для точек G2 x_i и скаляров s_i . Возвращает нулевую точку, если n=0 .Любое s_i допустимо, включая отрицательное.gas=30422+n*1280+n/floor(max(log2(n),4))*22840 |
BLS_G2_ZERO | - zero | Помещает нулевую точку в G2. 34 газа |
BLS_MAP_TO_G2 | f - x | Преобразует элемент FP2 f в точку G2.7984 газа |
BLS_G2_INGROUP | x - bool | Проверяет, что срез x представляет допустимый элемент G2.4284 газа |
BLS_G2_ISZERO | x - bool | Проверяет, что точка G2 x равна нулю.34 газа |
BLS_PAIRING | x_1 y_1 ... x_n y_n n - bool | Учитывая точки G1 x_i и точки G2 y_i , вычисляет и умножает пары x_i,y_i . Возвращает true, если результат является мультипликативным тождеством в FP12, в противном случае возвращает false. Возвращает false, если n=0 .gas=20034+n*11800 |
BLS_PUSHR | - r | Изменяет порядок G1 и G2 (приблизительно 2^255 ).34 газа |
INGROUP
, ISZERO
не выбрасывают исключение на недопустимых точках (кроме исключений переполнения ячеек), вместо этого они возвращают false.
Другие арифметические операции выбрасывают исключение на недопустимых точках кривой. Обратите внимание, что они не проверяют, принадлежат ли заданные точки кривой группе G1/G2. Используйте инструкцию INGROUP
, чтобы проверить это.
RUNVM
В настоящее время код в TVM не может вызвать внешний ненадежный код "в изолированной среде". Другими словами, внешний код всегда может необратимо обновить код, данные контракта или задать действия (например, отправку всех денег).
Инструкция RUNVM
позволяет создать независимый экземпляр виртуальной машины, запустить нужный код и получить необходимые данные (стек, регистры, потребление газа и т. д.) без риска загрязнения состояния вызывающей стороны. Безопасный запуск произвольного кода может быть полезен для плагинов в стиле v4, вычислений субконтрактов в стиле init
Tact's и т. д.
Синтаксис Fift | Стек | Описание |
---|---|---|
flags RUNVM | x_1 ... x_n n code [r] [c4] [c7] [g_l] [g_m] - x'_1 ... x'_m exitcode [data'] [c4'] [c5] [g_c] | Запускает дочернюю виртуальную машину с кодом code и стеком x_1...x_n . Возвращает результирующий стек x'_1...x'_m и код выхода.Другие аргументы и возвращаемые значения включаются флагами, см. ниже. |
RUNVMX | x_1 ... x_n n code [r] [c4] [c7] [g_l] [g_m] flags - x'_1 ... x'_m exitcode [data'] [c4'] [c5] [g_c] | То же самое, но извлекает флаги из стека. |
Флаги похожи на runvmx
в fift:
+1
: присвоить c3 значение кода+2
: вставить неявный 0 перед запуском кода+4
: взятьc4
из стека (постоянные данные), вернуть его конечное значение+8
: взять лимит газаg_l
из стека, вернуть потребленный газg_c
+16
: взятьc7
из стека (контекст смарт-контракта)+32
: вернуть конечное значениеc5
(действия)+64
: вытолкнуть жесткий лимит газа (включено ACCEPT)g_m
из стека+128
: "изолированное потребление газа". Дочерняя VM будет иметь отдельный набор посещенных ячеек и отдельный счетчик chksgn.+256
: вытолкнуть целое числоr
, вернуть ровноr
значений сверху:* Если вызов RUNVM успешен и установлено r, он возвращает r элементов. Если r не задано - возвращает все;
Стоимость газа:
- 66 газа
- 1 газ за каждый элемент стека, переданный дочерней виртуальной машине (первые 32 бесплатны)
- 1 газ за каждый элемент стека, возвращенный дочерней виртуальной машиной (первые 32 бесплатны)
Отправка сообщений
В настоящее время сложно рассчитать стоимость отправки сообщения в контракте (что приводит к некоторым приближениям, как в жетонах) и невозможно вернуть запрос, если фаза действия неверна. Т акже невозможно точно вычесть из входящего сообщения сумму "постоянной платы за логику контракта" и "расходов на газ".
SENDMSG
принимает ячейку и режим в качестве входных данных. Создает выходное действие и возвращает плату за создание сообщения. Режим имеет тот же эффект, что и в случае SENDRAWMSG. Кроме того,+1024
означает - не создавать действие, только оценить плату. Другие режимы влияют на расчет платы следующим образом:+64
заменяет весь баланс входящего сообщения в качестве исходящего значения (немного неточно, расходы на газ, которые невозможно оценить до завершения расчета, не учитываются),+128
заменяет значение всего баланса контракта до начала фазы расчета (немного неточно, поскольку расходы на газ, которые невозможно оценить до завершения фазы расчета, не учитываются).SENDRAWMSG
,RAWRESERVE
,SETLIBCODE
,CHANGELIB
- добавлен флаг+16
, что означает в случае сбоя действия - возврат транзакции. Никакого эффекта, если используется+2
.
Аудиты безопасности
Обновление виртуальной машины TON (TVM) было проанализировано на предмет безопасности и потенциальных уязвимостей.
Аудиторская фирма: Trail of Bits Аудиторский отчет: