Hyperledger Indy 初めて見ました。始めてみました。
Hyperledger Indy についての詳しい紹介などは本家サイトをご覧ください。
https://www.hyperledger.org/projects/hyperledger-indy
本稿では Hyperledger-Indy のindy-sdk
からjs版のクライアントサンプルを動かして indy がどんなもんか感触を確かめる、というところまでの手順をメモするものです。indyの使い方、扱い方には至っておりません。。。
indy プロジェクトとリポジトリの関係
まず、indyプロジェクトの実装があるgithubのリポジトリについてなんですが、けっこう入り組んでいるのでプリミティブな箇所だけご紹介します。
-
- indy-node : Hyperledger-Indy メインプロジェクト。ネットワークの本体
- 1-1. indy-plenum : Indy ネットワークのプロトコル。ビザンチン問題解決、ブロックチェーンなどなど
-
- indy-sdk : Indyのクライアントライブラリ、匿名資格証明書(anoncreds)、CLI、各言語向けのクライアントライブラリラッパー
-
-
indy-crypto : Indy の共通
暗号処理ライブラリ。Rustで書かれてます。indy-node、indy-sdkの双方からリンクされてます。
-
indy-crypto : Indy の共通
Indyのクライアントを開発する上では主に indy-sdkを使用した上での開発作業になります。
また、共通ライブラリのindy-cryptoがRustで書かれているお陰でsdkのコアライブラリはRustです。
Rust→シェアライブラリ(libindy.so)→各言語ラッパー→クライアント
という依存関係になっており、なかなかハードです。
indy プロジェクトのドキュメント
indyプロジェクトはドキュメントがかなり広範囲に散逸しているため一元的な情報収拾が難しい状況にあります。
以下、今回の環境構築で参照(発掘)した有益であろうと思われるドキュメントのリンクを残しておきます。
- indy-node README : https://github.com/hyperledger/indy-node/blob/master/README.md
- Hyperledger-indy の入り口。
- indy-sdk README : https://github.com/hyperledger/indy-sdk/blob/master/README.md
- indy-sdkの入り口。割とあっさり重要なリンクがふんだんに含まれている。
- indy-sdk ドキュメント : https://hyperledger-indy.readthedocs.io/projects/sdk/en/latest/
- indy-sdk/docs 以下のリポジトリ内容から生成されるindyのドキュメント。これ重要。
- https://chat.hyperledger.org/channel/indy : indy本家のチャットチャンネル。ググっても出てこない情報はだいたいここにあります。半年分くらい遡ってからページ内検索をした方がググるより有益です。
また上記以外にもリポジトリの各階層には割と細かくREADMEがあるのでこまめにチェックが必要です。(だからまとまってないんだけどね・・・)
構築する環境
今回、構築する環境はちょっとアレなんですが以下のようになってます。
- Ubuntu 18.04 の実機
- lxc: Ubuntu 16.04 -> indy-sdkビルド環境
- docker: Ubuntu 16.04 -> indy-nodeのテストネットワーク(自動生成)
- docker: Ubuntu 16.04 -> indy-sdkのサンプル実行環境(手動生成)
- lxc: 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
ファイルやapt
でlibindy
、libindy-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とあっていないので以下の変数に修正を加えます。
...
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から直接ノードを叩ける環境を提供してくれます。
ありがたいですが現状ではちょっといらないので、コメントアウトしてしまいます。
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で切り出すのにはいくつか理由があります。(というか切り出さないと全然ダメでした。)
- indy-nodeやindy-plenumの開発環境はUbuntu16.04+python3がマスト
- indylibのjs wrapperは
libindy.so
をリンクするためにnpm install
時にnode-gyp rebuild
します。お察しかと思いますがnode-gyp
はpython 3未対応です。 - JSのサンプル動かすのにpyenvするのはアレなのでさっさとコンテナ化してしまおう。
- サンプルプログラムからjs wrapperへのリンクが "../../wrappers/nodejs"でファイルパス指定されてて(しかも上位階層)、
npm install
がうまく動かなかった。これはコンテナから実行しているのが原因だと思います。仕方ないので、ファイルパス指定やめてリポジトリからインストールするようにしました。
はい、力不足で申し訳ない。。。node-gyp
とpython3の共存については詳しい方にお任せしてさっさと動かしてみたいと思います。
2-1. Dockerfile
の作成
js版のサンプルプログラムは以下の箇所にあります。
indy-sdk/tree/master/samples/nodejs/
ここに以下の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クライアントの開発にチャレンジしてみたいと思います。
本日は以上です。