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

Сообщения и транзакции

warning

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

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

Что такое сообщение?

Сообщение – это пакет данных, которым обмениваются участники (пользователи, приложения или смарт-контракты). Обычно оно содержит информацию, указывающую получателю, какое действие следует выполнить, например, обновить хранилище или отправить новое сообщение.



Работа с таким типом обмена данными напоминает запуск спутника в космос. Хотя мы точно знаем, какое сообщение мы создали, после запуска необходимо наблюдение, чтобы определить результат.

Что такое транзакция?

Транзакция в TON состоит из следующего:

  • входящее сообщение – инициирует запуск контракта (существуют специальные способы запуска)
  • действия контракта, вызванные входящим сообщением, например, обновление хранилища контракта (необязательно)
  • исходящие сообщения – создаются и отправляются другим участникам (необязательно).

Технически контракт может быть запущен с помощью специальных функций, таких как Tick-Tock, но эта функция чаще используется для внутренних контрактов ядра TON Blockchain.

Не каждая транзакция приводит к созданию исходящих сообщений или обновлению хранилища контракта – это зависит от действий, заложенных в коде контракта.



В асинхронной системе вы не можете получить ответ от целевого смарт-контракта в пределах той же транзакции. Обработка вызова контракта может занять несколько блоков, в зависимости от длины маршрута между источником и местом назначения.

Достижение парадигмы бесконечного шардинга требует полной параллелизации, гарантирующей, что каждая транзакция будет выполняться независимо от других. Поэтому вместо транзакций, которые затрагивают и изменяют состояние многих контрактов одновременно, каждая транзакция в TON выполняется только на одном смарт-контракте, а смарт-контракты обмениваются данными посредством сообщений. Таким образом, смарт-контракты могут взаимодействовать друг с другом только путем вызова их функций с помощью специальных сообщений и последующего получения на них ответа с помощью других сообщений.

Достижение парадигмы бесконечного шардинга требует полной параллелизации, гарантирующей, что каждая транзакция будет выполняться независимо от других. Поэтому вместо транзакций, которые затрагивают и изменяют состояние многих контрактов одновременно, каждая транзакция в TON выполняется только на одном смарт-контракте, а смарт-контракты обмениваются данными посредством сообщений. Таким образом, смарт-контракты могут взаимодействовать друг с другом только путем вызова их функций с помощью специальных сообщений и последующего получения на них ответа с помощью других сообщений.

к сведению

Более подробное и точное описание на странице Transaction Layout.

Результат транзакции

Существует код завершения TVM для транзакции, которая находилсь в фазе вычисления, и если значение данного кода не равно 0 или 1, то произошла ошибка. Также фаза вычислений TVM может быть пропущена, например, из-за отсутствия средств или статуса состояния.

для toncenter api v3

Для определения успешности транзакции следует использовать tx.description.action.success && tx.description.compute_ph.success:

"transactions": [
{
"description": {
. . . . . . . .
"action": {
"valid": true,
"success": true,
. . . . . . . .
},
. . . . . . . .
"destroyed": false,
"compute_ph": {
"mode": 0,
"type": "vm",
"success": true,

Транзакция может иметь один из трех результатов:

  • Success, exit code: 0 или 1 – успешно
  • Fail, aborted: true – неуспешно, прервано без выполнения
  • Fail, exit code, aborted: true – неуспешно, прервано.
для toncenter api v3

aborted: true является полем из Toncenter API, а не полем вывода транзакции

Что такое логическое время?

Строго гарантируется, что транзакция, являющаяся результатом сообщения, будет иметь lt больше, чем lt сообщения. Аналогично lt сообщения, отправленного в некоторой транзакции, строго больше, чем lt транзакции, которая его вызвала. Сообщения, отправленные с одного аккаунта и транзакции, произошедшие на одном аккаунте, также строго упорядочены.

Строго гарантируется, что транзакция, являющаяся результатом сообщения, будет иметь lt больше, чем lt сообщения. Аналогично lt сообщения, отправленного в некоторой транзакции, строго больше, чем lt транзакции, которая его вызвала. Сообщения, отправленные с одного аккаунта и транзакции, произошедшие на одном аккаунте, также строго упорядочены.



Благодаря lt мы всегда знаем порядок транзакций, полученных и отправленных сообщений для каждого аккаунта.

Более того, если аккаунт A отправил два сообщения аккаунту B, гарантируется, что сообщение с меньшим lt будет обработано раньше:

Если msg1_lt < msg2_lt => tx1_lt < tx2_lt.

Если msg1_lt < msg2_lt => tx1_lt < tx2_lt.



Для каждого блока мы можем определить lt-диапазон, который начинается с первой транзакции и заканчивается lt последнего события в блоке (сообщения или транзакции). Блоки упорядочены так же, как и другие события в TON, поэтому если один блок зависит от другого, он имеет более высокое lt. Дочерний блок в шарде имеет более высокое lt, чем его родитель. lt мастерчейн-блока выше, чем lts каждого вложенного шард-блока, поскольку мастер-блок зависит от вложенных шард-блоков. Каждый шард-блок содержит упорядоченную ссылку на последний мастер-блок (на момент создания шард-блока), поэтому lt шард-блока выше, чем lt мастер-блока на который они ссылаются.

Для каждого блока мы можем определить lt-диапазон, который начинается с первой транзакции и заканчивается lt последнего события в блоке (сообщения или транзакции). Блоки упорядочены так же, как и другие события в TON, поэтому если один блок зависит от другого, он имеет более высокое lt. Дочерний блок в шарде имеет более высокое lt, чем его родитель. lt мастерчейн-блока выше, чем lts каждого вложенного шард-блока, поскольку мастер-блок зависит от вложенных шард-блоков. Каждый шард-блок содержит упорядоченную ссылку на последний мастер-блок (на момент создания шард-блока), поэтому lt шард-блока выше, чем lt мастер-блока на который они ссылаются.

Доставка сообщений

К счастью, TON работает таким образом, что любое внутреннее сообщение будет обязательно получено целевым аккаунтом. Сообщение не может потеряться где-то между источником и получателем. С внешними сообщениями дело обстоит немного иначе, поскольку их принятие в блок происходит по усмотрению валидатора. Однако, как только сообщение будет принято в очередь входящих сообщений, оно будет доставлено.

Порядок доставки

Предположим, что существует два контракта – A и B. A получает внешнее сообщение, которое запускает отправку двух внутренних сообщений контракту B, назовем их сообщения 1 и 2. В этом простом случае мы можем на 100% быть уверены, что сообщение 1 будет обработано B раньше, чем 2 поскольку оно имеет меньшее lt.

Предположим, что существует два контракта – A и B. A получает внешнее сообщение, которое запускает отправку двух внутренних сообщений контракту B, назовем их сообщения 1 и 2. В этом простом случае мы можем на 100% быть уверены, что сообщение 1 будет обработано B раньше, чем 2 поскольку оно имеет меньшее lt.



Это простой случай, когда у нас только два контракта. Как наша система работает в более сложных случаях?

Несколько смарт-контрактов

Для большей наглядности предположим, что наши контракты отправляют обратно сообщения msg1' и msg2' после msg1 и msg2, выполненных контрактами B и C. В результате tx2' и tx1' будет применено к контракту A. Есть две возможные трассировки для этих транзакций,

Для большей наглядности предположим, что наши контракты отправляют обратно сообщения msg1' и msg2' после msg1 и msg2, выполненных контрактами B и C. В результате tx2' и tx1' будет применено к контракту A. Есть две возможные трассировки для этих транзакций,

  1. Первый возможный порядок – tx1'_lt < tx2'_lt:


  1. Второй возможный порядок – tx2'_lt < tx1'_lt:


Тоже самое происходит и в обратном случае, когда два контракта B и C отправляют сообщение одному контракту A. Даже если сообщение B -> A было отправлено раньше, чем C -> A, мы не можем знать какое из них будет доставлено первым. Маршрут B -> A может потребовать большего количества переходов по цепочке шардов.



Возможных сценариев взаимодействия смарт-контрактов может быть множество и в любом сценарии с более чем 2 контрактами порядок доставки сообщений может быть произвольным. Единственная гарантия заключается в том, что сообщения от любого контракта A к любому контракту B будут обрабатываться в порядке их логического времени. Некоторые примеры приведены ниже.







Заключение

Асинхронная структура блокчейна TON создает трудности с гарантией доставки сообщений. Логическое время помогает установить порядок событий и транзакций, но не гарантирует порядок доставки сообщений между несколькими смарт-контрактами из-за различий маршрутов в цепочках шардов. Несмотря на эти сложности, TON обеспечивает внутреннюю доставку сообщений, поддерживая надежность сети. Разработчики должны адаптироваться к этим нюансам, чтобы использовать весь потенциал TON для создания инновационных децентрализованных приложений.