#はじめに
ネタばらしを先にいくと、こちらで行われているハンズオンでやってること/言ってることそのままです。
初心者なので写経の気持ちで。
#Hyperledger composer
Hyperledger自身の説明については「クローズドな志向のブロックチェーンプラットフォーム」に留めるのであとは詳しい方たちに任せます。
開発言語ですが、そのまま作るとGo言語かJavaになり、細かくピアの定義などもできるみたいなのですが、Javaと聞くと敷居高そうですよね、、、、半年前ならJavaとJavaScriptの違いも分からなかったので「へー」だったのですが、初学者な今ではJavaなぞ聞くだけで尻尾を巻いて逃げ出します。
というわけで、Hyperledgerの開発環境がHyperledger composerです。
Hyperledger composer playgroundというWeb開発ツールをします。
こちら→https://composer-playground.mybluemix.net/
#サンプルを作る
上記にアクセスし、新規作成します。
business networkと呼んでいますが、プロジェクトみたいなものですね。
新規作成としては以下の3つが与えられています
- 完全なまっさらな状態から作る(empty-business-network)
- 最低限のものから自分で作る(basic-sample-network)
- サンプルから作る(samples on npmのところ)
つくるとこんな感じになります。
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プランというので無料で使えます。