» » » Система вызова смарт-контрактов в блокчейне Ethereum

 

Система вызова смарт-контрактов в блокчейне Ethereum

Автор: admin от 5-02-2018, 15:55, посмотрело: 160

Задача

Система вызова смарт-контрактов в блокчейне Ethereum


Часто разработчики смарт контрактов под Ethereum сталкиваются с, казалось бы, простой проблемой — вызов кода смарт-контракта в будущем или по расписанию. Но подходящего решения нет, и приходится разрабатывать отдельный сервис для вызова контрактов.



Разрабатывая контакты-шаблоны для платформы MyWish мы сразу столкнулись с этим ограничением. И мы задались целью, обойти это ограничение «красиво» — при помощи децентрализованного решения. Это система должна приводить контракты в действие, и поэтому решили назвать его Joule, в честь английского физика Джеймса Джоуля.



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

keccak (sha-3). Значением тоже является 256-и битное число (компилятор позволяет положить в состояние и большего размера значения, добавляя к ключу параметр смещения). Таким образом контракт может хранить 2^256 уникальных значений по 256 бит каждое, что во много порядков превышает потребности.



Хранилище ключ-значение можно рассмотреть как область памяти с произвольным доступом размерностью 2^256. В таком случае ключ является ссылкой на ячейку памяти. Структура данных, необходимая для хранения регистрации вызова, состоит из следующих полей: адрес контракта, момент вызова контракта, число газа необходимое для вызова контракта и стоимость газа. Все эти данные можно уместить в 256 бит (32 байта):



Система вызова смарт-контрактов в блокчейне Ethereum



Ограничения



Используя данную структуру хранения данных необходимо принять некоторые ограничения:




  • Address — 20 байт (адрес в сети Ethereum).

  • Timestamp — 4 байта, стандартное значение Unix Time, действующее от 1970-01-01 00:00:00 по 2106-02-07T09:28:15 (для беззнаковых величин). Простыми словами — максимальный срок регистрации — 2106 год. В будущем можно увеличить эту величину до 6812 года за счет использования лишнего байта от поля под величину газа.

  • Gas — 4 байта, но на самом деле сеть позволяет сделать одну транзакцию не более чем на 4 600 000 газа. С учетом затрат газа на работу системы Joule в момент вызова контракта сейчас прописано ограничение на 4 млн газа на 1 контракт. Хотя, конечно, для работы Joule не нужно 600 000 газа — в среднем достаточно 50 000 газа.

  • Gas Price — 4 байта. Предполагаемая при регистрации стоимость газа. Хранится данная величина в gwei (10^9 wei), поэтому минимальный размер это 0.000000001 ether, а максимальный — 4.294967296 ether.



Хранение цепочки записей



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



Для хранения списка в соотношении применяется следующая технология: значение записи (32 байта) рассматривается как ключ (или ссылка, если проводить аналогию с языком С++) на следующее значение.



Система вызова смарт-контрактов в блокчейне Ethereum



На изображении слева представлены записи регистрации R и функции получения ключа Система вызова смарт-контрактов в блокчейне Ethereum в виде цепочки значений. Справа представлено хранилище ключ-значение в виде таблицы. Видно, что значение Система вызова смарт-контрактов в блокчейне Ethereum теряется, из-за того что оно лишь является ключем к следующему значениею. В контракте нет возможности прочитать ключ из соотношения. Для этого в таблице присутствует нулевая запись (Head), которая всегда указывает на значение начала цепочки.



Порядок записей в цепочке — обратный хронологическому, для мгновенного получения следующего к вызову контракта. Одинаковые по времени регистрации упорядочены друг за другом в порядке добавления.



Индекс



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



Система вызова смарт-контрактов в блокчейне Ethereum



При таком подходе поиск элементов по дереву дает константное значение сложности, не зависящей от числа элементов в девере Система вызова смарт-контрактов в блокчейне Ethereum. Есть худший сценарий, который в текущей реализации составляет 168 переборов. Баланс дерева можно подобрать, меняя число уровней и множители.



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



Размещение и компоненты



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



Для решения данных проблем, контракт Joule разделен на несколько отдельных контрактов:



Система вызова смарт-контрактов в блокчейне Ethereum



Экосистема Joule состоит из следующих контрактов:




  • Joule — контракт, реализующий ключевую логику регистрации и вызова контрактов

  • Proxy — контракт с функцией фронт-контроллера, для доступа к функциям Joule. Proxy принимает регистрации, вызовы, и с его адреса происходят вызовы зарегистрированных контрактов. Любое взаимодействие с Joule со стороны пользователей (не зависимо от роли пользователя) происходит через Proxy.

  • Vault — хранилище средств, для компенсации вызовов.

  • Register — контракт, хранящий цепочку записей с регистрациями.

  • Index — контракт, для быстрого поиска места в регистре для вставки нового контракта.

  • State — контракт, реализующий базовые функции хранения. Используется контрактами Index и Register.



Такая архитектура позволяет изменять логику Joule, не теряя данных. Не нужно данные переносить или копировать. Не нужно делать механизмы для перевода средств (которые могут быть уязвимы к хакерским атакам).



Использование Proxy контракта упрощает интеграцию с системой Joule для внешних разработчиков. Им не нужно менять адрес контракта, если в Joule произойдут изменения. Упростится проверка в зарегистрированных контрактах, что вызов идет именно от Joule.



Использование



В данной части опишем то, как можно пользоваться получившейся системой.



Майнинг



Любой пользователь сети, имеющий адрес и достаточное количество средств для произведения вызова может приумножить свои средства при помощи Joule.



Для этого достаточно в нужный момент произвести транзакцию с вызовом к Joule (метод invoke или invokeOnce). В процессе выполнения транзакции Joule переведет вызывающему вознаграждение, которое было зарезервировано при регистрации контракта.



Момент, когда следует делать вызов можно легко определить при помощи метода getTop. Этот метод возвращает актуальное состояние очереди в Joule: время ближайшего вызова, минимальный газ, сумму вознаграждения по каждому контракту и другие значения.



Размер газа на транзакцию, который указывает майнер должен быть не меньше величины указанной в поле invokeGas для ближайшего контракта. Газ можно назначать с запасом — неиспользуемый газ вернется обратно (средства на него не будут списаны). Бывают случаи, что в очереди на выполнение находится несколько контрактов готовых к вызову. В таком случае, лучше выставлять газ равный сумме газа всех контрактов. Тогда (в случае метода invoke) будут вызваны несколько контрактов одной транзакцией, и майнер получит вознаграждение за каждый.



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



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



Регистрация своих контрактов



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



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




  • Address — адрес контракта, которой необходимо вызвать.

  • Timestamp — момент времени в формате unix timestamp в который вызов должен быть произведен. Важно понимать, что Joule гарантирует только то, что вызов не будет произведен ранее данного момента.

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

  • GasPrice — предполагаемая стоимость газа для вызова контракта.



В транзакцию вместе с вызовом register необходимо передать сумму в эфирах для вознаграждения за вызов. Точную величину суммы можно узнать при помощи метода getPrice. В случае, если будет передана избыточная сумма — остаток будет возвращен вызывающей стороне.



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



В случае успешной регистрации Joule публикует событие Registered, при помощи которого можно увидеть все свои регистрации.



Оба вида взаимодействия можно реализовать напрямую, работая с контрактом через клиент сети Ethereum, например Parity или Geth (Mist).



Также для удобства работы Joule имеет веб-интерфейс, позволяющий сделать вызов или зарегистрировать свой контракт использую лишь браузер с установленным в нем расширением, таким как Metamask или вообще без расширения, например, через MEW.



Вывод



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



Код Joule доступен на github.

Источник: Хабрахабр

Категория: Программирование » Game Development

Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

Добавление комментария

Имя:*
E-Mail:
Комментарий:
Полужирный Наклонный текст Подчеркнутый текст Зачеркнутый текст | Выравнивание по левому краю По центру Выравнивание по правому краю | Вставка смайликов Выбор цвета | Скрытый текст Вставка цитаты Преобразовать выбранный текст из транслитерации в кириллицу Вставка спойлера
Введите два слова, показанных на изображении: *