こんにちは。株式会社日立ソリューションズの田辺です。
この記事は、日立グループ OSS #2 Advent Calendar 2020の21日目の記事になります。
はじめに
去る2019年8月29日、それまでPantheonとして知られていたJavaベースのEthereumクライアントが、**Hyperledger Besu**としてHyperledgerプロジェクトに参加しました。これまでコンソーシアム型のプラットフォームに注力していたHyperledgerプロジェクトにおいて、初めてパブリックブロックチェーン上で動作できるBesuが参加したことで、今後、より多くのユースケースに適応できることが期待されています。
この記事では、Hyperledger Besuのコミュニティが提供する代表的なサンプルを順序立てて紹介すると共に、イメージや概念が伝わるように補足やリファレンスを示しながら解説をしていきます。
次のような読者に向けて書きました。
- ブロックチェーンに興味があるエンジニア
- 今すぐサンプルを動かしながらどのようなものかを把握したいエンジニア
前提となる環境
この記事は次の環境で確認しました。
# | 項目 | バージョン |
---|---|---|
1 | OS | Ubuntu 18.04 LTS |
2 | Node, npm | 12.16.2, 6.14.4 |
3 | Docker | 19.03.8 |
4 | docker-compose | 1.25.5 |
npmに含まれるnpxを必要とします
上記はWindowsにインストールされたVirtualBoxのVM上にVagrantを使用して構築しています。
OSの基本情報は次の通りです。
# | 項目 | 値 |
---|---|---|
1 | user | vagrant |
2 | IPアドレス | 192.168.33.12 |
3 | 作業ディレクトリ | /home/vagrant |
いざ、Quick Start !
1. quickstartのソース一式を取得します
次のコマンドでソース一式を取得します。
以降、ガイドに沿ってオプションを選択します。
npx quorum-dev-quickstart
Quorumという言葉は、OSSで開発されているHyperledger BesuとGoQuorumを
OSSレイヤーと見立てた時に、それらを総称する呼び名として使用しているようです。
ConsenSys社がJ.P. Morgan社よりQuorumを買収した際に、リブランディングを図ったものと思われます。
Frequently Asked Questions
上記の画面が表示されるので、Hyperledger Besuを選択します。
1
を入力してEnterを押します。
Do you want to try out Codefi Orchestrate? Note: choosing yes will direct you to a login/registration page. [Y/n]
Codefi OchestrateはBesuの上位パッケージとなるので、今回はお試しを遠慮しておきます。
n
を入力してEnterを押します。
Do you wish to enable support for private transactions? [Y/n]
標準で用意されているサンプルがプライベートトランザクションを前提としているので有効にします。
Y
を入力してEnterを押します。
Do you wish to enable support for logging with ELK (Elasticsearch, Logstash & Kibana)? [y/N]
ELKスタックを利用したロギングは、次回以降に試すことにして無効にします。
N
を入力してEnterを押します。
Where should we create the config files for this network?
Please choose either an empty directory, or a path to a new directory that
does not yet exist.
Default: ./quorum-test-network
ソース一式の保存先を指定します。
./quorum-test-network
を入力してEnterを押します。
すると、インストールが始まります。
インストールが完了すると、上記のメッセージが表示されます。
続いてディレクトリに入ってrun.sh
を実行します。
2. 必要な全てのコンテナを取得して起動します
run.sh
を実行します。
cd ~/quorum-test-network
./run.sh
以下が表示されれば、起動が完了しています。
ここで、出来上がったコンテナの構成を一覧にしてみましょう。
docker ps -a
以下は出力結果です。
思っていたよりも数が多いので図にしてみました。
大きくはブロックチェーンネットワークを構成するコンテナと、それらを監視するモニタリング/ツールとに分かれています。
各コンテナの種類と推測される役割は次の通りです。
# | コンテナの種類 | 役割 |
---|---|---|
1 | validator | ブロックの作成と署名を行うノードです。本環境ではコンセンサスアルゴリズムとしてIBFT2.0を使用しています。ビザンチン障害耐性を持たせるには少なくとも4台のvalidatorが必要です。 |
2 | orion | Private Transaction Managerと呼ばれ、プライベートトランザクションを発行する構成で必要なサービスです。 |
3 | besu | 各組織のノードを表します。menber1~3まで、3つの組織(メンバー)がある想定で構成されています。 |
4 | rpcnode | RPCリクエストを受け付けることのできるノードです。 |
5 | ethsigner proxy | トランザクションに署名をするためのサービスです。 |
6 | prometheus | 各ノードのメトリックを収集するサービスです。 |
7 | grafana | prometheusが収集したメトリックを可視化するサービスです。 |
8 | block-explorer | ブロック、トランザクション、およびアカウントレベルでブロックチェーンデータを探索できるサービスです。 |
実態として同じBesuノードでありながら、validatorとbesuについてコンテナ名が分かれている点は、コミュニティ側の意図を掘り下げた方が良いですね
list.sh
を実行するとエンドポイントとサービスを一覧表示できます。
ブラウザでhttp://192.168.33.12:25000
を開くと、block-explorerを表示できます。
ブラウザでhttp://192.168.33.12:3000/d/XE4V0WGZz/besu-overview?orgId=1&refresh=10s&from=now-30m&to=now&var-system=All
を開くと、GrafanaのBesu Overview(ダッシュボード)を表示できます。
ここで、環境の操作に関わるコマンドを整理しましょう。
# | コマンド名 | 内容 |
---|---|---|
1 | run.sh | 環境の初期構築および全てのコンテナを起動します。 |
2 | list.sh | エンドポイントとサービスを一覧表示します。 |
3 | stop.sh | 全てのコンテナを停止します。作業を終えるためのシステム停止はこのコマンドを使います。 |
4 | resume.sh | stop.shで停止した環境を再開します。作業を再開するためのシステム起動はこのコマンドを使います。 |
5 | remove.sh | 全てのコンテナを停止してコンテナイメージを削除します。環境をクリーンする場合はこのコマンドを使用します。 |
3. スマートコントラクトのデプロイとプライベートトランザクションの実行
サンプルは、3つの組織(member)が繋がれたコンソーシアムにおけるブロックチェーンにおいて、2つの組織間で秘匿化されたデータを授受するユースケースとなっています。
詳細は次の通りです。
- コントラクトをデプロイします。
-
member1
からmember3
に任意の値(0x2f)を送信します。 - 3つのmemberすべてにクエリを実行します。
-
member1
とmember3
のみがプライベートトランザクション関わっているため、任意の値(0x2f)を取得できますが、member2
は取得できないことを確認します。
サンプルのファイル構成は以下の通りです。
quorum-test-network/
└ smart_contracts/
├ contracts/
│ ├ EventEmitter.sol(storeで登録しvalueで取得するシンプルなスマコン)
│ └ EventEmitter.json(スマコンのABI、呼び出すために必要なIF定義ファイル)
└ scripts/
├ compile.js
├ deploy.js(デプロイ、トランザクションの実行、クエリまで全部乗せ実装)
└ keys.js(orionの公開鍵、各組織のbesuノードのURLを定義)
実行は次のように行います。
cd ~/quorum-test-network/smart_contracts
npm install
node scripts/deploy.js
実行結果は次の通りです。
実行結果からmember2
だけ値を取得できていないことが、確認できました。
振り返り
コミュニティが提供する代表的なサンプルを動かすことには成功しましたが、やってみて色々と疑問が沸いてきたので、掘り下げていきます。
Besuのバージョンは?
そういえば手順のどこにも登場しなかったバージョンの情報。
次のファイルでrun.sh
の延長で環境変数に20.10.0
として指定されていました。
# This file defines environment variables defaults for Docker-compose
# but we also use it for shell scripts as a sourced file
BESU_VERSION=20.10.0
QUORUM_VERSION=20.10.0
QUORUM_TESSERA_VERSION=20.10.0
QUORUM_ETHSIGNER_VERSION=20.10.0
QUORUM_ORION_VERSION=20.10.0
QUORUM_CAKESHOP_VERSION=0.11.0
LOCK_FILE=.quorumDevQuickstart.lock
ethsigner proxyは使用したのだろうか?
以下のコードによると、デモの目的のために直接keys.js
ハードコーディングしているので使用していないとのこと。
6 // WARNING: the keys here are demo purposes ONLY. Please use a tool like Orchestrate or EthSigner for production, rather than hard coding private keys
ハードコーディングの元となっている鍵情報がノード側にあるのかを捜していくと、
keys.js
内のbesu.member1.privateKey
の値はquorum-test-network/config/besu/networkFiles/member1/keys/key
と同じであることが確認できました。
docker-compose.ymlの方をみると、member1besu
のnode-private-key-file
オプションの指定先が、実ファイルとしてはquorum-test-network/config/besu/networkFiles/member1/keys/key
となっているので辻褄が合いそうです。
以下は、member1besu
のコンテナの定義です。
volumesの多くがquorum-test-network/config
以下のファイル群を指し示しているので、各オプションに引き当てているファイルの実態も確認することができます。
member1besu:
<< : *besu-def
entrypoint:
- /bin/bash
- -c
- |
while [ ! -f "/opt/besu/public-keys/bootnode_pubkey" ]; do sleep 5; done ;
/opt/besu/bin/besu \
--config-file=/config/config.toml \
--p2p-host=$$(hostname -i) \
--genesis-file=/config/genesis.json \
--node-private-key-file=/opt/besu/keys/key \
--min-gas-price=0 \
--privacy-enabled \
--privacy-url=http://member1orion:8888 \
--privacy-public-key-file=/config/orion/orion.pub \
--privacy-onchain-groups-enabled=${PRIVACY_ONCHAIN_GROUPS_ENABLED:-false} \
--rpc-http-api=EEA,WEB3,ETH,NET,PRIV,PERM,${BESU_CONS_API:-IBFT} \
--rpc-ws-api=EEA,WEB3,ETH,NET,PRIV,PERM,${BESU_CONS_API:-IBFT} ;
volumes:
- public-keys:/opt/besu/public-keys/
- ./config/besu/config.toml:/config/config.toml
- ./config/besu/permissions_config.toml:/config/permissions_config.toml
- ./config/besu/log-config.xml:/config/log-config.xml
- ./logs/besu:/var/log/
- ./config/besu/${BESU_CONS_ALGO:-ibft2}Genesis.json:/config/genesis.json
- ./config/besu/networkFiles/member1/keys:/opt/besu/keys
- ./config/orion/networkFiles/orion1/nodeKey.pub:/config/orion/orion.pub
depends_on:
- validator1
- member1orion
ports:
- 20000:8545/tcp
- 20001:8546/tcp
networks:
quorum-dev-quickstart:
ipv4_address: 172.16.239.16
芋づる式的に、上の定義にて、portsで8545のrpcポートを20000で外に見せているのもわかります。
また、rpc-http-api
にて利用可能なコンポーネントを指定しており、rpcnodeの役割としても機能していますね。
サンプルのdeploy.jsはどこに接続しているんだろう?
7 const { orion, besu } = require("./keys.js");
8 const chainId = 2018;
9 const web3 = new EEAClient(new Web3(besu.member1.url), chainId);
16 besu: {
17 member1: {
18 url: "http://127.0.0.1:20000",
besu.member1.url
をWeb3に指定しているので
20000ポートを外に向けて開いているmember1のbesuノードに向けて接続し、操作をしていることがわかります。
ということは、このサンプルではethsigner proxyコンテナに加えて、rpcnodeコンテナもデモ目的のために使用していない整理になりますね。
また、チェインIDは2018
で指定しています。
1 {
2 "config": {
3 "chainId": 2018,
ibft2Genesis.jsonにてchainIdに2018
を指定しているため、サンプルで呼び出す側の実装でも合わせているのですね。
プライベートトランザクションはどうやって呼び出すのか?
コントラクトのデプロイは次のように実装しています。
21 const contractOptions = {
22 data: '0x'+bytecode,
23 privateFrom: orion.member1.publicKey,
24 privateFor: [orion.member3.publicKey],
25 privateKey: besu.member1.privateKey
26 };
27 console.log("Creating contract...");
28 const c = await web3.eea.sendRawTransaction(contractOptions);
デプロイした後のプライベートトランザクションは次のように実装しています。
41 const contract = new web3.eth.Contract(abi);
42 // eslint-disable-next-line no-underscore-dangle
43 const functionAbi = contract._jsonInterface.find(e => {
44 return e.name === "store";
45 });
46 const functionArgs = web3.eth.abi
47 .encodeParameters(functionAbi.inputs, [value])
48 .slice(2);
49 const functionParams = {
50 to: address,
51 data: functionAbi.signature + functionArgs,
52 privateFrom: orion.member1.publicKey,
53 privateFor: [orion.member3.publicKey],
54 privateKey: besu.member1.privateKey
55 };
56 const transactionHash = await web3.eea.sendRawTransaction(functionParams);
まとめ
さて、Hyperledger Besuをいますぐ動かすからの、中身はどうなっているのだろう?を掘り下げて見ていきました。
ガイドに沿ってスッと環境が構築できた点は、とても作りこまれているなと感じました。
一方で、その全容を理解するためのドキュメントは物足りない印象もありましたので、本記事がその助けになればと思います。
なお、本記事の校閲は案件で最前線を走っている、株式会社日立ソリューションズの小島が担当致しました。
Future Work
まだまだ確認したいことは山ほどあるので、引き続き次のような項目を調査して、本記事に続けて情報発信を行っていきたいと考えています。
- ethsigner proxyを使用した構成
- プライベートトランザクションを使用しない、よりシンプルな構成。
- ロギングのためのELKスタックを有効にした構成。
- スマコン開発をシームレスに、TruffleやRemix IDEとの連携。
Let's get started with blockchain!