AWS Managed Blockchainの歩き方 #1 環境構築〜トランザクション実行編

# はじめに

AWS Managed BlockchainがGAになったので、ネットワーク作成からトランザクション実行までやってみました。今回はその手順をご紹介します。

# ブロックチェーンの始め方

今回はただ動かすことを目的に、[Get Started Creating a Hyperledger Fabric Blockchain Network Using Amazon Managed Blockchain](https://docs.aws.amazon.com/managed-blockchain/latest/managementguide/managed-blockchain-get-started-tutorial.html)を参考に、非常にシンプルなテスト用ネットワークを作ります。全貌が分かる絵がなかったので、簡単に描いてみました。おそらくこんな感じになると思います。

![fig-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319797/72228e8f-5f3e-0b0c-f7dd-d70c0d644d0d.png)

## ネットワークを作る

* [AWS Managed Blockchain コンソール](https://console.aws.amazon.com/managedblockchain/)を開きます。
* Create networkをクリックします。
* Blockchain frameworksを設定します。記載がない項目は、一旦デフォルトのままでOKです。

|項目|設定値|
|:---|:----|
|Blockchain frameworks|Hyperledger Fabric 1.2|
|Network edition|Starter|
|Network name|*network name*（適当に）|

* Member Configurationを設定します。ここで設定するAdmin usernameとAdmin passwordは後から使うので、どこかにメモしておくのがよいと思います。

|項目|設定値|
|:---|:----|
|Member name|*menber name*（適当に）|
|Admin username|*username*（適当に）|
|Admin password|*password*（適当に）|

* Review and createで内容を確認して、Create network and memberをクリックします。
* ネットワーク構築が始まります。StatusがAvailableになればOKです。結構時間がかかりますが、この時点でコケるとは考えづらいので安心して待ちます。

## VPCエンドポイントを作る

先ほど作成したネットワークを選択して内容を確認すると、**VPC endpoint service name**という項目があり、すでに名前がついていることが分かります。VPCエンドポイントとは、VPCと他のAWSのサービスとをプライベートに接続できるAWSのサービスらしいです。

つまり、AWS Managed Blockchainというサービスを使って、AWS上のどこぞやに作られた先ほどのネットワーク（マネージド故に、使う側があえて意識しなくてもよい世界）にアクセスするための入り口の名前、みたいなものかなぁという認識です。

このステップでは、VPC endpoint service nameに実際のVPCやサブネットをアタッチして、VPCエンドポイントとして実体化（VPCコンソールのエンドポイントから見える状態にするという意味で）します。後続の手順では、ここでアタッチしたサブネットにEC2を立てて、Hyperledger Fabric Clientをセットアップします。

* まず、VPCエンドポイントの作成に必要なセキュリティグループを作ります。公式リファレンスによると、VPCエンドポイントとEC2インスタンスにアタッチするセキュリティグループは同じものがいいらしいので、22ポートも開けておきます。

|Inbound/Outbound|Type|Source/Destination|Purpose|
|:--|:---|:-----------------|:------|
|Outbound|All traffic|0.0.0/0 (Anywhere)|default|
|Inbound|SSH (Port 22)|適切に|自分のPCからEC2にSSH接続するため|
|Inbound|Custom TCP (Port 30001 - 30003)|適切に|EC2からOrderer、CA、Peerにアクセスするため|

>We recommend that you launch the client Amazon EC2 instance in the same VPC and using the same security group as the VPC Endpoint that you created in Step 2: Create and Configure the Interface VPC Endpoint. This simplifies connectivity between the Amazon EC2 instance and the Interface VPC Endpoint.

[Configuring Security Groups](https://docs.aws.amazon.com/managed-blockchain/latest/managementguide/managed-blockchain-security-sgs.html)

* 次に、AWS Managed Blockchainコンソールから先ほど作成したネットワークを選択し、Create VPC endpointをクリックしてエンドポイントを作成します。

|項目|設定値|
|:---|:----|
|VPC|とりあえずなので、デフォルトVPCを選択|
|Subnets|サブネットを選択|
|Security groups|さっき作ったセキュリティグループ|

## Peer Nodeノードを作る

[Step 3: Set Up a Client](https://docs.aws.amazon.com/managed-blockchain/latest/managementguide/get-started-create-client.html)では、ブロックチェーン上のネットワークにチャンネルを作ったり、チェーンコードをインストールしたりするためのHyperledger Fabric Client(EC2インスタンス）を作成するのですが、地道にポチって環境構築するのはかなり大変です。。。

そこで今回は、CloudFormationのテンプレートが用意されていたので、それを使います。実際に使ってみると、予め必要なパッケージがほぼセットアップされたインスタンスがいきなり作れる上に、Hyperledger Fabric Clientの本体であるDockerコンテナも最初から起動した状態になるので、かなり手順がスキップできました。

公式リファレンスと順番が前後しますが、スタックを作る時にPeer Nodeのエンドポイントが必要となるため、先に作っておきます。

* AWS Managed Blockchainコンソールから作成したネットワークのメンバーを選択し、Create peer nodeをクリックします。
* Peer Nodeの設定を行います。

|項目|設定値|
|:---|:----|
|Blockchain instance type|bc.t3.small|
|Availability Zone|us-east-1a|

## Hyperledger Fabric Clientを作る

* [amazon-managed-blockchain-client-templates repository](https://github.com/awslabs/amazon-managed-blockchain-client-templates)を使って、EC2インスタンスを作成します。バージニア北部リージョンでCloudFormationコンソールを開いて、新しいスタックを作成します。

**EC2 instance parameters**

|パラメータ|設定値|
|:-------|:----|
|スタックの名前|*stackname*（適当に）|
|SubnetID|VPCエンドポイントにアタッチしたサブネットを選択|
|EC2SecurityGroup|VPCエンドポイントにアタッチしたセキュリティグループ|
|EC2KeyPairName|キーペア名（なければ予め作っておく）|
|InstanceType|デフォルト（t3.small)|

**Managed Blockchain parameters**

|パラメータ|設定値|
|:---|:-----|
|Version|1.2|
|MemberID|AWS Managed Blockchainで作ったメンバーのID（①）|

**Hyperledger Fabric parameters**

|パラメータ|設定値|
|:---|:-----|
|FabricCAEndpoint|AWS Managed Blockchainで作ったメンバーのCAエンドポイント（②）|
|OrderingServiceEndpoint|AWS Managed Blockchainで作ったOrdererのエンドポイント（③）|
|PeerNodeEndpoint|AWS Managed Blockchainで作ったPeerNodeのエンドポイント（④）|

* インスタンスが起動したら、sshでログインします。

```terminal
$ ssh -i key.pem ec2-user@ec2-XXX-XXX-XXX-XXX.compute-1.amazonaws.com
```

* 基本的に必要なパッケージはインストールされていますが、aws managedblockchainコマンドが使えなかったので、AWS CLIをアップデートします。アップデートしたら、aws configureコマンドで初期設定をしておきます。リージョンは、AWS Managed Blockchainサービスと同じバージニア北部（us-east-1）をセットしておきます。

```terminal
$ sudo pip install --upgrade awscli
$ aws configure
```

* AWS CLIやネットワークの設定が正しくできているかを確認します。まず、aws managedblockchainコマンドを実行してメンバー情報を取得します。network-id（⑤）とmember-idは、自分のものに置き換えてください。

```terminal
$ aws managedblockchain get-member \
--network-id n-MWY63ZJZU5HGNCMBQER7IN6OIU \
--member-id m-K46ICRRXJRCGRNNS4ES4XUUS5A
{
    "Member": {
        "NetworkId": "n-MWY63ZJZU5HGNCMBQER7IN6OIU", 
        "Status": "AVAILABLE", 
        "Name": "org1", 
        "FrameworkAttributes": {
            "Fabric": {
                "AdminUsername": "admin", 
                "CaEndpoint": "ca.m-K46ICRRXJRCGRNNS4ES4XUUS5A.n-MWY63ZJZU5HGNCMBQER7IN6OIU.managedblockchain.us-east-1.amazonaws.com:30002"
            }
        }, 
        "CreationDate": "2019-05-07T08:23:30.364Z", 
        "Id": "m-K46ICRRXJRCGRNNS4ES4XUUS5A"
    }
}
```

* コマンドが成功すると、CaEndpointが取得できます。次に、curlコマンドを実行し、EC2インスタンスからCAサーバにアクセスできることを確認します。

```terminal
$ curl https://ca.m-K46ICRRXJRCGRNNS4ES4XUUS5A.n-MWY63ZJZU5HGNCMBQER7IN6OIU.managedblockchain.us-east-1.amazonaws.com:30002/cainfo -k
{"result":{"CAName":"abcd1efghijkllmn5op3q52rst","CAChain":"LongStringOfCharacters","Version":"1.2.1-snapshot-"}
,"errors":[],"messages":[],"success":true}
```

![fig-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319797/6f1bc63b-2dc5-f739-a2bf-382938438d9e.png)
![fig-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319797/f07a93c4-ce7b-268f-4258-80682e109925.png)
![fig-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/319797/e372abf4-cf44-a42d-be21-18b7072150e9.png)

## Adminユーザーを登録する

* fabric-ca-clientコマンドを実行して、Adminユーザを登録します。AdminUsernameとAdminPasswordには、前述手順「ネットワークを作る」で指定したAdmin usernameとAdmin passwordをセットします。

```terminal
$ fabric-ca-client enroll \
-u https://AdminUsername:AdminPassword@ca.m-K46ICRRXJRCGRNNS4ES4XUUS5A.n-MWY63ZJZU5HGNCMBQER7IN6OIU.managedblockchain.us-east-1.amazonaws.com:30002 \
--tls.certfiles /home/ec2-user/managedblockchain-tls-chain.pem -M /home/ec2-user/admin-msp
2019/05/08 06:24:55 [INFO] TLS Enabled
2019/05/08 06:24:55 [INFO] generating key: &{A:ecdsa S:256}
2019/05/08 06:24:55 [INFO] encoded CSR
2019/05/08 06:24:55 [INFO] Stored client certificate at /home/ec2-user/admin-msp/signcerts/cert.pem
2019/05/08 06:24:55 [INFO] Stored root CA certificate at /home/ec2-user/admin-msp/cacerts/ca-abcd1efghijkllmn5op3q52rst-uqz2f2xakfd7vcfewqhckr7q5m-managedblockchain-us-east-1-amazonaws-com-30002.pem
```
* signcertsにpemが生成されました。これは、AdminユーザーとしてのMSP証明書でもあるので、admincertsにコピーしておきます。

```terminal
$ cp -r admin-msp/signcerts admin-msp/admincerts
```

## チャンネルを作る

* チャンネル構成用のyamlを作成します。MemberIDのところは、自分のものに置き換えてください。

```yaml
# /home/ec2-user/configtx.yaml
################################################################################
#
#   Section: Organizations
#
#   - This section defines the different organizational identities which will
#   be referenced later in the configuration.
#
################################################################################
Organizations:
    - &Org1
            # DefaultOrg defines the organization which is used in the sampleconfig
            # of the fabric.git development environment
        Name: MemberID #ここを自分のIDに置き換える
            # ID to load the MSP definition as
        ID: MemberID #ここを自分のIDに置き換える
        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:    

################################################################################
#
#   SECTION: Application
#
#   - This section defines the values to encode into a config transaction or
#   genesis block for application related parameters
#
################################################################################
Application: &ApplicationDefaults
        # Organizations is the list of orgs which are defined as participants on
        # the application side of the network
    Organizations:

################################################################################
#
#   Profile
#
#   - Different configuration profiles may be encoded here to be specified
#   as parameters to the configtxgen tool
#
################################################################################
Profiles:
    OneOrgChannel:
        Consortium: AWSSystemConsortium
        Application:
            <<: *ApplicationDefaults
            Organizations:
                - *Org1
```

* Genesis blockを作成します。

```terminal
$ docker exec cli configtxgen \
-outputCreateChannelTx /opt/home/mychannel.pb \
-profile OneOrgChannel -channelID mychannel \
--configPath /opt/home/
```

* 今後の作業を楽にするために、環境変数をセットします。MemberIDとPeerNodeEndpointは、自分のものに置き換えてください。

```shell
# .bash_profile
...other configurations
export MSP_PATH=/opt/home/admin-msp
export MSP=MemberID #ここを自分のIDに置き換える
export PEER=PeerNodeEndpoint #ここを自分のIDに置き換える
```

```terminal
$ source ~/.bash_profile
```

* チャンネルを作ります。

```terminal
$ 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
```

* Peerをチャンネルに参加させます。

```terminal
$ 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
```

## チェーンコードをインストールする

* チェーンコードをインストールします。

```terminal
$ 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
```

* インストールしたチェーンコードは、初回にインスタンス化が必要となります。

```terminal
$ 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
```

* 正しくインストールできているか、確認します。

```terminal
$ 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
```

## チェーンコードを実行する

* 先ほどインストールしたサンプルのチェーンコードを実行します。まずは、queryから。

```terminal
$ 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と返ってきたら、成功です。

* 次に、invokeです。

```terminal
$ 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

2019-05-08 06:52:28.831 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200 
```

トランザクションが成功すると、このように200が返ります。
もう一度、queryしてみてください。トランザクションが反映されているため、今度は90が返ってきます。

# さいごに

AWS Managed BlockchainのStarter Editionでネットワークを構成し、トランザクションを実行しました。以前のように、唸りながら、ハマりながら、、自前で環境構築していたことを思うと、AWS Managed Blockchainにとても有難味を感じました。

一方で、チャンネル作成やチェーンコードのセットアップあたりも、なにか画面が用意されていて、サクッとできるのかしら・・・と期待していたのですが、そこは相変わらず、Dockerコンテナ経由でコマンドを叩きまくる必要があります。このあたりは、今後のアップデートに期待です。