Перейти к основному содержимому

Схемы сообщений TL-B

warning

Эта страница переведена сообществом на русский язык, но нуждается в улучшениях. Если вы хотите принять участие в переводе свяжитесь с @alexgton.

В этом разделе подробное объяснение схем TL-B для сообщений.

Сообщение TL-B

TL-B

Основное сообщение Схема TL-B объявлена как комбинация нескольких вложенных структур

message$_ {X:Type} info:CommonMsgInfo
init:(Maybe (Either StateInit ^StateInit))
body:(Either X ^X) = Message X;

message$_ {X:Type} info:CommonMsgInfoRelaxed
init:(Maybe (Either StateInit ^StateInit))
body:(Either X ^X) = MessageRelaxed X;

_ (Message Any) = MessageAny;

Здесь Message X - это общая структура сообщения, MessageRelaxed X дополнительный тип с телом CommonMsgInfoRelaxed, а Message Any - это объединение обоих. Структура сообщения унифицирована с X:Type, то есть является ячейкой. Согласно TL-B мы можем объединить все данные в одной ячейке (если она уместится в 1023 бита) или использовать ссылки, объявленные с помощью символа ^.

Сериализованное Message X помещается в список действий с помощью метода FunC send_raw_message(), затем смарт-контракт выполняет это действие и отправляет сообщение.

Определение явной сериализации

Для построения допустимых двоичных данных в соответствии со структурой TL-B мы должны выполнить сериализацию, которая определяется для каждого типа рекуррентно. Это значит, что для сериализации сообщения X нам нужно знать, как сериализовать StateInit, CommonMsgInfo и т. д.

Каждую вложенную структуру мы должны получать из другой схемы TL-B по ссылке рекуррентно, пока сериализация для верхней структуры не станет явной - каждый бит будет определен булевым или битовым типом (bits, uint, varuint).

Структуры, которые в настоящее время не используются в обычной разработке, будут отмечены * в столбце Тип, например *Anycast обычно пропускается при сериализации.

message$_

Имеется верхняя схема TL-B для всех сообщений Message X:

message$_ {X:Type} info:CommonMsgInfo
init:(Maybe (Either StateInit ^StateInit))
body:(Either X ^X) = Message X;
СтруктураТипОбязательноОписание
message$_ConstructorОпределяется по правилам конструктора. Пустой тег $_ означает, что мы не будем добавлять никаких битов в начало
infoCommonMsgInfoОбязательноПодробные свойства сообщения определяют пункт назначения и его значение. Всегда помещаются в корневую ячейку сообщения.
initStateInitНеобязательноОбщая структура, используемая в TON для инициализации новых контрактов. Может быть записана как ссылка на ячейку или корневую ячейку.
bodyXОбязательноПолезная нагрузка сообщения. Может быть записана как ссылка на ячейку или корневую ячейку.
nothing$0 {X:Type} = Maybe X;
just$1 {X:Type} value:X = Maybe X;
left$0 {X:Type} {Y:Type} value:X = Either X Y;
right$1 {X:Type} {Y:Type} value:Y = Either X Y;

Вспомним, как работают Maybe и Either, мы можем сериализовать разные случаи:

  • [CommonMsgInfo][10][StateInit][0][X] - Сообщение X в одной ячейке


  • [CommonMsgInfo][11][^StateInit][1][^X] - Сообщение X со ссылками


CommonMsgInfo TL-B

CommonMsgInfo

CommonMsgInfo — это список параметров, который определяет, как сообщение будет доставлено в блокчейне TON.

//internal message
int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
src:MsgAddressInt dest:MsgAddressInt
value:CurrencyCollection ihr_fee:Grams fwd_fee:Grams
created_lt:uint64 created_at:uint32 = CommonMsgInfo;

//external incoming message
ext_in_msg_info$10 src:MsgAddressExt dest:MsgAddressInt
import_fee:Grams = CommonMsgInfo;

//external outgoing message
ext_out_msg_info$11 src:MsgAddressInt dest:MsgAddressExt
created_lt:uint64 created_at:uint32 = CommonMsgInfo;

int_msg_info$0

int_msg_info — это случай внутреннего сообщения. Это означает, что они могут быть отправлены между контрактами и только между контрактами. Случай использования — обычные сообщения между контрактами.

nanograms$_ amount:(VarUInteger 16) = Grams;
//internal message
int_msg_info$0 ihr_disabled:Bool bounce:Bool bounced:Bool
src:MsgAddressInt dest:MsgAddressInt
value:CurrencyCollection ihr_fee:Grams fwd_fee:Grams
created_lt:uint64 created_at:uint32 = CommonMsgInfo;
СтруктураТипОбязательноОписание
int_msg_info$0ConstructorОбязательноЗначение $0 тега означает, что при сериализации CommonMsgInfo, начинающийся с 0 бита, описывает внутреннее сообщение.
ihr_disabledBoolОбязательноФлаг маршрутизации гиперкуба.
bounceBoolОбязательноСообщение должно быть отклонено, если во время обработки возникли ошибки. Если flat bounce сообщения = 1, оно вызывает bounceable.
bouncedBoolОбязательноФлаг, описывающий, что само сообщение является результатом bounce.
srcMsgAddressIntОбязательноАдрес отправителя сообщения смарт-контракта.
destMsgAddressIntОбязательноАдрес получателя сообщения смарт-контракта.
valueCurrencyCollectionОбязательноСтруктура, описывающая информацию о валюте, включая общую сумму средств, переведенных в сообщении.
ihr_feeVarUInteger 16ОбязательноКомиссии за доставку гипермаршрутизации
fwd_feeVarUInteger 16ОбязательноКомиссии за пересылку сообщений, назначенные валидаторами
created_ltuint64ОбязательноЛогическое время отправки сообщения, назначенное валидатором. Используется для заказа действий в смарт-контракте.
created_atuint32ОбязательноВремя Unix

ext_in_msg_info$10

ext_in_msg_info$10 — это случай внешнего входящего сообщения. Означает, что этот тип сообщений отправляется из off-chain-пространства в контракты. Вариант использования — запрос приложения кошелька в контракт кошелька.

nanograms$_ amount:(VarUInteger 16) = Grams;
//external incoming message
ext_in_msg_info$10 src:MsgAddressExt dest:MsgAddressInt
import_fee:Grams = CommonMsgInfo;
СтруктураТипОбязательноОписание
ext_in_msg_info$10ConstructorОбязательноТег $10 означает, что в сериализации CommonMsgInfo, начинающийся с 10 бит, описывает внешнее входящее сообщение.
ihr_disabledBoolОбязательноФлаг гипермаршрутизации. (в настоящее время всегда true)
srcMsgAddressExtОбязательноАдрес внешнего отправителя сообщения.
destMsgAddressIntОбязательноАдрес смарт-контракта назначения сообщения.
import_feeVarUInteger 16ОбязательноПлата за выполнение и доставку сообщения.

ext_out_msg_info$11

ext_out_msg_info$11 — это случай внешнего исходящего сообщения. Это означает, что они могут быть отправлены из контрактов в off-chain пространство. Пример использования — логи.

//external outgoing message
ext_out_msg_info$11 src:MsgAddressInt dest:MsgAddressExt
created_lt:uint64 created_at:uint32 = CommonMsgInfo;
СтруктураТипОбязательноОписание
ext_out_msg_info$11ConstructorОбязательноТег $11 означает, что в сериализации CommonMsgInfo, начинающийся с бита 11, описывает внешнее исходящее сообщение.
srcMsgAddressIntОбязательноАдрес отправителя сообщения смарт-контракта.
destMsgAddressExtОбязательноАдрес внешнего назначения сообщения.
created_ltuint64ОбязательноЛогическое время отправки сообщения, назначенное валидатором. Используется для упорядочивания действий в смарт-контракте.
created_atuint32ОбязательноВремя Unix

StateInit TL-B

StateInit служит для доставки начальных данных в контракт и используется при развертывании контракта.

_ split_depth:(Maybe (## 5)) special:(Maybe TickTock)
code:(Maybe ^Cell) data:(Maybe ^Cell)
library:(HashmapE 256 SimpleLib) = StateInit;
СтруктураТипОбязательноОписание
split_depth(## 5)НеобязательноПараметр для highload контрактов определяет поведение разделения на несколько экземпляров в разных шардах. В настоящее время StateInit используется без него.
specialTickTock*НеобязательноИспользуется для вызова смарт-контрактов в каждом новом блоке блокчейна. Доступно только в мастерчейне. Обычные пользовательские контракты используются без него.
codeCellНеобязательноСериализованный код контракта.
dataCellНеобязательноНачальные данные контракта.
libraryHashmapE 256 SimpleLib*НеобязательноВ настоящее время используется StateInit без библиотек

Общие подробные пояснения к хэшмапам

MsgAddressExt TL-B

addr_none$00 = MsgAddressExt;
addr_extern$01 len:(## 9) external_address:(bits len)
= MsgAddressExt;

MsgAddress - это схема различных сериализаций для адресов. В зависимости от того, какой участник (off-chain или смарт-контракт) отправляет сообщения, используются различные структуры.

addr_none$00

addr_none$00 - используется для определения нулевого адреса off-chain участника. Это означает, что мы можем отправлять внешнее сообщение контракту без уникального адреса отправителя.

addr_none$00 = MsgAddressExt;
СтруктураТипОбязательноОписание
addr_none$00ConstructorОбязательноТег "$00" означает, что при сериализации MsgAddressExt начинается с битов "00". Это означает, что весь внешний адрес равен 00.

addr_extern$01

addr_extern$01 len:(## 9) external_address:(bits len)
= MsgAddressExt;
СтруктураТипОбязательноОписание
addr_extern$01ConstructorОбязательноТег $01 означает, что при сериализации MsgAddressExt, начинающийся с бита 01, описывает внешний адрес.
len## 9ОбязательноТо же, что и uintN - означает N-разрядное число без знака
external_address(bits len)ОбязательноАдрес - это битовая строка len, равная предыдущему "len"

MsgAddressInt TL-B

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;

addr_std$10

addr_std$10 anycast:(Maybe Anycast)
workchain_id:int8 address:bits256 = MsgAddressInt;
СтруктураТипОбязательноОписание
addr_std$10ConstructorОбязательноТег $10 означает, что в сериализации MsgAddressInt, начинающийся с 10 бит, описывает внутренний адрес.
anycastAnycast*НеобязательноДополнительные данные адреса, в настоящее время не используются в обычных внутренних сообщениях
workchain_idint8ОбязательноВоркчейн, в котором размещен смарт-контракт адреса назначения. В настоящий момент всегда равен нулю.
address(bits256)ОбязательноНомер идентификатора учетной записи смарт-контракта

addr_var$11

addr_var$11 anycast:(Maybe Anycast) addr_len:(## 9)
workchain_id:int32 address:(bits addr_len) = MsgAddressInt;
СтруктураТипОбязательноОписание
addr_var$11ConstructorОбязательноТег $11 означает, что в сериализации MsgAddressInt, начинающийся с 11 бит, описывает внутренний адрес контракта.
anycastAnycast*НеобязательноДополнительные данные адреса, в настоящее время не используются в обычных внутренних сообщениях
addr_len## 9ОбязательноТо же, что и uintN - означает N-разрядное число без знака
workchain_idint32ОбязательноВоркчейн, в котором размещен смарт-контракт адреса назначения. В настоящий момент всегда равен нулю.
address(bits256)ОбязательноАдрес полезной нагрузки (может быть идентификатором учетной записи)

Основные используемые типы

CurrencyCollection

nanograms$_ amount:(VarUInteger 16) = Grams;
currencies$_ grams:Grams other:ExtraCurrencyCollection
= CurrencyCollection;
СтруктураТипОбязательноОписание
currencies$_ConstructorОбязательно$_ пустой тег означает, что в сериализации CurrencyCollection мы не будем добавлять никаких битов в начало
grams(VarUInteger 16)ОбязательноЗначение сообщения в nanoTons
otherExtraCurrencyCollectionНеобязательноExtraCurrencyCollection — это словарь, предназначенный для дополнительных валют, который обычно пустой
  • ExtraCurrencyCollection сложный тип, который обычно пишется как пустой словарь в сообщениях

VarUInteger n

var_uint$_ {n:#} len:(#< n) value:(uint (len * 8))
= VarUInteger n;
var_int$_ {n:#} len:(#< n) value:(int (len * 8))
= VarInteger n;
СтруктураТипОбязательноОписание
var_uint$_ConstructorОбязательноvar_uint$_ пустой тег означает, что в сериализации CurrencyCollection мы не будем добавлять никаких битов в начало
lenuintNОбязательнобиты параметра len для следующего значения
value(uint (len * 8))Необязательнозначение uint для целого числа, записанного в (len * 8) бит

Пример сообщения

Обычное внутреннее сообщение на func

  var msg = begin_cell()
.store_uint(0, 1) ;; tag
.store_uint(1, 1) ;; ihr_disabled
.store_uint(1, 1) ;; allow bounces
.store_uint(0, 1) ;; not bounced itself
.store_slice(source)
.store_slice(destination)
;; serialize CurrencyCollection (see below)
.store_coins(amount)
.store_dict(extra_currencies)
.store_coins(0) ;; ihr_fee
.store_coins(fwd_value) ;; fwd_fee
.store_uint(cur_lt(), 64) ;; lt of transaction
.store_uint(now(), 32) ;; unixtime of transaction
.store_uint(0, 1) ;; no init-field flag (Maybe)
.store_uint(0, 1) ;; inplace message body flag (Either)
.store_slice(msg_body)
.end_cell();

Обычное сообщение на func в краткой форме

Части сообщения, которые всегда перезаписываются валидаторами, можно пропустить (заполнить нулевыми битами). Отправитель сообщения здесь также пропущен, сериализован как addr_none$00.

  cell msg = begin_cell()
.store_uint(0x18, 6)
.store_slice(addr)
.store_coins(amount)
.store_uint(0, 1 + 4 + 4 + 64 + 32 + 1 + 1)
.store_slice(message_body)
.end_cell();