(Запрещено создание своих обучающих материалов на основе этого без разрешения автора)

TVM - TON Virtual Machine.

Реализована 1 в 1 как в WP Николая Дурова, https://ton.org/tvm.pdf

Что нужно знать о VM? Это простая стековая виртуальная машина, то есть мы оперируем с данными, которые лежат на стеке. (Операции там например "Сложить два верхних числа, лежащих на стеке", или "поменять местами вторую и десятую переменные в стеке"). Из важного:

Код для TVM - это обычные данные.

Код просто хранится в памяти, и может и передаваться с сообщениями, и быть перезаписан. Есть операция tvm.setcode(code), которая поменяет код Вашего контракта (начиная со следующей транзакции), и даже операция tvm.setCurrentCode(code) которая поменяет код на новый прямо в текущей транзакции. С обновлением контракта есть нюансы. (см. дополнения “Как апгрейдить контракты”)

Сообщения и деньги.

В асинхронной архитектуре всё общение контрактов между собой происходит с помощью отправки сообщений.

Последовательность примерно такая (Тут я обхожу вопросы, как именно происходит доставка сообщений, для этого будет отдельная глава в дополнениях):

  1. Контракт получает EXTERNAL message из внешнего мира, и если контракт соглашается его оплатить, запускается транзакция, в результате которой контракт может создать сколько угодно исходящих внутренних сообщений (internal message). В исходящем сообщении есть адрес контракта назначения, какую функцию там надо вызвать и с какими аргументами.
  2. Контракт назначения получает входящее internal message, и запускается транзакция, в результате которой опять же могут быть созданы исходящие internal message.

С external message всё просто: ему выделяется 10к кредитного газа, и если контракт не согласится за этот газ оплатить транзакцию (платить за газ дальше), то такое сообщение просто будет отброшено, и транзакция не начнется.

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

Поэтому в ES ко всем исходящим сообщениям прикладывается value (ever-ы). Когда контракт получает сообщение, газ платится из тех денег, которые приложены к этому сообщению, и если деньги в сообщении закончатся, и контракт не захочет дальше платить сам, то транзакция упадёт с диагностикой Out of gas. Если после транзакции остались деньги в сообщении, то они просто добавляются к счету контракта (или контракт может отправить сдачу назад).