Хабрахабр

Простые и мощные краткосрочные смарт-контракты

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

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

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

Вы разработали сайт, выложили его в интернет, а провайдер прописал в DNS, что по адресу www.company.com находится определённый веб-сайт. Сравним контракт с веб-сайтом. Выкладку контракта в сеть Ethereum можно рассматривать схожим образом: вы разработали код, поместили его в сети (то есть послали специальную транзакцию «создай контракт») — и у контракта появился свой собственный адрес в Ethereum, в точности такой же, как адрес, который вы отдаёте кому-либо, чтобы он переслал вам эфир.

При этом у «сайта» в Ethereum есть полезные для смарт-контрактов свойства:

  • Код «сайта» нельзя изменить. Максимум можно прибить его, если заранее запрограммировать возможность «гибели» контракта при получении специального сообщения. Это не значит, что код исчезнет или смарт-контракт будет стёрт. Просто любая отправленная в него транзакция вернёт ошибку.
  • Каждый запрос к «сайту» — неоспоримая транзакция, навсегда сохраняемая в блокчейне. На ICO вы внесли один эфир и получили десять токенов — внутри контракта появилась запись о том, что у вас есть десять токенов. Ваш запрос изменил состояние контракта. Каждая такая транзакция уже неоспорима технически. Вы всегда сможете доказать, что транзакция была и её подписали именно вы (если есть нужный секретный ключ).
  • Каждый запрос от пользователя на «сайт» может содержать любое количество средств. Если мы рассматриваем контракт как сайт, то каждый запрос к «сайту» способен нести в себе эфир. Представьте себе сайт, где вы можете к каждому клику по кнопкам приложить любое количество денег, а сайт при этом понимает, сколько ему прислано, умеет отдавать сдачу и т. д.
  • Каждый запрос виден всем. Вы не можете ограничивать видимость запросов к «сайту». Вы послали запрос в смарт-контракт, а во время исполнения что-то сломалось — для Ethereum это штатная ситуация, и транзакция, вызвавшая ошибку, всё равно будет помещена в блоки, а майнеры всё равно получат свою комиссию за исполнение кода контракта (из вашего эфира, естественно).

Не забываем также, что каждая отправленная в блокчейн транзакция — это данные, подписанные электронной подписью со всеми её преимуществами (как минимум с подтверждением авторства). После того как сеть «принимает» код нового контракта (все майнеры проверили код, поместили в блоках, замайнили блок, опубликовали его в сети), контракт получает собственный адрес и может принимать транзакции. Говоря простыми словами, дело в отсутствии shared secret, известного двум сторонам. Зачем здесь блокчейн? В случае блокчейна единственный секрет — это ключ на клиенте, всё остальное не требует ни защищённых каналов связи, ни авторизации. PIN, голый хеш пароля, небезопасная web-сессия — всё это примеры того, чем может воспользоваться атакующий. Блокчейн фиксирует любую операцию, которая что-то изменяет внутри хранилища каждого помещённого в сети смарт-контракта. Ну, добавим ещё то, что ни одна из сторон не может сделать что-то незаметно для другой: каждое изменение состояния контракта фиксируется, даже неудавшиеся или зловредные транзакции. При этом операция может быть простой, а может делать и довольно сложные вещи, и любой участник сети абсолютно уверен в том, что код контракта у всех участников работает в точности так же, как и у него на машине.

Их крайне удобно использовать почти в любых проектах, так как из коробки мы получаем всю систему безопасности и отказоустойчивости. Даже в минимальном варианте (в краткосрочном виде) смарт-контракты — великолепные инструменты для учёта. Как мы увидим далее, порой даже минимума штатных функций достаточно, чтобы реализовать множество интересных задач.

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

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

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

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

Рассмотрим пример компании, в которой вы раздаёте доли: 10 % Васе, 10 % Пете, а вам — 80 %. Другой пример долгосрочного контракта — Equity (долевое владение). Equity делит деньги на потоке, распределяя входящие средства, и позволяет участникам неоспоримо получать свои доли, заодно фиксируя все платежи и суммы. Вы хотите, чтобы вся прибыль компании распределялась соответственно: если зашло 100 рублей, Васе и Пете достаётся по 10, а вам — 80. А ведь планируется, что компания будет работать долго, поэтому вы один раз просите программиста, чтобы он выложил в сеть ваш контракт, а потом годами без дополнительных усилий спокойно пользуетесь контрактом, иногда перераспределяя доли.

Они живут недолго (часы, дни) либо проводят мало операций (одиночный платёж, пару фиксаций событий). Краткосрочные контракты. Например, продавая стиральные машины, можно разместить в сети по контракту на каждую машину. Эти контракты заточены под отдельного пользователя, отдельную сделку или отдельный товар. От short-term контрактов нам нужен только одноразовый ввод-вывод средств с нужными проверками и фиксация события в блокчейне. В такой контракт заходит пользователь, один-два раза что-то делает (переводит средства, подтверждает что-то) — и после этого взаимодействие заканчивается. Нам, в общем-то, необязательно в неё что-то вкладывать: у неё уже есть подпись отправителя и время закрытия блока. В минимальном варианте любая транзакция, с эфиром или без, это сама по себе информация.

Получилось провести транзакцию — значит, покупка совершена. Если контракт умеет только принимать и отдавать фиксированное количество средств (и выдавать, например, сдачу), то любая успешная транзакция становится аналогом кассового чека, а блокчейн — удобным хранилищем данных об операциях. Это вообще избавляет магазины от необходимости иметь кассовые аппараты, теперь их забота — регистрировать ключи и адреса, принадлежащие магазину, и обеспечивать их безопасность и возможность смены при взломе. Показав ETH-адрес магазина в ФНС, можно пояснить: «Вот наши чеки и наши продажи». Также можно без особых проблем парой строк реализовать уплату налога прямо при покупке, было бы куда платить.

То, что контрактов много и они мелкие, сильно повышает стоимость помещения в сети Ethereum, ведь это довольно дорогая операция. У одноразовых контрактов есть преимущества и недостатки. Рисков, связанных с безопасностью, намного меньше в силу простоты кода и малого количества данных. Но зато контракты отвечают за относительно небольшие суммы, их существенно легче заменить, попросту перейдя на новую версию. Есть ещё несколько моментов, но о них позже. Простота кода также означает дешевизну для пользователей.

В качестве примеров опишем, скажем, три типа простых краткосрочных контрактов:

  • invoice-paid;
  • commit-reveal;
  • one-time multisig.

Поехали. Первый — это аналог выставленного счёта на оплату, второй позволяет «пообещать отдать деньги» и «позволить их забрать, доказав выполнение задания», третий — решить спор, «чьи деньги», с помощью арбитра.

Представьте, что мы продаём арбузы. Фактически перед нами ценник. После этого нам нужно, чтобы ценник либо принял 1 ETH, либо «сгнил» через сутки: возможно, на следующий день мы захотим продать арбуз за 2 эфира. Мы выпускаем ценник прямо под конкретный плод с конкретным весом, наклеиваем на арбуз и пишем: «Стоит 1 ETH».

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

В блокчейне сохранилась транзакция, а анализируя транзакции из контрактов, созданных магазином, легко получить всю историю продаж. Когда кто-то хочет купить товар, он присылает эфир в наш одноразовый контракт, а тот, в свою очередь, пересылает эфир на ETH-адрес магазина, отсылает сдачу (если нужно) и закрывается. В момент покупки контракт в том числе может платить налог или комиссии тому, кто привёл в него клиента.

Поэтому мы и назвали контракт invoice-paid: это два рабочих состояния, в которых он может находиться. Ещё одна довольно близкая аналогия такого контракта-ценника — выставленный счёт. Третье состояние, когда истекло время жизни (TTL — time-to-live), стандартно для всех краткосрочных контрактов. В режиме invoice он ждёт оплату, в режиме paid принял оплату и ничего не делает. Истекшее TTL заставляет контракт самоуничтожиться или попросту игнорировать любую пришедшую транзакцию.

В этом случае контракт принимает эфир строго с заданного адреса. Можно поместить полезные данные в invoice-paid, например выставить такой invoice конкретному адресу прямо в момент, когда покупатель решил приобрести товар. В контракт можно добавить хеш любых данных: фотографии товара, id’а объявления на Avito, архива с пакетом документов и т. п.

Эта схема в блокчейне используется для того, чтобы пообещать что-то сделать и потом доказать, что дело сделано.

Такая нода может создать собственную транзакцию с большей комиссией, которую block-producer’ы с большей вероятностью включат в блок и которая встанет в списке транзакций выше, чем исходная. При отправке транзакции в сеть любая нода, передающая транзакцию по p2p-сети, может проанализировать содержимое транзакции до того, как она будет включена в блок. Играть в неё, напрямую отправляя транзакции, в данном случае нельзя. Давайте вспомним игру «камень, ножницы, бумага». Понятно, что я не отправлю «ножницы» в контракт: мой оппонент может подсмотреть публичную транзакцию и создать свою, с «камнем».

Для этого мы отправляем в контракт сначала хеш от слова «ножницы» (я), затем хеш от слова «бумага» (мой оппонент). Решение задачи — в схеме, когда доказывающая сторона (в нашем примере их две, я и мой оппонент) «обещает» в будущем показать некоторое значение, пока секретное (наши «ножницы» или «бумагу»). Обмануть тут уже не получится: я открою «ножницы», только когда увижу хеш решения оппонента, то же самое касается его. Только затем я могу открыто опубликовать «ножницы», а оппонент — «бумагу». Смысл этапа размещения хешей хорошо передаёт слово commit, а этапа раскрытия значений — reveal, отсюда и название.

От криптостойкости числа зависит возможность «угадывать» выбор оппонента по опубликованному хешу, поэтому к его генерации надо подходить со всей серьёзностью. Обязательно надо отметить, что перед вычислением хеша строка («ножницы» или «бумага») обязательно дополняется случайным числом. Это число — временный секрет, оно опубликовывается вместе со строкой на этапе reveal, чтобы участники могли проверить корректность хеша.

Магазин посылает курьера вместе с товаром к клиенту и хочет, чтобы курьер получил оплату, только если доставит товар за три часа и вручит его лично клиенту. Давайте рассмотрим вариант контракта commit-reveal для оплаты курьерской доставки. Магазин выдаёт курьеру (в его мобильное приложение или браузер) адрес контракта, и курьер видит, что за три часа сможет забрать оплату, если узнает секретное слово. Для этого магазин генерирует секретное слово, создаёт контракт, помещает в него хеш слова и время (три часа), после которого магазин сможет просто вернуть свои средства, отправив транзакцию refund в контракт. Логику контракта описывает фраза «Если курьер пришлёт в течение трёх часов слово — прообраз хеша, использованного при создании контракта, я высылаю средства курьеру». Само слово магазин отправляет по SMS клиенту.

При конфликте с покупателем магазин может сам разблокировать средства для курьера, попросту отправив тому секретное слово.

Но основная схема commit-reveal — базовая для построения удобных протоколов взаимодействия бизнес-агентов. Разумеется, для реального использования контракты содержат ещё и модификации — дополнительные данные и проверки, комиссии, пороги входа, динамическое изменение стоимости доставки и т. п.

Этот контракт — адрес, с которого можно вывести средства, предоставив N из M подписей.

Хочется, чтобы контракт принимал и хранил средства, но не давал выводить их из контракта, пока не получит как минимум два из трёх подтверждений — от мужа, жены или банка. Предположим, муж и жена решили держать часть семейных сбережений в криптовалюте. В обычном режиме средства выводятся из контракта, когда и муж и жена предоставили свои подписи. Если у жены украдут телефон, муж сможет пойти в банк и, получив подпись банка, вывести деньги. Это крайне удобно, ибо взлом одного из участников не грозит несанкционированным выводом средств.

Когда покупаешь квартиру и банк отдаёт ключи от ячейки, только когда получает документы на недвижимость, — это и есть multisig 2/3. Вообще multisig может оперировать произвольными N и M, но его вариант «два из трёх» покрывает огромное количество бизнес-задач, где требуется третья сторона. Банк, как только видит договор о смене собственника, ставит свою электронную подпись. Деньги кладутся на multisig-адрес, где участвуют продавец квартиры, покупатель и банк. Для единичных задач, оперирующих большими суммами, разумно использовать именно одноразовые контракты. Такой контракт также включает в себя ограничения по времени и, конечно же, комиссию для банка. Уязвимость в огромном универсальном контракте, который будет управлять всеми аккредитивами, может привести к куда более серьёзным последствиям, нежели успешная атака на одноразовый контракт.

Вообще multisig — это как автомат Калашникова, с помощью краткосрочных multisig 2/2 и 2/3 легко реализуются сделки с escrow, сделки, требующие коллективного решения, а дальнейшее добавление функционала в multisig и динамическое изменение N и M — это уже переход к долевому голосованию и управлению (но это тема для отдельной статьи).

  1. Простота и, как следствие, безопасность. В Solidity приходится думать буквально над каждым шагом, любая операция стоит газа, каждый лишний вызов внешнего контракта — это потенциальная уязвимость, именно здесь кроется большое количество проблем с безопасностью. Краткосрочный контракт содержит мало кода и не требует взаимодействия с другими контрактами, поэтому более безопасен, чем его старший долгосрочный брат.
  2. Чем меньше кода, тем дешевле. Дешевле публиковать, разрабатывать и писать под него тесты. У простого контракта более простой и унифицированный интерфейс, который можно спокойно выставлять наружу в любом конструкторе. Это позволяет другим разработчикам работать с вашими смарт-контрактами, легко приспосабливая их под свои нужды.
  3. Краткосрочные смарт-контракты легко переносить на другие блокчейны. Если вы делаете простой краткосрочный смарт-контракт, то, скорее всего, сможете реализовать его безо всяких проблем на графене, EOS и других платформах. Простая логика — больше вероятность, что это уже реализовано в конкурирующих движках, а значит, разработка дешевле и контракт надёжней.
  4. Очень удобно фиксить. Дыра в токене — серьёзная проблема. Придётся заменять токен и перетаскивать баланс — это стоит огромное количество газа. В случае краткосрочных версий мы не контракты деплоим, а фиксим их версию, а потом просто ждём, пока плохие контракты «сгниют» и будут заменены новыми версиями.
  5. Правильно уничтожая контракты, мы будем чистить local storage на клиентах, оптимизируя используемое место. Тут пока ещё тонкий момент, удаляет ли selfdestruct контракта из storage db физически на клиенте, но, по идее, должен. Это позволит не раздувать сильно объём блокчейна.
  6. TTL. Если мы ищем по блокчейну контракты-ценники и знаем, что они живут не больше суток, то поисковик по Ethereum можно настроить на работу лишь с блокчейном за последние сутки. Это делает такие поисковики удобными и быстрыми, так как данных немного, а работающие с краткосрочными контрактами сайты очень быстрые и функциональные. В противном случае шерстить сотни гигабайт блокчейнов, делая tracking тысяч аккаунтов — непростая задача для программистов.

Первая проблема — газ. Не бывает всё очень хорошо. Сервис, которые «пуляет» десятки тысяч контрактов, требует серьёзного исследования и балансировки. На каждый деплой смарт-контракта придётся тратить газ. А иногда надо ставить 50 Gwei за газ и ждать час. В Ethereum сегодня можно послать транзакцию при цене газа 5 Gwei, и она прилетит за минуту. Выкладка контракта в сеть — процедура дорогая, поэтому краткосрочные контракты — удовольствие недешёвое. Те, кто используют смарт-контракты, не очень рады росту курса эфира, ибо это означает удорожание отправки контрактов в сеть.

Проблема стоимости исполнения — это их общая проблема. Мы рассматриваем не только Ethereum и на своей платформе планируем использовать сразу несколько сетей, работающих со смарт-контрактами. Кроме того, скорее всего, различаться по стоимости будут даже одинаковые типы операций, так что я не исключаю появление стратегий типа «выполняем контракты с криптопреобразованиями в одном блокчейне, а со строковыми операциями — в другом». Рано или поздно она решится — либо конкуренция за стоимость исполнения одной строки контракта сильно понизит стоимость.

Мы «пульнули» смарт-контракт, заплатили за него, а он умер в блокчейне, ничего не сделав. Вторая проблема — мёртвые, но не добитые selfdestruct’ом контракты. Возможно, скрипты-«дворники» за небольшую комиссию будут вызывать selfdestruct у контрактов с просроченным TTL. Это нехорошо для state-database, и мы размышляем, что бы такого придумать. 🙂

Управление таким количеством смарт-контрактов, их деплой, мониторинг требует серьёзной надстройки вокруг Ethereum и остальных блокчейнов. Третья проблема — сложная инфраструктура для отправки контрактов в сеть. Всё это весьма серьёзная история с точки зрения и безопасности, и архитектуры. Это и поисковик по блокчейну, и автоматический деплоер, и очереди для управления push’ами для мобильных клиентов, а также управление фондами с большими суммами эфира, адресами и ключами.

Строительство платформы, которая сможет поддержать запуск большого количества различных типов контрактов, не жертвуя при этом безопасностью и децентрализацией, уже идёт — это наш проект Smartz.io. Итак, мы рассмотрели некоторые особенности смарт-контрактов, описали несколько кейcов и немного порассуждали о проблемах и решениях. Будем знакомы 🙂 Разработчикам и небольшим командам платформа дает возможность заработка при размещении своих DApp-ов, а простым пользователям она предоставляет удобный способ в несколько кликов запустить и начать использовать один из множества полезных DApp-ов для персонального использования.

Показать больше

Похожие публикации

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»