Hyperledger composerで作ったものをIBM Cloud上にデプロイしてみる

#はじめに
ネタばらしを先にいくと、[こちら](http://www.cdevc.work/event/Cloud-Developers-Circle-6-Blockchain-Night.html)で行われているハンズオンでやってること／言ってることそのままです。

初心者なので写経の気持ちで。

#Hyperledger composer
Hyperledger自身の説明については「クローズドな志向のブロックチェーンプラットフォーム」に留めるのであとは詳しい方たちに任せます。
開発言語ですが、そのまま作るとGo言語かJavaになり、細かくピアの定義などもできるみたいなのですが、Javaと聞くと敷居高そうですよね、、、、半年前ならJavaとJavaScriptの違いも分からなかったので「へー」だったのですが、初学者な今ではJavaなぞ聞くだけで尻尾を巻いて逃げ出します。
というわけで、Hyperledgerの開発環境がHyperledger composerです。
Hyperledger composer playgroundというWeb開発ツールをします。
こちら→[https://composer-playground.mybluemix.net/](https://composer-playground.mybluemix.net/)

#サンプルを作る
上記にアクセスし、新規作成します。
<img width="1324" alt="Hyperledger_Composer_と_Hyperledger_Composer.png" src="https://qiita-image-store.s3.amazonaws.com/0/246332/425988f5-4858-fa58-3a8d-abae1424da65.png">
business networkと呼んでいますが、プロジェクトみたいなものですね。

新規作成としては以下の３つが与えられています

- 完全なまっさらな状態から作る（empty-business-network）
- 最低限のものから自分で作る（basic-sample-network）
- サンプルから作る（samples on npmのところ）


<img width="1302" alt="Hyperledger_Composer.png" src="https://qiita-image-store.s3.amazonaws.com/0/246332/a347c88d-8f4c-d918-8592-97dd93709f22.png">
今回はカーオークションのためのサンプルを使ってみます。
adminを作成する必要がるので適当にやっときます。

つくるとこんな感じになります。
<img width="1492" alt="Hyperledger_Composer.png" src="https://qiita-image-store.s3.amazonaws.com/0/246332/d167f0c0-3fc3-841a-da82-ecfc2475a0d5.png">
Hyperledger composerは3つの要素があり、左側に並んでるのがそれです。

- Model
- Logic
- ACL

それぞれいきます
####Model File
Model
資産（asset）と参加者（participant）、トランザクションを定義するもの。
今回のサンプルでのデフォルトは以下です。
javaをもとにしてるらしく、メソッドなどを調べるとjavaの記事に多くたどり着きました。
`namespace`とか`Double`とか`enum`とか`abstract`とか

```java
namespace org.acme.vehicle.auction //名前空間

asset Vehicle identified by vin {
  o String vin  //固有の番号らしい
  --> Member owner  //Member（下のほうで定義）というクラスの中のownerで構成
}
// 車（Vehicle）を資産とする。
// vinで定義

enum ListingState {
  o FOR_SALE //販売中
  o RESERVE_NOT_MET //最低価格未満
  o SOLD //売り切れ
}
// 出品リストのステータス（ListingState）を列挙型で定義


asset VehicleListing identified by listingId {
  o String listingId
  o Double reservePrice  //最低落札価格
  o String description  //詳細説明
  o ListingState state  //ステータス
  o Offer[] offers optional  // offerというトランザクションの際のoptional
  --> Vehicle vehicle  //Vehicle
}
// Vehicleを資産する。
// listingIdで定義


abstract participant User identified by email {
  o String email
  o String firstName
  o String lastName
}
// Userという抽象クラスを作成


participant Member extends User {
  o Double balance
}
//Memberという参加者を定義
//Userに加えて、残高(Balance)を持つ

participant Auctioneer extends User {
}
// Auctioneerという参加者を定義

transaction Offer {
  o Double bidPrice  
  --> VehicleListing listing
  --> Member member
}
// Offerというトランザクションを定義



transaction CloseBidding {
  --> VehicleListing listing
}
// CloseBiddingというトランザクションを定義
```

####Script File
Logic
トランザクションの中身を定義するもの
JavaScriptで書かれています。

```javascript
async function closeBidding(closeBidding) {  // eslint-disable-line no-unused-vars
    const listing = closeBidding.listing;
    if (listing.state !== 'FOR_SALE') {
        throw new Error('Listing is not FOR SALE');
    }
    // by default we mark the listing as RESERVE_NOT_MET
    listing.state = 'RESERVE_NOT_MET';
    let highestOffer = null;
    let buyer = null;
    let seller = null;
    if (listing.offers && listing.offers.length > 0) {
        // sort the bids by bidPrice
        listing.offers.sort(function(a, b) {
            return (b.bidPrice - a.bidPrice);
        });
        highestOffer = listing.offers[0];
        if (highestOffer.bidPrice >= listing.reservePrice) {
            // mark the listing as SOLD
            listing.state = 'SOLD';
            buyer = highestOffer.member;
            seller = listing.vehicle.owner;
            // update the balance of the seller
            console.log('#### seller balance before: ' + seller.balance);
            seller.balance += highestOffer.bidPrice;
            console.log('#### seller balance after: ' + seller.balance);
            // update the balance of the buyer
            console.log('#### buyer balance before: ' + buyer.balance);
            buyer.balance -= highestOffer.bidPrice;
            console.log('#### buyer balance after: ' + buyer.balance);
            // transfer the vehicle to the buyer
            listing.vehicle.owner = buyer;
            // clear the offers
            listing.offers = null;
        }
    }

    if (highestOffer) {
        // save the vehicle
        const vehicleRegistry = await getAssetRegistry('org.acme.vehicle.auction.Vehicle');
        await vehicleRegistry.update(listing.vehicle);
    }

    // save the vehicle listing
    const vehicleListingRegistry = await getAssetRegistry('org.acme.vehicle.auction.VehicleListing');
    await vehicleListingRegistry.update(listing);

    if (listing.state === 'SOLD') {
        // save the buyer
        const userRegistry = await getParticipantRegistry('org.acme.vehicle.auction.Member');
        await userRegistry.updateAll([buyer, seller]);
    }
}

/**
 * Make an Offer for a VehicleListing
 * @param {org.acme.vehicle.auction.Offer} offer - the offer
 * @transaction
 */
async function makeOffer(offer) {  // eslint-disable-line no-unused-vars
    let listing = offer.listing;
    if (listing.state !== 'FOR_SALE') {
        throw new Error('Listing is not FOR SALE');
    }
    if (!listing.offers) {
        listing.offers = [];
    }
    listing.offers.push(offer);

    // save the vehicle listing
    const vehicleListingRegistry = await getAssetRegistry('org.acme.vehicle.auction.VehicleListing');
    await vehicleListingRegistry.update(listing);
}
```
`getAssetRegistry`というので台帳に書き込んでるらしいです



####Access Control
ACL
各参加者の権限付

```java
rule Auctioneer {
    description: "Allow the auctioneer full access"
    participant: "org.acme.vehicle.auction.Auctioneer"
    operation: ALL
    resource: "org.acme.vehicle.auction.*"
    action: ALLOW
}

rule Member {
    description: "Allow the member read access"
    participant: "org.acme.vehicle.auction.Member"
    operation: READ
    resource: "org.acme.vehicle.auction.*"
    action: ALLOW
}

rule VehicleOwner {
    description: "Allow the owner of a vehicle total access"
    participant(m): "org.acme.vehicle.auction.Member"
    operation: ALL
    resource(v): "org.acme.vehicle.auction.Vehicle"
    condition: (v.owner.getIdentifier() == m.getIdentifier())
    action: ALLOW
}

rule VehicleListingOwner {
    description: "Allow the owner of a vehicle total access to their vehicle listing"
    participant(m): "org.acme.vehicle.auction.Member"
    operation: ALL
    resource(v): "org.acme.vehicle.auction.VehicleListing"
    condition: (v.vehicle.owner.getIdentifier() == m.getIdentifier())
    action: ALLOW
}

rule SystemACL {
    description:  "System ACL to permit all access"
    participant: "org.hyperledger.composer.system.Participant"
    operation: ALL
    resource: "org.hyperledger.composer.system.**"
    action: ALLOW<img width="1050" alt="カタログ_-_IBM_Cloud.png" src="https://qiita-image-store.s3.amazonaws.com/0/246332/1daa745a-bdb9-0831-2157-b3b92278d576.png">

}

rule NetworkAdminUser {
    description: "Grant business network administrators full access to user resources"
    participant: "org.hyperledger.composer.system.NetworkAdmin"
    operation: ALL
    resource: "**"
    action: ALLOW
}

rule NetworkAdminSystem {
    description: "Grant business network administrators full access to system resources"
    participant: "org.hyperledger.composer.system.NetworkAdmin"
    operation: ALL
    resource: "org.hyperledger.composer.system.**"
    action: ALLOW
}
```
車の所有者（`VehicleOwner`）と出品者（`VehicleListingOwner`）が同じだったら両方の権限を与えるようになってます

#エクスポート
Hyperledger fabricにデプロイできる形で出力。
左下の`Export`

#IBM Cloud上でブロックチェーンプラットフォームを作成
Hyperledger FablicといえばIBMなのでIBM Cloud上で作成します。
IBMアカウントがあり、カードなどを登録していれば、Starterプランというので無料で使えます。

##コードのインストール
先程出力した`bna`データをインストールすると動かせるようになります
<img width="1385" alt="IBM_Blockchain.png" src="https://qiita-image-store.s3.amazonaws.com/0/246332/0f301dfd-2dc8-8e0d-5613-774bb9be8fed.png">