Стандартная библиотека FunC
Эта страница переведена сообществом на русский язык, но нуждается в улучшениях. Если вы хотите принять участие в переводе свяжитесь с @alexgton.
В этом разделе обсуждается библиотека stdlib.fc со стандартными функциями, используемыми в FunC.
В настоящее время библиотека является просто оберткой для наиболее распространенного ассемблера команд TVM, которые не являются встроенными. Описание каждой команды TVM, используемой в библиотеке, можно найти в разделе документация TVM. Некоторые описания были взяты для этого документа.
Некоторые функции в файле закомментированы. Это означает, что они уже стали встроенными в целях оптимизации. Однако сигнатура типа и семантика остаются прежними.
Обратите внимание, что некоторые менее распространенные команды не представлены в stdlib. Они также будут добавлены в будущем.
Примитивы для манипулирования кортежами
Имена и типы в основном говорят сами за себя. См. полиморфизм с forall для получения дополнительной информации о полиморфных функциях.
Обратите внимание, что в настоящее время значения атомарного типа tuple
не могут быть преобразованы в составные типы кортежей (например, [int, cell]
) и наоборот.
Списки в стиле Lisp
Списки могут быть представлены как вложенные кортежи из 2 элементов. Пустой список традиционно представляется как значение TVM null
(его можно получить, вызвав null()
). Например, кортеж (1, (2, (3, null)))
представляет список [1, 2, 3]
. Элементы списка могут быть разных типов.
cons
forall X -> tuple cons(X head, tuple tail) asm "CONS";
Добавляет элемент в начало списка в стиле lisp.
uncons
forall X -> (X, tuple) uncons(tuple list) asm "UNCONS";
Извлекает начало и конец списка в стиле lisp.
list_next
forall X -> (tuple, X) list_next(tuple list) asm( -> 1 0) "UNCONS";
Извлекает начало и конец списка в стиле lisp. Может использоваться как (не)модифицирующий метод.
() 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
}
car
forall X -> X car(tuple list) asm "CAR";
Возвращает начало списка в стиле lisp.
cdr
tuple cdr(tuple list) asm "CDR";
Возвращает конец списка в стиле lisp.
Другие примитивы кортежа
empty_tuple
tuple empty_tuple() asm "NIL";
Создает кортеж из 0 элементов.
tpush
forall X -> tuple tpush(tuple t, X value) asm "TPUSH";
forall X -> (tuple, ()) ~tpush(tuple t, X value) asm "TPUSH";
Добавляет значение x
к Tuple t = (x1, ..., xn)
, но только если полученный Tuple t' = (x1, ..., xn, x)
не длиннее 255 символов. В противном случае выдается исключение проверки типа.
single
forall X -> [X] single(X x) asm "SINGLE";
Создает одиночку, т. е. кортеж длиной один.
unsingle
forall X -> X unsingle([X] t) asm "UNSINGLE";
Распаковывает одиночку.
pair
forall X, Y -> [X, Y] pair(X x, Y y) asm "PAIR";
Создает пару.
unpair
forall X, Y -> (X, Y) unpair([X, Y] t) asm "UNPAIR";
Распаковывает пару.
triple
forall X, Y, Z -> [X, Y, Z] triple(X x, Y y, Z z) asm "TRIPLE";
Создает тройку.
untriple
forall X, Y, Z -> (X, Y, Z) untriple([X, Y, Z] t) asm "UNTRIPLE";
Распаковывает тройку.
tuple4
forall X, Y, Z, W -> [X, Y, Z, W] tuple4(X x, Y y, Z z, W w) asm "4 TUPLE";
Создает кортеж из 4 элементов.
untuple4
forall X, Y, Z, W -> (X, Y, Z, W) untuple4([X, Y, Z, W] t) asm "4 UNTUPLE";
Распаковывает кортеж из 4 элементов.
first
forall X -> X first(tuple t) asm "FIRST";
Возвращает первый элемент кортежа.
second
forall X -> X second(tuple t) asm "SECOND";
Возвращает второй элемент кортежа.
third
forall X -> X third(tuple t) asm "THIRD";
Возвращает третий элемент кортежа.
fourth
forall X -> X fourth(tuple t) asm "3 INDEX";
Возвращает четвертый элемент кортежа.
pair_first
forall X, Y -> X pair_first([X, Y] p) asm "FIRST";
Возвращает первый элемент пары.
pair_second
forall X, Y -> Y pair_second([X, Y] p) asm "SECOND";
Возвращает второй элемент пары.
triple_first
forall X, Y, Z -> X triple_first([X, Y, Z] p) asm "FIRST";
Возвращает первый элемент тройки.
triple_second
forall X, Y, Z -> Y triple_second([X, Y, Z] p) asm "SECOND";
Возвращает второй элемент тройки.
triple_third
forall X, Y, Z -> Z triple_third([X, Y, Z] p) asm "THIRD";
Возвращает третий элемент тройки.
Примитивы, специфичные для домена
Извлечение информации из c7
Некоторые полезные сведения о вызове смарт-контракта можно найти в специальном рег истре c7. Эти примитивы служат для удобного извлечения данных.
now
int now() asm "NOW";
Возвращает текущее время Unix как целое число
my_address
slice my_address() asm "MYADDR";
Возвращает внутренний адрес текущего смарт-контракта как срез с MsgAddressInt
. При необходимости его можно проанализировать далее с помощью примитивов, таких как parse_std_addr
.
get_balance
[int, cell] get_balance() asm "BALANCE";
Возвращает оставшийся баланс смарт-контракта в виде tuple
, состоящего из int
(оставшийся баланс в nanotoncoin) и cell
(словарь с 32-битными ключами, представляющими баланс "дополнительных валют"). Поскольку это произойдет в фазе вычислений, баланс контракта будет включать входящее сообщение value
, вычитать storage_fee
и import_fee
.
Необработанные примитивы, такие как send_raw_message
, не обновляют это поле.
cur_lt
int cur_lt() asm "LTIME";
Возвращает логическое время текущей транзакции.
block_lt
int block_lt() asm "BLOCKLT";
Возвращает начальное логическое время текущего блока.
config_param
cell config_param(int x) asm "CONFIGOPTPARAM";
Возвращает значение глобального п араметра конфигурации с целочисленным индексом i
как cell
или null
значение.
Хэши
cell_hash
int cell_hash(cell c) asm "HASHCU";
Вычисляет хэш представления cell c
и возвращает его как 256-битное беззнаковое целое число x
. Полезно д ля подписи и проверки подписей произвольных сущностей, представленных деревом ячеек.
slice_hash
int slice_hash(slice s) asm "HASHSU";
Вычисляет хэш slice s
и возвращает его как 256-битное целое число без знака x
. Результат такой же, как если бы была создана обычная ячейка, содержащая только данные и ссылки из s
, и ее хэш был вычислен cell_hash
.
string_hash
int string_hash(slice s) asm "SHA256U";
Вычисляет sha256 бит данных slice s
. Если длина бит s
не делится на восемь, выдается исключение потери значимости ячейки. Значение хэша возвращается как 256-битное целое число без знака x
.
Проверка подписи
check_signature
int check_signature(int hash, slice signature, int public_key) asm "CHKSIGNU";
Проверяет signature
Ed25519 для hash
(256-битное беззнаковое целое число, обычно вычисляемое как хэш некоторых данных) с помощью public_key
(также представленного 256-битным беззнаковым целым числом). Подпись должна содержать не менее 512 бит данных; используются только первые 512 бит. Если подпись действительна, результат равен -1
; в противном случае это 0
. Обратите внимание, что CHKSIGNU
создает 256-битный срез с хешем и вызывает CHKSIGNS
. То есть, если hash
вычисляется как хеш некоторых данных, эти данные хешируются дважды, второе хеширование происходит внутри CHKSIGNS
.
check_data_signature
int check_data_signature(slice data, slice signature, int public_key) asm "CHKSIGNS";
Проверяет, является ли signature
допустимой подписью Ed25519 части данных slice data
, используя public_key
, аналогично check_signature
. Если длина бит data
не делится на восемь, выдается исключение переполнения ячейки. Проверка подписей Ed25519 является стандартной, с использованием sha256 для сокращения data
до 256-битного числа, которое фактически подписано.
Вычисление размера boc
Приведенные ниже примитивы могут быть полезны для расчета платы за хранение предоставленных пользователем данных.
compute_data_size?
(int, int, int, int) compute_data_size?(cell c, int max_cells) asm "CDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT";
Возвращает (x, y, z, -1)
или (null, null, null, 0)
. Рекурсивно вычисляет количество отдельных ячеек x
, битов данных y
и ссылок на ячейки z
в DAG с корнем cell c
, фактически возвращая общее хранилище, используемое этим DAG, с учетом идентификации равных ячеек. Значения x
, y
и z
вычисляются путем обхода в глубину этого DAG с хэш-таблицей хэшей посещенных ячеек, используемых для предотвращения посещений уже посещенных ячеек. Общее количество посещенных ячеек x
не может превышать неотрицательного max_cells
; в противном случае вычисление преры вается до посещения (max_cells + 1)
-й ячейки и возвращается нулевой флаг, указывающий на ошибку. Если c
равно null
, возвращается x = y = z = 0
.
slice_compute_data_size?
(int, int, int, int) slice_compute_data_size?(slice s, int max_cells) asm "SDATASIZEQ NULLSWAPIFNOT2 NULLSWAPIFNOT";
Аналогично compute_data_size?
, но принимает slice s
вместо cell
. Возвращаемое значение x
не учитывает ячейку, содержащую сам срез s
; однако биты данных и ссылки на ячейки s
учитываются в y
и z
.
compute_data_size
(int, int, int) compute_data_size(cell c, int max_cells) impure asm "CDATASIZE";
Не тихая версия compute_data_size?
, которая выдает исключение переполнения ячейки (8) при сбое.
slice_compute_data_size
(int, int, int) slice_compute_data_size(slice s, int max_cells) impure asm "SDATASIZE";
Не тихая версия slice_compute_data_size?
, которая выдает исключение переполнения ячейки (8) при сбое.
Сохранение и загрузка постоянного хранилища
get_data
cell get_data() asm "c4 PUSH";
Возвращает ячейку постоянного хранилища контракта. Позже ее можно проанализировать или изменить с помощью примитивов среза и конструктора.
set_data
() set_data(cell c) impure asm "c4 POP";
Устанавливает ячейку c
как постоянные данные контра кта. Вы можете обновить постоянное хранилище контракта с помощью этого примитива.
Примитивы продолжения
get_c3
cont get_c3() impure asm "c3 PUSH";
Обычно c3
имеет продолжение, инициализированное всем кодом контракта. Оно используется для вызовов функций. Примитив возвращает текущее значение c3
.
set_c3
() set_c3(cont c) impure asm "c3 POP";
Обновляет текущее значение c3
. Обычно используется для обновления кода смарт-контракта во время выполнения. Обратите внимание, что после выполнения этого примитива текущий код (и стек рекурсивных вызовов функций) не изменится, но любой другой вызов функции будет использовать функцию из нового кода.
bless
cont bless(slice s) impure asm "BLESS";
Преобразует slice s
в простое обычное продолжение c
с c.code = s
, пустым стеком и списком сохранения.
Примитивы, связанные с газом
accept_message
() accept_message() impure asm "ACCEPT";
Устанавливает текущий лимит газа gl
на максимально допустимое значение gm
и сбрасывает газовый кредит gc
на ноль, уменьшая значение gr
на gc
в процессе. Другими словами, текущий смарт-контракт соглашается купить немного газа, чтобы завершить текущую транзакцию. Это действие требуется для обработки внешних сообщений, которые не несут никакой ценности (следовательно, нет газа).
Для получения более подробной информации проверьте accept_message effects
set_gas_limit
() set_gas_limit(int limit) impure asm "SETGASLIMIT";
Устанавливает текущий лимит газа gl
на минимальное значение limit
и gm
и сбрасывает газовый кредит gc
на ноль. В этот момент, если количество потребленного газа (включая текущую инструкцию) превышает результирующее значение gl
, перед установкой новых лимитов газа выдается (необработанное) исключение отсутствия газа. Обратите внимание, что set_gas_limit
с аргументом limit ≥ 2^63 − 1
эквивалентно accept_message
.
Для получения более подробной информации см. accept_message effects
commit
() commit() impure asm "COMMIT";
Фиксирует текущее состояние регистров c4
("постоянные данные") и c5
("действия"), так что текущее выполнение считается "успешным" с сохраненными значениями, даже если позже выдается исключение.
buy_gas
() buy_gas(int gram) impure asm "BUYGAS";
Код операции BUYGAS
в настоящее время не реализован
Вычисляет количество газа, которое можно купить за gram
nanotoncoin, и устанавливает gl
соответственно так же, как set_gas_limit
.
Примитивы действий
raw_reserve
() raw_reserve(int amount, int mode) impure asm "RAWRESERVE";
Создает выходное действие, котор ое зарезервирует ровно amount
nanotoncoin (если mode = 0
), максимум amount
nanotoncoin (если mode = 2
) или все, кроме amount
nanotoncoin (если mode = 1
или mode = 3
) из оставшегося баланса на аккаунте. Это примерно эквивалентно созданию исходящего сообщения, переносящего amount
nanotoncoin (или b − amount
nanotoncoin, где b
— оставшийся баланс) самому себе, так что последующие выходные действия не смогут потратить больше денег, чем остаток. Бит +2 в mode
означает, что внешнее действие не терпит неудачу, если указанная сумма не может быть зарезервирована; вместо этого весь оставшийся баланс резервируется. Бит +8 в mode
означает amount <- -amount
перед выполнением любых дальнейших действий. Бит +4 в mode
означает, что amount
увеличивается на исходный баланс текущего аккаунта (до фазы вычислений), включая все дополнительные валюты перед выполнением любых других проверок и действий. В настоящее время amount
должно быть неотрицательным целым числом, а mode
должно быть в диапазоне 0..15
.