Перейти к содержанию
Learning Platform
Глоссарий Troubleshooting
Урок 03.03 · 20 мин
Средний
Internal MessagesExternal MessagesBounceMessage Structure

Типы Сообщений: Internal и External

Различие между internal и external сообщениями — это ключ к безопасности ваших контрактов. External сообщения приходят из «внешнего мира» (кошельки, боты), а internal — от других контрактов внутри блокчейна. От типа сообщения зависит, кто платит за газ, какие проверки нужно выполнять и какие атаки возможны. Неправильная обработка external сообщений — одна из самых критичных уязвимостей в TON.

В TON существует три типа сообщений, каждый из которых играет свою роль в экосистеме.


External-in сообщения

External-in — сообщения из внешнего мира в блокчейн. Это точка входа для пользователей.

  • Отправитель: кошелёк пользователя (off-chain)
  • Получатель: смарт-контракт (on-chain)
  • Подпись: обязательна (проверяется контрактом-получателем)
  • Value: 0 TON (нельзя прикрепить TON извне)
Пользователь (off-chain) ──── external-in ────→ Wallet Contract

Типичный пример: пользователь подписывает транзакцию в Tonkeeper и отправляет external message в свой wallet contract.

NOTE

В TON wallet contract оплачивает gas за обработку external message из своего баланса. В отличие от Ethereum, где gas оплачивается из EOA напрямую.


Internal сообщения

Internal — сообщения между контрактами внутри блокчейна. Основной механизм взаимодействия.

  • Отправитель: смарт-контракт (on-chain)
  • Получатель: смарт-контракт (on-chain)
  • Value: любое количество TON (прикрепляется к сообщению)
  • Bounce: можно включить/выключить
Contract A ──── internal ────→ Contract B

Internal сообщения создаются контрактами в процессе обработки входящих сообщений.


External-out сообщения

External-out — сообщения из блокчейна во внешний мир. Аналог events в Ethereum.

  • Отправитель: смарт-контракт (on-chain)
  • Получатель: off-chain сервис
  • Назначение: логирование, уведомления, events
Contract ──── external-out ────→ Off-chain (indexer, UI)

External-out сообщения не доставляются другим контрактам. Они записываются в блок и могут быть прочитаны off-chain сервисами.


Структура сообщения

Каждое сообщение в TON содержит:

ПолеОписание
srcАдрес отправителя (для internal)
destАдрес получателя
valueКоличество прикреплённых TON (нано-TON)
bodyPayload — данные для обработки (Cell)
bounceФлаг: возвращать ли TON при ошибке
bouncedФлаг: это bounced сообщение?
ihr_disabledФлаг: использовать ли Instant Hypercube Routing
fwd_feeКомиссия за маршрутизацию

Механизм Bounce

Bounce — ключевой механизм безопасности в TON.

Если контракт-получатель не может обработать internal message (ошибка, нехватка gas, контракт не существует), и флаг bounce: true, то:

  1. Сообщение “отскакивает” обратно отправителю
  2. Прикреплённые TON возвращаются (минус gas за bounce)
  3. Bounced message имеет флаг bounced: true
Contract A ──── bounce: true ────→ Contract B (ОШИБКА!)
Contract B ──── bounced: true ────→ Contract A (возврат TON)
WARNING

Распространённая ошибка: если контракт отправляет сообщение с bounce: true, он обязан обрабатывать bounced сообщения. Иначе возвращённые TON будут потеряны или вызовут неожиданное поведение.

Когда использовать bounce?

СценарийbounceПочему
Перевод TONtrueВернуть TON при ошибке получателя
УведомлениеfalseНе нужен возврат, уведомление опционально
Деплой контрактаfalseКонтракт ещё не существует, bounce невозможен
Запрос данныхtrueВернуть gas при ошибке

Обработка сообщений контрактом

Контракт на Tact обрабатывает сообщения через receive():

contract MyContract {
    // Обработка internal message
    receive(msg: MyMessage) {
        // ... логика
    }

    // Обработка bounced message
    bounced(msg: bounced<MyMessage>) {
        // Откат локального состояния
    }

    // Обработка external message
    external(msg: MyExternalMessage) {
        acceptMessage(); // Подтвердить оплату gas
        // ... логика
    }
}

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

  1. Вызывают accept_message() до проверки подписи во внешнем сообщении, что позволяет злоумышленнику опустошить баланс контракта, заставив его оплачивать газ за мусорные сообщения.
  2. Забывают, что external-сообщения не имеют отправителя (sender = 0), и проверка sender для авторизации не работает для внешних сообщений.
  3. Не учитывают replay protection: одно и то же external-сообщение может быть отправлено повторно, если контракт не проверяет seqno или другой механизм защиты.
  4. Путают формат тела (body) internal и external сообщений, которые имеют разную структуру, и парсинг одного формата как другого приведёт к ошибке.

Проверка знанийKnowledge check
Что произойдёт, если контракт A отправит internal message с bounce: true контракту B, а B не существует?
ОтветAnswer
Сообщение 'отскочит' (bounce) обратно контракту A. Прикреплённые TON будут возвращены (минус gas за обработку bounce). Контракт A получит bounced message с флагом bounced: true, который он должен корректно обработать.

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

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

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

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