En

JazzTeam Software Development Company

Agile Java Development

Разработка децентрализованных приложений

Глоссарий
Введение
Децентрализованное приложение
Блокчейн
Умные контракты
Средства разработки
Metamask
Truffle
Uport
Mist
IPFS
Архитектура децентрализованных приложений (DApp)

Примечание: Статья подготовлена осенью 2017 года, с тех пор технологии могли измениться.

Глоссарий

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

GAS (газ) - единица оплаты за выполнение операции в блокчейне. Имеет эквивалент в eth.

DApp - децентрализованное приложение.

Введение

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

Децентрализованное приложение

Рассмотрим обычное приложение, такое как “Заметки”. Пользователь делает записи - приложение сохраняет их в памяти компьютера, то есть на жёстком диске. Жесткий диск всего лишь устройство, и как всё в этом мире имеет свойство выходить из строя, разрушаться. Это значит, что при возникновении непредвиденной ситуации или при окончании предписанного срока службы жесткого диска, мы потеряем наши заметки, в которых могла содержаться ценная информация. Решением данной проблемы может стать переход на клиент-серверное приложение, например, на веб-приложение “Заметки”. В нём мы будем делать заметки в браузере и загружать их на удаленный сервер. В данном случае мы перекладываем ответственность за хранение нашей информации на сторонний сервер, который так же как и наш компьютер хранит нашу информацию. Но что, если владелец сервера запретит доступ или сервер выйдет из строя? Мы опять же потеряем свою информацию.

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

DApp, так же как и классическое web-приложение, имеет frontend и backend часть.

Отличительной особенностью является использование блокчейна вместо централизованного удаленного сервера, то есть, как backend.

Основной особенностью и его главным преимуществом является децентрализация. По определению блокчейн является цепочкой блоков, которые содержат информацию. То есть, например, наши заметки. В блокчейне Ethereum у каждого участника сети независимо друг от друга хранится копия цепочки блоков с нашей информацией. Это значит, что бы потерять нашу информацию - необходимо вывести из строя или уничтожить жёсткие диски всех участников сети. Сеть блокчейна Ethereum содержит тысячи участников и быстро расширяется, что сводит возможность утери информации к критическому минимуму.

Блокчейн

Блокчейн - это связанная цепочка из блоков. Блок - это структура, в которой присутствует его хеш, хеш прошлого блока для связи и список транзакций.

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

Транзакция представляет из себя перевод криптовалюты от одного адреса к другому.

Например, данная транзакция переводит 0,41 эфира:


 
Блок, в котором находится данная транзакция:


 
Ал­го­ритм хе­ши­ро­ва­ния, ис­поль­зу­е­мый Ethereum, на­зы­ва­ет­ся ethash. Он хе­ши­ру­ет ме­та­дан­ные по­след­не­го блока в си­сте­ме (транзакции и хеш прошлого блока), ис­поль­зуя спе­ци­аль­ный код под на­зва­ни­ем nonce: слу­чай­ное дво­ич­ное число (генерирует алгоритм ethereum-а), ко­то­рое и за­да­ет уни­каль­ное зна­че­ние хеш-функ­ции. Для каж­до­го но­во­го блока в блок­чейне сеть уста­нав­ли­ва­ет це­ле­вое зна­че­ние хеша (устанавливается после заполнения нового блока транзакциями), и все май­не­ры в сети пы­та­ют­ся уга­дать зна­че­ние nonce, ко­то­рое при­ве­дет к та­ко­му зна­че­нию.

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

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

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

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

Умные контракты

Умный контракт - это программный код, хранящий свою логику и состояние в блокчейне.

Умные контракты в Ethereum представлены в виде классов, которые могут быть реализованы на различных языках, включая визуальное программирование, и компилируются в байт-код для виртуальной машины Эфириума (Ethereum Virtual Machine, EVM) перед отправкой в блокчейн. Изменение состояния виртуальной машины может быть записано на полном по Тьюрингу языке сценариев, то есть сопоставимым с большинством популярных языков программирования.

В отличие от языка сценариев в протоколе биткоина, EVM поддерживают циклы, поэтому платформа использует механизм, называемый “газом”, для ограничения контрактов, которые могут занять много времени для выполнения. То есть в зависимости от сложности вызова (сложность зависит от степени изменения состояния контракта, то есть вызов while(true){2+2} ничего не стоит для блокчейна) с вызывающего будет взята комиссия за вычисления в виде газа, который конвертируется в эфир.

При этом можно создать контракт, который бы возмещал затраты, но такой способ имеет недостатки.

Рассмотрим простой контракт:


 
Данный контракт написан на JavaScript-подобном языке Solidity. Язык выбран по причине активной поддержки сообществом и разработчиками.

В приведённом выше контракте при вызове метода greet с параметром выводится строка. Код на Solidity не имеет каких-то радикальных особенностей по сравнению с JavaScript. Хочется отметить важность property msg.sender, так как она возвращает адрес вызвавшего метод, что в свою очередь позволяет ограничивать доступ к методу. Функции require и assert в новых версиях Solidity являются аналогом конструкции if throw.

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


 
В строке “To” отображен адрес, который выполняет Deploy контракта, а в ‘From’ адрес самого контракта. В поле InputData находится код контракта в виде 16-ричного байткода. Отметим, что код контракта может просматривать любой, хранить в коде секретные данные является не лучшей практикой.

Вызов метода, который меняет состояние контракта, оформляется в блокчейне как транзакция. Например:


 
Всё аналогично с деплоем.

Средства разработки

Основной средой разработки контрактов на Solidity является Remix IDE. Приложение довольно элементарное, поэтому отметим только режимы работы с Ethereum (пункт Environment).

После чего выполнить: remixd -S <путь к расшаренной папке для Remix IDE>
 

Нажать на значок звена, и всё должно заработать. Возможно, при установке Remixd понадобится поставить .NET SDK 2005.

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

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

В примере используется Metamask в качестве кошелька, ноды (полностью синхронизированный блокчейн на сервере metamask) и Web3 provider. Metamask является просто дополнением к Chrome и ничего больше. Данное дополнение предоставляет доступ к удалённым синхронизированным блокчейнам от серверов метамаска (тот же Parity скачивает блокчейн непосредственно на компьютер с ним), что позволяет отказаться от скачивания. А так же оно внедряет настроенный под сервера Metamask JavaScript-модуль Web3 в каждую страницу, на которой запущено дополнение, что в свою очередь позволяет общаться js-приложениям c контрактами в блокчейне и избавляет от необходимости настройки подключения. Плюс ко всему метамаск - это простой кошелек с историей транзакций и менеджером аккаунтов.

Для примера рассмотрим диаграмму работы Metamask:

Metamask

Если идти классическим путем, то нам придется скачать клиент Ethereum и синхронизировать всю цепочку блоков на локальный компьютер, фактически мы станем нодой. Это может занять значительное место на жёстком диске и тратить ресурсы сети на синхронизацию с сетью. К тому же, в DApp придется вручную встраивать и настраивать под необходимую ноду Web3.js.

Metamask может решить эти проблемы и значительно облегчить работу с блокчейном сети Ethereum. Metamask - это расширение для браузера, которое является “мостом” между браузером и блокчейном Ethereum. При работе с основным блокчейном и тестовыми, Metamask предоставляет доступ к своим удаленным нодам, что избавляет от необходимости скачивать всю цепочку блоков нужного блокчейна. Ещё одной особенностью Metamask является автоматическая инжекция объекта Web3js во все веб-страницы. Данный объект уже настроен на сеть и аккаунт, которые выбраны в интерфейсе расширения.

Устанавливаем Metamask под свой браузер с официального сайта и приступаем к настройке в интерфейсе расширения.

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

Нам необходим Ropsten Test Net.

Далее, нам необходимо создать аккаунт в сети Ropsten. Для этого кликаем по кнопке смены аккаунта и выбираем пункт Create Account. После этого выбираем в списке созданный аккаунт.

В контекстном меню нашего аккаунта мы можем скопировать и получить наш Ethereum-адрес .

Но для платы за транзакцию нам необходим gas, который конвертируется в ETH, а его на новом аккаунте 0. Основным преимуществом Ropsten является, то что мы можем получить бесплатный eth.Для это необходимо кликнуть клавишу Buy и выбрать сервис. На открывшийся странице запросить Eth и подождать до подтверждения транзакции.

После выполнения всех операций мы имеем полностью настроенное окружение для работы с DApp.

Truffle

Truffle - фреймворк, существующий для работы со смарт-контрактами Ethereum.

Основные возможности фреймворка:

Для установки truffle необходимо выполнить команду:
npm install -g truffle

Чтобы инициализировать truffle, нужно в директории с фреймворком выполнить:
truffle init

Для дальнейшей работы требуется в папке contracts создать файлы .sol с контрактами.

Далее, командой truffle compile можно выполнить компиляцию контрактов. Это команда создаст в папке build файлы с необходимой информацией для деплоя контрактов.

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

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

Рассмотрим простейшую миграцию для деплоя одного контракта:

В данном случае подгружается контракт MyContract и с помощью модуля deployer деплоится в блокчейн, настройки которого находятся в файле truffle.js (корень).

Запуск миграций осуществляется командой truffle migrate.

Unit тестирование контрактов реализовано как на JavaScript, так и на Solidity. JavaScript-тестирование работает на основе фреймворка Mocha.

Подробнее по работе с Truffle.

Uport

Данный фреймворк находится в бета-тестировании.

Uport может стать заменой Metamask в реальном проекте. При этом uport концептуально отличается.

Сервис Uport является полностью децентрализованным. То есть хранение данных и логика сосредоточены в смарт контрактах.

Алгоритм работы с Uport:

  1. Пользователь устанавливает мобильное приложение Uport к себе на смартфон и регистрируется в системе. Получает свой идентификатор в системе и также адрес в блокчейне.
  2. При надобности происходит регистрация своего приложения (умного контракта) в системе. После чего мы получаем идентификатор и ключи приложения (они завязаны только на uport).
  3. Разработчик применяет в разработке библиотеки uport и строит приложение по определённому шаблону:

Mist

Mist является официальным Dapp веб-браузером. Отличие этого браузера от обычных заключается в том, что в него встроен кошелек Ethereum (позволяет управлять аккаунтами и создавать простейшие транзакции по пересылке Ethereum, деплоить контракты). Фактически Mist - это обычный браузер со встроенным Metamask, но в отличии от него, Mist скачивает весь блокчейн полностью на диск, а не пользуется удалёнными нодами как у Metamask.

IPFS

Мы знаем, что одной из особенностей работы блокчейна, является дублирование блоков с транзакциями, в которых хранятся контракты и их состояние, на каждой ноде. Это значит, что если у нас огромная система, манипулирующая сложными структурами данных, нам придётся тратить огромное количество “газа” на выполнение действий над данными в контрактах, а также хранить на своём ПК лишние данные, которые возможно и не понадобятся клиенту.

Решением может быть обычная база данных (MySql, Oracle и тд), и тогда в смарт-контракте можно хранить просто id нужной записи. Но какой смысл от преимуществ блокчейна, если мы зависим от централизованной базы данных? База данных может выйти из строя и вся система потеряет смысл, так как одни Id без базы нам ничего не говорят.

IPFS — контентно-адресуемый, одноранговый гипермедийный протокол связи. Несмотря на определение выше, стоит рассматривать IPFS как некую файловую систему. В данной файловой системе, в отличии от привычной нам, файлы контентно адресуются, а не по имени. То есть в IPFS мы обращаемся к файлу по его хешу, который рассчитан по его содержанию. Это означает, что если файл изменится и соответственно его хеш, то в файловой системе IPFS он будет считаться новым файлом. Данное свойство чем-то напоминает GIT и, в принципе, при помощи IPFS мы можем организовать сохранение версий файла.

Рассмотрим, в чём же заключается децентрализованность IPFS. В этом она похожа на BitTorrent. Мы загружаем файл через клиент IPFS, получаем его хеш и он попадает в наш локальный кеш (/UserName/.ipfs). Когда другому пользователю необходим наш файл, мы передаем ему его хеш и пользователь делает http-запрос по адресу localhost:5001/ipfs/[хеш необходимого файла] (если мы хотим работать с локальным клиентом) - система ищет данный файл и участника сети IPFS, у которого этот файл можно скачать. Так как данный файл пока находится только у меня и я в сети, то второй клиент скачает этот файл у меня и подгрузит автоматически его к себе в кэш. Следующий клиент может запросить файл по нашему хешу и получить его, например, от второго клиента, при этом первому клиенту для этой операции уже нет необходимости быть в сети.

По аналогии с BitTorrent мы выкладываем файл в сеть, то есть “раздаем” его с нашего компьютера, а другие пользователи скачивают его и, при этом являясь равноправным участником сети, раздают его аналогично, обеспечивая децентрализованный обмен файлами.

Преимущества IPFS:

Недостатки IPFS:

Каждый пользователь должен иметь клиент IPFS для непосредственной работы с ним. Клиент представляет из себя консольное приложение, при первом запуске которого мы должны инициализировать папку кэша командой ipfs init. После чего мы можем работать через консоль или через web-gui, запустив команду ipfs daemon и перейдя по адресу http://localhost:8080/webui.
Для разработки фронтэнд приложений с использованием IPFS применяется соответствующая библиотека, которая через RPC-API общается с клиентом IPFS.

Интересной особенностью является добавление целой папки, что позволяет простейшим образом выкладывать целые сайты в децентрализованную сеть. Чтобы это сделать, воспользуемся командой ipfs add -r [путь к папке] и получим следующий результат:


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

localhost:8080/ipfs/QmYHa9yW5yWRqFhkg7cq6foWcu8HN3RK5pqF2Uj5APGfnQ setup.ini
Одной из особенностей IPFS является система IPNS. Она добавляет немного изменчивости в IPFS. Суть её заключается в том, чтобы по идентификатору пира (отдельного клиента) получать ipfs хеш, который мы можем динамически менять. А пользователи при этом знают только ваш идентификатор IPNS (он же идентификатор пира) и по обращении к нему они получают ipfs кэш, который может динамически меняться. Данная особенность используется для хостинга динамических сайтов.

Архитектура децентрализованных приложений (DApp)

Выделим важные архитектурные моменты при построении DApp на блокчейне:

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

Учитывая вышеприведенную информацию, можно выделить две возможные архитектуры построения DApp на основе блокчейна Ethereum:

1.Веб-приложение на публичном блокчейне

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

Архитектуру можно представить данной схемой:

Мы видим DApp браузер в начале цепочки. В настоящий момент таким браузером является Mist и браузер с дополнением Metamask (Chrome и FireFox). Главная задача такого браузера - предоставить интерфейс для работы с аккаунтами и внедрить настроенный под выбранную сеть блокчейна объект Web3. Но мы вполне можешь и сами воссоздать данный функционал и обойтись обычным браузером.

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

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

Примеры данной архитектуры:

https://storage.googleapis.com/1000guess/src/index.html
https://www.hellosugoi.com/

2.Самодостаточное приложение на приватном блокчейне

Рассмотрим диаграмму архитектуры:

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

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

Далее, нужно определиться с клиентом. Он будет представлять самодостаточное десктопное приложение, которое установит при надобности geth и клиент ipfs, а также всё настроит. Что избавит конечного пользователя от необходимости настраивать окружение вручную.

Приложение будет разработано на Angular. Electron используется для обёртки веб-приложения в десктопную оболочку (становится обычным оконным приложением).
Для особой надежности, взаимодействие клиента и блокчейна осуществляется с помощью технологии IPC .Оно позволяет непосредственно общаться между процессом клиента и geth (имплементации Ethereum на Go), что исключает вмешательства извне.

В данной архитектуре применение ipfs под вопросом. Так как мы можем себе позволить хранить весь блокчейн, ведь в нём находятся транзакции только нашей организации. Но IPFS необходим для хранения таких файлов как картинки, документы и тд. Тогда, было бы не плохо сделать IPFS локальным. Это возможно. Для этого нужно провести research, чтобы узнать подробности.

Отметим одну проблему в реализации данной архитектуры: разработчики Web3Js удалили поддержку API для работы с аккаунтами, чтобы обезопасить пользователей. По их мнению нужно использовать Mist и Metamask для работы с аккаунтами, что противоречит приведенной выше архитектуре.

Возможные решения данной проблемы:

  1. Пересобрать библиотеку Web3Js под свои нужды.
  2. Использовать библиотеку web3_ipc для управления аккаунтами совместно с Web3Js09-

Вариант номер 2 менее затратный по времени.

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

Вот как может выглядеть контракт решающий проблему:

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

, , , , , ,

Leave a Reply

Your email address will not be published. Required fields are marked *