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

Адреса смарт-контрактов

В этом разделе будут описаны особенности адресации смарт-контрактов в блокчейне TON. Также будет объяснено, как акторы являются синонимами смарт-контрактов на TON.

Все является умным контрактом

В TON смарт-контракты строятся с использованием модели [Actor model] (/learn/overviews/ton-blockchain#single-actor). Фактически, акторы в TON технически представлены в виде смарт-контрактов. Это означает, что даже Ваш кошелек является простым актором (и смарт-контрактом).

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

ОПЫТ РАБОТЫ С EVM

В виртуальной машине Ethereum (EVM) адреса полностью отделены от смарт-контрактов. Не стесняйтесь узнать больше о различиях, прочитав нашу статью "Шесть уникальных аспектов блокчейна TON, которые удивят разработчиков Solidity", написанную Талом Колом.

Адрес смарт-контракта

Адреса смарт-контрактов, работающих на TON, обычно состоят из двух основных компонентов:

  • (workchain_id): обозначает ID рабочей цепи (знаковое 32-битное целое число)

  • (account_id) обозначает адрес аккаунта (64-512 бит, в зависимости от рабочего цепочки)

В разделе этой документации, посвященном обзору сырых адресов, мы обсудим, как выглядят пары (workchain_id, account_id).

Идентификатор рабочей цепи и идентификатор учетной записи

Идентификатор рабочей цепи

Как мы уже видели ранее, на блокчейне TON можно создать до 2^32 рабочих цепей. Мы также отметили, что адреса смарт-контрактов с 32-битным префиксом идентифицируют и связываются с адресами смарт-контрактов в разных рабочих цепях. Это позволяет смарт-контрактам отправлять и получать сообщения в разные рабочие цепочки TON Blockchain и из них.

В настоящее время в блокчейне TON работает только мастерчейн (workchain_id=-1) и время от времени основной workchain (workchain_id=0).

Оба они имеют 256-битные адреса, поэтому мы предполагаем, что workchain_id равен либо 0, либо -1, а адрес внутри рабочей цепочки точно равен 256 битам.

Идентификатор счета

Все идентификаторы учетных записей на TON используют 256-битные адреса на Мастерчейне и Бейсчейне (или базовом рабочем цепочке).

Фактически, идентификаторы аккаунта (account_id) определяются как хэш-функции для объектов смарт-контракта (в частности, SHA-256). Каждый смарт-контракт, работающий на блокчейне TON, хранит два основных компонента. К ним относятся:

  1. Скомпилированный код. Логика смарт-контракта, скомпилированная в виде байткода.
  2. Инициальное состояние. Значения контракта в момент его развертывания на цепи.

Наконец, чтобы точно определить адрес контракта, необходимо вычислить хэш, соответствующий паре (Начальный код, Начальное состояние) объектов. Сейчас мы не будем глубоко вникать в то, как работает TVM, но важно понимать, что идентификаторы счетов на TON определяются по такой формуле: : account_id = hash(начальный код, начальное состояние).

Со временем, на протяжении всей этой документации, мы будем углубляться в технические характеристики и обзор схемы TVM и TL-B. Теперь, когда мы знакомы с генерацией account_id и их взаимодействием с адресами смарт-контрактов на TON, давайте объясним, что такое Raw и User-Friendly адреса.

Обращается к государству

Каждый адрес может находиться в одном из возможных состояний:

  • nonexist - по этому адресу не было принято ни одной транзакции, поэтому он не содержит никаких данных (или контракт был удален). Можно сказать, что изначально все2256 адресов находятся в таком состоянии.
  • uninit - адрес имеет некоторые данные, которые содержат баланс и мета-информацию. В этом состоянии у адреса еще нет кода смарт-контракта/постоянных данных. Адрес переходит в это состояние, например, когда он не существовал, и какой-то другой адрес отправил ему токены.
  • Активный - адрес имеет код смарт-контракта, постоянные данные и баланс. В этом состоянии он может выполнять некоторую логику во время транзакции и изменять свои постоянные данные. Адрес переходит в это состояние, когда он был uninit и поступило сообщение с параметром state_init (обратите внимание, что для развертывания этого адреса хэш из state_init и code должен быть равен адресу).
  • заморозка - адрес не может выполнять никаких операций, это состояние содержит только два хэша предыдущего состояния (ячейки кода и состояния соответственно). Когда заряд памяти адреса превышает его баланс, он переходит в это состояние. Чтобы разморозить его, Вы можете послать внутреннее сообщение с state_init и code, которые хранят описанные ранее хэши и некоторое количество Toncoin. Восстановить его может быть сложно, поэтому не стоит допускать такой ситуации. Существует проект по размораживанию адреса, который Вы можете найти здесь.

Сырые и удобные адреса

После краткого обзора того, как адреса смарт-контрактов на TON используют рабочие цепи и идентификаторы учетных записей (для Мастерчейна и Бейсчейна в частности), важно понять, что эти адреса выражаются в двух основных форматах:

  • Сырые адреса: Оригинальное полное представление адресов смарт-контрактов.
  • Удобные для пользователя адреса: Удобные для пользователя адреса - это улучшенный формат сырого адреса, который обеспечивает лучшую безопасность и простоту использования.

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

Сырой адрес

Необработанные адреса смарт-контрактов состоят из идентификатора рабочей цепи и идентификатора учетной записи (workchain_id, account_id) и отображаются в следующем формате:

  • [десятичный workchain_id]:[64 шестнадцатеричных цифр с account_id].

Ниже приведен пример необработанного адреса смарт-контракта, в котором используются идентификатор рабочей цепи и идентификатор учетной записи вместе (выраженные как workchain_id и account_id):

-1:fcb91a3a3816d0f7b8c2c76108b8a9bc5a6b7a55bd79f8ab101c52db29232260

Обратите внимание на -1 в начале строки адресов, которая обозначает workchain_id, принадлежащий Мастерчейну.

примечание

Прописные буквы (такие как 'A', 'B', 'C', 'D' и т.д.) могут использоваться в адресных строках вместо их строчных аналогов (таких как 'a', 'b', 'c' 'd' и т.д.).

Проблемы с сырыми адресами

При использовании формы "Сырой адрес" возникают две основные проблемы:

  1. При использовании необработанного формата адресов невозможно проверить адреса, чтобы исключить ошибки перед отправкой транзакции. Это означает, что если Вы случайно добавите или удалите символы в адресной строке перед отправкой транзакции, Ваша транзакция будет отправлена не по назначению, что приведет к потере средств.
  2. При использовании необработанного формата адреса невозможно добавить специальные флаги, подобные тем, что используются при отправке транзакций, в которых используются удобные для пользователя адреса. Чтобы помочь Вам лучше понять эту концепцию, ниже мы объясним, какие флаги можно использовать.

Удобный для пользователя адрес

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

Удобная структура адресов

Удобные для пользователя адреса состоят всего из 36 байт и получаются путем генерации следующих компонентов по порядку:

  1. [флаги - 1 байт] - Флаги, которые прикрепляются к адресам, изменяют способ реакции смарт-контрактов на полученное сообщение. Типы флагов, использующие удобный формат адреса, включают:

    • isBounceable. Обозначает отскакивающий или неотскакивающий тип адреса. (0x11 для "bounceable", 0x51 для "non-bounceable")
    • isTestnetOnly. Обозначает тип адреса, используемый только для целей тестовой сети. Адреса, начинающиеся с 0x80, не должны приниматься программным обеспечением, работающим в рабочей сети
    • isUrlSafe. Обозначает устаревший флаг, который определен как URL-safe для адреса. После этого все адреса считаются безопасными для URL.
  2. [workchain_id - 1 байт] - Идентификатор рабочей цепи (workchain_id) определяется подписанным 8-битным целым числом workchain_id.\ (0x00 для BaseChain, 0xff для MasterChain)

  3. [account_id - 32 байта] - ID счета состоит из (big-endian) 256-битного адреса в рабочей цепочке.

  4. [Проверка адреса - 2 байта] - В дружественных адресах проверка адреса состоит из CRC16-CCITT-подписи из предыдущих 34 байт. (Пример) На самом деле, идея, относящаяся к проверке для дружественных адресов, очень похожа на алгоритм Luhn, который используется на всех кредитных картах, чтобы предотвратить ввод пользователями несуществующих номеров карт по ошибке.

Сложение этих 4 основных компонентов означает, что: 1 + 1 + 32 + 2 = 36 байт в сумме (на один удобный для пользователя адрес).

Чтобы сгенерировать удобный для пользователя адрес, разработчик должен закодировать все 36 байт, используя либо:

  • base64 (т.е. с цифрами, латинскими буквами верхнего и нижнего регистра, '/' и '+')
  • base64url (с '_' и '-' вместо '/' и '+')

После этого процесса создание удобного для пользователя адреса длиной 48 символов без пробелов завершается.

ФЛАГИ АДРЕСОВ DNS

На TON вместо необработанных и удобных для пользователя адресов иногда используются DNS-адреса, такие как mywallet.ton. На самом деле, DNS-адреса состоят из удобных для пользователя адресов и включают в себя все необходимые флаги, которые позволяют разработчикам получить доступ ко всем флагам из DNS-записи в домене TON.

Примеры удобной кодировки адресов

Например, смарт-контракт "test giver" (специальный смарт-контракт, находящийся в мастерчейне testnet, который отправляет 2 тестовых токена всем, кто их запрашивает) использует следующий сырой адрес:

-1:fcb91a3a3816d0f7b8c2c76108b8a9bc5a6b7a55bd79f8ab101c52db29232260

Приведенный выше сырой адрес "test giver" должен быть преобразован в удобную для пользователя форму адреса. Это можно сделать с помощью форм base64 или base64url (которые мы представили ранее) следующим образом:

  • kf/8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15+KsQHFLbKSMiYIny (base64)
  • kf_8uRo6OBbQ97jCx2EIuKm8Wmt6Vb15-KsQHFLbKSMiYIny (base64url)
к сведению

Обратите внимание, что обе формы (base64 и base64url) действительны и должны быть приняты!

Отказоустойчивые и неотказоустойчивые адреса

Основная идея, лежащая в основе флага отклоняемого адреса, заключается в безопасности средств отправителя.

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

Что касается конкретно отказоустойчивых адресов:

  1. Флаг bounceable=false обычно означает, что получателем является кошелек.
  2. Флаг bounceable=true обычно обозначает пользовательский смарт-контракт с собственной прикладной логикой (например, DEX). В этом примере сообщения, не подлежащие отмене, не должны отправляться по соображениям безопасности.

Не стесняйтесь читать больше на эту тему в нашей документации, чтобы лучше понять [непрыгающие сообщения] (/develop/smart-contracts/guidelines/non-bouncable-messages).

Представления Armored base64

Дополнительные двоичные данные, связанные с блокчейном TON, используют аналогичные "бронированные" представления адресов в формате base64. Они отличаются друг от друга в зависимости от первых 4 символов их байтовой метки. Например, 256-битные открытые ключи Ed25519 представляются путем создания 36-байтовой последовательности, используя следующий процесс по порядку:

  • Однобайтовая метка, использующая формат 0x3E, обозначает открытый ключ
  • Однобайтовая метка, использующая формат 0xE6, обозначает открытый ключ Ed25519.
  • 32 байта, содержащие стандартное двоичное представление открытого ключа Ed25519
  • 2 байта, содержащие представление CRC16-CCITT предыдущих 34 байт в большом порядке

Полученная 36-байтовая последовательность преобразуется в 48-символьную строку base64 или base64url стандартным образом. Например, открытый ключ Ed25519 E39ECDA0A7B0C60A7107EC43967829DBE8BC356A49B9DFC6186B3EAC74B5477D (обычно представленный последовательностью из 32 байт, такой как: 0xE3, 0x9E, ..., 0x7D) представляет себя через "бронированное" представление следующим образом:

Pubjns2gp7DGCnEH7EOWeCnb6Lw1akm538YYaz6sdLVHfRB2

Преобразование адресов, удобных для пользователя, и сырых адресов

Самый простой способ преобразовать удобные для пользователя и необработанные адреса - использовать один из нескольких API TON и других инструментов, включая:

Кроме того, существует два способа преобразования удобных и необработанных адресов кошельков с помощью JavaScript:

Также можно использовать подобные механизмы с помощью SDKs.

Примеры адресов

Узнайте больше примеров по адресам TON в [Поваренной книге TON] (/develop/dapps/cookbook#working-with-contracts-addresses).

Возможные проблемы

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

Что произойдет, если Вы переведете Toncoin на неинициативный адрес?

Транзакция с включенным state_init

Если Вы включите state_init (который состоит из кода и данных кошелька или смарт-контракта) в Вашу транзакцию. Сначала смарт-контракт развертывается с помощью предоставленного state_init. После развертывания входящее сообщение обрабатывается, аналогично отправке на уже инициализированный счет.

Транзакция без установленного флага state_init и bounce

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

Транзакция без установленного флага state_init и bounce

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

Как сделать это правильно

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

В блокчейне TON реализована защита от ошибочных транзакций

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

Если необходимо быстро получить адрес в форме bounceable/non-bounceable, это можно сделать здесь.

Ответственность за заказные продукты

Если Вы разрабатываете собственный продукт на блокчейне TON, необходимо реализовать аналогичные проверки и логику:

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