Полное руководство по dApp для разработчиков полного стека

Что такое децентрализованное приложение?

DApp — это приложение, которое в основном или полностью децентрализовано.

Рассмотрим все возможные аспекты приложения, которое может быть децентрализовано:

  • Серверное программное обеспечение (логика приложения)
  • Интерфейсное программное обеспечение
  • Хранилище данных
  • Обмен сообщениями
  • Разрешение имени

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

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

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

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

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

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

Бэкенд (смарт-контракт)

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

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

Одним из основных соображений проектирования архитектуры смарт-контрактов является невозможность изменить код смарт-контракта после его развертывания. Его можно удалить, если он запрограммирован с доступным кодом операции САМОУНИЧТОЖЕНИЕ, но, кроме полного удаления, код нельзя изменить каким-либо образом.

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

Внешний интерфейс (веб-интерфейс пользователя)

В отличие от бизнес-логики dApp, которая требует от разработчика понимания EVM и новых языков, таких как Solidity, клиентский интерфейс dApp может использовать стандартные веб-технологии (HTML, CSS, JavaScript и т. д.). Это позволяет традиционному веб-разработчику использовать знакомые инструменты, библиотеки и фреймворки. Взаимодействие с Ethereum, такое как подписание сообщений, отправка транзакций и управление ключами, часто осуществляется через веб-браузер с помощью расширения, такого как MetaMask.

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

Внешний интерфейс обычно связан с Ethereum через библиотеку JavaScript web3.js, которая связана с ресурсами внешнего интерфейса и обслуживается браузером веб-сервером.

Хранилище данных

Из-за высокой стоимости газа и низкого лимита газа в настоящее время смарт-контракты плохо подходят для хранения или обработки больших объемов данных. Следовательно, большинство DApps используют службы хранения данных вне цепочки, то есть они хранят объемные данные вне цепочки Ethereum на платформе хранения данных. Эта платформа хранения данных может быть централизованной (например, обычная облачная база данных) или данные могут быть децентрализованы и храниться на платформе P2P, такой как IPFS, или на собственной платформе Ethereum Swarm.

Децентрализованное хранилище P2P идеально подходит для хранения и распространения больших статических ресурсов, таких как изображения, видео и ресурсы внешнего веб-интерфейса приложения (HTML, CSS, JavaScript и т. д.). Далее мы рассмотрим несколько вариантов.

ИПФС

Межпланетная файловая система (IPFS) — это децентрализованная система хранения с адресацией содержимого, которая распределяет сохраненные объекты между одноранговыми узлами в сети P2P. «Адресное содержимое» означает, что каждая часть содержимого (файл) хешируется, и этот хэш используется для идентификации этого файла. Затем вы можете получить любой файл с любого узла IPFS, запросив его по его хешу.

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

Более подробную информацию об IPFS можно найти на https://ipfs.io.

Рой

Swarm — это еще одна система хранения P2P с адресацией контента, похожая на IPFS. Swarm был создан Ethereum Foundation как часть набора инструментов Go-Ethereum. Как и IPFS, он позволяет хранить файлы, которые распространяются и реплицируются узлами Swarm. Вы можете получить доступ к любому файлу Swarm, обратившись к нему по хешу. Swarm позволяет получить доступ к веб-сайту из децентрализованной системы P2P вместо центрального веб-сервера.

Домашняя страница Swarm хранится в Swarm и доступна на вашем узле Swarm или шлюзе: https://swarm-gateways.net/bzz:/theswarm.eth/.

Децентрализованные протоколы обмена сообщениями

Еще одним важным компонентом любого приложения является взаимодействие между процессами. Это означает возможность обмена сообщениями между приложениями, между разными экземплярами приложения или между пользователями приложения. Традиционно это достигается за счет использования централизованного сервера. Однако существует множество децентрализованных альтернатив серверным протоколам, предлагающих обмен сообщениями по сети P2P. Наиболее известным протоколом обмена сообщениями P2P для DApps является Whisper, который является частью набора инструментов Go-Ethereum от Ethereum Foundation.

Последним аспектом приложения, которое можно децентрализовать, является разрешение имен. Позже в этой главе мы подробно рассмотрим службу имен Ethereum; теперь, однако, давайте копаться в примере.

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

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

Общий процесс аукциона можно увидеть на изображении ниже.

Основными компонентами нашего DApp Auction являются:

  • Смарт-контракт, реализующий невзаимозаменяемые токены ERC721 «deed» (DeedRepository).
  • Смарт-контракт, реализующий аукцион (AuctionRepository) для продажи прав
  • Веб-интерфейс, использующий фреймворк Vue/Vuetify JavaScript.
  • Библиотека web3.js для подключения к цепочкам Ethereum (через MetaMask или другие клиенты).
  • Клиент Swarm для хранения ресурсов, таких как изображения.
  • Клиент Whisper для создания чатов для всех участников аукциона.

Вы можете найти исходный код аукционного dApp здесь.

Auction DApp: внутренние смарт-контракты

Наш пример Auction DApp поддерживается двумя смарт-контрактами, которые нам необходимо развернуть в блокчейне Ethereum для поддержки приложения: AuctionRepository и DeedRepository.

Давайте начнем с рассмотрения DeedRepository, показанного в DeedRepository.sol: токен документа ERC721 для использования на аукционе. Этот контракт является невзаимозаменяемым токеном, совместимым с ERC721.

Пример 1. DeedRepository.sol: токен документа ERC721 для использования на аукционе.

link:code/auction_dapp/backend/contracts/DeedRepository.sol[]

Как видите, контракт DeedRepository — это простая реализация токена, совместимого с ERC721.

Наше приложение Auction DApp использует контракт DeedRepository для выпуска и отслеживания токенов для каждого аукциона. Сам аукцион организуется контрактом AuctionRepository. Этот контракт слишком длинный, чтобы включать его здесь полностью, но AuctionRepository.sol: основной смарт-контракт Auction DApp показывает основное определение контракта и структуры данных.

Пример 2. AuctionRepository.sol: основной смарт-контракт Auction DApp

Контракт AuctionRepository управляет всеми аукционами со следующими функциями:

Вы можете развернуть эти контракты в блокчейне Ethereum по вашему выбору (например, Ropsten), используя Truffle в репозитории книги:

$ cd code/auction_dapp/backend
$ truffle init
$ truffle compile
$ truffle migrate --network ropsten

управление децентрализованными приложениями

Если вы прочитаете два смарт-контракта Auction dApp, вы заметите кое-что важное: нет специальной учетной записи или роли, которая имеет особые привилегии в отношении dApp. У каждого аукциона есть владелец с некоторыми особыми возможностями, но само приложение Auction dApp не имеет привилегированного пользователя.

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

Вопрос управления является особенно сложным для решения, поскольку он представляет собой палку о двух концах. С одной стороны, привилегированные учетные записи опасны; в случае взлома они могут подорвать безопасность DApp. С другой стороны, без какой-либо привилегированной учетной записи нет вариантов восстановления в случае обнаружения ошибки. Мы видели, как оба этих риска проявляются в приложениях Ethereum DApp. В случае с The DAO и историей форка Эфириума было несколько привилегированных учетных записей, называемых «кураторами», но они были очень ограничены в своих возможностях. Эти учетные записи не смогли отменить вывод средств злоумышленником DAO. В более недавнем случае децентрализованная биржа Bancor подверглась массовой краже из-за взлома привилегированной учетной записи управления. Оказывается, Bancor не был настолько децентрализован, как предполагалось изначально.

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

Auction DApp: пользовательский интерфейс

После развертывания контрактов Auction DApp вы можете взаимодействовать с ними, используя вашу любимую консоль JavaScript и web3.js или другую библиотеку web3. Однако большинству пользователей потребуется простой в использовании интерфейс. Наш пользовательский интерфейс Auction DApp создан с использованием JavaScript-фреймворка Vue2/Vuetify от Google.

Вы можете найти код пользовательского интерфейса в папке code/auction_dapp/frontend в репозитории. Каталог имеет следующую структуру и содержание:

frontend/
|-- build
|   |-- build.js
|   |-- check-versions.js
|   |-- logo.png
|   |-- utils.js
|   |-- vue-loader.conf.js
|   |-- webpack.base.conf.js
|   |-- webpack.dev.conf.js
|   `-- webpack.prod.conf.js
|-- config
|   |-- dev.env.js
|   |-- index.js
|   `-- prod.env.js
|-- index.html
|-- package.json
|-- package-lock.json
|-- README.md
|-- src
|   |-- App.vue
|   |-- components
|   |   |-- Auction.vue
|   |   `-- Home.vue
|   |-- config.js
|   |-- contracts
|   |   |-- AuctionRepository.json
|   |   `-- DeedRepository.json
|   |-- main.js
|   |-- models
|   |   |-- AuctionRepository.js
|   |   |-- ChatRoom.js
|   |   `-- DeedRepository.js
|   `-- router
|       `-- index.js

После развертывания контрактов отредактируйте конфигурацию внешнего интерфейса в frontend/src/config.js и введите адреса контрактов DeedRepository и AuctionRepository, как они были развернуты. Внешнему приложению также требуется доступ к узлу Ethereum, предлагающему интерфейс JSON-RPC и WebSockets. После того, как вы настроили интерфейс, запустите его с помощью веб-сервера на вашем локальном компьютере:

$ npm install
$ npm run dev

Интерфейс Auction dApp запустится и будет доступен через любой веб-браузер по адресу http://localhost:8080.

Если все пойдет хорошо, вы должны увидеть экран, показанный в пользовательском интерфейсе Auction DApp, который иллюстрирует Auction dApp, работающий в веб-браузере.

Дальнейшая децентрализация DApp аукциона

Наше децентрализованное приложение уже достаточно децентрализовано, но мы можем улучшить ситуацию.

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

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

Есть две вещи, которые мы можем сделать, чтобы сделать это dApp децентрализованным и устойчивым:

  • Храните весь код приложения в Swarm или IPFS.
  • Получите доступ к dApp по ссылке на имя, используя службу имен Ethereum.

Мы рассмотрим первый вариант в следующем разделе, а второй — в Службе имен Ethereum (ENS).

Хранение DApp аукциона в Swarm

Ранее в этой главе мы представили Swarm в Swarm. Наше децентрализованное приложение Auction уже использует Swarm для хранения изображения значка для каждого аукциона. Это гораздо более эффективное решение, чем попытка хранить данные в Ethereum, что дорого. Это также намного более устойчиво, чем если бы эти изображения хранились в централизованной службе, такой как веб-сервер или файловый сервер.

Но мы можем сделать еще один шаг вперед. Мы можем хранить весь интерфейс самого dApp в Swarm и запускать его напрямую из узла Swarm вместо запуска веб-сервера.

Подготовка роя

Для начала вам необходимо установить Swarm и инициализировать узел Swarm. Swarm является частью набора инструментов Go-Ethereum от Ethereum Foundation. См. инструкции по установке Go-Ethereum в [go_ethereum_geth] или для установки бинарного релиза Swarm следуйте инструкциям в Документации Swarm.

После того, как вы установили Swarm, вы можете проверить, правильно ли он работает, запустив его с помощью команды version:

$ swarm version
Version: 0.3
Git Commit: 37685930d953bcbe023f9bc65b135a8d8b8f1488
Go Version: go1.10.1
OS: linux

Чтобы запустить Swarm, вы должны сообщить ему, как подключиться к экземпляру Geth, чтобы получить доступ к JSON-RPC API. Начните, следуя инструкциям в Руководстве по началу работы.

Когда вы запустите Swarm, вы должны увидеть что-то вроде этого:

Maximum peer count                       ETH=25 LES=0 total=25
Starting peer-to-peer node               instance=swarm/v0.3.1-225171a4/linux...
connecting to ENS API                    url=http://127.0.0.1:8545
swarm[5955]: [189B blob data]
Starting P2P networking
UDP listener up                          self=enode://f50c8e19ff841bcd5ce7d2d...
Updated bzz local addr                   oaddr=9c40be8b83e648d50f40ad3... uaddr=e
Starting Swarm service
9c40be8b hive starting
detected an existing store. trying to load peers
hive 9c40be8b: peers loaded
Swarm network started on bzz address: 9c40be8b83e648d50f40ad3d35f...
Pss started
Streamer started
IPC endpoint opened                      url=/home/ubuntu/.ethereum/bzzd.ipc
RLPx listener up                         self=enode://f50c8e19ff841bcd5ce7d2d...

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

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

Загрузка файлов в Swarm

Как только у вас будет запущен локальный узел Swarm и шлюз, вы сможете загрузить его в Swarm, и файлы будут доступны на любом узле Swarm, просто по ссылке на хэш файла.

Давайте проверим это, загрузив файл:

$ swarm up code/auction_dapp/README.md
ec13042c83ffc2fb5cb0aa8c53f770d36c9b3b35d0468a0c0a77c97016bb8d7c

Swarm загрузил файл README.md и вернул хэш, который можно использовать для доступа к файлу с любого узла Swarm. Например, вы можете использовать публичный шлюз Swarm.

Хотя загрузка одного файла относительно проста, загрузка всего интерфейса dApp немного сложнее. Это связано с тем, что различные ресурсы dApp (HTML, CSS, JavaScript, библиотеки и т. д.) имеют встроенные ссылки друг на друга. Обычно веб-сервер преобразует URL-адреса в локальные файлы и обслуживает правильные ресурсы. Мы можем добиться того же для Swarm, упаковав наше dApp.

В Auction dApp есть скрипт для упаковки всех ресурсов:

$ cd code/auction_dapp/frontend
$ npm run build
> [email protected] build /home/aantonop/Dev/ethereumbook/code/auction_dapp/frontend
> node build/build.js
Hash: 9ee134d8db3c44dd574d
Version: webpack 3.10.0
Time: 25665ms
Asset     Size
static/js/vendor.77913f316aaf102cec11.js  1.25 MB
static/js/app.5396ead17892922422d4.js   502 kB
static/js/manifest.87447dd4f5e60a5f9652.js  1.54 kB
static/css/app.0e50d6a1d2b1ed4daa03d306ced779cc.css  1.13 kB
static/css/app.0e50d6a1d2b1ed4daa03d306ced779cc.css.map  2.54 kB
static/js/vendor.77913f316aaf102cec11.js.map  4.74 MB
static/js/app.5396ead17892922422d4.js.map   893 kB
static/js/manifest.87447dd4f5e60a5f9652.js.map  7.86 kB
index.html  1.15 kB
Build complete.

Результатом этой команды будет новый каталог code/auction_dapp/frontend/dist, который содержит весь интерфейс Auction DApp, упакованный вместе:

dist/
|-- index.html
`-- static
    |-- css
    |   |-- app.0e50d6a1d2b1ed4daa03d306ced779cc.css
    |   `-- app.0e50d6a1d2b1ed4daa03d306ced779cc.css.map
    `-- js
        |-- app.5396ead17892922422d4.js
        |-- app.5396ead17892922422d4.js.map
        |-- manifest.87447dd4f5e60a5f9652.js
        |-- manifest.87447dd4f5e60a5f9652.js.map
        |-- vendor.77913f316aaf102cec11.js
        `-- vendor.77913f316aaf102cec11.js.map

Теперь вы можете загрузить все dApp в Swarm, используя команду up и параметр —recursive. Здесь мы также сообщаем Swarm, что index.html — это путь по умолчанию для загрузки этого dApp:

$ swarm --bzzapi http://localhost:8500 --recursive \
  --defaultpath dist/index.html up dist/
ab164cf37dc10647e43a233486cdeffa8334b026e32a480dd9cbd020c12d4581

Теперь все наше dApp Auction размещено на Swarm и доступно по URL-адресу Swarm:

  • bzz://ab164cf37dc10647e43a233486cdeffa8334b026e32a480dd9cbd020c12d4581

Мы добились определенного прогресса в децентрализации нашего DApp, но усложнили его использование. Такой URL гораздо менее удобен для пользователя, чем красивое имя вроде auction_dapp.com. Вынуждены ли мы жертвовать удобством использования ради децентрализации? Не обязательно.

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

Служба имен Ethereum (ENS)

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

В традиционном Интернете система доменных имен (DNS) позволяет нам использовать удобочитаемые имена в браузере, одновременно преобразуя эти имена в IP-адреса или другие идентификаторы за кулисами. В блокчейне Ethereum та же проблема решается системой именования Эфириума (ENS), но децентрализованно.

Например, адрес для пожертвований Ethereum Foundation — 0xfB6916095ca1df60bB79Ce92cE3Ea74c37c5d359; в кошельке, поддерживающем ENS, это просто ethereum.eth.

ENS — это больше, чем смарт-контракт; это само по себе фундаментальное dApp, предлагающее децентрализованную службу имен. Кроме того, ENS поддерживается рядом приложений dApp для регистрации, управления и аукционов зарегистрированных имен. ENS демонстрирует, как dApps могут работать вместе: это dApp, созданное для обслуживания других dApp, поддерживаемое экосистемой dApp, встроенное в другие dApp и так далее.

В этом разделе мы рассмотрим, как работает ENS. Мы продемонстрируем, как вы можете настроить свое собственное имя и связать его с кошельком или адресом Ethereum, как вы можете встроить ENS в другое dApp и как вы можете использовать ENS для присвоения имени вашим ресурсам dApp, чтобы упростить их использование.

Спецификация ENS

ENS указан в основном в трех предложениях по улучшению Ethereum: EIP-137, в котором указаны основные функции ENS; EIP-162, описывающий аукционную систему для корня .eth; и EIP-181, определяющий обратное разрешение адресов.

ENS следует философии дизайна «сэндвича»: очень простой нижний слой, за которым следуют слои более сложного, но заменяемого кода, с очень простым верхним слоем, в котором все средства хранятся на отдельных счетах.

Нижний уровень: владельцы имен и преобразователи

ENS работает с «узлами» вместо удобочитаемых имен: удобочитаемое имя преобразуется в узел с использованием алгоритма «Namehash».

Базовый уровень ENS — это продуманно простой контракт (менее 50 строк кода), определенный ERC137, который позволяет только владельцам узлов устанавливать информацию об их именах и создавать подузлы (эквивалент ENS поддоменов DNS).

Единственными функциями на базовом уровне являются те, которые позволяют владельцу узла устанавливать информацию о своем собственном узле (в частности, преобразователь, время жизни или передача права собственности) и создавать владельцев новых подузлов.

Алгоритм Namehash — это рекурсивный алгоритм, который может преобразовать любое имя в хэш, который идентифицирует имя.

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

Namehash рекурсивно хеширует компоненты имени, создавая уникальную строку фиксированной длины (или «узел») для любого допустимого входного домена. Например, узел Namehash для subdomain.example.eth — keccak('<example.eth>' node) + keccak('<subdomain>'). Подзадача, которую мы должны решить, состоит в том, чтобы вычислить узел для примера.eth, который равен keccak('<.eth>' node) + keccak('<example>'). Для начала мы должны вычислить узел для eth, то есть keccak(<root node>) + keccak('<eth>').

Корневой узел — это то, что мы называем «базовым случаем» нашей рекурсии, и мы, очевидно, не можем определить его рекурсивно, иначе алгоритм никогда не завершится! Корневой узел определяется как 0x0000000000000000000000000000000000000000000000000000000000000000 (32 нулевых байта).

Собрав все это вместе, узел subdomain.example.eth, таким образом, будет keccak(keccak(keccak(0x0...0 + keccak('eth')) + keccak('example')) + keccak('subdomain')).

Обобщая, мы можем определить функцию Namehash следующим образом (базовый случай для корневого узла или пустого имени, за которым следует рекурсивный шаг):

namehash([]) = 0x0000000000000000000000000000000000000000000000000000000000000000
namehash([label, ...]) = keccak256(namehash(...) + keccak256(label))

В Python это становится:

def namehash(name):
  if name == '':
    return '\0' * 32
  else:
    label, _, remainder = name.partition('.')
    return sha3(namehash(remainder) + sha3(label))

Таким образом, mastering-ethereum.eth будет обрабатываться следующим образом:

namehash('mastering-ethereum.eth')
⇒ sha3(namehash('eth') + sha3('mastering-ethereum'))
⇒ sha3(sha3(namehash('') + sha3('eth')) + sha3('mastering-ethereum'))
⇒ sha3(sha3(('\0' * 32) + sha3('eth')) + sha3('mastering-ethereum'))

Конечно, поддомены сами могут иметь поддомены: может быть sub.subdomain.example.eth после subdomain.example.eth, затем sub.sub.subdomain.example.eth и так далее. Чтобы избежать дорогостоящего повторного вычисления, поскольку Namehash зависит только от самого имени, узел для заданного имени может быть предварительно вычислен и вставлен в контракт, что устраняет необходимость манипулирования строками и позволяет осуществлять немедленный поиск записей ENS независимо от количества компонентов в контракте. сырое имя.

Как выбрать допустимое имя?
Имена состоят из ряда меток, разделенных точками. Хотя буквы верхнего и нижнего регистра допускаются, все метки должны следовать процессу нормализации UTS #46, который сворачивает метки перед их хешированием, поэтому имена с разными регистрами, но одинаковым написанием, в конечном итоге будут иметь один и тот же Namehash.

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

  • Метки должны быть не длиннее 64 символов каждая.
  • Полные имена ENS должны содержать не более 255 символов.
  • Метки не должны начинаться или заканчиваться дефисами или цифрами.

Владение корневым узлом

Одним из результатов этой иерархической системы является то, что она опирается на владельцев корневого узла, которые могут создавать домены верхнего уровня (TLD).

Хотя конечная цель состоит в том, чтобы принять децентрализованный процесс принятия решений для новых TLD, на момент написания статьи корневой узел контролируется мультиподписью 4 из 7, которой владеют люди в разных странах (построенная как отражение 7 держатели ключей системы DNS). В результате для внесения любых изменений требуется большинство, по крайней мере, 4 из 7 держателей ключей.

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

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

Резолверы
Базовый контракт ENS не может добавлять метаданные к именам; это работа так называемых «контрактов решателя». Это создаваемые пользователем контракты, которые могут отвечать на вопросы об имени, например, какой адрес Swarm связан с приложением, на какой адрес поступают платежи в приложение (в эфире или токенах) или каков хэш приложения (для проверки его целостность).

Средний уровень: узлы .eth

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

Примечание. В настоящее время ведется работа по предоставлению владельцам традиционных доменов DNS возможности претендовать на владение ENS. Хотя теоретически это может работать для .com, единственный домен, для которого это было реализовано, — .xyz, и только в тестовой сети Ropsten.

Домены .eth распределяются через аукционную систему. Нет зарезервированного списка или приоритета, и единственный способ получить имя — использовать систему. Система аукционов представляет собой сложный фрагмент кода (более 500 строк); большая часть ранних усилий по разработке (и ошибок!) в ENS была связана с этой частью системы. Однако его также можно заменить и обновить без риска для средств — об этом позже.

Аукционы Викри

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

В блокчейне требуются некоторые изменения:

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

Поэтому аукцион состоит из четырех этапов:

  1. Начать аукцион. Это необходимо для трансляции намерения зарегистрировать имя. Это создает все сроки аукциона. Имена хэшируются, поэтому только те, у кого есть это имя в словаре, узнают, какой аукцион был открыт. Это обеспечивает некоторую конфиденциальность, что полезно, если вы создаете новый проект и не хотите делиться подробностями о нем. Вы можете открывать несколько фиктивных аукционов одновременно, поэтому, если кто-то следит за вами, он не может просто делать ставки на всех открытых вами аукционах.
  2. Сделайте закрытую ставку. Вы должны сделать это до истечения срока торгов, привязав заданное количество эфира к хэшу секретного сообщения (содержащему, среди прочего, хэш имени, фактическую сумму ставки и соль). Вы можете заблокировать больше эфира, чем вы на самом деле предлагаете, чтобы скрыть свою истинную оценку.
  3. Раскрыть ставку. В течение периода раскрытия вы должны совершить транзакцию, которая раскрывает ставку, которая затем рассчитает самую высокую ставку и вторую по величине ставку и отправит эфир обратно проигравшим участникам торгов. Каждый раз, когда раскрывается ставка, текущий победитель пересчитывается; поэтому последний, который будет установлен до истечения крайнего срока выявления, становится абсолютным победителем.
  4. Убирать после. Если вы выиграете, вы можете завершить аукцион, чтобы вернуть разницу между вашей ставкой и второй по величине ставкой. Если вы забыли раскрыть информацию, вы можете сделать это позднее и восстановить часть своей ставки.

Верхний слой: Дела

Верхний уровень ENS — это еще один сверхпростой контракт с единственной целью: удерживать средства.

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

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

Регистрация имени

Как мы видели на аукционах Vickrey, регистрация имени в ENS — это четырехэтапный процесс. Сначала мы делаем ставку на любое доступное имя, а затем раскрываем нашу ставку через 48 часов, чтобы закрепить имя. Временная шкала ENS для регистрации представляет собой диаграмму, показывающую временную шкалу регистрации.

Давайте зарегистрируем наше имя!

Мы будем использовать один из нескольких доступных удобных интерфейсов для поиска доступных имен, размещения ставки на имя ethereumbook.eth, раскрытия ставки и защиты имени.

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

Во-первых, нам нужно убедиться, что имя, которое мы хотим, доступно. При написании этой книги мы очень хотели зарегистрировать имя mastering.eth, но, увы, поиск имен ENS на MyCrypto.com показал, что оно уже занято! Поскольку регистрация ENS длится всего один год, в будущем может появиться возможность защитить это имя. А пока давайте поищем ethereumbook.eth.

Рисунок 6. Поиск имен ENS на MyCrypto.com

Большой! Имя доступно. Чтобы зарегистрировать его, нам нужно перейти к началу аукциона для имени ENS. Давайте разблокируем MetaMask и начнем аукцион на ethereumbook.eth.

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

Предупреждение
Как упоминалось в аукционах Vickrey, вы должны объявить свою ставку в течение 48 часов после завершения аукциона, иначе вы потеряете средства в своей ставке. Мы забыли это сделать и сами потеряли 0,01 ETH? Вы держите пари, что мы сделали.

Сделайте снимок экрана, сохраните свою секретную фразу (в качестве резервной копии для вашей ставки) и добавьте в свой календарь напоминание о дате и времени раскрытия, чтобы вы не забыли и не потеряли свои средства.

Наконец, мы подтверждаем транзакцию, нажав большую зеленую кнопку отправки, показанную в транзакции MetaMask, содержащей вашу ставку.

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

Управление вашим именем ENS

После того, как вы зарегистрировали имя ENS, вы можете управлять им с помощью другого удобного интерфейса: ENS Manager.

Оказавшись там, введите имя, которым вы хотите управлять, в поле поиска (см. Веб-интерфейс ENS Manager). Вам необходимо разблокировать кошелек Ethereum (например, MetaMask), чтобы DApp ENS Manager мог управлять именем от вашего имени.

Из этого интерфейса мы можем создавать поддомены, устанавливать контракт распознавателя (подробнее об этом позже) и подключать каждое имя к соответствующему ресурсу, например, адресу Swarm внешнего интерфейса DApp.

Создание субдомена ENS

Во-первых, давайте создадим субдомен для нашего примера Auction DApp (см. Добавление субдомена auction.ethereumbook.eth). Мы назовем аукцион поддоменов, поэтому полное имя будет auction.ethereumbook.eth.

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

Резольверы ENS

В ENS разрешение имени представляет собой двухэтапный процесс:

  1. Реестр ENS вызывается с именем для разрешения после его хеширования. Если запись существует, реестр возвращает адрес ее распознавателя.
  2. Преобразователь вызывается с использованием метода, соответствующего запрашиваемому ресурсу. Преобразователь возвращает желаемый результат.

Этот двухэтапный процесс имеет несколько преимуществ. Отделение функциональности распознавателей от самой системы именования дает нам гораздо больше гибкости. Владельцы имен могут использовать собственные преобразователи для разрешения любого типа или ресурса, расширяя функциональные возможности ENS. Например, если в будущем вы захотите связать ресурс геолокации (долготу/широту) с именем ENS, вы можете создать новый преобразователь, который отвечает на запрос geolocation. Кто знает, какие приложения могут быть полезны в будущем? С пользовательскими преобразователями единственным ограничением является ваше воображение.

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

Поскольку мы хотим связать наше Auction dApp с хэшем Swarm, мы можем использовать общедоступный преобразователь, который поддерживает разрешение контента, как показано в разделе Настройка общедоступного преобразователя по умолчанию для auction.ethereumbook.eth; нам не нужно кодировать или развертывать собственный распознаватель.

Преобразование имени в хэш Swarm (контент)

Как только резолвер для auction.ethereumbook.eth установлен как общедоступный резолвер, мы можем настроить его так, чтобы он возвращал хеш Swarm в качестве содержимого нашего имени (см. Настройка «контента» для возврата для auction.ethereumbook.eth).

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

или выполнив поиск в браузере DApp или шлюзе Swarm для URL-адреса Swarm:

  • bzz://ab164cf37dc10647e43a233486cdeffa8334b026e32a480dd9cbd020c12d4581

Теперь, когда мы привязали его к имени, все намного проще:

Мы также можем найти его, выполнив поиск «auction.ethereumbook.eth» в любом ENS-совместимом кошельке или браузере DApp (например, Mist).

От приложения к децентрализованному приложению

За последние несколько разделов мы постепенно создали децентрализованное приложение. Мы начали с пары смарт-контрактов для проведения аукциона по ERC721. Эти контракты были разработаны без управляющих или привилегированных учетных записей, поэтому их работа действительно децентрализована. Мы добавили интерфейс, реализованный на JavaScript, который предлагает удобный и удобный интерфейс для нашего dApp. Аукцион dApp использует децентрализованную систему хранения Swarm для хранения ресурсов приложения, таких как изображения. Приложение dApp также использует протокол децентрализованной связи Whisper, чтобы предлагать зашифрованный чат для каждого аукциона без каких-либо центральных серверов.

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

С каждым из этих шагов мы увеличивали децентрализацию нашего приложения. Конечным результатом является децентрализованное приложение, которое не имеет ни центральной точки власти, ни центральной точки отказа и выражает видение «web3».

Архитектура Auction dApp показывает полную архитектуру Auction dApp.

Заключение

Децентрализованные приложения являются кульминацией видения Ethereum, выраженного его основателями в самых ранних разработках. Хотя сегодня многие приложения называют себя «dApps», большинство из них не полностью децентрализовано.

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

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