Всем доброго времени суток! Я достаточно давно занимаюсь Backend разработкой и последние несколько лет, все больше и больше пишу разные блокчейн проекты (Solidity на EVM). Погружение в блокчейн мне давалось непросто и мой бэкендерский мозг несколько раз ломался, и я решил поделиться своим взглядом на погружение в блокчейн-разработку.
У этого поста, также, есть видео - версия: https://youtu.be/1Rw9zKaU0Mc
![](https://habrastorage.org/getpro/habr/upload_files/f62/eb1/06d/f62eb106d3714666b884330eb3fb6374.jpg)
Пост получился большой, поэтому начну с навигации:
Коротко про сам блокчейн, что это такое в моем понимании, и с чем я его ассоциирую.
Особенности блокчейн-разработки глазами бэкенд-разработчика.
Бэкендом занимаюсь уже около 10 лет и бэкендерскому мозгу было непросто изначально понять какие - то вещи в блокчейн-разработке.Основные термины.
Как и в любой другой технологии стоит понимать базовую терминологию.Боли и неприятности.
Проблема блокчейна в том, что там все завязано на деньги. Если я выкатил hello-world сервис в прод с уязвимостями, то я мало чем рискую. А hello-world проект в блокчейне, который идет в прод, уже связан с деньгами и риском их потерять. Я терял деньги — свои и клиентов и не хочу, чтобы теряли вы.Заключение
Дисклеймер: все описанное далее исключительно мое мнение. Могу ошибаться и ошибаюсь регулярно:)
Блокчейн — очень крутая технология, которая реально может подвинуть наш мир немножко вперед. Но пока ей много кто пользуется для купи-продай-обмани-наварись. Я не буду и не планирую рассматривать крипту как актив.
Да, есть куча разных роликов и постов, которые рассказывают про “вот, такая - то крипта сейчас может вырасти, такая крипта упала. Ребят, давайте инвестируем, закупаем...” Я вам про это ничего рассказывать не буду.
Скажу лишь одно — крипту для заработка стоит обходить стороной. Если вы разработчик, то лучше пробуйте зарабатывать как разработчик, не надо лезть в инвестиции. А если уж очень хочется в инвестиции, то не в крипту.
Про блокчейн и почему это интересно
Стоит начать с важного. Блокчейн — это не криптовалюта. Блокчейн - это технология, на которой построена криптовалюта, но называть криптовалюту блокчейном всё равно, что всю индустрию разработки называть словом “Javascript”. Да, вроде бы JavaScript - это частный случай разработки, но когда мы говорим про разработку, мы не имеем в виду именно JavaScript. Хотя есть люди, которые имеют в виду только JavaScript…
Идти в блокчейн за деньгами
![](https://habrastorage.org/getpro/habr/upload_files/d4f/a9f/695/d4fa9f6954da87417b2f12e6c6265613.png)
Первое, что приходит в голову - это деньги. Блокчейн-разрабам платят довольно таки хорошо. Я лично сам открывал такие вакансии, сам лично откликался на подобные вакансии, где за такой же объем времени, проведенный в сутки за работой, можно получить больше, чем тому же backend-разрабу. Блокчейн-разработчики в стартапах, которые построены на базе блокчейна, на вес золота. Особенно хороший блокчейн-разработчик!
Что такое хороший БЧ-разработчик?
Вряд ли можно стать хорошим backend-разработчиком, ниразу не уронив и не починив прод. Возможно, я просто неудачник и учусь только через негативный опыт, но у меня такая теория:
Если бэкендер опытный, то он точно запускал решения в прод
Если он запускал в прод, значит знает как это запускается и знает, что бывает с продуктом под нагрузкой
Если он держал сервисы под нагрузкой, то точно ловил даунтаймы и падения сервисов
А если он ловил падения сервисов, то возможно их и поднимал.
Опытность фэйлами не изменишь, но опыт фейловых ситуаций позволяет дать понять, что опыт имеется.
Тяжело стать хорошим бч-разработчиком, не потеряв деньги:
если с моего контракта еще не воровали деньги, значит я не запускал что - то с реальными деньгами (чтобы на контракте лежала хотя бы $1000)
если я не запускал что-то с реальными деньгами или запускал только на тестовых сетях (с фэйковыми деньгами), то я понятия не имею, что меня ждет в реальном токсичном мире блокчейна
если я не знаю, что меня ждет, то я основательно обожгусь при первом запуске и тут вопрос команды/компании, которая готова взять на себя риск быть первым плательщиком за мой косяк.
Идти в блокчейн ради технологии
![](https://habrastorage.org/getpro/habr/upload_files/8ae/a58/25f/8aea5825f74c1bc775754c6bf8ebb1ca.png)
На изображении выше изображен первый в мире самолет братьев Райт, и полетел он довольно таки плохо. Но он полетел, и в свое время отношение к самолетам у обычного человека было примерно такое:
дорого
неудобно
непонятно зачем
А сейчас авиаотрасль — прекрасная часть нашей жизни, соединяющая людей по всей планете на расстоянии нескольких часов. Логистика сейчас на том уровне, на котором и не снилась самим братьям Райт! Весь мир живет иначе благодаря самолетам.
Про блокчейн сейчас я скажу тоже самое — это дорого, неудобно и непонятно зачем. Пока не погрузился в бч-разработку для меня действительно это выглядело чем-то бесполезным для обмана инвесторов (=стрижки хомяков). Но если посмотреть на это с другой стороны — это возможность децентрализованно хранить любые факты без возможности их подмены. “без возможности подмены” — важная деталь.
Но, увы, ассоциации со словом “блокчейн” достаточно скучны и однообразны:
биткоин
инвестиции
скам
эфир, рипл, {подставьте название монеты}
пузырь, который скоро лопнет
Ну и классический мем:
![](https://habrastorage.org/getpro/habr/upload_files/84b/f67/bf4/84bf67bf4e74654d34b20e842493d7a2.png)
Мне вспоминаются слова великого умного человека - Менделеева, который сказал такую фразу:
"Сжигать нефть, это всё равно, что топить печку ассигнациями" Менделеев Д.И.
Если мы возьмём пачку денег бумажных, кинем в печку, печка хорошо разгорится, и деньги даже какое-то время будут давать тепло. Но это абсурд.
Так и с блокчейном. Использовать его только для денег и крипты — плохо, но другое пока не приживается… Одним из главных двигателей любого развития продукта являются деньги. Если есть на чем-то можно хорошенько и мощно заработать, то это "что-то" будет активно развиваться. И поэтому, пока что, на базе блокчейна, по-настоящему, живут финансовые проекты, которые базируются на том, чтобы деньги кому-то заработать, а кому-то потерять.
Теория
Децентрализация
В чем отличие централизованного от децентрализованного сервиса? Давайте сначала рассмотрим централизованный. Есть я и еще кто-то, и мы решили сделать между нами сервис. Пусть это будет банк или вообще любой другой сервис, для того, чтобы мне, другому человеку, чего-то через сервис передать.
![](https://habrastorage.org/getpro/habr/upload_files/87e/bbd/b46/87ebbdb46abcfd55ccc9e0582b32b534.gif)
Давайте представим, что у нас есть банк, который является централизованным сервисом. Я дальше в этот банк отправляю команду: "Переведи, пожалуйста, этому кому-то 100 рублей". Банк у себя фиксирует, что у меня стало на 100 рублей меньше, а у кого-то на 100 рублей больше.
Но в чем проблема централизованного сервиса? За этим централизованным сервисом есть какой-то владелец, да? Обычно какие-то крупные компании, холдинги, неважно, в нашем случае пусть будет один человек. Этот один человек может такое сказать: "А давайте-ка сделаем так, пусть Антон отправит 100 рублей, но при этом эти 100 рублей никто не получит. Мне они нужнее”.
![](https://habrastorage.org/getpro/habr/upload_files/042/d2a/2fa/042d2a2fa6464d2843eeab02d8f81f3b.gif)
Централизованные сервисы имеют своих владельцев. Проблема заключается в том, что владелец может принимать негативные решения, забирая деньги. Причем это может быть не только “забрать деньги себе”. Например, можно написать “у нас есть в банке 100500 рублей” и надеяться, что все вкладчики не пойдут за этими деньгами… как это было с SVB и другими погибшими недавно банками.
Bitcoin, как раз-таки, и был изобретён для децентрализации управления деньгами.
![](https://habrastorage.org/getpro/habr/upload_files/dbf/f91/08c/dbff9108c9f9f37aebc8716e7f1fb73b.gif)
Децентрализованный сервис строится на сети узлов, где каждый узел хранит и передаёт информацию. То есть, простыми словами, узлы договорились о том какая информация считается верной, а какая нет, и как мы ее храним.
Можно провести аналогию с комнатой — один человек кричит информацию, которую хочет, чтобы остальные сохранили. Далее уже каждый участник комнаты работает с той информацией, что сохранил после крика.
Например, блокчейн может хранить и передавать сообщения или информацию о переводах денег. Участники сети проверяют информацию перед её записью.
В аналогии с комнатой я кричу “я перевожу 100 рублей Васе”. Каждый у себя записывает, что у меня стало на 100 рублей меньше, а у Васи на 100 рублей больше. Если вдруг, перед переводом, у меня будет меньше 100 рублей, то никто эту транзакцию себе не запишет.
![](https://habrastorage.org/getpro/habr/upload_files/c45/d5a/c85/c45d5ac856d717094ea5165e7eada6e6.gif)
Смарт-контракты?
В блокчейне можно создавать смарт-контракты на языке Solidity (в случае блокчейна на EVM). Смарт-контракт - это программа, которая выполняется в сети блокчейна. Он может содержать механизмы проверки, обработки ошибок и другие функции.
![](https://habrastorage.org/getpro/habr/upload_files/bfb/c98/9e2/bfbc989e23a82b8197b9b5ccb03d315b.png)
Опять же, в случае с комнатой где мы кричим команды, смарт-контракт - это я заранее каждому участнику в комнате передал код программы: как реагировать на мои команды, что проверять и что сохранять. И потом уже кричу “выполните программу с такими-то параметрами”. Дальше каждый уже исполняет инструкции.
Пример простого смарт-контракта - хранилище информации с функциями добавления и получения данных. Код контракта компилируется в байт-код и передаётся участникам блокчейна для выполнения.
![](https://habrastorage.org/getpro/habr/upload_files/922/a05/f0a/922a05f0ac2529fe955f3b56a3e4fc6b.png)
Как обрабатывать те или иные запросы, которые будут отправлены к этому смарт-контракту? Если проводить аналогию с бэкендом, то это сервис, который может обрабатывать запросы POST и GET. POST сохраняет информацию. GET тут информацию, которую мы сохранили, передает обратно. Обычно так устроен любой бэкенд.
![](https://habrastorage.org/getpro/habr/upload_files/d8a/59c/d89/d8a59cd895db5d1c43a800f8bca5888c.png)
За время моей разработки на бэкенде я очень сильно привык к раскладу, что апишка, база данных и все что связано с хранением и обработкой данных происходит на моей стороне. А я уже, словно за стеной, предоставляю пользователю интерфейс для работы с этими данными по заранее подготовленному сценарию.
Например, пользователь 1 приходит, сохраняет контент (пост, например) через метод POST. Дальше приходит пользователь 2 и забирает этот контент методом GET. Пользователи знать не знают, где и как это лежит — для них бэк - это черный ящик.
![](https://habrastorage.org/getpro/habr/upload_files/0cd/6aa/434/0cd6aa434c0cbd0767bce0f590f9a952.gif)
И тут мы подходим к одной очень важной части блокчейна. Давайте вернемся к нашим примерам с узлами или людьми, стоящими в комнате. Допустим, проводя аналогию с бэкендом, у нас каждый раз будет проходить следующее: я кидаю в блокчейн метод "ADD", и тогда каждый у себя локально вызывает метод и потом уже дальше может информацию из своей копии блокчейна забирать.
То есть получается у нас в сети появляется куча куча разных копий, из которых узлы забирают информацию. Неприятность блокчейна в том, что за каждую операцию записи мы должны отдавать реальные деньги. Платится за это валютой сети, которую можно купить за реальные деньги (или намайнить, но сегодня не об этом).
![](https://habrastorage.org/getpro/habr/upload_files/06c/d98/f00/06cd98f00530287fc40c7780088a9492.gif)
Если сравнивать между собой блокчейн и бэкенд, то картина следующая:
в обычных сервисах мы пишем бесплатно, читаем бесплатно и зависимо
в блокчейне мы пишем платно, читаем бесплатно и независимо.
Например, есть Telegram с централизованной БД. Мы всегда к ней можем бесплатно обратиться и выкачать свои сообщения, фотки, видео и тд. Но если вдруг “вырубить” сервера телеграма, то нам все это будет недоступно.
Для того чтобы виртуальная машина EVM выполнила какую-то команду смарт-контракта, в которой предусмотрена запись информации в блокчейн, то мы должны заплатить. Она выполняет какие-то расчеты, складывает что-то, умножает, перемножает, и в итоге появляется новый артефакт в хранилище блокчейна, который обновляется на всех нодах, участвующих в блокчейне.
Любой участник сети может запустить себе полную ноду, куда будет закачаны сотни гигабайт данных блокчейна и работать с ними локально. А можно пользоваться легковесной версии ноды, которая не будет хранить в себе весь блокчейн, но через нее можно будет обращаться к полноценным нодам в сети и извлекать нужную информацию.
Идея в том, что каждая запись в блокчейн представляет собой блок, в котором собрана пачка транзакций, в которых происходят изменения состояния блокчейна. Каждый следующий блок зависит от предыдущего цепочкой на основании алгоритмов хэширования.
В общем, базово, стоит иметь в виду — за каждый чих надо платить, если данные меняются. Кстати, деплой контракта — тоже запись в блокчейн и стоит недешево!
Деплой смарт-контракта
В мире бекенда я привык к примерно следующему жизненному циклу разработки фичи:
Написали код
Запушил в гитлаб
GitLab CI запускает тесты, все проверяет
Если все ок, то CI начинает разворачивать новую версию приложения на сервере
![](https://habrastorage.org/getpro/habr/upload_files/9f1/4e2/05c/9f14e205c5e3e05a8f0a5fad48e4ee75.png)
То есть мы привыкли работать так, и происходит это бесплатно. Хотя условно бесплатно, потому что за серверы мы всё-таки платим. А что же блокчейном?
В случае с блокчейном нам надо записывать новый код нашего “приложения” (смарт-контракта) в блокчейн. Выше я уже писал — за каждую запись нужно заплатить. Прежде чем делать транзакцию к своему смарт-контракту надо сделать транзакцию с размещением смарт-контракта.
Дальше уже сервер клиента\сервиса будет обращаться к какой-нибудь из нод для получения или сохранения информации в контракт.
![](https://habrastorage.org/getpro/habr/upload_files/5e6/336/211/5e6336211602e707adce976cd8dbef55.gif)
Есть огромное количество нод, которые нужно оповестить — “ребята, вот байт-код контракта, алгоритмы которого надо делать при моих транзакциях”. Обязательно надо сделать так, чтобы на всех нодах, которые учатся блокчейне, появился один и тот же код, который будет выполняться одинаково, независимо от того, кто вызывает, как его вызывает. Механика будет одна и неизменна. И более того, нельзя допустить того, чтобы на какой-то из нод смарт-контракт был как-то изменён и работал по-другому.
Ниже пример транзакции, в рамках которой я деплоил достаточно давно контракт в сеть ETH
![](https://habrastorage.org/getpro/habr/upload_files/bfe/c82/867/bfec828677b6fb32160f2572e730f1cc.png)
Это был тестовый контракт, который в бою так и не использовался. За его деплой было заплачено 200 долларов в эфирах. То есть мы еще ничего не сделали с этим контрактом — ни одного запроса, а 200 долларов уже потратили. Я до сих пор грущу, когда вспоминаю этот ошибочный деплой не того контракта…
На тему этого есть забавная картинка про CI в блокчейне.
![](https://habrastorage.org/getpro/habr/upload_files/470/888/a79/470888a798a707141d4e3bd66395602e.png)
Хранилище данных
Давайте поговорим про хранилище данных. Мы с вами все привыкли, что у нас на бэкенде есть PostgreSQL, MySQL, MongoDB, Redis и прочие другие сервисы, которые позволяют удобно работать с данными. В случае с блокчейном ничего подобного даже близко нет.
![](https://habrastorage.org/getpro/habr/upload_files/dbd/5b1/fd6/dbd5b1fd63346fed4eb4cbf65a2b8f6e.png)
В блокчейне хранилище реализуется, как переменные в классе на других языках. То просто key-value или массивы. Тут нет реляционных таблиц с удобными связями и тд. Просто — пиши в переменную и радуйся.
На момент сейчас я не знаю другого способа организации хранилища в блокчейне. Ну может быть ситуация уже изменилась, может быть, когда вы читаете это, такой способ уже есть — напишите в комментах.
Например, если мы хотим хранить не просто в массиве? А мы хотим информацию сохранять по ключу — для этого есть маппинг.
![](https://habrastorage.org/getpro/habr/upload_files/199/fe9/70b/199fe970b9e70cfd93f9602337ebb1a0.png)
Знак доллара нарисован неспроста — за каждый set будет браться комиссия сети.
Расчет комиссии
Как всё-таки формируется комиссия? Почему я заплатил 200 долларов за то, чтобы залить какой-то контракт? Как эта комиссия расчитывалась?
Для этого мы вводим новый термин. Есть такая условная единица комиссии, как газ. GAS - это количество попугаев, в которых измеряются те или иные арифметические и не только операции. Каждая сложная операция состоит из ряда примитивных операций. Стоимость каждой примитивной операции описана в ETH Yellow Paper.
Также есть термин GAS PRICE — стоимость одной единицы GAS в валюте сети. Возьмем кусок скрина выше, где я демонстрировал деплой контракта.
![](https://habrastorage.org/getpro/habr/upload_files/8f6/7b9/f5f/8f67b9f5fca12455155eb1537c17977c.png)
Это цена, которая сейчас колеблется на рынке, в момент текущего времени на каком-то уровне. Есть майнеры, которые указывают за какую стоимость они готовы делать те или иные арифметические операции, и эта стоимость определяется этими майнерами и теми, кто готов за это заплатить. Если есть майнер, который готов работать за цену поменьше, то все идут к нему.
Если я отправил транзакцию с GP (Gas Price) 20, а все остальные отправляют за 30, то мою транзакцию никто не возьмет, пока желающих “покупать” GAS за 30 не станет заметно меньше. В итоге я либо жду, либо сдаюсь и ставлю цену 30. Таких как я становится много и появляются те, кто за скорость готов отдать 35 и так раз-за-разом.
В сети ETH (самая дорогая на момент сейчас) транзакция спокойно может провисеть несколько дней, чтобы залить контракт на 100-200 долларов дешевле. На заре эфира GP стоил реально копейки — за 3 рубля можно было залить контракт и быть довольным результатом. Потом 3 рубля стали 4-мя, 5-ю и теперь несколько сотен долларов, иногда улетают в молоко, ради деплоя контракта.
Для того, чтобы быть уверенным, что у пользователя есть деньги, которые могут быть потребованы за газ, с пользователя сразу списывается GAS LIMIT по тому GAS PRICE, который пользователь выбрал. Деньги блокируются и дальше возвращается сдача из расчета потраченного газа.
Важные моменты про Gas Limit:
Gas Limit можно установить любой при отправке
При отправке с кошелька «холдится» GasLimit*GasPrice
Майнер выполняет операцию, считает сколько ушло GAS
На одну и ту-же операцию может потребоваться разное кол-во газа
Умножает Gas на Gas price и забирает себе комиссию
-
Если во время выполнения газа начало уходить больше чем GasLimit:
Выполнения транзакции останавливается
Все изменения хранилища в рамках этой транзакции откатываются
Деньги за газ никому не возвращаются
Пример расчета комиссии
Вернемся к контракту, который просто хранилище данных.
На его деплой 173 000 GAS
Вызов set один раз стоит 50 000 GAS
На странице с gas price берем среднюю стоимость. Умножаем количество газа на эту цену
В итоге получаем 0.004 ETH или около 7 долларов за эти действия. А действия эти достаточно примитивны. А иногда цена за газ подскакивает так, что выходит не 7 долларов, а 100 долларов или ждать пока цена за газ упадет.
Боли и неприятности
В этом блоке я пройдусь по тем вещам, которые меня удивили или возмутили. Их гораздо больше, чем в этом документе, но я поделюсь тем, что первое попало мне в моей практике.
Важно заметить, что большинство из “болей” являются вполне объяснимыми по каким-то логичным причинам. Но это не отменяет боли для моего бэкендерского мозга.
Например, я привык, что мы легко могу пройтись по всем элементам чего угодно. Не важно — массив это или объект или карта. В Solidity, для этой цели, придется хранить отдельно массив всех ключей и тогда, при необходимости, проходить по всем ним и по каждому ключу извлекать элементы из карты. Ну и на дополнительную запись в этот массив ключей и его инициализацию мы тоже тратим газ.
![](https://habrastorage.org/getpro/habr/upload_files/6e5/010/674/6e5010674df791aa59965b31ebfcfb8f.png)
Всякие удобные сортировки по ключам нам тоже недоступны. Ну либо доступны за газ…
Логгирование
Также неприятно дела обстоят с логгированием. Дебажить я привык через дебаггер в среде разработки, но тут стоит забыть даже про нормальное логгирование.
Если в Typescript я привык просто написать console.log(a)
и сразу получить в консоли вывод, то тут тоже есть console.log
, который работает только при запуске в локальной среде разработки hardhat. И, что прекрасно, после того как я раздебажил что нужно, то перед деплоем контракта надо все эти логгирования удалять, потому что иначе контракт весит больше и дороже его деплой и на проде это вообще не будет работать.
В итоге получается, что когда мы запустили проект уже в бой, мы хотим увидеть что не так, мы не можем увидеть, что пошло не так. Но мы можем увидеть, что пошло так. Есть система событий внутри смарт-контрактов. Вот, допустим, пример: мы хотим иметь событие того, что был добавлен новый элемент под таким индексом с таким-то значением.
![](https://habrastorage.org/getpro/habr/upload_files/2f1/35c/545/2f135c5456cdf42eab62af670e4266f8.png)
Мы внутри метода set
этот вызываем это событие и логи эти мы можем увидеть только при успешном выполнении. Если что-то пошло не так, или у вас там были множественные вызовы контрактов, если у нас транзакция упала, то логи тоже не сохранились, поскольку информация в блокчейне откатывается назад.
Если у вас произошло событие и после него упало в простом контракте, то тут информация в эксплорере будет видна.. Но в случае, если вас используется цепочки из нескольких контрактов, и допустим у вас есть в первом контракте вызвались одни события, потом вызывается второй контракт, который вызывает другие события, и потом все падает то, что было вызвано внутри второго контракта, будет удалено точно полностью раз и навсегда.
Надо быть очень внимательным, когда мы хотим логгировать происходящее внутри блокчейна, и иметь в виду то, что нормальное логирование, которое мы привыкли, нам здесь попросту не доступно.
![](https://habrastorage.org/getpro/habr/upload_files/2c6/302/6fa/2c63026fa02421362f24412ece3cc77f.png)
Еще одна неприятная штука: в операции записи мы не можем получить информацию из нашей транзакции. Если мы делаем операцию, в которой происходит запись чего-либо в блокчейн (то есть платная транзакция), то return
ничего не отдаст нашему сервису, который интегрируется с контрактом. Этот return работает только внутри самого контракта или во view
(бесплатных) функциях.
Например, мы бы хотели, чтобы, когда мы добавляем новое значение в наш блокчейн, мы могли захотеть узнать размер хранилища после сохранения (скрин выше). То есть мы можем только через события выяснять, что именно было добавлено. А для этого надо выдернуть события, которые были вызваны внутри этой транзакции.
Работа со строками
Тут для меня был прям сюрприз — работать со строками нормально нельзя. Блокчейн не был создан для строк. Перейдем к примерам.
Код ниже отработает без проблем.
![](https://habrastorage.org/getpro/habr/upload_files/81b/6c8/fc3/81b6c8fc3d9754920733dfd04df36009.png)
А этот код уже работать не будет:
![](https://habrastorage.org/getpro/habr/upload_files/edd/583/fca/edd583fca572b8f39075633a9218e721.png)
Я уже давно привык нормально работать со строками, менять символы в строках, разрезать строки, конкатенировать их — всего этого из коробки нет. Также нет возможности вывести длину строки. То есть такой код не скомпилируется:
![](https://habrastorage.org/getpro/habr/upload_files/e9e/4c7/4cd/e9e4c74cd974812eee3961116185905f.png)
Если вам уж очень нужна длина строки, то можно пойти через конвертацию в байты и потом считать количество байт. Но проблема в том, что некоторые спецсимволы в байты конвертируются не 1в1. А некоторые просто не конвертируются и транзакция может упасть.
![](https://habrastorage.org/getpro/habr/upload_files/1b0/0f0/b7b/1b00f0b7b8dce66c4d94c965231cc92c.png)
В итоге можно написать контракт, который работает со строками и проверить на обычных строках. А потом прилетит строка, которую не обработается и все будет падать или длина строки будет считаться неверно из-за особенных символов.
Вывод по строкам простой: со строками не работайте и не опирайтесь на строки внутри контракта. Если важно сохранить строки, то сохраняйте байты и опирайтесь на байты, а строки конвертируйте в байты уже на самом сервисе.
Проблема внешних вызовов
Следующая сложность, которая является продолжением основной фичи блокчейна — изолированность. Все данные, которые находятся в блокчейне, рождаются внутри блокчейна или же передаются ему из-вне. Но сам блокчейн никогда не сможет стучаться во внешний мир — только в другие контракты.
![](https://habrastorage.org/getpro/habr/upload_files/5e0/5ef/1b3/5e05ef1b3b8cf605089b22f0408ec834.gif)
Проблема заключается в том, что все команды смарт-контракта выполняются на каждом участнике сети. И доверять внешнему источнику нельзя, т.к. нельзя быть уверенным в том, что на каждой ноде будет получена одна и та же информация. Будет так, что на каждой ноде будет своя версия блокчейна с разными данными и цепочка блоков порушится.
И банальная задача “получить текущую температуру на улице” становится чем-то невозможным. Если погода нам нужна далеко не всегда, то некоторые данные (вроде курса валют или текущего состояния какой-то внешней системы) бывают остро необходимы. Решение заключается в следующем подходе:
![](https://habrastorage.org/getpro/habr/upload_files/818/596/14a/81859614af6fe974220a0b523680627f.gif)
У нас есть Operator Contract. С нашего сервиса туда отправляется задача вида “сделай-ка мне запрос на этот сервер с такими-то параметрами”
Контракт эмиттит событие (Event)
На это событие подписывается отдельный бэкенд, извлекает информацию из события, где сказано “куда и с какими параметрами отправить запрос” и ответ “положи сюда в этот контракт”
Сервер отправляет запрос с нужными параметрами, получает ответ
Сервер отправляет ответ в нужный контракт (в анимации выше отправил в оператор контракт)
Дальше происходит то, что должно происходить с этими данными.
Получается такая длинная цепочка. Печаль истории в том, что деньги забираются при моем первом запросе вида “а сходи за мне по такому запросу” и на втором запросе, который уже делает сервер, выполнивший запрос.
И, например, на все про все у нас уходит 50к газа на каждый этап. Мы запускаем транзакцию ставим 50к GAS LIMIT и думаем, что у нас будет хорошо. Но, например, механика сохранения новой погоды меняется — теперь при температуре выше 10 градусов нам нужно перевести деньги одному из участников. Логика расширяется и теперь на транзакцию уйдет, например, 80к газа.
![](https://habrastorage.org/getpro/habr/upload_files/eb0/843/d85/eb0843d85052057a37d49434656c989a.gif)
В итоге, уже на второй транзакции, вся цепочка рушится из-за нехватки газа на операцию. Такой огород вокруг внешних вызовов усложняет подобные проекты. Скорее всего, если у вас жесткая завязка на внешний мир, то вам и не стоит выбирать блокчейн для проекта.
Также нет нормального рандома, который нельзя предопределить. Этот рандом тоже предоставляется разными провайдерами “как есть” — просто в контракт регулярно пишется рандомное значение. Но доверять такому для реальных финансовых проектов — опасно.
Особого внимание заслуживает факт, что значение переменной block.timestamp
задается майнером блока. Конечно сложно представить, что майнер будет заранее знать что именно он смайнит блок, и он может подменить время, но возможность такая гипотетически есть. Эта опасность актуальна в разрезе 15 секунд и если мы опираемся на минуты и большие временные промежутки, то этой проблемы нет.
Вопрос безопасности
Про безопасность много говорить не планирую. Но выделю важный аспект — в блокчейне видно всё и всем. Единственное, что недоступно другим — ваш приватный ключ (если вы его не спалили). Код смарт-контракта выкладывается на открытом виде для того, чтобы пройти аудиты и чтобы пользователи смарт-контракта могли ему доверять.
Процедура аудита — нанимается компания, которая смотрит код контракта и проверяет, что именно этот контракт выложен под этому адресу. Проверяется вопрос безопасности контракта и того, что он выполняет то, что декларируется разработчиками. Дальше компания-аудитор размещает у себя на сайте информацию вида “этот контракт был нами верифицирован — может верить”
Иммутабельные переменные
Но даже если код контракта не предоставлен, его легко можно декомпилировать. Например, следующий код имеет иммутабельную переменную — она просто заменяется везде на константу в коде далее.
![](https://habrastorage.org/getpro/habr/upload_files/7dc/42e/0d6/7dc42e0d614dc964c591a554ace019d3.png)
После деплоя этого контракта и открыв его через декомпилятор, мы видим следующее:
![](https://habrastorage.org/getpro/habr/upload_files/dea/4e8/c8b/dea4e8c8b0307f57b4daec5765e2ff82.png)
То есть это значение переменной мы сразу получаем.
Приватные переменные
Я привык, что в бэкенде я могу быть спокоен, что значение приватных переменных прочитать без доступа к памяти будет проблематично. Тут тоже самое — просто доступ к “памяти” есть у всех.
![](https://habrastorage.org/getpro/habr/upload_files/152/3da/c56/1523dac56513a44384f1248f0d94fff0.png)
Мы обозвали переменную amount
приватной. Деплоим контракт, и дальше простым сниппетом кода выдергиваем ее значение:
![](https://habrastorage.org/getpro/habr/upload_files/aa3/489/434/aa34894346cc96bc12d7a0dc1c6979cb.png)
В итоге так можно вытаскивать, что угодно. Так что не вздумайте в контракте хранить хоть чего-нибудь чувствительное!
Деплой контрактов
Откатить свои изменения, базово, невозможно. Деплой контракта происходит единоразово и дальше в нём ничего менять нельзя. Он будет лежать в блокчейне до скончания веков и еще немного.
Upgradeable Contracts
Поэтому приходится сразу писать все правильно и хорошо. Я так не умею, и поэтому я быстро пришел к интересному костылю — Upgradeable Contract. Их механика работает следующим образом.
![](https://habrastorage.org/getpro/habr/upload_files/64a/080/164/64a08016432e4f4ba3ab2ab229c20d9c.gif)
Выкладывается первая версия контракта (Contract V1)
-
Выкладывается Proxy Contract и у него следующая задача
Все запросы перебрасывать 1в1 на Contract V1
Использовать СВОЁ хранилище, а от целевого контракта использовать только логику
Дальше пользователь уже общается с прокси-контрактом также, как с основным
-
Если необходимо обновить контракт, то админ
деплоит Contract V2
Через admin-contract говорит proxy-contract что теперь реализация находится на адресе Contract V2
Дальше пользователь также общается с прокси и уже выполняются механики из Contract V2
У этого механизма есть ряд ограничений и приколов. Например, нельзя чтобы в новой версии контракта были как то изменены переменные из предыдущей версии. Если переменная больше не нужна, то ее все равно надо оставить и деплоить в новый контракт.
Разумеется у этого решения и у многих других уже есть заранее готовые костыли наработки. Основной хороший поставщик этих наработок — OpenZeppelin. Так что, к счастью, велосипеды изобретать необязательно.
Важный момент Upgradeable Contract
Это отличный повод не пройти аудит. Мир блокчейна построен на доверии и сейчас в контракта может быть выложена механика честная и открытая, а потом владелец контракта подменит реализацию на ту, где он забирает себе все деньги и на этом все.
Небольшое заключение
На этом мой пост подходит к концу. В блокчейне много болей, но возможность децентрализировать хранение данных и выполнение операций, иногда того стоят. Например, на блокчейне можно построить удобное хранение данных, подтверждающих право доступа.
Например, взять права. Сейчас я до сих пор с собой вожу бумажные права, чтобы показать их сотруднику ГИБДД и он, по водяным знакам, понял что эти права выдало действительно ГИБДД, а не я напечатал их себе на принтере.
Казалось бы — почему бы ему онлайн не проверять, что у меня есть право ехать на этой машине? А онлайн есть далеко не везде и на дорогах, зачастую, интернета нет вообще или есть ужасно медленный. Поэтому пока гаишники опираются на глаза и знания водяных знаков, чтобы понять наличие у меня открытой категории.
![](https://habrastorage.org/getpro/habr/upload_files/4f5/8ef/14e/4f58ef14e2abe3687487c66482abc15e.gif)
На блокчейне можно построить систему, при которой отдельный участник сети (ГИБДД) записывает подпись факта “у Антона с такими то паспортными данными и тд., есть права категории B”. Не саму строку, а именно подпись. Подпись фиксированного размера и много месте не займет.
В начале рабочей смены сотрудник ГИББД выкачивает себе обновления в блокчейне (новые подписи), и дальше принимает от меня уже факт “я Антон с такими то данными и у меня есть категория B”, берет подпись этого факта из БЧ и понимает, что я действительно имею право ехать дальше.
![](https://habrastorage.org/getpro/habr/upload_files/6ed/ce0/05d/6edce005d0bba53793cd0282bee3b2bc.gif)
Благодарю за внимание! Надеюсь, вам понравилось. Буду рад любой обратной связи. Если интересен контент от меня, то приглашаю в свой Telegram и Youtube.
Комментарии (20)
vagon333
04.09.2023 20:23Полны противоречий.
Стоит начать с важного. Блокчейн — это не криптовалюта. Блокчейн - это технология ...
И рядом:
Проблема блокчейна в том, что там все завязано на деньги. Если я выкатил hello-world сервис в прод с уязвимостями, то я мало чем рискую. А hello-world проект в блокчейне, который идет в прод, уже связан с деньгами и риском их потерять.
В вашей статье блокчейн привязан к крипте, хотя есть масса других областей использования блокчейн, не имеющих отношения к крипте.
amorev Автор
04.09.2023 20:23Увы, но действительно я лично не делал проектов в проде на БЧ не про деньги. Только делали тестовые сборки проекта по примеру того, что описал в конце статьи (децентрализованная идентификация).
Я бы с радостью поделился бы этим опытом, если бы он был(
А так я рад тому, что появляются проекты на БЧ без привязки к крипте
splashx
04.09.2023 20:23Если не сложно, опишите типовые задачи, которые решаются с помощью контрактов
amorev Автор
04.09.2023 20:23Увы, но сейчас с помощью EVM контрактов чаще решаются задачи сбора/раздачи денег. А можно решать задачу вроде той, что я описал в конце статьи.
Лично я сам не писал ничего полезного на блокчейне, к сожалению. Спроса на это не видел.
Если говорить про другие блокчейны, то на блокчейне есть проекты в РЖД - https://rzddigital.ru/technology/blokcheyn/, также S7 - https://habr.com/ru/companies/s7/articles/474122/. Но, увы, лично я с ними не общался
splashx
04.09.2023 20:23+1Именно такого ответа я и боялся) Инструмент в виде неизменяемого архива - отличная вещь (бумагу можно изменить и подписи с печатями поделать), но никто не придумал зачем это нужно кроме хайпа, спекуляций и манипуляций(
amorev Автор
04.09.2023 20:23Я вообще очень недоволен, что оно так. Но дальше "недовольства" уйти не смог, потому что являюсь клавиатурным героем)
vagon333
04.09.2023 20:23Есть проблема изменения электронных банковских документов после передачи между хранилищами. Работаем над стандартами использования bc.
Хайп 2018 отбил желание у индустрии - масса денег ушло впустую.amorev Автор
04.09.2023 20:23Хайп вообще зло. Надеюсь, все-же, найдется применение блокчейну кроме "купи-продай-обмани-проиграй"
dph
04.09.2023 20:23А зачем тут блокчейн, а не просто подпись?
vagon333
04.09.2023 20:23Потому что:
- не все типы документов (600+) поддерживают цифровую подпись, а разработка стандарта цифровой подписи для каждого типа - длительный процесс;
- создатель документа позже находит ошибки, делает правки и заново подписывает. Не разберешься, чья версия верна. И таких версий может быть несколько.dph
04.09.2023 20:23А зачем типу документов поддерживать подпись? Подпись ставится сверху в любом подписанном контейнере, да хоть PGP.
Если у создателя несколько подписанных документов - то они все верны, в чем проблема?vagon333
04.09.2023 20:23+1Если у создателя несколько подписанных документов - то они все верны, в чем проблема?
Проблема в том, что пользователь создал и отдал документ другой организации (допустим проверка кредитной истории), а затем обнаружил ошибку и подправил, но в CR организацию повторный запрос не послал т.к. это деньги.
Получилось несколько правд.dph
04.09.2023 20:23Так это не про достоверность обмена, а про актуальность предоставленной версии, но тут блокчейн тоже не спасет, так как если клиент не отправил документ, то откуда про него кто-нибудь узнает?
Это другой кейс вообще и, вообще говоря, не имеет решения вообще, нельзя клиента заставить всем отправлять актуальные данные.
Единый же для всех реестр, например, клиентских документов - не требует никакого блочейна, достаточно одной клиентской подписи.vagon333
04.09.2023 20:23... но тут блокчейн тоже не спасет,
Спорное заявление.
По нашему опыту - спасет.Нужен источник правды для каждого документа (Single Source of Truth).
Может быть централизованная база, но практика показала ущербность такого решения.
Может быть децентрализованная с консенсусом, например, FBA (Federated Byzantine Agreement) где ноды - участники обмена документами.dph
04.09.2023 20:23А при чем тут блокчейн?
1) В этот источник правды клиент должен свой документ поместить. И при этом достоверность документа начинает считаться как "поместил в источник правды" (что совсем не про "клиент взял и поменял данные"), но это ничем не отличается от "клиент обязан уведомить об изменениях".
И это не задача про "а
2) К этому источнику у всех должен быть доступ, причем авторизованный. Вариант "у всех есть вся база" довольно дорогой и довольно сложный при реализации авторизации
В результате - проще всего реализовать схему вообще без блокчейна, с помощью обычного централизованного сервиса, где легко сделать и авторизацию доступа и единый источник данных и нотификации всех заинтересованных и так далее.
И никакой ущербности в этом решении нет, оно самое простое, надежное, эффективное и защищенное.
dph
04.09.2023 20:23+2Ну, задачу описанную в конце - проще решить без блокчейна. Там достаточно один раз подписи закрытым ключем и открытый ключ у полицейского.
Собственно, почти все задачи блокчейна проще решить без него.
mikegordan
04.09.2023 20:23Не увидел как это масштабируется ? Внутри кода есть потоки ? если 1миллион пользователей вызовут 1 метод, они все будет последовательно по очереди обрабатываться ?
dph
04.09.2023 20:23На одном узле - никак. Масштабирование только за счет множества узлов. Но пока в блокчейне нигде и не нужно масштабирование, очень низкие реальные нагрузки.
amorev Автор
04.09.2023 20:23все последовательно. Более того - если с одного адреса слать транзакции, то только поочереди. Одновременно один адрес может только одну транзакцию делать, а потом уже после нее следующую
x88
Я не смог это дочитать.
Микс "блокчейн для чайников и выдранные углубленные вещи" с информацией 2 летней давности. Начали про Events, перешли к оракулам, так и не упомянув этот термин. Приводится устаревший, до EIP-1559 механизм подсчета газа.