由於此係統將包含我們不希望每個人都看到的敏感資料,因此我們需要實現控制對此個人資料的訪問許可權。
讓我們首先建立一個用於儲存應用程式的資料夾:
mkdir insurance-application && cd insurance-application
現在讓我們使用yeoman為我們的業務網路建立一個框架
yo hyperledger-composer:businessnetwork
Business network name: risk-analysis-tutorial
Description: 分線分析教程
Author name: 你的名字
Author email: 你的郵箱
License: Apache-2.0
Namespace: org.acme.riskanalysis
Do you want to generate an empty template network? (您想生成空模板網路嗎?)Yes
cd risk-analysis-tutorial
執行命令ls應顯示以下資料夾和檔案:
- models
- package.json
- permissions.acl
- README.md
因此,首先我們要定義我們網路中的參與者,誰是投保人和誰是保險人。我們開啟檔案org.acme.riskanalysis.cto,可以在models資料夾中找到該檔案。
participant Policyholder identified by id {
o String id
o String name
o Double balance default = 0.0
o Integer noClaimsYears default = 0
}
participant InsuranceCompany identified by id {
o String id
o String name
o Double balance default = 0.0
o Integer insuranceContracts default = 0
}
保單持有人還希望能夠新增房屋或汽車等資產,因此我們定義一個名為PrivateAsset的資產以及一個名為AssetType的列舉。PrivateAsset依賴於將成為建立資產的人的保單持有人。只有3種型別的資產可以新增到系統中,由enum AssetType定義。
asset PrivateAsset identified by id {
o String id
o AssetType assetType
o Double value
--> Policyholder policyholder
o Integer durationInMonths
o Double riskAnalysisScore default = 0.0
--> InsuranceCompany insuranceCompany optional
}
enum AssetType {
o CAR
o HOUSE
o PHONE
}
我們將增加兩種資產型別,一種用於保險報價,另一種用於索賠。
asset InsuranceOffer identified by id {
o String id
--> Policyholder policyholder
--> InsuranceCompany insuranceCompany
--> PrivateAsset privateAsset
o Double monthlyCost
o Integer durationInMonths
o String status default = "pending"
}
asset Claim identified by id {
o String id
--> PrivateAsset privateAsset
--> Policyholder policyholder
--> InsuranceCompany insuranceCompany
o String description
o Double claimValue
o String status default = "pending"
}
接下來,我們需要為網路定義我們的事務。
transaction AcceptInsuranceOffer {
--> InsuranceOffer offer
}
transaction MakeInsuranceOffer {
--> Policyholder policyholder
--> InsuranceCompany insuranceCompany
--> PrivateAsset privateAsset
o Double monthlyCost
}
transaction RiskAnalysis {
--> PrivateAsset privateAsset
}
transaction CreateNewAsset {
--> Policyholder policyholder
o AssetType assetType
o Double value
o Integer durationInMonths
}
transaction CreateClaim {
--> PrivateAsset privateAsset
--> Policyholder policyholder
o String description
o Double claimValue
}
transaction ProcessClaim {
-->Claim claim
o String status
}
您的完整模型檔案應該是這樣的:
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace org.acme.riskanalysis
participant Policyholder identified by id {
o String id
o String name
o Double balance default = 0.0
o Integer noClaimsYears default = 0
}
participant InsuranceCompany identified by id {
o String id
o String name
o Double balance default = 0.0
o Integer insuranceContracts default = 0
}
asset PrivateAsset identified by id {
o String id
o AssetType assetType
o Double value
--> Policyholder policyholder
o Integer durationInMonths
o Double riskAnalysisScore default = 0.0
--> InsuranceCompany insuranceCompany optional
}
enum AssetType {
o CAR
o HOUSE
o PHONE
}
asset InsuranceOffer identified by id {
o String id
--> Policyholder policyholder
--> InsuranceCompany insuranceCompany
--> PrivateAsset privateAsset
o Double monthlyCost
o Integer durationInMonths
o String status default = "pending"
}
asset Claim identified by id {
o String id
--> PrivateAsset privateAsset
--> Policyholder policyholder
--> InsuranceCompany insuranceCompany
o String description
o Double claimValue
o String status default = "pending"
}
transaction AcceptInsuranceOffer {
--> InsuranceOffer offer
}
transaction MakeInsuranceOffer {
--> Policyholder policyholder
--> InsuranceCompany insuranceCompany
--> PrivateAsset privateAsset
o Double monthlyCost
}
transaction RiskAnalysis {
--> PrivateAsset privateAsset
}
transaction CreateNewAsset {
--> Policyholder policyholder
o AssetType assetType
o Double value
o Integer durationInMonths
}
transaction CreateClaim {
--> PrivateAsset privateAsset
--> Policyholder policyholder
o String description
o Double claimValue
}
transaction ProcessClaim {
-->Claim claim
o String status
}
接下來,我們需要實現我們的事務,這是鏈程式碼完成。
首先,您需要在Hyperledger編寫器專案的主目錄中建立一個名為lib的新目錄,您將在其中看到諸如package.json之類的檔案,或者如果您位於終端的models目錄中,請執行以下命令:
mkdir ../lib/ && cd ../lib/
在lib目錄中,我們現在將建立一個名為logic.js的新檔案,它將成為我們的鏈程式碼檔案。
讓我們首先實現CreateNewAsset。您會注意到我們使用decorators 為我們的函式提供後設資料。
/**
* Create a new asset
* @param {org.acme.riskanalysis.CreateNewAsset} asset
* @transaction
*/
async function createNewAsset(asset) {
let assetRegistry = await getAssetRegistry('org.acme.riskanalysis.PrivateAsset');
var factory = getFactory()
num_id = (Math.floor(Math.random() * ( 999999 - 100000) + 100000)).toString(10)
var assetID = asset.policyholder.id + num_id;
var newAsset = factory.newResource('org.acme.riskanalysis', 'PrivateAsset', assetID)
newAsset.policyholder = asset.policyholder;
newAsset.assetType = asset.assetType;
newAsset.value = asset.value;
newAsset.durationInMonths = asset.durationInMonths;
await assetRegistry.add(newAsset)
}
現在我們已經完成了,讓我們測試一下它是否有效。
首先,我們必須啟動Hyperledger Fabric。找到您已下載的目錄並執行指令碼,如下所示:
cd ~/fabric-dev-servers
./startFabric.sh
./createPeerAdminCard.sh
注意,如果以前沒有執行過Hyperledger Fabric或以前執行過/teardownfabric.sh,則只需執行/createpeeradincard.sh。
nvm use 8
現在回到risk-analysis-tutorial目錄,我們將開始部署我們網路的0.0.1版本。
執行此命令將生成名為admin@chaindaily的業務網路歸檔檔案
composer archive create -t dir -n .
接下來,我們將在我們設定的Hyperledger Fabric對等裝置上安裝Composer業務網路
composer network install --card admin@chaindaily
--archiveFile admin@chaindaily
現在我們可以開始我們的業務網路,這可能需要幾分鐘
composer network start --networkName risk-analysis-tutorial
--networkVersion 0.0.1 --networkAdmin admin --networkAdminEnrollSecret
adminpw --card admin@chaindaily --file networkadmin.card
然後只需將網路管理員身份匯入為可用的業務網絡卡
composer card import --file networkadmin.card
要測試這是否全部成功,只需ping網路即可
composer network ping --card admin@chaindaily
檢查已部署的網路執行的當前版本
composer network ping -c admin@chaindaily | grep Business
Hyperledger Composer可以基於業務網路生成定製的REST API。對於我們的網路,我們現在只想保持簡單,所以只需執行以下命令即可建立REST API
composer-rest-server -c admin@chaindaily -n never -u true -w true
現在,您可以透過定位到測試REST API
http://localhost:3000/explorer
您應該看到以下螢幕
Hyperledger Composer REST Server
如果我們要測試我們的CreateNewAsset函式,我們首先需要建立一些保單持有人,所以選擇Policyholder,然後選擇post並輸入以下內容,然後單擊try out out
{
"$class": "org.acme.riskanalysis.Policyholder",
"id": "joe",
"name": "Joe",
"balance": "50000",
"noClaimsYears": "2"
}
現在使用以下資訊以相同的方式建立另一個保單持有人
{
"$class": "org.acme.riskanalysis.Policyholder",
"id": "mary",
"name": "Mary",
"balance": "50000",
"noClaimsYears": "5"
}
如果不出現錯誤訊息,則對兩者的響應應為200,並檢視程式碼是否存在任何潛在錯誤。
現在我們準備測試CreateNewAsset函式了。要執行此操作,請轉到CreateNewAsset> Post。讓我們為Joe創造一輛價值2000美元的氣車,並尋求12個月的保險。
{
"$class": "org.acme.riskanalysis.CreateNewAsset",
"policyholder": "resource:org.acme.riskanalysis.Policyholder#joe",
"assetType": "CAR",
"value": 2000,
"durationInMonths": 12
}
如果一切正常,響應程式碼應為200。請注意它區分大小寫。
現在,如果您轉到PrivateAssets> Get,然後單擊“try it out”,您應該看到我們剛建立的資產。
現在讓我們透過單擊終端中的ctrl-c關閉REST伺服器,我們將完成其餘的事務處理。
RiskAnalysis交易的邏輯只是檢查資產型別以及保單持有人沒有索賠的年數和資產的價值。
/**
* Risk Analysis
* @param {org.acme.riskanalysis.RiskAnalysis} asset
* @transaction
*/
async function riskAnalysis(asset) {
let assetRegistry = await getAssetRegistry('org.acme.riskanalysis.PrivateAsset');
let score = 0
if (asset.privateAsset.policyholder.noClaimsYears == 1) {
score += 1
}
if (asset.privateAsset.policyholder.noClaimsYears == 2) {
score += 2
}
if (asset.privateAsset.policyholder.noClaimsYears > 2) {
score += 4
}
if (asset.privateAsset.description == 'Phone') {
score +=2
}
if (asset.privateAsset.description == 'House') {
score +=3
}
if (asset.privateAsset.description == 'Car') {
score +=2
}
if (asset.privateAsset.value < 10000.0) {
score += 1
}
if (asset.privateAsset.value < 1000.0) {
score += 1
}
asset.privateAsset.riskAnalysisScore = score
assetRegistry.update(asset.privateAsset)
}
要對此進行測試,請轉到package.json檔案並將版本號從0.0.1更改為0.0.2,然後建立新的業務網路存檔檔案
composer archive create --sourceType dir --sourceName . -a admin@chaindaily
安裝新檔案
composer network install --card admin@chaindaily --archiveFile admin@chaindaily
更新網路
composer network upgrade -c admin@chaindaily -n risk-analysis-tutorial -V 0.0.2
檢查網路是否已升級到版本:0.0.2
composer network ping -c admin@chaindaily | grep Business
然後再次執行Composer REST SERVER
composer-rest-server -c admin@chaindaily -n never -u true -w true
您之前建立的所有保單持有人和資產仍將在此處,因此無需再次設定這些保單持有人和資產。 讓我們獲取之前為Joe新增的汽車的ID。 然後轉到RiskAnalysis> Post並輸入以下用您的資產ID替換ASSETID。
{
"$class": "org.acme.riskanalysis.RiskAnalysis",
"privateAsset": "resource:org.acme.riskanalysis.PrivateAsset#ASSETID"
}
現在回到PrivateAsset> Get,您應該看到風險分析得分從0變為3。
接下來,讓我們實現MakeInsuranceOffer
/**
* Make an insurance offer
* @param {org.acme.riskanalysis.MakeInsuranceOffer} insurance
* @transaction
*/
async function makeInsuranceOffer(insurance) {
let assetRegistry = await getAssetRegistry('org.acme.riskanalysis.InsuranceOffer');
num_id = (Math.floor(Math.random() * ( 999999 - 100000) + 100000)).toString(10)
var factory = getFactory()
var insuranceId = insurance.policyholder.id + '' + num_id
var insuranceOfferAsset = factory.newResource('org.acme.riskanalysis', 'InsuranceOffer', insuranceId)
insuranceOfferAsset.policyholder = insurance.policyholder
insuranceOfferAsset.insuranceCompany = insurance.insuranceCompany
insuranceOfferAsset.privateAsset = insurance.privateAsset
insuranceOfferAsset.durationInMonths = insurance.privateAsset.durationInMonths
insuranceOfferAsset.monthlyCost = insurance.monthlyCost
await assetRegistry.add(insuranceOfferAsset)
}
現在讓我們新增AcceptInsuranceOffer的功能
/**
* Accepting an insurance offer
* @param {org.acme.riskanalysis.AcceptInsuranceOffer} offer
* @transaction
*/
async function acceptInsuranceOffer(offer) {
let insuranceOfferAssetRegistry = await getAssetRegistry('org.acme.riskanalysis.InsuranceOffer');
let policyholderParticipantRegistry = await getParticipantRegistry('org.acme.riskanalysis.Policyholder');
let privateAssetParticipantRegistry = await getAssetRegistry('org.acme.riskanalysis.PrivateAsset');
let insuranceCompanyParticipantRegistry = await getParticipantRegistry('org.acme.riskanalysis.InsuranceCompany');
var costToDebit = offer.offer.monthlyCost;
let insuranceCompany = "resource:org.acme.riskanalysis.InsuranceCompany#" + offer.offer.insuranceCompany.id;
if (offer.offer.policyholder.balance < costToDebit) {
throw new Error('Not enough funds in balance')
}
offer.offer.policyholder.balance -= costToDebit
offer.offer.insuranceCompany.balance += costToDebit
offer.offer.insuranceCompany.insuranceContracts += 1
offer.offer.status = "accepted";
offer.offer.privateAsset.insuranceCompany = offer.offer.insuranceCompany;
await insuranceOfferAssetRegistry.update(offer.offer);
await policyholderParticipantRegistry.update(offer.offer.policyholder)
await insuranceCompanyParticipantRegistry.update(offer.offer.insuranceCompany)
await privateAssetParticipantRegistry.update(offer.offer.privateAsset)
}
讓我們實現CreateClaim
/**
* Create a claim
* @param {org.acme.riskanalysis.CreateClaim} claim
* @transaction
*/
async function makeClaim(claim) {
let assetResource = "resource:org.acme.riskanalysis.PrivateAsset#" + claim.privateAsset.id;
let assetInsuranceOffer = await query('selectInsuranceCompanyByInsuredAsset', { privateAsset: assetResource });
num_id = (Math.floor(Math.random() * ( 999999 - 100000) + 100000)).toString(10)
let assetRegistry = await getAssetRegistry('org.acme.riskanalysis.Claim');
var factory = getFactory()
var claimId = claim.policyholder.id + '' + num_id
var newClaim = factory.newResource('org.acme.riskanalysis', 'Claim', claimId)