Amazon Managed BlockchainでHyperledger Fabric基盤を構築する

以前試した、[AWS Blockchain TemplatesでHyperledger Fabric基盤を構築する](https://qiita.com/nkmk1215/items/adb86a4931ef2bf4245f)から新しいブロックチェーンサービスが出たので試してみた。

（参考）
[Get Started Creating a Hyperledger Fabric Blockchain Network Using Amazon Managed Blockchain](https://docs.aws.amazon.com/ja_jp/managed-blockchain/latest/managementguide/managed-blockchain-get-started-tutorial.html)
[Amazon Managed BlockchainでHyperledger Fabricのブロックチェーンネットワークを構築してみた](https://qiita.com/kai_kou/items/e02e34dd9abb26219a7e)


## 概要
### Amazon Managed Blockchainとは
 - Amazon Managed Blockchainはブロックチェーン基盤を構築するサービスである
 - ブロックチェーン基盤の1つであるHyperledger Fabricをサポートしている
    - Hyperledger Fabricはブロックチェーンを利用したDLT（分散型台帳技術）の1つである
 - Amazon Managed Blockchainはデータを台帳として分散して保持するネットワークをフルマネージドで構築できるサービス


### （参考）Amazon QLDBとは
 - 台帳データベースのサービスである
 - 台帳データベースではデータの変更履歴がトレース可能な状態で保持される
 - ブロックチェーンは利用していない
 - QLDBはDLTを利用していないサービスである


## 環境構築
今回作成するネットワークは以下のピンク枠内
![01_000.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/2bba06f8-28fd-7947-6010-7cc880ade1f5.png)

### ネットワーク作成
「Network edition」は立てるノード数による
今回はお試しなので、「Starter」を選択
ネットワーク名、説明は任意の値
「Voting policy」は今回使わないのでデフォルト値
![01_013.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/8450f192-42af-5595-737a-17d3d5af5420.jpeg)

組織名と説明は任意の値
ネットワークの管理者のユーザー名とパスワードは任意の値
![01_014.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/b3aebef1-9384-eb17-eb95-f7e42c65964e.jpeg)



### VPCエンドポイントの作成
ネットワーク作成後、「Create VPC endpoint」からエンドポイントを作成
指定するVPCは任意
指定するVPC内のインスタンスから管理者としてアクセスし、設定等を行う


![01_028.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/8cff527b-4e50-19b2-60d1-a9596e7f62a9.jpeg)
![01_038.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/e14a12c0-dc92-4e29-5c76-1de524d8e979.jpeg)


### 管理者クライアント（EC2）の作成
さきほど指定したVPC内にインスタンスを立ち上げる
接続設定をシンプルにするために今回はSGはVPCエンドポイントと同じものを指定
VPCエンドポイント作成したサブネットを設定
![01_115.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/da391dab-8068-455d-8ac3-3c400ebeae90.jpeg)

SSMセッションマネージャーでログインするので、鍵は生成せずにインスタンス作成
![01_118.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/d4362bec-9731-2425-e8f4-e3384b15402f.jpeg)





### パッケージインストール
管理者クライアントからコマンドを実行していく
#### ログイン
セッションマネージャーを利用
![01_120.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/b5709151-81bc-376c-9204-e96690ac4268.jpeg)

ログイン後に以下のコマンド実行
（参考）[AWS Systems Manager のセッションマネージャで EC2 (Linux) にアクセスした際に気をつけたいこととその緩和策](https://dev.classmethod.jp/cloud/aws/mitigation-idea-for-session-manager/)

```
sudo -iu ec2-user
pwd
script ./session001.log
w
```
![01_121.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/87028890-63c3-bcc5-da07-36a250e46b97.jpeg)


#### dockerをインストール

```console:bc-client
sudo yum update -y
sudo yum install -y telnet
sudo yum -y install emacs
sudo yum install -y docker
sudo service docker start
sudo usermod -a -G docker ec2-user
```

#### docker composeをインストール

```console:bc-client
sudo curl -L \
https://github.com/docker/compose/releases/download/1.20.0/docker-compose-`uname \
-s`-`uname -m` -o /usr/local/bin/docker-compose
sudo chmod a+x /usr/local/bin/docker-compose
sudo yum install libtool -y
```

#### goをインストール

```console:bc-client
wget https://dl.google.com/go/go1.10.3.linux-amd64.tar.gz
tar -xzf go1.10.3.linux-amd64.tar.gz
sudo mv go /usr/local
sudo yum install libtool-ltdl-devel -y
sudo yum install git -y
```

#### .bash__profileを更新
```console:bc-client
vim ./.bash_profile
```

.bash__profileがデフォルトであれば以下で上書き

```console:.bash_profile
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi

# User specific environment and startup programs
PATH=$PATH:$HOME/.local/bin:$HOME/bin:/usr/local/bin:/home/ec2-user/go/bin

# GOROOT is the location where Go package is installed on your system
export GOROOT=/usr/local/go

# GOPATH is the location of your work directory
export GOPATH=$HOME/go

# Update PATH so that you can access the go binary system wide
export PATH=$GOROOT/bin:$PATH
export PATH=$PATH:/home/ec2-user/go/src/github.com/hyperledger/fabric-ca/bin
```

上書き後に再読み込み

```console:bc-client
source ~/.bash_profile
```

#### バージョン確認
以下であることを確認

 - Docker–17.06.2-ce or later
 - Docker-compose–1.14.0 or later
 - Go–1.10.x


```console:bc-client
docker version
docker-compose version
go version
```

#### （参考）AWS CLIの更新
AWS CLIのバージョンが低い場合は、更新する
Amazon Linux2の場合、pipのインストールが必要


```console:bc-client(更新前)

[ec2-user@ip-172-31-5-178 ~]$ aws --version
aws-cli/1.16.102 Python/2.7.16 Linux/4.14.123-86.109.amzn1.x86_64 botocore/1.12.92
```

```console:bc-client
sudo pip install -U awscli
```


```console:bc-client(更新後)
[ec2-user@ip-172-31-5-178 ~]$ aws --version
aws-cli/1.16.198 Python/2.7.16 Linux/4.14.123-86.109.amzn1.x86_64 botocore/1.12.188
```

更新後、AWSコマンドが利用できない場合は以下コマンドでセットアップ
（参考）[AWS CLI の設定](https://docs.aws.amazon.com/ja_jp/cli/latest/userguide/cli-chap-configure.html)
※「Default output format」で「json」ではなく「JSON」を指定すると動かない

```console:bc-client
aws configure
```

#### CAに接続
「network-id」と「member-id」はマネジメントコンソールで確認
レスポンスに含まれる「CaEndpoint」をメモ

```console:bc-client
aws managedblockchain get-member \
--network-id n-RBYM74VOSBG57LWTGAP5A4FJQE \
--member-id m-DNGBD4KRKVBTDKIFIU2MCBUMQ4
```



#### エンドポイントの有効化
メモした「CaEndpoint」を利用

```console:bc-client
curl https://ca.m-dngbd4krkvbtdkifiu2mcbumq4.n-rbym74vosbg57lwtgap5a4fjqe.managedblockchain.us-east-1.amazonaws.com:30002/cainfo -k
```

#### （参考）つながらない場合
 - VPCエンドポイントとEC2のセキュリティグループが同一であることを確認
 - SGのインバウンド設定にて、自身のSGからのアクセスを許可しているか確認

#### CA設定

```console:bc-client
go get -u github.com/hyperledger/fabric-ca/cmd/...
cd /home/ec2-user/go/src/github.com/hyperledger/fabric-ca
git fetch
git checkout release-1.2
make fabric-ca-client
```

#### サンプルリポジトリをクローン

```console:bc-client
cd /home/ec2-user
git clone https://github.com/hyperledger/fabric-samples.git
```

#### docker composeを起動

```console:bc-client
touch ./docker-compose-cli.yaml
vim ./docker-compose-cli.yaml
```

```yaml:docker-compose-cli.yaml
version: '2'
services:
  cli:
    container_name: cli
    image: hyperledger/fabric-tools:1.2.0
    tty: true
    environment:
      - GOPATH=/opt/gopath
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      - CORE_LOGGING_LEVEL=info # Set logging level to debug for more verbose logging
      - CORE_PEER_ID=cli
      - CORE_CHAINCODE_KEEPALIVE=10
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
    command: /bin/bash
    volumes:
        - /var/run/:/host/var/run/
        - /home/ec2-user/fabric-samples/chaincode:/opt/gopath/src/github.com/
        - /home/ec2-user:/opt/home

```

```console:bc-client
docker-compose -f docker-compose-cli.yaml up -d
```

### 管理者を登録
#### 証明書取得

```console:bc-client
aws s3 cp s3://us-east-1.managedblockchain/etc/managedblockchain-tls-chain.pem  /home/ec2-user/managedblockchain-tls-chain.pem
```

#### 管理者ユーザーの登録
ネットワークの管理者のユーザー名とパスワード、メモした「CaEndpoint」を指定

```console:bc-client
fabric-ca-client enroll \
-u https://Administrator:password@ca.m-DNGBD4KRKVBTDKIFIU2MCBUMQ4.n-RBYM74VOSBG57LWTGAP5A4FJQE.managedblockchain.us-east-1.amazonaws.com:30002 \
--tls.certfiles /home/ec2-user/managedblockchain-tls-chain.pem -M /home/ec2-user/admin-msp
```

#### MSP（Membership Service Providers）に必要な証明書をコピー

```console:bc-client
sudo cp -r admin-msp/signcerts admin-msp/admincerts
```

### ノード作成
マネジメントコンソールにて作成可能
組織を指定し、「Create peer node」からノード作成
![01_085.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/258f27d3-12a2-09c7-49d8-11e0d2fa6cad.jpeg)

インスタンスタイプ、AZは任意
![01_086.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/5f2ea471-3cc1-8388-06e9-3b24ebe4c8f8.jpeg)
![01_087.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/242897/d83f5bf1-79d6-cf8b-fa01-11779a94db6d.jpeg)


### チャネル作成
#### 設定ファイル作成、実行
「Name」と「ID」はmember-idを指定（マネジメントコンソールで確認）

```console:bc-client
cd ~
touch ./configtx.yaml
vim ./configtx.yaml
```

```yaml:configtx.yaml
Organizations:
    - &Org1
            # DefaultOrg defines the organization which is used in the sampleconfig
            # of the fabric.git development environment
        Name: m-DNGBD4KRKVBTDKIFIU2MCBUMQ4
            # ID to load the MSP definition as
        ID: m-DNGBD4KRKVBTDKIFIU2MCBUMQ4
        MSPDir: /opt/home/admin-msp
            # AnchorPeers defines the location of peers which can be used
            # for cross org gossip communication.  Note, this value is only
            # encoded in the genesis block in the Application section context    
        AnchorPeers:    
            - Host: 
              Port:    

Application: &ApplicationDefaults
        # Organizations is the list of orgs which are defined as participants on
        # the application side of the network
    Organizations:

Profiles:
    OneOrgChannel:
        Consortium: AWSSystemConsortium
        Application:
            <<: *ApplicationDefaults
            Organizations:
                - *Org1
```



```console:bc-client
docker exec cli configtxgen \
-outputCreateChannelTx /opt/home/mychannel.pb \
-profile OneOrgChannel -channelID mychannel \
--configPath /opt/home/
```

#### 環境変数の設定
マネジメントコンソールから設定値を確認し、変数に追加


```console:bc-client
cat >> ~/.bash_profile << "EOF"

export MSP_PATH=/opt/home/admin-msp
export MSP=m-DNGBD4KRKVBTDKIFIU2MCBUMQ4
export ORDERER=orderer.n-rbym74vosbg57lwtgap5a4fjqe.managedblockchain.us-east-1.amazonaws.com:30001
export PEER=nd-xezvqn2klzcr5pl6j7zhqeyaje.m-dngbd4krkvbtdkifiu2mcbumq4.n-rbym74vosbg57lwtgap5a4fjqe.managedblockchain.us-east-1.amazonaws.com:30003

EOF

```

上書き後に再読み込み

```console:bc-client
source ~/.bash_profile
```

#### チャネル作成
```console:bc-client
docker exec -e "CORE_PEER_TLS_ENABLED=true" \
-e "CORE_PEER_TLS_ROOTCERT_FILE=/opt/home/managedblockchain-tls-chain.pem" \
-e "CORE_PEER_ADDRESS=$PEER" \
-e "CORE_PEER_LOCALMSPID=$MSP" \
-e "CORE_PEER_MSPCONFIGPATH=$MSP_PATH" \
cli peer channel create -c mychannel \
-f /opt/home/mychannel.pb -o $ORDERER \
--cafile /opt/home/managedblockchain-tls-chain.pem --tls
```

#### チャネル参加
```console:bc-client
docker exec -e "CORE_PEER_TLS_ENABLED=true" \
-e "CORE_PEER_TLS_ROOTCERT_FILE=/opt/home/managedblockchain-tls-chain.pem" \
-e "CORE_PEER_ADDRESS=$PEER" \
-e "CORE_PEER_LOCALMSPID=$MSP" \
-e "CORE_PEER_MSPCONFIGPATH=$MSP_PATH" \
cli peer channel join -b mychannel.block \
-o $ORDERER --cafile /opt/home/managedblockchain-tls-chain.pem --tls
```

### chaincode（cc）の実行
#### ccのインストール
a、bそれぞれ数値を持ち、値の移動を行うccをインストール
https://github.com/mcenatie/fabric/blob/master/examples/chaincode/go/chaincode_example02/chaincode_example02.go

```console:bc-client
docker exec -e "CORE_PEER_TLS_ENABLED=true" \
-e "CORE_PEER_TLS_ROOTCERT_FILE=/opt/home/managedblockchain-tls-chain.pem" \
-e "CORE_PEER_LOCALMSPID=$MSP" \
-e "CORE_PEER_MSPCONFIGPATH=$MSP_PATH" \
-e "CORE_PEER_ADDRESS=$PEER" \
cli peer chaincode install \
-n mycc -v v0 -p github.com/chaincode_example02/go

```

#### ccのインスタンス化
初期値として、aに100、bに200を設定

```console:bc-client
docker exec -e "CORE_PEER_TLS_ENABLED=true" \
-e "CORE_PEER_TLS_ROOTCERT_FILE=/opt/home/managedblockchain-tls-chain.pem" \
-e "CORE_PEER_LOCALMSPID=$MSP" \
-e "CORE_PEER_MSPCONFIGPATH=$MSP_PATH" \
-e "CORE_PEER_ADDRESS=$PEER" \
cli peer chaincode instantiate \
-o $ORDERER -C mychannel -n mycc -v v0 \
-c '{"Args":["init","a","100","b","200"]}' \
--cafile /opt/home/managedblockchain-tls-chain.pem --tls
```

#### （参考）コンソールログ
```console:bc-client
[ec2-user@ip-172-31-7-168 ~]$ docker exec -e "CORE_PEER_TLS_ENABLED=true" \
> -e "CORE_PEER_TLS_ROOTCERT_FILE=/opt/home/managedblockchain-tls-chain.pem" \
> -e "CORE_PEER_LOCALMSPID=$MSP" \
> -e "CORE_PEER_MSPCONFIGPATH=$MSP_PATH" \
> -e "CORE_PEER_ADDRESS=$PEER" \
> cli peer chaincode install \
> -n mycc -v v0 -p github.com/chaincode_example02/go
2019-07-14 15:50:06.540 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2019-07-14 15:50:06.541 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
2019-07-14 15:50:07.225 UTC [chaincodeCmd] install -> INFO 003 Installed remotely response:<status:200 payload:"OK" >
[ec2-user@ip-172-31-7-168 ~]$ docker exec -e "CORE_PEER_TLS_ENABLED=true" \
> -e "CORE_PEER_TLS_ROOTCERT_FILE=/opt/home/managedblockchain-tls-chain.pem" \
> -e "CORE_PEER_LOCALMSPID=$MSP" \
> -e "CORE_PEER_MSPCONFIGPATH=$MSP_PATH" \
> -e "CORE_PEER_ADDRESS=$PEER" \
> cli peer chaincode instantiate \
> -o $ORDERER -C mychannel -n mycc -v v0 \
> -c '{"Args":["init","a","100","b","200"]}' \
> --cafile /opt/home/managedblockchain-tls-chain.pem --tls
2019-07-14 15:51:12.286 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2019-07-14 15:51:12.287 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc

```

#### ccがインスタンス化、デプロイされたことを確認
```console:bc-client
docker exec -e "CORE_PEER_TLS_ENABLED=true" \
-e "CORE_PEER_TLS_ROOTCERT_FILE=/opt/home/managedblockchain-tls-chain.pem" \
-e "CORE_PEER_LOCALMSPID=$MSP" \
-e  "CORE_PEER_MSPCONFIGPATH=$MSP_PATH" \
-e "CORE_PEER_ADDRESS=$PEER"  \
cli peer chaincode list --instantiated \
-o $ORDERER -C mychannel \
--cafile /opt/home/managedblockchain-tls-chain.pem --tls
```

#### （参考）実行結果
```console:bc-client
[ec2-user@ip-172-31-7-168 ~]$ docker exec -e "CORE_PEER_TLS_ENABLED=true" \
> -e "CORE_PEER_TLS_ROOTCERT_FILE=/opt/home/managedblockchain-tls-chain.pem" \
> -e "CORE_PEER_LOCALMSPID=$MSP" \
> -e  "CORE_PEER_MSPCONFIGPATH=$MSP_PATH" \
> -e "CORE_PEER_ADDRESS=$PEER"  \
> cli peer chaincode list --instantiated \
> -o $ORDERER -C mychannel \
> --cafile /opt/home/managedblockchain-tls-chain.pem --tls
Get instantiated chaincodes on channel mychannel:
Name: mycc, Version: v0, Path: github.com/chaincode_example02/go, Escc: escc, Vscc: vscc
```

#### cc実行（Query）
aの値を確認するコマンド

```console:bc-client
docker exec -e "CORE_PEER_TLS_ENABLED=true" \
-e "CORE_PEER_TLS_ROOTCERT_FILE=/opt/home/managedblockchain-tls-chain.pem" \
-e "CORE_PEER_ADDRESS=$PEER" \
-e "CORE_PEER_LOCALMSPID=$MSP" \
-e "CORE_PEER_MSPCONFIGPATH=$MSP_PATH" \
cli peer chaincode query -C mychannel \
-n mycc -c '{"Args":["query","a"]}'
```

#### cc実行（Invoke）
aからbに10移動


```console:bc-client
docker exec -e "CORE_PEER_TLS_ENABLED=true" \
-e "CORE_PEER_TLS_ROOTCERT_FILE=/opt/home/managedblockchain-tls-chain.pem" \
-e "CORE_PEER_ADDRESS=$PEER"  -e "CORE_PEER_LOCALMSPID=$MSP" \
-e "CORE_PEER_MSPCONFIGPATH=$MSP_PATH" \
cli peer chaincode invoke -C mychannel \
-n mycc -c  '{"Args":["invoke","a","b","10"]}' \
-o $ORDERER --cafile /opt/home/managedblockchain-tls-chain.pem --tls
```


#### 実行結果

```console:bc-client（実行前）
[ec2-user@ip-172-31-7-168 ~]$ docker exec -e "CORE_PEER_TLS_ENABLED=true" \
> -e "CORE_PEER_TLS_ROOTCERT_FILE=/opt/home/managedblockchain-tls-chain.pem" \
> -e "CORE_PEER_ADDRESS=$PEER" \
> -e "CORE_PEER_LOCALMSPID=$MSP" \
> -e "CORE_PEER_MSPCONFIGPATH=$MSP_PATH" \
> cli peer chaincode query -C mychannel \
> -n mycc -c '{"Args":["query","a"]}'
100

```

```console:bc-client（実行後）
[ec2-user@ip-172-31-7-168 ~]$ docker exec -e "CORE_PEER_TLS_ENABLED=true" \
> -e "CORE_PEER_TLS_ROOTCERT_FILE=/opt/home/managedblockchain-tls-chain.pem" \
> -e "CORE_PEER_ADDRESS=$PEER" \
> -e "CORE_PEER_LOCALMSPID=$MSP" \
> -e "CORE_PEER_MSPCONFIGPATH=$MSP_PATH" \
> cli peer chaincode query -C mychannel \
> -n mycc -c '{"Args":["query","a"]}'
90

[ec2-user@ip-172-31-7-168 ~]$ docker exec -e "CORE_PEER_TLS_ENABLED=true" \> -e "CORE_PEER_TLS_ROOTCERT_FILE=/opt/home/managedblockchain-tls-chain.pem" \> -e "CORE_PEER_ADDRESS=$PEER" \
> -e "CORE_PEER_LOCALMSPID=$MSP" \
> -e "CORE_PEER_MSPCONFIGPATH=$MSP_PATH" \
> cli peer chaincode query -C mychannel \
> -n mycc -c '{"Args":["query","b"]}'
210

```

## AWS Blockchain Templatesと比較して
 - Hyperledger Fabricのサポートバージョンが1.0から1.2になった
 - 今回は試してないが、メンバーの追加で他AWSアカウントを参加させられる
    - 組織ごとにもつAWSアカウントを利用できるのでより実用的になった
        - 共有備品や会議室の予約等、部署をまたいで管理
        - セキュアな情報を社外の組織と共有
 - ネットワークを構築するためのVPCをわざわざ作成する必要がなくなった
 - ノードの作成がコンソールで可能
    - より簡単にノードを立てられるようになった
    - 専用のインスタンスタイプができた
    - AZは6つから選択可能
 - docker等のインストールはコマンドを実行してやらないといけない
 - CAやチャネル、CCの設定に手間がかかる点は変わらず
    - これらもマネジメントコンソールからやりたい