LoginSignup
4
3

More than 5 years have passed since last update.

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

Posted at

はじめに

ネタばらしを先にいくと、こちらで行われているハンズオンでやってること/言ってることそのままです。

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

Hyperledger composer

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

サンプルを作る

上記にアクセスし、新規作成します。
Hyperledger_Composer_と_Hyperledger_Composer.png
business networkと呼んでいますが、プロジェクトみたいなものですね。

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

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

Hyperledger_Composer.png
今回はカーオークションのためのサンプルを使ってみます。
adminを作成する必要がるので適当にやっときます。

つくるとこんな感じになります。
Hyperledger_Composer.png
Hyperledger composerは3つの要素があり、左側に並んでるのがそれです。

  • Model
  • Logic
  • ACL

それぞれいきます

Model File

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

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で書かれています。

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
各参加者の権限付

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データをインストールすると動かせるようになります
IBM_Blockchain.png

4
3
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
4
3