Help us understand the problem. What is going on with this article?

【2019年3月版】Hyperledger Indy 事始め

Hyperledger Indy 初めて見ました。始めてみました。

Hyperledger Indy についての詳しい紹介などは本家サイトをご覧ください。
https://www.hyperledger.org/projects/hyperledger-indy

本稿では Hyperledger-Indy のindy-sdkからjs版のクライアントサンプルを動かして indy がどんなもんか感触を確かめる、というところまでの手順をメモするものです。indyの使い方、扱い方には至っておりません。。。

indy プロジェクトとリポジトリの関係

まず、indyプロジェクトの実装があるgithubのリポジトリについてなんですが、けっこう入り組んでいるのでプリミティブな箇所だけご紹介します。

  • 1. indy-node : Hyperledger-Indy メインプロジェクト。ネットワークの本体
    • 1-1. indy-plenum : Indy ネットワークのプロトコル。ビザンチン問題解決、ブロックチェーンなどなど
  • 2. indy-sdk : Indyのクライアントライブラリ、匿名資格証明書(anoncreds)、CLI、各言語向けのクライアントライブラリラッパー
  • 3. indy-crypto : Indy の共通 暗号処理ライブラリ。Rustで書かれてます。indy-node、indy-sdkの双方からリンクされてます。

Indyのクライアントを開発する上では主に indy-sdkを使用した上での開発作業になります。
また、共通ライブラリのindy-cryptoがRustで書かれているお陰でsdkのコアライブラリはRustです。
Rust→シェアライブラリ(libindy.so)→各言語ラッパー→クライアント という依存関係になっており、なかなかハードです。

indy プロジェクトのドキュメント

indyプロジェクトはドキュメントがかなり広範囲に散逸しているため一元的な情報収拾が難しい状況にあります。
以下、今回の環境構築で参照(発掘)した有益であろうと思われるドキュメントのリンクを残しておきます。

また上記以外にもリポジトリの各階層には割と細かくREADMEがあるのでこまめにチェックが必要です。(だからまとまってないんだけどね・・・)

構築する環境

今回、構築する環境はちょっとアレなんですが以下のようになってます。

  • Ubuntu 18.04 の実機
    • lxc: Ubuntu 16.04 -> indy-sdkビルド環境
      • docker: Ubuntu 16.04 -> indy-nodeのテストネットワーク(自動生成)
      • docker: Ubuntu 16.04 -> indy-sdkのサンプル実行環境(手動生成)

Xenialの実機が用意できなかったのでlxcでXenialコンテナ作りました。サンプル実行環境の構築に手間取ったのも第1弾ロケットがコンテナである影響、あると思います。
用意できるならXenial実機が素直に良いと思います。(いや、このためにわざわざ買ってこないけどね。)

indy-nodeのテストネットワークはindyプロジェクト内のテストで使用するためあらかじめDockerfile、docker-comopse.ymlが用意されています。そのためコマンドで立ち上げるだけでOKです。
サンプル実行環境のdockerについては以下で作成手順をご紹介いたします。

またdockerが動くlxcコンテナの作り方についてはこちらをご参照ください。

環境の構築手順

docker,docker-composeなどのツールは上記のページでインストール済みであるとします。

0. indyユーザーの作成

以下の手順ではrootではないsdkビルド専用のユーザーindyでの作業をメインに行なっていきます。
またindyユーザーがdockerを実行するために、dockerグループにindyを追加します。

# useradd -m indy
# echo 'indy:indypass' |chpasswd
# gpasswd -a indy docker
Adding user indy to group docker

(こういうところがね〜、dockerは嬉しくないんだけどね〜)

1. indy-sdk のビルド環境を構築する

それではさっそく以下の手順に習って、indy-sdkのビルド環境を構築していきましょう。
indy-sdk の環境構築、ビルド手順は一通り以下のURLに記載されています。

1-1. Rust のインストール

indy ユーザーで Rust をインストールします。

$ curl https://sh.rustup.rs -sSf | sh

表示される選択肢で、1を選択。

1-2. 依存パッケージのインストール

続いてビルドに必要なツール類を apt でインストール。ここでは indy ユーザーから抜けて root で実行します

$ exit
# apt-get install -y \
   build-essential \
   pkg-config \
   cmake \
   libssl-dev \
   libsqlite3-dev \
   libzmq3-dev \
   libncursesw5-dev

1-3. libsodiumをビルド

以下の手順でlibsodium をソースからビルド

# cd /tmp && \
  curl https://download.libsodium.org/libsodium/releases/old/libsodium-1.0.14.tar.gz | tar -xz && \
   cd /tmp/libsodium-1.0.14 && \
   ./configure --disable-shared && \
   make && \
   make install && \
   cd .. && \
   rm -rf /tmp/libsodium-1.0.14

1-4. deb生成ツールのインストール

indyユーザに戻り、cargoコマンドからdebを生成するためのプラグインをインストールします。

# su - indy
$ cargo install cargo-deb

これで本体をビルドする環境は整いました。

2. ソースのクローン

Github からindy-node、indy-sdkをクローンします。

~$ git clone https://github.com/hyperledger/indy-node.git
~$ git clone https://github.com/hyperledger/indy-sdk.git

3. libindyのビルド

この手順は今回のサンプルを実行する手順では必須ではありません。とりあえずサンプルだけ動かしたい場合はこの手順を飛ばして下の"JS版サンプルの実行"の手順に進んで頂いてOKです。

3-1. ビルド

libindy のビルドを行います。

$ cd ~/indy-sdk/libindy
$ cargo build

cargo buildのオプションなしではlibindy/target/debug以下にアセンブリが生成されます。
--releaseオプションでlibindy/target/release以下にアセンブリが生成されます。

3-2. テストの実行

libindyのテスト実施にはテスト用のindy-nodeのネットワークが必要です。
別ターミナルを開いてindyユーザーでテスト用のネットワークを立ち上げておきます。

$ cd indy-node/environment/docker/pool/
~/indy-node/environment/docker/pool$ ./pool_start.sh

で indy 動作用の Docker コンテナがモリモリ作成されます。初回は長大な時間がかかりますがノード4つが立ち上がります。

Creating pool network pool-network
...
Starting node node1 10.0.0.2
...
Starting node node2 10.0.0.3
...
Starting node node3 10.0.0.4
...
Starting node node4 10.0.0.5
...

テスト用のネットーワクが立ち上がったら元のターミナル側でlibindyのテストを実行します。

$ RUST_TEST_THREADS=1 TEST_POOL_IP=10.0.0.2 cargo test

3-3. 番外編 debパッケージ

3-3-1. debパッケージの生成

debパッケージは以下のコマンドで生成できます。アセンブリを手作業でインストールするのはアレなのでdpkgコマンドで直接インストールできるようにdebファイルを作っておきます。

$ cargo build --release
$ cargo deb

libindy/target/debian/以下にdebファイルが生成されます。

3-3-2. debのインストール

debからインストールするにはindyを抜けてrootユーザーでdpkgコマンドを使用します。

$ exit
# dpkg -i /home/indy/indy-sdk/libindy/target/debian/libindy_1.8.1_amd64.deb

4. CLI

本家ドキュメントではオプショナルですが、libindyのビルドやインストールがうまくいっているかどうかを確かめるにはcliのビルドが手っ取り早いです。

4-1. CLIのビルド

以下のコマンドでcliフォルダに移動してビルドを行います。

$ cd ../cli
$ RUSTFLAGS=" -L ../libindy/target/debug" cargo build

また、debファイルやaptlibindylibindy-devを直接インストールした場合は、RUSTLAGSなしでビルド可能です。

$ cargo build

ここでエラーが出る場合は、アセンブリの生成やインストールがミスっていることがわかります。
ただし、CLIは直接 libindyを参照しているわけではなく、indy/wrappers/rustのRustラッパーを経由してのlibindyの使用です。どちらのビルドがうまくいっているか or いってないかをログをみて判断する必要があります。
つまり、

libindyはOKか? → Rust WrapperはOKか? → CLIはOKか?

の順にチェックしていく必要があります。
CLIのビルドに限らずHyperledger Indyのクライアント開発においては上記のように言語ラッパーがちゃんとはまっているか?を頭に入れておく必要があります。

4-2. CLIのインストール

以下の手順でCLIコマンドが使用可能になります。

$ cargo install
warning: Using: Using `cargo install` to install the binaries for the package in current working directory is deprecated, use `cargo install --path .` instead. Use `cargo build` if you want to simply build the package.
  Installing indy-cli v1.8.1 (/home/indy/indy-sdk/cli)
    Finished release [optimized] target(s) in 0.22s
  Installing /home/indy/.cargo/bin/indy-cli
$ indy-cli
indy>
indy>
indy> exit
Goodbye...

TODO: 4-3. CLIの使用

CLIの使用方法についてはちょっと膨大なのでTODOとさせてください。すいません。。

JS版サンプルの実行

JS版サンプルプログラムの概要は以下のページにあります。
https://github.com/hyperledger/indy-sdk/tree/master/samples/nodejs
ただし今回はそもそもnpm installがうまくいかなかったので、このままの手順ではないです。

0. libindy用テストネットワークの停止

上記のlibindyのテストを実施した場合はテストネットが10.0.0.2で動いていると思いますが、サンプルプロジェクトでは新規にネットワークを立ち上げるため、libindyテスト用のネットワークは停止させます。
別のターミナルを開き、以下のコマンドでテストネットワークを停止します。

~$ cd indy-node/environment/docker/pool/
~/indy-node/environment/docker/pool$ ./pool_stop.sh

1. サンプル実行用テストネットワークの準備

サンプル実行用のネットワークを構築するのは以下のdocker-compose.ymlです。
indy-sdk/docs/getting-started/docker-compose.yml
また、ここから参照されている実体のDockerfileは以下です。
indy-sdk/ci/indy-pool.dockerfile

このdockerfile, docker-compose.ymlのネットワークは先のpool_start.shで作成されるdockerコンテナが4つ立ち上がる構成ではなく、1つのdockerコンテナ内に、ノードが4つ立ち上がり別ポートでアクセスするネットワークとなっています。

1-1. indy-pool.dockerfileの修正

indy-pool.dockerfileで指定されているライブラリのバージョンが若干古いのと、indy-nodeがListenするIPアドレスがdocker-composeとあっていないので以下の変数に修正を加えます。

indy-pool.dockerfile
...
ARG indy_plenum_ver=1.6.721
ARG indy_node_ver=1.6.860
...
ARG pool_ip=10.0.0.2
...

1-2. docker-compose.yml の修正

docker-compose.ymlではindyのネットワークの他に、jupyterコンテナが立ち上がってjupyterから直接ノードを叩ける環境を提供してくれます。
ありがたいですが現状ではちょっといらないので、コメントアウトしてしまいます。

docker-compose.yml
version: '2'
services:
  indy_pool:
    build:
      context: ../../ci/
      dockerfile: indy-pool.dockerfile
      args:
        pool_ip: '10.0.0.2'
    image: indy_pool
    container_name: indy_pool
    working_dir: /home/indy
    ports:
      - "9701:9701"
      - "9702:9702"
      - "9703:9703"
      - "9704:9704"
      - "9705:9705"
      - "9706:9706"
      - "9707:9707"
      - "9708:9708"
    networks:
      pool_network:
        ipv4_address: 10.0.0.2
    volumes:
       - sandbox:/var/lib/indy/sandbox/
#  jupyter:
#    build:
#      context: .
#      dockerfile: getting-started.dockerfile
#    command: jupyter notebook --ip=0.0.0.0
#    image: getting-started
#    container_name: getting_started
#    working_dir: /home/indy
#    volumes:
#       - ./getting-started.ipynb:/home/indy/getting-started.ipynb
#      - sandbox:/home/indy/sandbox
#    ports:
#      - "8888:8888"
#    networks:
#      - pool_network
#    links:
#      - indy_pool
networks:
  pool_network:
    driver: bridge
    ipam:
      driver: default
      config:
        -
          subnet: 10.0.0.0/24
volumes:
     sandbox:

また、ネットワークにpool_network、そしてボリュームにsandboxが生成されるのが注目点です。

1-3. テストネットワーク起動

docker-composeのお陰でネットワークの起動は簡単です。

$ cd ~/indy-sdk/docs/getting-started/
$ docker-compose up &

indy-poolという名前のコンテナが起動します。

1-4. 接続設定ファイルの取得

ネットワークに接続するには各ノードへの接続トークなどが記載されている設定ファイルのpool_transactions_genesisが必須です。
今回のサンプルではプログラム内に直打ち(!!)されているので必要ないですが、通常はマストかと思います。
以下の手順で取得します。

$ docker exec -it indy_pool bash

$ cat /var/lib/indy/sandbox/pool_transactions_genesis

表示される内容をコピペなどしておき、接続情報を退避しておきましょう。
また indy のログなどは上記の /var/lib/{ネットワーク名}/{ノード名}.xxxなどのようにファイルが生成されます。

1-5. ネットワークの停止

停止の手順は非常に簡単ですが、indyプログラムの動作確認で非常に重要なのがボリュームの削除です。

$ docker-compose down
$ docker volume rm getting-started_sandbox

ブロックチェーンであるindyは一度、テストプログラムを流してしまったら元の状態には戻せないので、再度サンプルを動かすためにはボリュームの削除しかないです。
接続のエラーでうまくいかない場合にもなんらかの情報が残ってしまっている可能性がありますので、サンプルプログラムからの接続がうまくいかずにネットワークを再起動する場合にもボリュームの削除がマストです。
(というか、調子悪かったらだいたいボリューム削除すればなんとかなる。)

2. サンプルプログラム実行環境の構築

サンプルプログラムの実行環境だけをdockerで切り出すのにはいくつか理由があります。(というか切り出さないと全然ダメでした。)

  1. indy-nodeやindy-plenumの開発環境はUbuntu16.04+python3がマスト
  2. indylibのjs wrapperはlibindy.soをリンクするためにnpm install時に node-gyp rebuildします。お察しかと思いますがnode-gypはpython 3未対応です。
  3. JSのサンプル動かすのにpyenvするのはアレなのでさっさとコンテナ化してしまおう。
  4. サンプルプログラムからjs wrapperへのリンクが "../../wrappers/nodejs"でファイルパス指定されてて(しかも上位階層)、npm installがうまく動かなかった。これはコンテナから実行しているのが原因だと思います。仕方ないので、ファイルパス指定やめてリポジトリからインストールするようにしました。

はい、力不足で申し訳ない。。。node-gypとpython3の共存については詳しい方にお任せしてさっさと動かしてみたいと思います。

2-1. Dockerfileの作成

js版のサンプルプログラムは以下の箇所にあります。
indy-sdk/tree/master/samples/nodejs/
ここに以下のDockerfileを作成します。

Dockerfile
FROM ubuntu:xenial

RUN sed -i.bak -e "s%archive.ubuntu.com%jp.archive.ubuntu.com%g" /etc/apt/sources.list

RUN apt update && \
  apt upgrade -y && \
  apt-get install -y build-essential pkg-config make cmake curl git \
  libssl-dev libsqlite3-dev libzmq3-dev libncursesw5-dev python \
  apt-transport-https

RUN cd /tmp && \
  curl https://download.libsodium.org/libsodium/releases/old/libsodium-1.0.16.tar.gz | tar -xz && \
  cd /tmp/libsodium-1.0.16 && \
  ./configure --disable-shared && \
  make && \
  make install && \
  cd .. && \
  rm -rf /tmp/libsodium-1.0.16

RUN apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 68DB5E88
RUN echo "deb https://repo.sovrin.org/sdk/deb xenial stable" >> /etc/apt/sources.list
RUN apt-get update -y && apt-get install -y \
  libindy libindy-dev

RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash

SHELL ["/bin/bash", "-c"]
RUN source ~/.nvm/nvm.sh && nvm install --lts && nvm use --lts

WORKDIR /opt
RUN git clone https://github.com/hyperledger/indy-sdk.git

WORKDIR /opt/indy-sdk/samples/nodejs
RUN sed -i -e "s%file:\.\./\.\./wrappers/nodejs%^1.8.1%" package.json
RUN source ~/.nvm/nvm.sh && nvm use --lts && npm install
ENV TEST_POOL_IP=10.0.0.2

要はこれまでのindy-sdk開発環境丸ごととpython2.7、nodejsを入れた環境を構築しています。
ちょっとnpm installでうまくいかず試行錯誤したので、いくつかのバージョンのnodeを試すためにnvmを使いました。が、shではsourceできないのでbashを使うなど小さな苦労が積み重なっているのでここにそのまま掲載します。

以下のコマンドでイメージをビルドします。

$ docker build -t indy-sample-nodejs .

2-2. サンプルプログラムの実行

では、コンテナを動かしてサンプルプログラムを実行します。肝はテストネットと同じdockerのネットワークに参加する部分です。

$ docker run -it --rm --net=getting-started_pool_network --ip=10.0.0.15 indy-sample-nodejs bash

サンプルプログラム実行環境のコンテナが立ち上がり、中に入った状態となります。位置はDockerfileのWORKDIRで指定した/opt/indy-sdk/samples/nodejsとなります。
接続情報となるトークンの最終確認です。以下のコマンドで、util.jsの中身がざーっと表示されます。

$ cat src/util.js

ここで上記で揚げた接続情報の直打ち(!!)の内容が表示されています。先の手順で取得したpool_transactions_genesisの中身とトークンなどが違っていたら修正します。(多分、そのまま行けると思います。)
そして以下のコマンドですべてのサンプルプログラムが実行されます。

$ node src/main.js
gettingStarted.js -> started
Open Pool Ledger: pool1
==============================
=== Getting Trust Anchor credentials for Faber, Acme, Thrift and Government  ==
------------------------------
"Sovrin Steward" -> Create wallet
"Sovrin Steward" -> Create and store in Wallet DID from seed
==============================
== Getting Trust Anchor credentials - Government Onboarding  ==
------------------------------
"Sovrin Steward" > Create and store in Wallet "Sovrin Steward Government" DID
"Sovrin Steward" > Send Nym to Ledger for "Sovrin Steward Government" DID
...

このgettingStarted.js -> started以下で流れているログが、https://github.com/hyperledger/indy-sdk/blob/master/docs/getting-started/indy-walkthrough.md#about-alice 以下で解説されているself-sovereignのシナリオをプログラムとして実行した結果となります。
これでやっとindyのシナリオがちゃんと解読できますね〜!

いや〜、長かった。。。

ですけどこれ、スタートラインっすね

ということでサンプルプログラムはなんとか動きましたがまだまだスタートラインに立ったばかりです。引き続きindyクライアントの開発にチャレンジしてみたいと思います。
本日は以上です。

koinori
最近の記事はタグが5つじゃ足りない。
pro-japan
ソフトウェアの受託開発・SES・メディア事業・ブロックチェーンの開発提案など。「あったらいいな」を実現します!
https://www.pro-japan.co.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした