LoginSignup
20
7

More than 3 years have passed since last update.

こんにちは。株式会社日立ソリューションズの田辺です。
この記事は、:christmas_tree:日立グループ OSS #2 Advent Calendar 2020:christmas_tree:の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

quickstart.png

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を押します。
すると、インストールが始まります。

installation_complete.png

インストールが完了すると、上記のメッセージが表示されます。
続いてディレクトリに入ってrun.shを実行します。

2. 必要な全てのコンテナを取得して起動します

run.shを実行します。

cd ~/quorum-test-network
./run.sh

以下が表示されれば、起動が完了しています。

run_end.PNG

ここで、出来上がったコンテナの構成を一覧にしてみましょう。

docker ps -a

以下は出力結果です。

container_list.PNG

思っていたよりも数が多いので図にしてみました。

structure.PNG

大きくはブロックチェーンネットワークを構成するコンテナと、それらを監視するモニタリング/ツールとに分かれています。
各コンテナの種類と推測される役割は次の通りです。

# コンテナの種類 役割
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を実行するとエンドポイントとサービスを一覧表示できます。

endpoint.PNG

ブラウザでhttp://192.168.33.12:25000を開くと、block-explorerを表示できます。

block-explorer.PNG

ブラウザで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(ダッシュボード)を表示できます。

grafana2.PNG

Use metrics to monitor node performance

ここで、環境の操作に関わるコマンドを整理しましょう。

# コマンド名 内容
1 run.sh 環境の初期構築および全てのコンテナを起動します。
2 list.sh エンドポイントとサービスを一覧表示します。
3 stop.sh 全てのコンテナを停止します。作業を終えるためのシステム停止はこのコマンドを使います。
4 resume.sh stop.shで停止した環境を再開します。作業を再開するためのシステム起動はこのコマンドを使います。
5 remove.sh 全てのコンテナを停止してコンテナイメージを削除します。環境をクリーンする場合はこのコマンドを使用します。

3. スマートコントラクトのデプロイとプライベートトランザクションの実行

サンプルは、3つの組織(member)が繋がれたコンソーシアムにおけるブロックチェーンにおいて、2つの組織間で秘匿化されたデータを授受するユースケースとなっています。

詳細は次の通りです。

  1. コントラクトをデプロイします。
  2. member1からmember3に任意の値(0x2f)を送信します。
  3. 3つのmemberすべてにクエリを実行します。
  4. member1member3のみがプライベートトランザクション関わっているため、任意の値(0x2f)を取得できますが、member2は取得できないことを確認します。

member3.PNG

サンプルのファイル構成は以下の通りです。

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

実行結果は次の通りです。

sample.PNG

実行結果からmember2だけ値を取得できていないことが、確認できました。

振り返り

コミュニティが提供する代表的なサンプルを動かすことには成功しましたが、やってみて色々と疑問が沸いてきたので、掘り下げていきます。

Besuのバージョンは?

そういえば手順のどこにも登場しなかったバージョンの情報。
次のファイルでrun.shの延長で環境変数に20.10.0として指定されていました。

quorum-test-network/.env
# 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

Release 20.10.0

ethsigner proxyは使用したのだろうか?

以下のコードによると、デモの目的のために直接keys.jsハードコーディングしているので使用していないとのこと。

quorum-test-network/smart_contract/scripts/deploy.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の方をみると、member1besunode-private-key-fileオプションの指定先が、実ファイルとしてはquorum-test-network/config/besu/networkFiles/member1/keys/keyとなっているので辻褄が合いそうです。
以下は、member1besuのコンテナの定義です。
volumesの多くがquorum-test-network/config以下のファイル群を指し示しているので、各オプションに引き当てているファイルの実態も確認することができます。

Node keys and node address

quorum-test-network/docker-compose.yml
  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はどこに接続しているんだろう?

quorum-test-network/smart_contract/scripts/deploy.js
7  const { orion, besu } = require("./keys.js");
8  const chainId = 2018;
9  const web3 = new EEAClient(new Web3(besu.member1.url), chainId);
quorum-test-network/smart_contract/scripts/keys.js
16  besu: {
17    member1: {
18      url: "http://127.0.0.1:20000",

besu.member1.urlをWeb3に指定しているので
20000ポートを外に向けて開いているmember1のbesuノードに向けて接続し、操作をしていることがわかります。
ということは、このサンプルではethsigner proxyコンテナに加えて、rpcnodeコンテナもデモ目的のために使用していない整理になりますね。

また、チェインIDは2018で指定しています。

quorum-test-network/config/besu/ibft2Genesis.json
1  {
2    "config": {
3      "chainId": 2018,

ibft2Genesis.jsonにてchainIdに2018を指定しているため、サンプルで呼び出す側の実装でも合わせているのですね。

プライベートトランザクションはどうやって呼び出すのか?

コントラクトのデプロイは次のように実装しています。

quorum-test-network/smart_contract/scripts/deploy.js
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);

web3js-eea client library

デプロイした後のプライベートトランザクションは次のように実装しています。

quorum-test-network/smart_contract/scripts/deploy.js
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);

sendRawTransaction

まとめ

さて、Hyperledger Besuをいますぐ動かすからの、中身はどうなっているのだろう?を掘り下げて見ていきました。
ガイドに沿ってスッと環境が構築できた点は、とても作りこまれているなと感じました。
一方で、その全容を理解するためのドキュメントは物足りない印象もありましたので、本記事がその助けになればと思います。
なお、本記事の校閲は案件で最前線を走っている、株式会社日立ソリューションズの小島が担当致しました。

Future Work

まだまだ確認したいことは山ほどあるので、引き続き次のような項目を調査して、本記事に続けて情報発信を行っていきたいと考えています。

  • ethsigner proxyを使用した構成
  • プライベートトランザクションを使用しない、よりシンプルな構成。
  • ロギングのためのELKスタックを有効にした構成。
  • スマコン開発をシームレスに、TruffleやRemix IDEとの連携。

Let's get started with blockchain!

20
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
7