(株)日立製作所 研究開発グループ サービスコンピューティング研究部の渡辺です。
Hyperledger Fabric(以下、HLF) は、コンセンサスアルゴリズム(Orderingのサービス実装)として従来のKafkaやSoloに加え、v1.4.1より新たにRaftをサポートしました。本記事では、Raft OrderingサービスによるHLFv1.4.4環境(2019/11/30執筆時点で最新)を構築し、Build Your First Network(以下、BYFN)チュートリアルに従い動作確認をします。また、冗長構成をとるOrdererサービスのRaft Leaderダウン時の挙動も確認をした内容を記事後半で紹介させていただきます。
本記事では以下を参考にさせて頂きました。
HLF公式ドキュメントー What"s new in v1.4 / Raft ordering service
https://hyperledger-fabric.readthedocs.io/en/release-1.4/whatsnew.html
HLF公式ドキュメントー The Ordering Service
https://hyperledger-fabric.readthedocs.io/en/release-1.4/orderer/ordering_service.html
Hyperledger Fabric v1.4 公式ドキュメントーBuilding Your First Network
https://hyperledger-fabric.readthedocs.io/en/release-1.4/build_network.html
Coinmonks ー Hyperledger Fabric — The Taste of Raft
https://medium.com/coinmonks/hyperledger-fabric-the-taste-of-raft-4f9f0df20b5e
1. セットアップ
1.1. HLF前提環境のセットアップ
HLFネットワークを構築するに先立ち前提環境をセットアップします。
前提コンポーネント | バージョン | 前提条件 |
---|---|---|
Ubuntu | 18.04.1 LTS(Bionic Beaver) | - |
Docker | v19.03.5 | v17.06.2-ce以上 |
Docker Compose | v1.25.0 | v1.14.0以上 |
Go | v1.12.13 | v1.12.x |
Node.js | v10.17.0 (LTS/dubnium) | v8.9.4以上(v8の場合)、v10.15.3以上(v10の場合) |
NPM | v6.11.3 | |
Python | v2.7.15 | v2.7.x |
参考URL:
Hyperledger Fabric v1.4 公式ドキュメント GettingStarted - Prerequisites
https://hyperledger-fabric.readthedocs.io/en/release-1.4/prereqs.html
$ sudo apt-get update
### Dockerのインストール
$ curl -sSL https://get.docker.com/ | sh
$ sudo usermod -aG docker $(whoami)
$ docker -v
Docker version 19.03.5, build 633a0ea838
### Docker-Composeのインストール
$ sudo curl -L "https://github.com/docker/compose/releases/download/1.25.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
$ docker-compose version
docker-compose version 1.25.0, build 0a186604
docker-py version: 4.1.0
CPython version: 3.7.4
OpenSSL version: OpenSSL 1.1.0l 10 Sep 2019
### Goのインストール
$ wget https://dl.google.com/go/go1.12.13.linux-amd64.tar.gz
$ sudo tar -C /usr/local/ -xzf go1.12.13.linux-amd64.tar.gz
$ sudo vim /etc/profile.d/golang.sh
$ echo <<END >> /etc/profile.d/golang.sh
export GOROOT=/usr/local/go
export PATH=$PATH:$GOROOT/bin
END
$ . /etc/profile.d/golang.sh
$ echo <<END >> ~/.bash_profile
export GOPATH=$HOME/go
export PATH=$PATH:$GOPATH/bin
END
$ . ~/.bash_profile
$ go version
go version go1.12.13 linux/amd64
### Node.jsとNPMのインストール
$ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.1/install.sh | bash
$ echo <<END >> ~/.bash_profile
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
END
$ . ~/.bash_profile
$ nvm install v10.17.0
$ node -v
v10.17.0
$ npm -v
6.11.3
### Pythonのインストール
$ sudo apt-get install python
$ python --version
Python 2.7.15+
1.2. HLFとサンプルプログラム(fabric-sample)の取得
以下のコマンドを実行します。バージョン指定しないと最新バージョンのHLF(2019/11/29時点でv1.4.4)がgit cloneされます。
$ curl -sSL https://raw.githubusercontent.com/hyperledger/fabric/master/scripts/bootstrap.sh | bash -s
もし、バージョン(以下の例ではv1.4.4)を明示して指定する場合は以下のようにして引数指定して実行します。
$ curl -sSL https://raw.githubusercontent.com/hyperledger/fabric/master/scripts/bootstrap.sh | bash -s -- 1.4.4 1.4.4 0.4.18
このスクリプトは以下のものをダウンロードします。
- fabric-samplesソースコード
$ tree . -L2
.
└── fabric-samples
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Jenkinsfile
├── LICENSE
├── MAINTAINERS.md
├── README.md
├── SECURITY.md
├── balance-transfer
├── basic-network
├── bin
├── chaincode
├── chaincode-docker-devmode
├── ci
├── ci.properties
├── commercial-paper
├── config
├── docs
├── fabcar
├── first-network
├── high-throughput
├── interest_rate_swaps
├── off_chain_data
└── scripts
- Platform-Specificバイナリ (暗号鍵生成、genesisblock生成のためのバイナリ)
$ tree fabric-samples/bin
fabric-samples/bin
├── configtxgen
├── configtxlator
├── cryptogen
├── discover
├── fabric-ca-client
├── idemixgen
├── orderer
└── peer
- HLFネットワーク設定ファイルとノード設定ファイル
$ tree fabric-samples/config
fabric-samples/config
├── configtx.yaml
├── core.yaml
└── orderer.yaml
- Dockerイメージ
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hyperledger/fabric-javaenv 1.4.4 4648059d209e 12 days ago 1.7GB
hyperledger/fabric-javaenv latest 4648059d209e 12 days ago 1.7GB
hyperledger/fabric-ca 1.4.4 62a60c5459ae 13 days ago 150MB
hyperledger/fabric-ca latest 62a60c5459ae 13 days ago 150MB
hyperledger/fabric-tools 1.4.4 7552e1968c0b 2 weeks ago 1.49GB
hyperledger/fabric-tools latest 7552e1968c0b 2 weeks ago 1.49GB
hyperledger/fabric-ccenv 1.4.4 ca4780293e4c 2 weeks ago 1.37GB
hyperledger/fabric-ccenv latest ca4780293e4c 2 weeks ago 1.37GB
hyperledger/fabric-orderer 1.4.4 dbc9f65443aa 2 weeks ago 120MB
hyperledger/fabric-orderer latest dbc9f65443aa 2 weeks ago 120MB
hyperledger/fabric-peer 1.4.4 9756aed98c6b 2 weeks ago 128MB
hyperledger/fabric-peer latest 9756aed98c6b 2 weeks ago 128MB
hyperledger/fabric-zookeeper 0.4.18 ede9389347db 3 weeks ago 276MB
hyperledger/fabric-zookeeper latest ede9389347db 3 weeks ago 276MB
hyperledger/fabric-kafka 0.4.18 caaae0474ef2 3 weeks ago 270MB
hyperledger/fabric-kafka latest caaae0474ef2 3 weeks ago 270MB
hyperledger/fabric-couchdb 0.4.18 d369d4eaa0fd 3 weeks ago 261MB
hyperledger/fabric-couchdb latest d369d4eaa0fd 3 weeks ago 261MB
1.3. HLFネットワークの起動
以下のコマンドを実行し、HLFネットワークを起動します。
$ cd fabric-samples/first-network/
## 証明書生成〜チャネル生成〜チャネル上に各組織のアンカーピアを生成
$ echo y | ./byfn.sh generate -o etcdraft
## HLFネットワークの起動(各種Dockerコンテナの生成と起動)
$ echo y | ./byfn.sh up -o etcdraft
...
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
cfb7abffc553 hyperledger/fabric-tools:latest "/bin/bash" 1 second ago Up Less than a second cli
57393aafb10b hyperledger/fabric-peer:latest "peer node start" 11 seconds ago Up 3 seconds 0.0.0.0:10051->10051/tcp peer1.org2.example.com
be24ebc743c7 hyperledger/fabric-orderer:latest "orderer" 11 seconds ago Up 8 seconds 0.0.0.0:8050->7050/tcp orderer2.example.com
96a650ddbda4 hyperledger/fabric-orderer:latest "orderer" 11 seconds ago Up 9 seconds 0.0.0.0:11050->7050/tcp orderer5.example.com
33a0d9bf8421 hyperledger/fabric-peer:latest "peer node start" 11 seconds ago Up 4 seconds 0.0.0.0:7051->7051/tcp peer0.org1.example.com
cd359ed55dbe hyperledger/fabric-orderer:latest "orderer" 11 seconds ago Up 5 seconds 0.0.0.0:9050->7050/tcp orderer3.example.com
c68a964a7e09 hyperledger/fabric-peer:latest "peer node start" 11 seconds ago Up 6 seconds 0.0.0.0:8051->8051/tcp peer1.org1.example.com
faa0fd93854e hyperledger/fabric-peer:latest "peer node start" 11 seconds ago Up 1 second 0.0.0.0:9051->9051/tcp peer0.org2.example.com
975b594c061b hyperledger/fabric-orderer:latest "orderer" 11 seconds ago Up 2 seconds 0.0.0.0:10050->7050/tcp orderer4.example.com
b3363ac48a53 hyperledger/fabric-orderer:latest "orderer" 11 seconds ago Up 7 seconds 0.0.0.0:7050->7050/tcp orderer.example.com
Sleeping 15s to allow etcdraft cluster to complete booting
____ _____ _ ____ _____
/ ___| |_ _| / \ | _ \ |_ _|
\___ \ | | / _ \ | |_) | | |
___) | | | / ___ \ | _ < | |
|____/ |_| /_/ \_\ |_| \_\ |_|
Build your first network (BYFN) end-to-end test
Channel name : mychannel
Creating channel...
+ peer channel create -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/channel.tx --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
+ res=0
+ set +x
2019-11-29 06:43:48.128 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2019-11-29 06:43:48.155 UTC [cli.common] readBlock -> INFO 002 Got status: &{NOT_FOUND}
2019-11-29 06:43:48.161 UTC [channelCmd] InitCmdFactory -> INFO 003 Endorser and orderer connections initialized
2019-11-29 06:43:48.363 UTC [cli.common] readBlock -> INFO 004 Got status: &{SERVICE_UNAVAILABLE}
2019-11-29 06:43:48.366 UTC [channelCmd] InitCmdFactory -> INFO 005 Endorser and orderer connections initialized
2019-11-29 06:43:48.568 UTC [cli.common] readBlock -> INFO 006 Got status: &{SERVICE_UNAVAILABLE}
2019-11-29 06:43:48.572 UTC [channelCmd] InitCmdFactory -> INFO 007 Endorser and orderer connections initialized
2019-11-29 06:43:48.774 UTC [cli.common] readBlock -> INFO 008 Got status: &{SERVICE_UNAVAILABLE}
2019-11-29 06:43:48.778 UTC [channelCmd] InitCmdFactory -> INFO 009 Endorser and orderer connections initialized
2019-11-29 06:43:48.980 UTC [cli.common] readBlock -> INFO 00a Got status: &{SERVICE_UNAVAILABLE}
2019-11-29 06:43:48.985 UTC [channelCmd] InitCmdFactory -> INFO 00b Endorser and orderer connections initialized
2019-11-29 06:43:49.187 UTC [cli.common] readBlock -> INFO 00c Got status: &{SERVICE_UNAVAILABLE}
2019-11-29 06:43:49.194 UTC [channelCmd] InitCmdFactory -> INFO 00d Endorser and orderer connections initialized
2019-11-29 06:43:49.398 UTC [cli.common] readBlock -> INFO 00e Received block: 0
===================== Channel 'mychannel' created =====================
Having all peers join the channel...
+ peer channel join -b mychannel.block
+ res=0
+ set +x
2019-11-29 06:43:49.482 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2019-11-29 06:43:49.557 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel
===================== peer0.org1 joined channel 'mychannel' =====================
+ peer channel join -b mychannel.block
+ res=0
+ set +x
2019-11-29 06:43:52.633 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2019-11-29 06:43:52.678 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel
===================== peer1.org1 joined channel 'mychannel' =====================
+ peer channel join -b mychannel.block
+ res=0
+ set +x
2019-11-29 06:43:55.754 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2019-11-29 06:43:55.823 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel
===================== peer0.org2 joined channel 'mychannel' =====================
+ peer channel join -b mychannel.block
+ res=0
+ set +x
2019-11-29 06:43:58.894 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2019-11-29 06:43:58.950 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel
===================== peer1.org2 joined channel 'mychannel' =====================
Updating anchor peers for org1...
+ peer channel update -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/Org1MSPanchors.tx --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
+ res=0
+ set +x
2019-11-29 06:44:02.028 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2019-11-29 06:44:02.045 UTC [channelCmd] update -> INFO 002 Successfully submitted channel update
===================== Anchor peers updated for org 'Org1MSP' on channel 'mychannel' =====================
Updating anchor peers for org2...
+ peer channel update -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/Org2MSPanchors.tx --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
+ res=0
+ set +x
2019-11-29 06:44:05.117 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2019-11-29 06:44:05.135 UTC [channelCmd] update -> INFO 002 Successfully submitted channel update
===================== Anchor peers updated for org 'Org2MSP' on channel 'mychannel' =====================
Installing chaincode on peer0.org1...
+ peer chaincode install -n mycc -v 1.0 -l golang -p github.com/chaincode/chaincode_example02/go/
+ res=0
+ set +x
2019-11-29 06:44:08.221 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2019-11-29 06:44:08.221 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
2019-11-29 06:44:08.552 UTC [chaincodeCmd] install -> INFO 003 Installed remotely response:<status:200 payload:"OK" >
===================== Chaincode is installed on peer0.org1 =====================
Install chaincode on peer0.org2...
+ peer chaincode install -n mycc -v 1.0 -l golang -p github.com/chaincode/chaincode_example02/go/
+ res=0
+ set +x
2019-11-29 06:44:08.628 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2019-11-29 06:44:08.628 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
2019-11-29 06:44:08.947 UTC [chaincodeCmd] install -> INFO 003 Installed remotely response:<status:200 payload:"OK" >
===================== Chaincode is installed on peer0.org2 =====================
Instantiating chaincode on peer0.org2...
+ peer chaincode instantiate -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n mycc -l golang -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P 'AND ('\''Org1MSP.peer'\'','\''Org2MSP.peer'\'')'
+ res=0
+ set +x
2019-11-29 06:44:09.033 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2019-11-29 06:44:09.033 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
===================== Chaincode is instantiated on peer0.org2 on channel 'mychannel' =====================
Querying chaincode on peer0.org1...
===================== Querying on peer0.org1 on channel 'mychannel'... =====================
Attempting to Query peer0.org1 ...3 secs
+ peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'
+ res=0
+ set +x
100
===================== Query successful on peer0.org1 on channel 'mychannel' =====================
Sending invoke transaction on peer0.org1 peer0.org2...
+ peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["invoke","a","b","10"]}'
+ res=0
+ set +x
2019-11-29 06:44:43.529 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200
===================== Invoke transaction successful on peer0.org1 peer0.org2 on channel 'mychannel' =====================
Installing chaincode on peer1.org2...
+ peer chaincode install -n mycc -v 1.0 -l golang -p github.com/chaincode/chaincode_example02/go/
+ res=0
+ set +x
2019-11-29 06:44:43.604 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2019-11-29 06:44:43.604 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
2019-11-29 06:44:43.906 UTC [chaincodeCmd] install -> INFO 003 Installed remotely response:<status:200 payload:"OK" >
===================== Chaincode is installed on peer1.org2 =====================
Querying chaincode on peer1.org2...
===================== Querying on peer1.org2 on channel 'mychannel'... =====================
Attempting to Query peer1.org2 ...3 secs
+ peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'
+ res=0
+ set +x
90
===================== Query successful on peer1.org2 on channel 'mychannel' =====================
========= All GOOD, BYFN execution completed ===========
_____ _ _ ____
| ____| | \ | | | _ \
| _| | \| | | | | |
| |___ | |\ | | |_| |
|_____| |_| \_| |____/
5つのRaftベースのordererサービス、4つのPeerサービス(組織毎に2つのPeerサービスの構成で2組織)からなるHLFネットワークが構成されました。また、HLFネットワークが起動した後e2eテストが実行され、正常に動作していることが確認できました。
- 参考情報(ワークアラウンド)
- 初回起動で失敗する場合、一旦停止した後、再び起動すると正常動作することがあります。
$ ./byfn.sh -m down
$ ./byfn.sh -m up -o etcdraft
- 挙動確認
=========
ここでは、冗長構成をとっているOrderer ServiceのRaft Leader ダウン時の挙動を確認します。
Raft Leaderをkill (1/5停止状態)
現行のRaft Leaderを特定します。以下のログだとorderer3がRaft Leaderです。
$ docker logs orderer3.example.com
....
2019-11-29 07:03:53.544 UTC [orderer.consensus.etcdraft] Start -> INFO 02d Starting Raft node channel=mychannel node=3
...
2019-11-29 07:06:55.560 UTC [orderer.consensus.etcdraft] serveRequest -> INFO 06d Raft leader changed: 0 -> 3 channel=mychannel node=3
...
現行のRaft Leaderをkillします。
$ docker stop orderer3.example.com
Raft LeaderをkillしてもHLFネットワークは正常に動作しています。
$ docker exec -it cli bash
root# peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
90
root# peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["invoke","a","b","10"]}'
2019-11-29 07:34:20.421 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200
root# peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
80
Raft Leaderはorderer2になっています。
$ docker logs orderer4.example.com
2019-11-29 07:06:55.560 UTC [orderer.consensus.etcdraft] serveRequest -> INFO 06d Raft leader changed: 0 -> 2 channel=mychannel node=2
####再びRaft Leaderをkill (2/5停止状態)
Raft Leaderをkillします。
$ docker stop orderer2.example.com
Raft Leaderがorderer5に切り替わります。
$ docker logs orderer.example.com
2019-11-29 07:54:02.065 UTC [orderer.consensus.etcdraft] serveRequest -> INFO 085 Raft leader changed: 0 -> 5 channel=mychannel node=1
再びRaft Leaderをkill(3/5停止状態)
$ docker stop orderer5.example.com
以下のログにRaft Leader切り替りのログが出力されず、今度は新たなRaft Leaderに切り替わらないことがわかります。5台中3台のOrdererが停止しMajority Ruleが守れない構成となったためです。
$ docker logs orderer.example.com
killしたordererを復活 (2/5停止状態)
Raft Leaderが選出されたことがログからわかります。
2019-11-29 08:00:02.062 UTC [orderer.consensus.etcdraft] run -> INFO 363 raft.node: 1 elected leader 4 at term 5 channel=mychannel node=1
2019-11-29 08:00:02.063 UTC [orderer.consensus.etcdraft] serveRequest -> INFO 364 Raft leader changed: 0 -> 4 channel=mychannel node=1
まとめ
以上のように、HLFv1.4.1より新たにサポートしたRaft Orderingサービス構成にてHLF環境を構築し動作状況を確認できました。また、構築したHLF環境において、冗長構成をとるOrdererサービスのRaft Leaderを一つずつダウンさせたときの挙動も確認できました。HLFでは、現在も様々な新機能の実装が続いています。動向を引き続きウォッチし、ご紹介していきたいと思います。
参考
ブロックチェーンの特徴やユースケースについて
https://www.hitachi.co.jp/products/it/blockchain/index.html