Как устроена платформа
Смарт-контракты¶
Смарт-контракт – это отдельное приложение, которое записывает в блокчейн свои входные данные и результаты исполнения заложенного алгоритма. Блокчейн-платформа Waves Enterprise поддерживает разработку и применение Тьюринг-полных смарт-контрактов для создания высокоуровневых бизнес-приложений.
Когда смарт-контракт запускается в блокчейн сети, его код нельзя произвольно изменить, заменить или запретить его выполнение без вмешательства в работу всей сети. Это свойство позволяет обеспечить безопасность работы бизнес-приложений.
Смарт-контракт может быть разработан на любом языке программирования и не имеет ограничений на реализацию заложенной логики.
Блокчейн-платформа Waves Enterprise реализует два типа смарт-контрактов:
Docker смарт-контракты – исполняются в контейнере Docker,
WASM смарт-контракты – исполняются на виртуальной машине WEVM.
Доступ смарт-контракта к стейту ноды для обмена данными осуществляется через API ноды. Docker смарт-контракты используют для этого gRPC API интерфейс. Доступ WASM смарт-контрактов к АПИ ноды предоставлен напрямую.
У каждого смарт-контракта есть собственный баланс, на котором могут храниться токены. Подробнее об управлении токенами из Docker смарт-контракта см. ниже. Управлении токенами из WASM смарт-контракта осуществляется аналогично.
Создавать и вызывать смарт-контракты может любой участник сети.
Создание и обновление смарт-контракта осуществляет один и тот же аккаунт. В связи с этим может возникнуть угроза безопасности контрактов: например, утечка мнемонической фразы от аккаунта позволит злоумышленнику обновить контракт и вывести средства. Чтобы исключить такие ситуации, можно использовать технологию смарт-аккаунта в качестве дополнительного средства безопасности.
Если вам необходимо ограничить доступ к смарт-контракту, создайте конфиденциальный смарт-контракт. Вызывать его и получать его результат смогут только ноды из списка, заданного вами при создании контракта. В дальнейшем вы сможете изменять этот список нод. Подробнее о конфиденциальных смарт-контрактах:
Важно
В релизах 1.14.0 и 1.15.0 WASM смарт-контракты не поддерживают атомарные транзакции и конфиденциальные смарт-контракты.
В ноду внедрен механизм MVCC (Multiversion concurrency control) – управление параллельным доступом к состоянию смарт-контрактов посредством многоверсионности. Благодаря этому нода позволяет параллельно выполнять несколько транзакций любых смарт-контрактов. При этом гарантируется согласованность данных. Механизм MVCC реализован одинаково для Docker и WASM смарт-контрактов.
Docker смарт-контракты¶
Docker смарт-контракт исполняется в контейнере Docker. Благодаря этому запуск и исполнение смарт-контракта отделены от самой блокчейн-платформы.
Разработанный смарт-контракт упаковывается в Docker-образ, который хранится в открытом репозитории Waves Enterprise. Этот репозиторий основан на технологии Docker Registry, к нему имеет доступ любой разработчик смарт-контрактов.
Для добавления смарт-контракта в репозиторий свяжитесь со службой технической поддержки. После одобрения вашей заявки смарт-контракт будет загружен в репозиторий, и вы сможете вызвать его при помощи клиентского приложения или запроса по REST API к вашей ноде.
Если вы планируете использовать смарт-контракты в собственной частной блокчейн-сети, вам потребуется создать собственный репозиторий для загрузки и вызова смарт-контрактов.
Общая схема работы Docker смарт-контракта¶
Ниже приведена общая схема работы Docker смарт-контракта:
Управление токенами из Docker смарт-контракта¶
Начиная с релиза 1.12 после активации функциональной возможности 1120 у смарт-контрактов блокчейн-платформы Waves Enterprise появляется собственный баланс, на котором могут храниться как системные токены WEST, так и любые другие токены. При этом для существовавших ранее смарт-контрактов баланс системных токенов WEST устанавливается равным нулю.
Также смарт-контрактам становятся доступны базовые функции работы с токенами:
выпуск токенов,
довыпуск токенов,
сжигание токенов, находящихся на балансе смарт-контракта,
перевод токенов с баланса смарт-контракта на баланс по адресу пользователя или пользователей.
Эти функции реализует метод CommitExecutionSuccess.
При помощи этой функциональности смарт-контракты имеют возможность изменять стейты ассетов и пользователей (их балансы). Пользователи также могут отправлять токены на баланс смарт-контракта.
Создание и установка Docker смарт-контракта¶
Практические указания по разработке логики смарт-контрактов, а также пример реализации на Python приведены в статье Разработка и применение смарт-контрактов Docker.
Участник, разрабатывающий смарт-контракт, должен иметь роль contract_developer в сети. Участник с ролью разработчика смарт-контрактов получает возможность вызывать смарт-контракты, а также запрещать их исполнение и обновлять их код.
Создание смарт-контракта начинается с подготовки Docker-образа, который содержит готовый код смарт-контракта, сценарный файл Dockerfile, а также, в случае использования gRPC-интерфейса для обмена данных с нодой, необходимые protobuf-файлы.
Подготовленный образ собирается при помощи утилиты build, входящей в состав пакета Docker, после чего отправляется в репозиторий.
Для установки смарт-контракта и работы с ним необходима настройка секции docker-engine
конфигурационного файла ноды.
Если ваша нода работает в сети Waves Enterprise Mainnet, на ней по умолчанию настроены установка смарт-контрактов из открытого репозитория и установлены рекомендованные параметры для обеспечения оптимального исполнения смарт-контрактов.
Установка смарт-контракта в блокчейне выполняется посредством транзакции 103 CreateContract Transaction, в теле которой указывается ссылка на образ смарт-контракта в репозитории. При работе со смарт-контрактами рекомендуется отправлять транзакции последних версий.
При работе в частной сети транзакция 103 предусматривает загрузку Docker-образа контракта не только из репозиториев, указанных в секции docker-engine
конфигурационного файла ноды.
Если вам необходимо загрузить смарт-контракт из репозитория, не внесенного в конфигурационный файл, укажите в поле name
транзакции 103 полный адрес смарт-контракта в созданном вами репозитории.
Пример заполнения полей транзакции 103 приведен в ее описании.
После получения транзакции нода скачивает образ по ссылке, указанной в поле image
.
Затем скачанный образ проверяется нодой и запускается в Docker-контейнере.
Запуск Docker смарт-контракта и фиксация результатов исполнения¶
Запуск смарт-контракта инициируется участником сети при помощи транзакции 104 CallContract Transaction.
В этой транзакции передается id Docker-контейнера, в котором запускается смарт-контракт, а также его входные и выходные параметры в виде пар «ключ-значение».
Контейнер запускается, если не был запущен ранее.
Смарт-контракт выполняется и отправляет результат через gRPC API-интерфейс на ноду, которая инициировала запуск смарт-контракта. Нода, в свою очередь, генерирует транзакцию о результате выполнения смарт-контракта 105 ExecutedContract Transaction. Таким образом результат исполнения смарт-контракта фиксируется в его стейте при помощи транзакции 105 ExecutedContract.
Ноды-валидаторы выполняют проверку того, что все, кто исполнял этот смарт-контракт с этими данными получили один и тот же результат. В случае успешного прохождения проверки нода-майнер помещает транзакции в блок, и результат выполнения смарт-контракта попадает в блокчейн.
Запрет запуска Docker смарт-контракта¶
Для того, чтобы отключить запуск смарт-контракта в блокчейне, отправьте транзакцию 106 DisableContract Transaction с указанием идентификатора контракта в блокчейн сети – contractId. Отправить эту транзакцию может только участник с ролью contract_developer, который создал этот контракт.
После отключения смарт-контракт становится недоступен для запуска. Информация об отключенном смарт-контракте продолжает храниться в блокчейне и доступна для gRPC или REST API-методов.
Обновление Docker смарт-контракта¶
Если вы изменили код вашего смарт-контракта, обновите его. Для этого заново загрузите смарт-контракт в репозиторий Waves Enterprise, отправив заявку на обновление смарт-контракта в службу технической поддержки.
Затем отправьте на ноду транзакцию 107 UpdateContract Transaction. Обновляемый смарт-контракт не должен быть отключен при помощи транзакции 106.
После обновления смарт-контракта ноды-майнеры блокчейна скачивают его и проверяют корректность исполнения. Затем информация об обновлении смарт-контракта вносится в его стейт при помощи транзакции 105, содержащей тело исполненной транзакции 107.
Подсказка
Изменять смарт-контракт может только участник с ролью contract_developer, создавший транзакцию 103 CreateContract Transaction для этого смарт-контракта.
Валидация Docker смарт-контрактов¶
Блокчейн-платформа поддерживает три варианта политик валидации смарт-контракта для обеспечения дополнительного контроля его целостности. Эта возможность доступна при выполнении следующих условий:
в сети активирована функциональная возможность 162;
в сети присутствует хотя бы один участник с активной ролью contract_validator;
для загрузки и обновления смарт-контрактов используются транзакции 103 и 107 версии 4 (и выше).
Политика валидации настраивается при помощи строкового поля validationPolicy.type
соответствующей транзакции.
Доступные политики валидации:
any
– сохраняется действующая в сети общая политика валидации: для майнинга обновляемого смарт-контракта майнер подписывает соответствующую транзакцию 105. Также этот параметр устанавливается, если в сети нет ни одного зарегистрированного валидатора.majority
– транзакция считается валидной, если она подтверждена большинством валидаторов: 2/3 от общего числа зарегистрированных адресов с ролью contract_validator.majorityWithOneOf(List[Address])
– транзакция считается валидной, если собрано большинство валидаторов, среди которых присутствует хотя бы один из адресов, включенных в список параметра. Адреса, включаемые в список, должны иметь действующую роль contract_validator.
Предупреждение
При выборе политики валидации majorityWithOneOf(List[Address])
, список адресов должен содержать хотя бы один адрес, передача пустого списка запрещена.
Параллельное исполнение Docker контрактов¶
На платформе Waves Enterprise можно запускать несколько смарт-контрактов одновременно. Для этого на ноде реализован механизм MVCC (Multiversion concurrency control) – управление параллельным доступом посредством многоверсионности. Механизм позволяет параллельно выполнять несколько транзакций контейнеризированных смарт-контрактов и сохранять согласованность данных.
Все транзакции делятся на две группы:
non-executable транзакции – атомарные контейнеры и все классические транзакции: transfer transaction, data transaction и т. п.;
executable транзакции – транзакции всех контейнеризированных смарт-контрактов.
Транзакции первой группы всегда выполняются последовательно (уровень параллелизма равен единице).
Для второй группы транзакций параллелизм исполнения определяется значением параметра node.docker-engine.contracts-parallelism
в конфигурации ноды:
node.docker-engine.contracts-parallelism = 8
По умолчанию используется значение 8
.
Таким образом все смарт-контракты выполняются параллельно, независимо от Docker-образа.
Примечание
Между двумя группами транзакций присутствует конкуренция: если в UTX-пуле накапливаются разнородные транзакции, то параллельность может снижаться. Такое поведение можно сгладить, увеличив размер pulling буфера, но полностью исключить нельзя.
Логика кода смарт-контракта, как и язык программирования, выбранный для его разработки, должны учитывать специфику параллельного исполнения смарт-контрактов. Например, если смарт-контракт с функцией инкремента переменной при каждой транзакции вызова контракта будет исполняться параллельно, то результат получится некорректным, поскольку используется общий ключ авторизации во время каждого вызова контракта.
API-инструменты, доступные Docker смарт-контракту¶
Для обмена данными между смарт-контрактом и нодой предусмотрены методы gRPC API. При использовании этих методов вы можете осуществлять широкий спектр операций с блокчейном.
Подробнее:
WASM смарт-контракты¶
В отличие от Docker смарт-контрактов, WASM смарт-контракты представляют собой скомпилированный байт-код, который исполняется на виртуальной машине WEVM. Такой подход позволяет повысить стабильность и скорость выполнения контрактов за счет исключения дополнительных компонентов и общения между ними, потому что виртуальная машина интегрирована внутрь платформы.
Важно
WASM смарт-контракты можно использовать на платформе Waves Enterprise начиная с релиза 1.14.0 после активации функциональной возможности 1140.
Основные преимущества WASM:
Высокая производительность и совместимость,
Малый размер WASM байт-кода,
Изолированное и платформо-независимое исполнение,
Расширенная языковая поддержка.
Важно
В релизах 1.14.0 и 1.15.0 WASM смарт-контракты не поддерживают атомарные транзакции и конфиденциальные смарт-контракты.
Общие настройки WASM смарт-контрактов задаются в секции node.wasm
конфигурационного файла ноды.
Общая схема работы WASM смарт-контракта¶
WASM смарт-контракты представляют собой base-64 WASM байт-код, расположенный внутри ContractInfo.
Основным отличием реализации WASM смарт-контракта от Docker смарт-контракта является доступ к API ноды напрямую без использования gRPC API.
Ниже приведена общая схема работы WASM смарт-контракта:
При исполнении WASM смарт-контракта создается WASMService, который получает доступ к функционалу блокчейна (предоставляет интерфейс к инстансу DelegatedBlockchain, например, TransactionsAccumulator).
WASMContractExecutor вызывает executeTransaction. Внутри executeTransaction WASMExecutor вызывает исполнение байткода смарт-контракта (runContract) и его валидацию (validateBytecode).
В случае транзакции создания контракта CreateContractTransaction, вызывается метод
runBytecode
с переданной функцией_constructor
.В случае транзакции изменения контракта UpdateContractTransaction, метод
runBytecode
не вызывается; возвращаетсяContractExecutionSuccess
с пустыми изменениями.В случае транзакции вызова контракта CallContractTransaction, вызывается метод
runBytecode
с переданной в CallContractTransaction функциейcallFunc
. Функцией в CallContractTransaction не может быть_constructor
.
При формировании очередного блока транзакция извлекается из UTX-пула, создаётся одноразовый инстанс класса WASMService и аккумулируется транзакция через WASMService.
Разработка WASM смарт-контракта¶
WASM смарт-контракт можно разработать на любом языке программирования, который поддерживает компиляцию исходного кода в WebAssembly байт-код. Виртуальная машина предоставляет весь необходимый набор функций для написания контрактов любой сложности. Перед созданием WASM контракта на платформе достаточно его скомпилировать.
Практические указания по разработке WASM смарт-контрактов приведены в статье Разработка и применение WASM смарт-контрактов.
Создание и вызов WASM смарт-контракта¶
Для создания и вызова WASM смарт-контрактов используются те же транзакции, что и для Docker контрактов.
Для создания контракта необходимо в транзакции 103 CreateContract версии 7 указать байт-код контракта в виде base64 строки и его хэш байт-кода.
Важно
У участника, который разрабатывает смарт-контракт, должна быть роль contract_developer в сети. Участник с этой ролью может вызывать смарт-контракты, а также запрещать их исполнение и обновлять их код.
Все WASM контракты хранятся внутри состояния блокчейна, поэтому при запуске контракта не требуется дополнительная загрузка или сторонние сервисы.
Запуск WASM смарт-контракта инициируется участником сети при помощи транзакции 104 CallContract Transaction версии 7. Для вызова WASM контракта необходимо указать вызываемую функцию и список аргументов, необходимый для данной функции.
Фиксация результатов исполнения WASM смарт-контракта¶
Результатом выполнения контракта является число 0
, если контракт выполнен успешно, либо код ошибки. В таблице ниже перечислены коды ошибок, которые возвращает WASM смарт-контракт.
Код ошибки |
Название ошибки |
Условие при котором возвращается ошибка |
---|---|---|
100 |
InvalidBytecode |
Не удалось распознать и валидировать байт-код WASM |
101 |
ConstructorNotFound |
Не удалось найти конструктор контракта |
102 |
MemoryError |
Ошибка при работе с виртуальной или линейной памятью |
103 |
MemoryLimits |
Ограничение объема памяти ниже u32::MAX |
104 |
LinkerError |
Ошибка при работе с инстансами Linker |
105 |
InstantiateFailed |
Не удалось создать и запустить байт-код WASM |
106 |
HeapBaseNotFound |
Не удалось найти Global heap base |
107 |
FuncNotFound |
Не удалось найти функцию |
108 |
InvalidNumArgs |
Недопустимое количество аргументов |
109 |
FailedParseFuncArgs |
Не удалось распознать аргумент функции |
110 |
FailedDeserializeDataEntry |
Не удалось распознать аргументы DataEntry |
111 |
FailedExec |
Сбой во время выполнения |
112 |
StackOverflow |
Ошибка переполнения стека вызовов |
304 |
no data for this key: <key> |
Попытка обратиться к ключу, для которого не инициализирован storage |
501 |
DataIsMissing |
Не существует contractKey или contractBytecode |
502 |
InvalidArgument |
Передан некорректный аргумент из WEVM, например некорректный адрес получателя |
503 |
InvalidTransfer |
Ошибки переводов, например при попытке передать в Transfer значение меньше 0 или создать слишком много переводов на баланс контракта (поле |
Если контракт производит какие-либо изменения своего состояния, или совершает операцию над ассетами, то WASMService фиксирует такие изменения, вызывая внешние функции (Environment).
Смарт-контракт выполняется и отправляет результат через API на ноду, которая инициировала его запуск. Нода, в свою очередь, генерирует транзакцию 105 ExecutedContract Transaction о результате выполнения смарт-контракта. Таким образом результат исполнения смарт-контракта фиксируется в его стейте при помощи транзакции 105 ExecutedContract.
Ноды-валидаторы выполняют проверку того, что все, кто исполнял этот смарт-контракт с этими данными получили один и тот же результат. В случае успешного прохождения проверки нода-майнер помещает транзакции в блок, и результат выполнения смарт-контракта попадает в блокчейн.
Запрет запуска WASM смарт-контракта¶
Запуск WASM смарт-контракта отключается так же как и запуск Docker смарт-контракта.
Обновление WASM смарт-контракта¶
Если вы изменили код вашего WASM смарт-контракта, обновите его с помощью транзакции 107 UpdateContract Transaction версии 7.
Важно
Обновляемый смарт-контракт не должен быть отключен при помощи транзакции 106 DisableContract Transaction.
Подсказка
Изменять смарт-контракт может только участник с ролью contract_developer, создавший транзакцию 103 CreateContract Transaction для этого смарт-контракта.
Валидация WASM смарт-контрактов¶
Для обеспечения дополнительного контроля целостности WASM смарт-контрактов блокчейн-платформа поддерживает те же политики валидации, что и для Docker смарт-контрактов.
Параллельное исполнение WASM смарт-контрактов¶
На платформе Waves Enterprise можно запускать несколько смарт-контрактов одновременно с помощью реализованного на ноде механизма управления параллельным доступом к состоянию смарт-контрактов посредством многоверсионности (MVCC). Этот механизм позволяет параллельно выполнять несколько транзакций контейнеризированных смарт-контрактов и сохранять согласованность данных.
Механизм MVCC для WASM смарт-контрактов аналогичен механизму для Docker смарт-контрактов.