Hyperledger Fabric — это блокчейн-платформа с открытым исходным кодом от Linux Foundation. С её помощью можно создавать блокчейн-приложения и управлять доступом и разрешениями для данных в цепочке блоков. Hyperledger Fabric стоит использовать в том случае, если требуется создать частную блокчейн-сеть или установить ограничения на то, какие транзакции может видеть каждая сторона.

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

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

Amazon Managed Blockchain


У AWS есть сервис Amazon Managed Blockchain. Он позволяет развертывать блокчейн-сети с помощью пользовательских интерфейсов консоли AWS. Но, получив некоторый опыт работы с Amazon Managed Blockchain, нам пришлось отказаться от идеи использования сервиса в коммерческих проектах. Причин для этого было несколько. Основные из них:

  1. В Amazon Managed Blockchain была доступна лишь версия Hyperledger Fabric 1.2, а на момент написания этой статьи для построения корпоративных блокчейн-сетей используется версия 1.4. Это также не позволяет применять современные версии инструментов Node.js SDK;
  2. Amazon Managed Blockchain не поддерживает базу данных CouchDB, что затрудняет создание тех приложений, в которых индексируются хранимые данные.

Поэтому, наше мнение: для построения сетей с помощью фреймворка Hyperledger Fabric лучше использовать виртуальные или физические серверы.

О каналах приложения


В Hyperledger Fabric есть понятие «канала». Канал — это подсеть для проведения конфиденциальных транзакций. В нашем приложении будет два канала.

  • «parentshospital». Он предназначен для проведения транзакций между участниками организаций Parents и Hospital: как создание и изменение медицинских карт, создание соглашения с педиатром, подпись педиатром соглашения.
  • «parentshospitalkindergarten». В пределах этого канала участники организаций Parents и Hospital будут взаимодействовать с участниками организации Kindergarten. Также здесь будут создаваться отчёты на основании данных из медицинских карт.

Рабочее окружение


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

Вся наша сеть будет расположена на серверах AWS EC2. Информация внутри блокчейн-сети будет храниться в CouchDB. Hyperledger Fabric поддерживает и базу данных LevelDB, однако CouchDB является хранилищем для JSON-документов, а не хранилищем значений ключей, поэтому позволяет индексировать содержимое документов. Также будем использовать Fabric Certificate Authority — это модульный компонент для управления сетевыми идентификаторами всех организаций и их пользователей. Он обеспечивает регистрацию участников сети и выпуск сертификатов.

EC2-серверов у нас будет четыре:

  1. Orderer, MySQL DB (для хранения информации)
  2. Parents organisation (Peer0, Peer1), CouchDB, Fabric-CA, CLI
  3. Hospital organisation (Peer0, Peer1), CouchDB, Fabric-CA
  4. Kindergarten organisation (Peer0, Peer1), CouchDB, Fabric-CA

Создание серверов EC2 на AWS


Нам для работы необходимы t2.medium-сервисы. Этот тип EC2-серверов имеет достаточные вычислительные мощности для установки всего необходимого программного обеспечения и работы с инструментом Hyperledger Fabric. В Configure Security Group устанавливаем All traffic, а Source — 0.0.0.0/0, ::/0.


Рис.1. Настройка Security Group в панели AWS.

Получили четыре EC2-сервера:

  1. ec2-18-232-164-119.compute-1.amazonaws.com
  2. ec2-54-145-203-186.compute-1.amazonaws.com
  3. ec2-54-80-241-117.compute-1.amazonaws.com
  4. ec2-52-87-193-235.compute-1.amazonaws.com

У вас, естественно, будут свои пути к серверам EC2.


Рис.2. Подготовленные для работы серверы EC2.

Установка необходимого ПО на серверы EC2


Теперь на каждый сервер EC2 нам необходимо установить Docker и Git. Для удобства откроем в терминале четыре вкладки. Зайдем в каждый сервис EC2 по SSH:

Терминал 1:

HOST1=ec2-18-232-164-119.compute-1.amazonaws.com
ssh ec2-user@$HOST1 -i ./key-poc.pem

Терминал 2:

HOST2=ec2-54-145-203-186.compute-1.amazonaws.com
ssh ec2-user@$HOST2 -i ./key-poc.pem

Терминал 3:

HOST3=ec2-54-80-241-117.compute-1.amazonaws.com
ssh ec2-user@$HOST3 -i ./key-poc.pem

Терминал 4:

HOST4=ec2-52-87-193-235.compute-1.amazonaws.com
ssh ec2-user@$HOST4 -i ./key-poc.pem

В каждом терминале выполним следующие команды:

sudo yum update -y
sudo yum install -y docker
sudo service docker start
sudo docker info
sudo yum install git
sudo usermod -a -G docker ec2-user
newgrp docker

Теперь у нас установлены Docker и Git.

Сеть


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

git clone https://gitlab.nixdev.co/poc-blockchain/network.git

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

Выполним эти действия на каждом из четырех серверов:

cd network && mkdir chaincode && cd chaincode
git clone https://gitlab.nixdev.co/poc-blockchain/medical-contract.git
git clone https://gitlab.nixdev.co/poc-blockchain/kindergarten-contract.git

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

cd network/poc-network
./1_generate_connection_files.sh
./2_generating_channel_configuration.sh

Теперь скопируем папки channel-artifacts и crypto-config на остальные три хоста в папку poc-network родительской директории network. Обратите внимание: при копировании на EC2-сервер организаций необходимо удалить из папки crypto-config/peerOrganizations сторонние сертификаты, которые относятся к работе иных организаций. Например, при копировании на хост Parents нам в этой папке необходимо оставить папку parents.poc-network.com, но удалить hospital.poc-network.com и kindergarten.poc-network.com.

Создание стека Docker Swarm


Чтобы контейнеры, которые принадлежат различным организациям и находятся на разных серверах EC2, имели возможность обращаться друг к другу, нам необходимо объединить их в стек. Давайте просмотрим наш файл network/poc-network/docker-compose-general.yaml. В нём прописана конфигурация сервисов, указано, на какие хосты будет развернут тот или иной сервис (ключ node.hostname), указаны псевдонимы (ключ aliases).

Нам необходимо инициализировать swarm в первом терминале:

docker swarm init
docker swarm join-token manager

Появится токен для присоединения другого EC2-сервера в стек. Что-то типа: docker swarm join --token SWMTKN-1-42ml0ohnnbidg8kflgp8xp9dkkus6mn1lslqc15hrxj4tk9e3q-5h4vbzbfk8p90n83oe08gbltf 172.31.46.214:2377.

Теперь мы можем выполнить в остальных терминалах:

docker swarm join --token SWMTKN-1-2xzco7t7txohnzd09318eczpbgmm8woex80byxptpt1jl5i2ar-bsg37h40xze1gaabg80i96gw2 172.31.38.245:2377

В консоли появится сообщение:

This node joined a swarm as a manager.

После того, как все три хоста присоединены к Swarm, мы сможем их увидеть в терминале первого хоста, выполнив команду:

docker node ls


Рис.3. Список серверов в Docker Swarm.

В папке network/poc-network есть файл .env.template, в котором необходимо прописать hostname для каждого из хостов:

ORDERER=ip-172-31-38-245
PARENTS=ip-172-31-43-64
HOSPITAL=ip-172-31-38-130
KINDERGARTEN=ip-172-31-40-157

Чтобы сгенерировать .env файл, необходимо запустить файл ./3_env_gen.sh.

Теперь создадим сеть с драйвером overlay:

docker network create --driver overlay --attachable stage_byfn

Запустим Swarm для создания стека на основании файла docker-compose-general.yaml:

env $(cat .env | grep ^[A-Z] | xargs) docker stack deploy -c docker-compose-general.yaml stage 2>&1

Этой командой мы также устанавливаем переменные окружения, которые описаны в файле .env и которые необходимы для корректной работы сети.

Можете выполнить команду docker service ls в первом терминале. Вы увидите список всех сервисов, которые запущены на всех наших экземплярах EC2.


Рис.4. Список всех сервисов, которые были запущены на всех серверах EC2.

Если вы видите в своем терминале то же самое, что и на скриншоте, то всё отлично. Теперь запустим нашу сеть. Во втором терминале необходимо войти в контейнер CLI (ведь именно на втором хосте развернут этот контейнер):

docker exec -ti stage_cli.1.owni217t53m53efjtikb5oa2f /bin/bash

Имя контейнера можно увидеть, выполнив в терминале команду docker ps.

В контейнере выполним все наши команды из файла 4_create_channels.sh, копируя их поочередно в терминал. В папке bin у нас находятся бинарники для создания сети:

  • peer channel create — создание каналов;
  • peer channel join — присоединение пира к каналу;
  • peer channel update — обновление конфигураций;
  • peer chaincode install — установка чейнкода;
  • peer chaincode instantiate — развернуть указанный цепной код в сети.

Теперь можно покинуть контейнер, выполнив команду exit.

Back-приложение для организации Parents


Установим приложение на второй хост:

cd ~
git clone https://gitlab.nixdev.co/poc-blockchain/back.git

Также нам необходимо установить NodeJS и Gcc-c++ (компилятор):

curl -sL https://rpm.nodesource.com/setup_10.x | sudo bash -
sudo yum install nodejs
cd back
sudo yum install gcc-c++ -y
npm install

Мы также можем зайти в нашу базу через adminer с такими авторизационными данными:

<HOST_1>:3306 (где <HOST_1> — это адрес первого сервера EC2, на котором хранится база данных)
dev
devpass
poc_database

Также необходимо подключить к базе данных наше API-приложение:

vim ~/back/config/config.json

Присваиваем верное значение ключу host. Наше back-приложение имеет подготовленные миграции и сиды. Надо запустить их:

npx sequelize-cli db:migrate
npx sequelize-cli db:seed:all

В базе данных должны появиться таблицы. А в таблице organisations мы увидим три строки с нашими организациями — parents, hospital, kindergarten.

При генерировании сертификатов в самом начале мы получили для каждой организации на первом хосте файлы для соединения с сетью. Скопируем файл connection-parents.json с первого хоста на второй. Для этого откроем еще один терминал из папки, где лежит наш key, и выполним команды:

HOST1=ec2-18-232-164-119.compute-1.amazonaws.com
HOST2=ec2-54-145-203-186.compute-1.amazonaws.com
scp -i ./key-poc.pem -r ec2-user@$HOST1:~/network/poc-network/connection-parents.json ~
scp -i ./key-poc.pem ~/connection-parents.json ec2-user@$HOST2:~/network/poc-network

Исправим exports.hostName в constants.js (значение для текущего хоста):

vim ~/back/constants.js

Запустим наше приложение во втором терминале:

npm start

В файле userGenerator.sh присвоим переменной HOST_2 верное значение:

vim ~/back/generators/userGenerator.sh

Далее необходимо запустить скрипт, который создаст пользователей организации Parents:

./back/generators/userGenerator.sh parents

Запускаем скрипт для генерирования медицинских карт:

node ~/back/generators/setCards.js

В блокчейне создадутся две карты, которые также запишутся в SQL-базу данных в таблицу cards.

Back-приложение для организации Hospital


По аналогии с предыдущим back-приложением нам надо разместить файл для соединения с сетью на третьем хосте. Для этого в пятом терминале выполним:

scp -i ./key-poc.pem -r ec2-user@$HOST1:~/network/poc-network/connection-hospital.json ~
scp -i ./key-poc.pem ~/connection-hospital.json ec2-user@$HOST3:~/network/poc-network

Склонируем наше приложение на третий хост:

cd ~
git clone https://gitlab.nixdev.co/poc-blockchain/back.git

Установим NodeJS и Gcc-c++ (компилятор):

curl -sL https://rpm.nodesource.com/setup_10.x | sudo bash -
sudo yum install nodejs
cd back
sudo yum install gcc-c++ -y
npm install

Исправим exports.hostName в constants.js (значение для текущего хоста):

vim ~/back/constants.js

Запустим наше приложение в третьем терминале:

npm start

В файле userGenerator.sh присвоим переменной HOST_3 верное значение:

vim ~/back/generators/userGenerator.sh

Далее нам необходимо запустить скрипт, который создаст пользователей организации Hospital:

./back/generators/userGenerator.sh hospital

У нас в базе теперь появился второй пользователь в таблице Users.

Back-приложение для организации Kindergarten


По аналогии с предыдущим back-приложением, нам надо разместить файл для соединения с сетью на третьем хосте. Для этого в пятом терминале выполним:

scp -i ./key-poc.pem -r ec2-user@$HOST1:~/network/poc-network/connection-kindergarten.json ~
scp -i ./key-poc.pem ~/connection-kindergarten.json ec2-user@$HOST4:~/network/poc-network

Склонируем наше приложение на третий хост:

cd ~
git clone https://gitlab.nixdev.co/poc-blockchain/back.git

Установим NodeJS и Gcc-c++ (компилятор):

curl -sL https://rpm.nodesource.com/setup_10.x | sudo bash -
sudo yum install nodejs
cd back
sudo yum install gcc-c++ -y
npm install

Исправим exports.hostName в constants.js (значение для текущего хоста):

vim ~/back/constants.js

Запустим наше приложение в третьем терминале:

npm start

В файле userGenerator.sh присвоим переменной HOST_4 верное значение:

vim ~/back/generators/userGenerator.sh

Далее нам необходимо запустить скрипт, который создаст пользователей организации Hospital:

./back/generators/userGenerator.sh kindergarten

У нас в базе теперь появился третий пользователь в таблице Users.

Установка wkhtmltopdf на второй, третий и четвёртый серверы EC2


Важный момент. Для генерации PDF-отчета о состоянии здоровья ребенка в back-приложении используется библиотека wkhtmltopdf.

Нам необходимо установить libpng — официальную библиотеку для работы с растровой графикой в формате PNG. Библиотека платформонезависимая и состоит из функций, написанных на языке Си.

Первая команда установит wkhtmltox — библиотеку LGPLv3 с открытым исходным кодом для отрисовки HTML в PDF и различные форматы изображений с помощью механизма отрисовки QtWebKit:

wget https://downloads.wkhtmltopdf.org/0.12/0.12.5/wkhtmltox-0.12.5-1.centos7.x86_64.rpm
sudo yum install -y wkhtmltox-0.12.5-1.centos7.x86_64.rpm

Второй блок команд загрузит и развернет библиотеку libpng15:

wget https://sourceforge.net/projects/libpng/files/libpng15/older-releases/1.5.15/libpng-1.5.15.tar.gz/download -O libpng-1.5.15.tar.gz
tar -zxvf libpng-1.5.15.tar.gz
cd libpng-1.5.15

Третий блок команд нужен для установки компилятора:

sudo yum groupinstall -y "Development Tools"
./configure --prefix=/usr
sudo make install

Еще необходимо установить LibTIFF:

sudo yum install -y libtiff

Можем протестировать:

wkhtmltopdf https://majestic.cloud majestic.pdf

Теперь вы сможете генерировать и просматривать PDF-документы.

Немного про Node SDK


NodeJS-инструменты для работы с сетью Hyperledger Fabric представлены в виде пакетов «fabric-ca-client -v 1.4.0» и «fabric-network» v 1.4.0». Все сервисы backend-приложения, которые с помощью Node SDK взаимодействуют с сетью, расположены в папке Services, в корне проекта.

Об этих инструментах и об их методах вы можете почитать в официальной документации.

Flow applications


Теперь расскажем о том, как взаимодействуют между собой участники сети в данном приложении. Все процессы описаны в UML-диаграмме. Рассмотрим каждый из них подробнее.


Рис.5. Графическое описание бизнес-процессов в приложении.

Итак, в сети присутствуют несколько организаций: Parents, Hospital и Kindergarten.

Участник организации Parents создает электронные медицинские карты для двоих своих детей. Эти данные будут храниться (и дополняться) в блокчейн-сети. Далее родитель отправляет запрос на соглашение с педиатром, который будет наблюдать его детей до достижения ими совершеннолетия (на диаграмме — request for an agreement with a doctor).

Участник организации Hospital подписывает соглашение (на диаграмме — doctor signs an agreement).

Далее родитель отправляет запрос в детский сад с просьбой зачислить его ребенка (на диаграмме — request for kindergarten to receive a child).


Рис.6. Страница со списком доступных учебных заведений в личном кабинете родителя.

Детский сад видит запрос в списке новых запросов:


Рис.7. Страница со списком заявок на поступление в личном кабинете учебного заведения.

Детский сад перед принятием решения о зачислении ребенка должен убедиться в его удовлетворительном состоянии здоровья. Для этого детский сад отправляет запрос в поликлинику, в которой наблюдается этот ребенок (на диаграмме — child health report request). Запрос к педиатру выполняется автоматически после того, как запрос на зачисление в сад перемещается во вкладку «Accepted».


Рис.8. Страница со списком одобренных заявок на поступление в личном кабинете учебного заведения.

Педиатр видит запрос и формирует отчёт, в котором содержатся данные о здоровье ребенка (на диаграмме — child health report create).


Рис.9. Страница со списком заявок на создание отчета о состоянии здоровья ребенка в личном кабинете больницы.

Родитель видит, что педиатр сформировал отчёт...:


Рис.10. Страница в личном кабинете родителя, где отображается статус отчетов о состоянии здоровья ребенка.

… и принимает решение о предоставлении доступа учебному дошкольному заведению к просмотру и скачиванию отчёта (на диаграмме — give permission to view the report).


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

Родитель нажимает «Confirm»:


Рис.12. Уведомление о том, что выбранное учебное заведение получило разрешение на просмотр медицинского отчета.

В списке отчётов в приложении учебного заведения появляется информация о том, что отчёт сформирован и доступен к просмотру и скачиванию в формате PDF.


Рис.13. Ссылка на скачивание отчета в формате PDF в строке с одобренной заявкой.

Вот такой отчёт вы увидите в новой вкладке на своём компьютере:


Рис.14. Сформированный сотрудником больницы отчет о состоянии здоровья ребенка.

Создание медицинских карт и соглашения с педиатром, подпись соглашения


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

Первый сервер EC2:

node ~/back/generators/setCards.js

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

С этого сервера EC2 нам надо создать соглашение с педиатром, который будет наблюдать детей:

node ~/back/generators/createAgreement.js

Теперь это соглашение необходимо подписать пользователем, которого мы создавали для организации Hospital. Выполняем команду со второго хоста:

node ~/back/generators/signAgreement.js

Наше соглашение подписано доктором и мы можем продолжать работать над нашим приложением. Далее нам необходимо установить frontend-приложение на второй, третий и четвёртый серверы EC2.

P.S.: Все команды для генерирования пользователей, карточек, соглашения и подписания соглашения вы можете найти в папке ~/back/generators.

Frontend-приложение для организации Parents


Выполним на втором хосте (где расположена организация Parents):

cd ~
git clone https://gitlab.nixdev.co/poc-blockchain/front.git

Исправим имя хоста, на котором будет расположено наше frontend-приложение:

VUE_APP_API_BASE_URL='http://ec2-107-22-75-46.compute-1.amazonaws.com:3006/'

Необходимо установить зависимости:

cd front
npm install

Также необходимо собрать приложение и запустить его на порте 8080:

docker build . -t my-app
docker run -d -p 8080:80 my-app

Наше приложение будет доступно по адресу: http://<HOST_2>:8080, где <HOST_2> — это адрес второго сервера EC2, на котором расположено наше приложение.

Логин: parents, пароль: password.

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


Рис.15. Информация о медицинских картах детей в личном кабинете родителя.

Frontend-приложение для организации Hospital


Выполним на втором хосте (где расположена организация Hospital):

cd ~
git clone https://gitlab.nixdev.co/poc-blockchain/front.git

Исправим имя хоста, на котором будет расположено наше frontend-приложение:

VUE_APP_API_BASE_URL='http://ec2-3-91-238-161.compute-1.amazonaws.com:3006/'

Необходимо установить зависимости:

cd front
npm install

Также необходимо собрать приложение и запустить его на порте 8080:

docker build . -t my-app
docker run -d -p 8080:80 my-app

Наше приложение будет доступно по адресу: http://<HOST_3>:8080, где <HOST_3> — это адрес третьего сервера EC2.

Логин: hospital, пароль: password.

Frontend-приложение для организации Kindergarten


Выполним на втором хосте (где расположена организация Kindergarten):

cd ~
git clone https://gitlab.nixdev.co/poc-blockchain/front.git

Исправим имя хоста, на котором будет расположено наше frontend-приложение:

VUE_APP_API_BASE_URL='http://ec2-107-22-12-137.compute-1.amazonaws.com:3006/'

Необходимо установить зависимости:

cd front
npm install

Также необходимо собрать приложение и запустить его на порте 8080:

docker build . -t my-app
docker run -d -p 8080:80 my-app

Наше приложение будет доступно по адресу: http://<HOST_4>:8080, где <HOST_4> — это адрес четвертого сервера EC2.

Логин: kindergarten, пароль: password.

Заключение


Мы рассмотрели, как развернуть сеть блокчейн-приложения на нескольких виртуальных или физических серверах. Статья рассчитана на то, что вы знакомы с основами блокчейн-технологии, знаете, что такое смарт-контракты, и хотя бы поверхностно знакомы с фреймворком Hyperledger Fabric и его стандартным приложением fabric-samples.