Перейти к содержанию
Learning Platform
Глоссарий Troubleshooting
Урок 03.07 · 25 мин
Продвинутый
TL-BSerializationData FormatsTEPCells

Язык схем TL-B

TL-B (Type Language - Binary) — это язык описания структур данных в TON, играющий ту же роль, что и ABI в Ethereum или Protobuf в gRPC. Каждое сообщение, каждая ячейка состояния, каждый блок в TON описывается схемой TL-B. Умение читать и писать TL-B схемы — обязательный навык для работы с низкоуровневыми API, парсинга транзакций и взаимодействия с системными контрактами.

В уроке о ячейках и BoC (M01-L04) мы узнали, что все данные в TON хранятся в ячейках (cells) — структурах с битами и ссылками. Но как понять, что именно записано в ячейке? Какие биты отвечают за адрес, какие — за сумму, а какие — за код операции? Ответ — TL-B (Type Language - Binary), формальный язык описания схем данных TON.

TL-B — это “система типов” всей экосистемы TON. Каждая структура ячеек, каждый формат сообщений и каждое хранилище контрактов описаны в TL-B. Понимание TL-B необходимо для чтения стандартов TEP, разбора on-chain данных и понимания протокола на глубоком уровне.


Зачем нужен TL-B

Если ячейки — это формат хранения (контейнер из битов и ссылок), то TL-B — это схема содержимого (что означает каждый бит внутри ячейки).

Ячейка (Cell) vs TL-B схема
Ячейка (Cell)
1010...0011 (биты)
ref0, ref1 (ссылки)
"сырые данные"
TL-B
op:uint32 query_id:uint64
amount:Coins destination:MsgAddr
"что означают эти данные"

TL-B нужен для:

  • Чтения стандартов TEP — TEP-74 (Jettons), TEP-62 (NFTs) и другие стандарты описывают свои интерфейсы именно через TL-B-схемы
  • Парсинга on-chain данных — чтобы прочитать содержимое ячейки, нужно знать её TL-B-схему
  • Понимания форматов сообщений — internal messages, external messages, state_init и другие протокольные структуры определены в TL-B
TIP

Связь с предыдущими уроками: в M01-L04 мы разобрали, как данные упаковываются в ячейки (cells) и сериализуются в BoC. В M02-L03 мы изучили типы сообщений (internal, external). TL-B — это язык, который формально описывает структуру всех этих данных.


Базовый синтаксис

Конструкторы

Основная единица TL-B — конструктор. Он описывает один вариант структуры данных:

constructor_name$tag field1:type1 field2:type2 = TypeName;
  • constructor_name — имя конструктора (для людей)
  • $tag — двоичный тег-префикс, по которому парсер различает варианты
  • field1:type1 — поля с типами
  • TypeName — результирующий тип (после =)

Пример: простое сообщение с кодом операции и данными:

transfer$0x5fcc3d14 query_id:uint64 new_owner:MsgAddress
  response_destination:MsgAddress custom_payload:(Maybe ^Cell)
  forward_amount:(VarUInteger 16) forward_payload:(Either Cell ^Cell)
  = InternalMsgBody;

Теги

Теги — это двоичные префиксы, позволяющие различать несколько конструкторов одного типа:

Формат тегаПримерОписание
$0, $1_ $0 = Bool;Один бит: 0 или 1
$10, $11a$10 = X; b$11 = X;Два бита
#ccext_message#cc ...Hex-тег (автоматически переводится в биты)
(без тега)_ field:Type = Name;CRC32 от определения (автоматически)

Пример: тип Bool с двумя конструкторами:

bool_false$0 = Bool;
bool_true$1  = Bool;

Парсер читает один бит: если 0 — это bool_false, если 1 — bool_true.

Встроенные типы

ТипОписание
#uint32 (32 бита, беззнаковое)
## NN-битное беззнаковое целое
uint1..uint256Беззнаковые целые от 1 до 256 бит
int1..int257Знаковые целые от 1 до 257 бит
bits1..bits1023Битовые строки фиксированной длины
CellПроизвольная ячейка
AnyЛюбой тип (полиморфный)

Ссылки и вложенные ячейки

Ячейка может содержать до 1023 бит и до 4 ссылок на другие ячейки. В TL-B ссылки обозначаются оператором ^:

^TypeName    — данные типа TypeName хранятся в ссылочной ячейке

Пример: структура с телом сообщения в отдельной ячейке:

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

Здесь ^StateInit означает, что StateInit хранится в отдельной ячейке (по ссылке), а не inline в текущей.

Можно также определить содержимое ссылочной ячейки inline:

^[ field1:uint32 field2:uint64 ]

Это эквивалентно созданию анонимного типа с указанными полями в отдельной ячейке.


Условные поля и ограничения

Условные поля

Поле может присутствовать только при определённом условии:

flag:(## 1) value:(flag?uint32) = ConditionalExample;

Здесь value существует в ячейке только если flag == 1. Если flag == 0, поля value нет вообще (ни одного бита).

Ограничения значений

Фигурные скобки задают ограничения:

storage$_ x:uint32 y:uint32 { x + y <= 100 } = BoundedPair;

Ограничение { x + y <= 100 } проверяется при валидации — данные считаются невалидными, если сумма превышает 100.


Параметризованные типы

TL-B поддерживает типы с параметрами — аналог дженериков:

Hashmap n X — словарь с ключами длиной n бит и значениями типа X

Пример: хранилище балансов как словарь с 256-битными адресами:

balances:(Hashmap 256 Coins)

Это означает: Hashmap, где ключ — 256 бит (адрес), значение — тип Coins.

Другие параметризованные типы:

ТипОписание
Maybe XОпциональный: 1 бит-флаг + X (если 1)
Either X YОдин из двух: 0-бит + X или 1-бит + Y
VarUInteger nПеременной длины uint (длина кодируется в ceil(log2(n)) битах)
HashmapE n XHashmap с пустым вариантом (может быть пустым)

Чтение реальных TL-B схем

Рассмотрим практические примеры чтения TL-B-схем, с которыми вы столкнётесь при работе с 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;

Разбор по полям:

$0                — тег: 1 бит "0" = это internal message
ihr_disabled:Bool — 1 бит: IHR отключён (обычно true)
bounce:Bool       — 1 бит: сообщение bounced-capable
bounced:Bool      — 1 бит: это bounced-сообщение?
src:MsgAddressInt — адрес отправителя (переменная длина)
dest:MsgAddressInt— адрес получателя (переменная длина)
value             — сумма перевода
ihr_fee, fwd_fee  — комиссии (Grams = VarUInteger 16)
created_lt:uint64 — логическое время создания
created_at:uint32 — UNIX timestamp создания

Jetton Transfer (TEP-74)

transfer#0f8a7ea5 query_id:uint64 amount:(VarUInteger 16)
  destination:MsgAddress response_destination:MsgAddress
  custom_payload:(Maybe ^Cell)
  forward_ton_amount:(VarUInteger 16)
  forward_payload:(Either Cell ^Cell) = InternalMsgBody;

Разбор:

#0f8a7ea5            — 32-битный op-code (hex тег)
query_id:uint64      — 64-битный ID запроса для отслеживания
amount               — сколько жетонов переводится
destination          — кому переводить (адрес кошелька)
response_destination — куда отправить подтверждение
custom_payload       — опциональные данные (Maybe = бит-флаг + ^Cell)
forward_ton_amount   — сколько TON приложить к уведомлению
forward_payload      — данные для получателя
TIP

Эта TL-B схема из TEP-74 описывает сообщение Jetton Transfer. Мы подробнее разбираем архитектуру жетонов в M05-L01 (Jetton Architecture), где эта схема используется на практике.

Внешнее сообщение кошелька v4

external_message$_ signature:bits512
  ^[ seqno:uint32 subwallet_id:uint32 valid_until:uint32
     send_mode:uint8 message_to_send:^Cell ] = ExternalBody;

Разбор:

signature:bits512     — 512 бит подписи Ed25519
^[...]                — остальное в ссылочной ячейке:
  seqno:uint32        — порядковый номер (защита от replay)
  subwallet_id:uint32 — ID подкошелька
  valid_until:uint32  — срок действия сообщения (UNIX time)
  send_mode:uint8     — режим отправки
  message_to_send     — внутреннее сообщение для отправки

Инструменты для работы с TL-B

Для практической работы с TL-B существует несколько инструментов:

ИнструментНазначениеСсылка
TL-B Online EditorИнтерактивный редактор TL-B схем в браузереton-community.github.io/tlb-editor
tlb-codegenГенерация TypeScript-кода из TL-B схемnpm: @ton-community/tlb-codegen
tonpyPython-библиотека с поддержкой TL-B парсингаpip: tonpy

tlb-codegen особенно полезен: он принимает .tlb файл и генерирует TypeScript-функции для сериализации и десериализации данных. Это позволяет работать с on-chain данными типобезопасно, не парся биты вручную.


Чтение стандартов TEP

Стандарты TEP (TON Enhancement Proposal) используют TL-B для формального описания интерфейсов. Умение читать TL-B — ключ к пониманию любого TEP.

Как TEP-74 (Jettons) использует TL-B

TEP-74 определяет стандарт жетонов через набор TL-B-схем:

  1. Сообщения: transfer, transfer_notification, burn — каждое описано TL-B-конструктором с op-кодом
  2. Get-методы: возвращаемые значения get_wallet_data и get_jetton_data описаны TL-B-схемами
  3. Хранилище: формат persistent storage мастер-контракта и кошелька определён TL-B

Алгоритм чтения TEP с TL-B:

  1. Найдите раздел “Message Layouts” — там TL-B-схемы всех сообщений
  2. Определите op-коды (hex-теги конструкторов) — по ним контракт маршрутизирует входящие сообщения
  3. Прочитайте поля каждого сообщения — типы, порядок, условные поля
  4. Проверьте get-методы — их возвращаемые значения тоже описаны TL-B

TEP-62 (NFTs)

TEP-62 аналогично описывает NFT через TL-B:

  • transfer сообщение для передачи NFT
  • ownership_assigned уведомление нового владельца
  • Get-метод get_nft_data возвращает данные в формате, описанном TL-B
NOTE

TL-B — это не только про сообщения. Форматы хранилища контрактов (persistent data), структуры блоков и даже формат самих транзакций в TON описаны TL-B-схемами. Это буквально “язык описания всего” в экосистеме TON.


Ключевые выводы

  1. TL-B — это система типов TON: каждая структура данных, формат сообщений и хранилище контрактов описаны TL-B-схемами
  2. Ячейки — контейнер, TL-B — содержимое: Cell определяет, как данные хранятся (биты + ссылки), TL-B определяет, что эти данные означают
  3. Конструкторы и теги позволяют описывать несколько вариантов одного типа и различать их по битовому префиксу
  4. Оператор ^ означает ссылочную ячейку — данные хранятся не inline, а в отдельной ячейке
  5. TEP-стандарты (Jettons, NFTs и другие) используют TL-B для формального описания своих интерфейсов — умение читать TL-B необходимо для работы с любым стандартом
  6. Инструменты (tlb-codegen, online editor) упрощают практическую работу, генерируя код из TL-B-схем

Частые ошибки

  1. Путают TL-B с TL (Type Language из Telegram): это родственные, но разные языки; TL-B специализирован для бинарной сериализации в ячейки TON.
  2. Забывают указывать размер полей в битах (например, uint32 vs uint64), что приводит к неправильной десериализации данных.
  3. Не учитывают выравнивание и padding при чтении данных из ячеек, поскольку TL-B работает на уровне битов, а не байтов.
  4. Игнорируют конструкторы (constructor tags) в TL-B, которые необходимы для различения вариантов типа при десериализации.

Проверка знанийKnowledge check
Что означает запись ^Cell в TL-B схеме и чем она отличается от просто Cell?
ОтветAnswer
Оператор ^ в TL-B означает, что данные хранятся в отдельной ячейке по ссылке (reference), а не inline в текущей ячейке. Запись ^Cell означает: 'в этом месте стоит ссылка на другую ячейку, содержащую произвольные данные'. Просто Cell означает, что данные находятся прямо в текущей ячейке. Это важно для понимания того, как данные распределяются по дереву ячеек: каждая ячейка ограничена 1023 битами и 4 ссылками, поэтому крупные структуры выносят части данных в ссылочные ячейки через ^.

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 7