Децентрализованное хранилище данных Ethereum Swarm
Блокчейн Ethereum интересен своими смарт-контрактами, а также возможностью создания децентрализованных приложений DApp (Decentralized Application). Однако такому приложению необходимо децентрализованное хранилище данных.
Хранение данных большого объема в блокчейне может стоить немалых денег. На помощь приходят такие децентрализованные хранилища, как Ethereum Swarm («swarm» переводится как «рой», «куча»). Если кратко, то Ethereum Swarm представляет собой программный код, работающий на пиринговой сети Ethereum. Он обеспечивает децентрализованное хранение данных на дисках узлов, владельцы которых отдают свои ресурсы в общее пользование.
В этой статье мы расскажем о том, как установить локальный узел Ethereum Swarm для приватной сети Ethereum с целью тестирования технологии и разработки децентрализованных приложений, хранящих данные в Ethereum Swarm.
Почему для DApp нужно децентрализованное хранилище данных
Блокчейн Ethereum (как и другие блокчейны) представляет собой распределенный журнал, очень хорошо защищенный от подделок и атак со стороны злоумышленников.
Защита эта достигается, с одной стороны, использованием хеширования и криптографических алгоритмов, алгоритмов добавления новых блоков в блокчейн, а с другой — огромным количеством узлов Ethereum, обеспечивающих хранение данных и обработку транзакций. Эти узлы расположены по всему миру. Ни у кого нет достаточно ресурсов, чтобы «сломать» блокчейн, и это обеспечивает доверие к записанной в нем информации.
«SkyNet всюду и нигде единого центра нет. Отключать нечего.» (Терминатор-3: Восстание машин)
Но как я уже отмечал выше, блокчейн не подходит для хранения данных большого объема, таких как документы, изображения, описания товаров, заказы и т.п. Теоретически вы, конечно, можете записать их в блокчейн, но стоимость записи будет слишком велика.
Где же хранить данные DApp большого объема?
Например, вы собираетесь при помощи блокчейна зафиксировать авторские права на изображения, сохранить навсегда сведения о заказе, сделанном в интернет-магазине, или сохранить сканы бумажных документов. Здесь потребуется какое-то другое хранилище данных.
Конечно, для хранения данных DApp вы можете арендовать сервер, место в облачном хранилище или использовать какое-либо другое традиционное хранилище. Но серверы, облака и хранилища контролируются компаниями или отдельными людьми. Они могут быть заблокированы по какой-либо причине или атакованы злоумышленниками.
При использовании централизованного хранилища теряется основное преимущество DApp — устойчивость к атакам и действиям злоумышленников. Более того, ваше приложение перестает быть децентрализованным. А значит теряется и доверие к DApp. Ведь если заблокировать или нарушить работу централизованного хранилища, пропадет доступ к части информации, зафиксированной DApp при помощи блокчейна, и пропадет весь смысл использования DApp.
Как работает Ethereum Swarm
Представьте себе, что по всеми миру разбросаны десятки тысяч узлов сети Ethereum Swarm, которые предоставляют свои ресурсы для хранения данных, загруженных пользователями. Предполагается, что владельцы узлов будут получать вознаграждение за предоставление ресурсов, при этом стоимость размещения данных будет ниже, чем в традиционных облачных хранилищах.
Когда пользователь загружает файл в сеть Ethereum Swarm, этот файл сначала попадает на один из узлов. Далее файл реплицируется на остальные узлы сети в процессе синхронизации. При этом используется протокол bzz, работающий поверх сети Ethereum.
До тех пор пока работает хоть один узел Ethereum Swarm, загруженный файл остается доступным. Это обеспечивает надежность хранения данных, т.к. практически невозможно вывести из строя или заблокировать огромное количество узлов Ethereum Swarm.
Подробнее обо все этом вы сможете прочитать на сайте Ethereum Swarm.
В документации отмечено, что к настоящему моменту Ethereum Swarm реализован в версии 0.2 как доказательство концепции (POC, proof of concept). В этой версии сохранность загруженных данных не гарантируется. Стабильный релиз ожидается во втором квартале 2018 года, так что ждать осталось недолго. Тогда же планируется создание системы вознаграждений за предоставление ресурсов для сети Ethereum Swarm.
Однако мы не будем ничего ждать, а начнем тестировать Ethereum Swarm прямо сейчас. Мы создадим собственный узел Ethereum Swarm в своей приватной сети Ethereum.
Установка Ethereum Swarm и Geth на Debian и Ubuntu
Я расскажу об установке Ethereum Swarm на серверах Debian и Ubuntu. В целом нужно действовать по этой инструкции, но есть некоторые нюансы.
Установка Go
Очень важно перед началом работ установить Go новой версии, не ниже 1.9.2. В репозитории Debian и Ubuntu могут быть старые версии Go, поэтому устанавливаем из исходников.
Скачиваем и распаковываем исходники под непривилегированным пользователем:
$ curl -O https://storage.googleapis.com/golang/go1.9.2.linux-amd64.tar.gz
$ sudo tar -C /usr/local -xzf go1.9.2.linux-amd64.tar.gz
Создаем у пользователя каталог go и устанавливаем переменные окружения:
$ mkdir -p ~/go; echo "export GOPATH=$HOME/go" >> ~/.bashrc
$ echo "export PATH=$PATH:$HOME/go/bin:/usr/local/go/bin" >> ~/.bashrc
$ source ~/.bashrc
Проверяем, что переменные окружения установлены:
$ printenv | grep go
PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/home/frolov/go/bin:/usr/local/go/bin
GOPATH=/home/frolov/go
В операционной системе Debian вместо файла .bashrc используйте файл .profile. Можно просто скопировать:
cp .bashrc .profile
Проверяем версию go:
$ go version
go version go1.9.2 linux/amd64
Версия go должна быть не ниже 1.9.2.
Если ранее была установлена старая версия go из репозитория ОС, удаляем ее так:
$ sudo apt-get remove golang-go
$ sudo apt-get remove --auto-remove golang-go
Устанавливаем Geth и Ethereum Swarm
Загружаем исходный код из репозитория:
$ mkdir -p $GOPATH/src/github.com/ethereum
$ cd $GOPATH/src/github.com/ethereum
$ git clone https://github.com/ethereum/go-ethereum
$ cd go-ethereum
$ git checkout master
$ go get github.com/ethereum/go-ethereum
Запускаем компиляцию клиента geth и демона swarm:
$ go install -v ./cmd/geth
$ go install -v ./cmd/swarm
Проверяем версию установленного geth и swarm:
$ geth version
Geth
Version: 1.8.0-unstable
Architecture: amd64
Protocol Versions: [63 62]
Network Id: 1
Go Version: go1.9.2
Operating System: linux
GOPATH=/home/frolov/go
GOROOT=/usr/local/go
$ swarm version
Swarm
Version: 1.8.0-unstable
Network Id: 0
Go Version: go1.9.2
OS: linux
GOPATH=/home/frolov/go
GOROOT=/usr/local/go
Подготовка приватного блокчейна для запуска Ethereum Swarm
Прежде всего, создайте в домашнем каталоге пользователя файл genesis.json:
{
"config": {
"chainId": 1907,
"homesteadBlock": 0,
"eip155Block": 0,
"eip158Block": 0
},
"difficulty": "40",
"gasLimit": "5100000",
"alloc": {}
}
Далее создайте в домашнем каталоге подкаталог node1:
$ mkdir node1
Инициализацию узла можно сделать при помощи пакетного файла init_node.sh:
geth --datadir node1 account new
geth --datadir node1 init genesis.json
При запуске этого файла будет создан аккаунт и запрошен пароль, который вам необходимо сохранить в безопасном месте.
Создайте файл start_node.sh для запуска узла:
geth --datadir node1 --nodiscover --mine --minerthreads 1 --maxpeers 0 --verbosity 3 --networkid 98765 --rpc --rpcapi="db,eth,net,web3,personal,web3" console
Запустите этот файл и дождитесь завершения генерации DAG.
С помощью файла attach_node.sh вы сможете открыть консоль geth и подключиться к приватному узлу:
geth --datadir node1 --networkid 98765 attach ipc://home/frolov/node1/geth.ipc
Запуск демона swarm
Здесь вам потребуется адрес аккаунта, созданного на этапе инициализации узла. Если вы его не сохранили, ничего страшного. Просто зайтите в консоль geth, открытую с помощью скрипта attach_node.sh, и выдайте там следующую команду:
> web3.eth.accounts
["0xcd9fcb450c858d1a7678a2bccf36ea5decd2b09b"]
Команда покажет адрес созданных учетных записей. Сразу после инициализации там будет только один адрес.
Для запуска демона Ethereum Swarm в режиме единственного узла (Singleton) подготовьте командный файл swarm_start.sh:
swarm --bzzaccount cd9fcb450c858d1a7678a2bccf36ea5decd2b09b --datadir "/home/ethertest/data/node1" --maxpeers 0 -nodiscover --verbosity 4 --ens-api /home/ethertest/data/node1/geth.ipc
Укажите в нем адрес аккаунта, созданного на вашем узле, без »0x».
При запуске демона вам будет нужно ввести пароль от созданного ранее аккаунта:
$ sh swarm_start.sh
Unlocking swarm account 0xCD9Fcb450C858D1A7678a2bCCf36EA5decd2B09B [1/3]
Passphrase:
Загружаем файл в Ethereum Swarm
Проще всего загрузить файл с помощью команды swarm с параметром up. Дополнительно нужно указать путь к загружаемому файлу:
$ swarm up start_node.sh
f2073b8f0cf0cfe1e165060882da71a37bb6fd97bdec6be71b4f66ebcf0aba9f
Данная команда вернет хеш загруженного файла. Хеш можно использовать для чтения файла. Вы можете это сделать с помощью команд wget или curl:
$ wget http://localhost:8500/bzz:/f2073b8f0cf0cfe1e165060882da71a37bb6fd97bdec6be71b4f66ebcf0aba9f/
$ curl http://localhost:8500/bzz:/f2073b8f0cf0cfe1e165060882da71a37bb6fd97bdec6be71b4f66ebcf0aba9f/
Команда wget позволяет сохранить содержимое файла на локальном диске. Используйте параметр -O, чтобы задать имя файла. Команда curl выведет содержимое файла на консоль, поэтому в таком виде ее не следует использовать для просмотра содержимого бинарных файлов. В конце URL необходим слеш, иначе произойдет редирект.
Когда файл загружается в Ethereum Swarm описанным выше образом, для него создается и сохраняется так называемый манифест. Это заголовок, описывающий содержимое, доступное в хранилище по заданному идентификатору.
Ниже мы загрузили файл Net-Ethereum-0.28.tar.gz с помощью простой команды swarm up:
$ swarm up Net-Ethereum-0.28.tar.gz
8da3713d49c62740f5ab594b06173975ac97cb3dd3848ae996484ec264a10e2f
Теперь, указав протокол bzz-list, мы можем просмотреть манифест:
$ curl http://localhost:8500/bzz-list:/8da3713d49c62740f5ab594b06173975ac97cb3dd3848ae996484ec264a10e2f/
{"entries":[{"hash":"543ee6e744f93de76ac132b8ab71982e32beaf90d1005e771dde003b2a4a54c3","path":"/","contentType":"application/gzip","mode":420,"size":12403,"mod_time":"2018-01-13T14:57:54+03:00"}]}
Манифест будет показан в формате JSON.
В манифесте хранится пусть к файлу (имя файла), его размер, тип (Content Type), дата и время модификации, а также хеш файла.
Чтобы извлечь содержимое файла по его идентификатору и сохранить под именем t.tar.gz, сделайте так:
$ wget -O t.tar.gz http://localhost:8500/bzz:/8da3713d49c62740f5ab594b06173975ac97cb3dd3848ae996484ec264a10e2f/
Загрузка каталогов с подкаталогами
Для рекурсивной загрузки каталога вместе с его содержимым в хранилище Ethereum Swarm укажите параметр --recursive:
$ swarm --recursive up Net-Ethereum/
4fb1f2270381c022461037151f70ce081082f0ae1a2a23d8c7ea602da69b4115
В манифесте будет показана информация обо всех файлах загруженного подкаталога:
$ curl http://localhost:8500/bzz-list:/4fb1f2270381c022461037151f70ce081082f0ae1a2a23d8c7ea602da69b4115/
{"common_prefixes":["blib/","lib/","t/"],"entries":[{"hash":"feea799e7d53fa8465489baf13f66becda29f94695d6ddad161af4bfc51556b4","path":"Changes","mode":420,"size":314,"mod_time":"2018-01-13T14:56:39+03:00"},{"hash":"11fe71c1ab60779eb7b055c96a6fe0fe88d498ca60ece51d79db62d6677f1bf9","path":"MANIFEST","mode":420,"size":241,"mod_time":"2018-01-09T18:38:06+03:00"},{"hash":"1fa030391282faa61b01c1ca07bc483db54c04173801e90477be0919bb9fa2b8","path":"META.json","contentType":"application/json","mode":420,"size":822,"mod_time":"2018-01-09T18:38:06+03:00"},{"hash":"261487aa0cb7218ee3953ac1a67b757cc59d19aadca0b6b4272b8751ba4dfe64","path":"META.yml","mode":420,"size":470,"mod_time":"2018-01-09T18:38:06+03:00"},{"hash":"4a4ef37333596472a6a5bcee20456621f039f2f3bb9a331f0afc289a1e122af5","path":"MYMETA.json","contentType":"application/json","mode":420,"size":862,"mod_time":"2018-01-13T14:57:41+03:00"},{"hash":"374603f37acd044b3605dc0c051b9996625c9dfcce4919e80ba84bda21b4bbcd","path":"MYMETA.yml","mode":420,"size":510,"mod_time":"2018-01-13T14:57:41+03:00"},{"hash":"18cdc7c003810e53974187bcee1b7d2c536c4b952fe0f199d264e5af21d6548c","path":"Makefile.PL","contentType":"text/x-perl; charset=utf-8","mode":420,"size":664,"mod_time":"2018-01-13T12:24:37+03:00"},{"hash":"44481e1b88e2c00cd30717108d8490d839358bb4cb9895962e4fa64c2be6ed73","path":"Makefile","mode":420,"size":27605,"mod_time":"2018-01-13T14:57:41+03:00"},{"hash":"543ee6e744f93de76ac132b8ab71982e32beaf90d1005e771dde003b2a4a54c3","path":"Net-Ethereum-0.28.tar.gz","contentType":"application/gzip","mode":420,"size":12403,"mod_time":"2018-01-13T14:57:54+03:00"},{"hash":"c6ff1f1742a156aeaf98fcfb480cfb168857029a8790ac8c3bc7a00aef415021","path":"README","mode":420,"size":1303,"mod_time":"2018-01-13T14:57:31+03:00"},{"hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","path":"pm_to_blib","mode":420,"mod_time":"2018-01-13T14:57:49+03:00"}]}
Другие возможности Ethereum Swarm
В этой статье я не рассказал обо всех возможностях Ethereum Swarm, ограничившись лишь самым необходимым.
Помимо загрузки отдельных файлов и содержимого каталогов вы можете добавлять данные к манифесту. При этом создается новый элемент данных с дополненным манифестом и с добавленными файлами.
Есть возможность загружать файлы без манифеста, а также считывать их в так называемом «сыром» (raw) виде.
При считывании файла можно указывать его имя (полностью или частично). При этом будет задействован сервис имен ENS (Ethereum Name Service). Такая возможность позволит вам получить только некоторые файлы из блока, объединенного общим манифестом.
Я также не описал SWarm Accounting Protocol (SWAP) и некоторые другие возможности. Проект Ethereum Swarm активно развивается, в нем обязательно появится еще что-нибудь интересное для разработчиков децентрализованных приложений.
Модуль Perl Net: Ethereum: Swarm
Для того чтобы работать с децентрализованным хранилищем данных Ethereum Swarm в системах, написанных на языке Perl, я разработал и выложил на CPAN модуль Net: Ethereum: Swarm.
С помощью этого модуля вы сможете загружать в Ethereum Swarm текстовые и бинарные файлы, получать манифест для загруженных данных, а также загружать файлы из Ethereum Swarm по их идентификатору.
Модуль Net: Ethereum: Swarm работает с узлом Ethereum Swarm с помощью HTTP-запросов GET и POST. Использование запросов описано в разделе The HTTP API документации.
Взаимодействие через HTTP-запросы можно легко реализовать практически на любом языке программирования.
Другие мои статьи о блокчейне и смарт-контрактах Ethereum
- Эксперименты с контрактами Solidity в тестовой сети Rinkeby блокчейна Ethereum
- Модуль Net: Ethereum для работы с контрактами Solidity