根据搜集的资料安装测试并整理的文档,如有不足希望不吝赐教。
目录
1.在计算机上使用 Docker 运行 Playground
系统:Ubuntu 17.10
docker:Docker version 18.03.1-ce, build 9ee9f40
docker-composer:docker-compose version 1.21.2, build a133471
(其余软件等版本在文中相应位置)
需要web浏览器
【Ubuntu系统】
查看Ubuntu系统版本:cat /etc/issue 或者 sudo lsb_release -a
【nvm】
使用nvm进行node多版本管理
查看已经安装的版本:nvm ls
查看可以安装的版本:nvm ls-remote
安装指定版本:nvm install <version> (例如:nvm install 8.11.1)
删除指定版本:nvm uninstall <version> (例如:nvm uninstall 10.0.0)
使用选定版本:nvm use <version> (例如:nvm use 8.11.1)
(本机安装所有版本的node.js安装位置应该在 /home/USERNAME/.nvm/versions/node/)
【npm】
npm全局安装包同时安装相应的依赖:npm install -g –save <pagename>
例如:npm install -g –save composer
安装时可以指定安装特定版本:npm install -g –save composer@0.19.1
npm查看全局安装过的包:npm list -g --depth 0
设置npm的registry:npm config set registry https://registry.npm.taobao.org
重启npm:npm restart
需要注意的是Hyperledger Composer在部署测试的时候对相应工具的版本有要求,以下指定相关版本测试成功,其余版本需要自行测试。
以下内容中主要介绍部署测试步骤,大部分概念需要自行搜索。
参考链接:
Hyperledger Composer相关概念介绍等请自行搜索或参考一中的链接。
通过使用纯浏览器模式,可以使用一个位于浏览器本地存储中的模拟区块链账本来建模并测试业务网络。第一部分将使用此方法。
从一个终端窗口执行此命令:
docker run --name composer-playground --publish 8080:8080 hyperledger/composer-playground
这会以交互方式启动 Docker(此处使用的方式)。如果您想要分开运行 Playground,只需添加 --detach:
docker run --name composer-playground --publish 8080:8080 --detach hyperledger/composer-playground
执行成功后(可能会有警告信息),打开浏览器并访问 http://localhost:8080,会看到一个类似下图的界面:
此时,可以根据一中第一个链接Hyperledger Composer 基础中的‘视频:运行 Playground,浏览 UI’来尝试创建一个空的业务模型并了解Playground 用户界面。
运行 Playground 后(暂时不需要结束),交互模式下可以用 ctrl+c 结束该容器。如果在分离模式下运行,可执行此命令:
docker stop composer-playground
如果结束容器,则需要清理 Docker 容器,否则在您尝试再次运行该容器时,Docker 会报错,命令如下:
docker rm -f composer-playground
在前一步根据视频进行了操作,需要执行删除 localhost 浏览器存储。视频最后有步骤。删除完成后刷新浏览器,看到一个类似1中的欢迎屏幕。
在纯浏览器模式中,Hyperledger Composer 仅允许一次使用一个模型。如果加载了另一个模型,可能需要在加载该模型前删除浏览器的本地存储。
Playground 应该能将当前模型替换为新模型。但是,如果您遇到错误,可以删除浏览器的本地存储来“从头”开始。该过程会因为浏览器不同而各不相同。
在 Playground 中创建新模型
单击 Let's Blockchain 按钮开始(参见1中图)。接下来,利用 perishable-network 模板创建一个新业务网络。将它命名为 perishable-iot-network 并单击 Deploy。
在 Admin ID 卡上,单击 Connect now 链接。您会看到类似下图的界面。
- README.md - 这个 Markdown 文件提供了 Perishable Goods 网络的简要概述
- models/perishable.cto - 包含业务模型
- lib/logic.js - 包含业务逻辑(智能合约)代码,该代码包括交易实现
当您选择 FILES 下的一个文件时,该文件会在右侧的编辑器窗口中打开。继续打开模型文件 (perishable.cto),其中包含模型。
鼓励您熟悉一下该模型,以及各种资源在编辑器中的外观。对 lib/logic.js 执行相同操作并熟悉 JavaScript 代码。
实例化模型
单击屏幕顶部的 Test 选项卡,您会看到类似下图的界面:
第一次创建业务网络时,Asset 和 Participant 注册表都是空的。您需要创建 Asset 和 Participant 实例,这些实例将放在注册表中。
要执行SetupDemo交易,请单击Submit Transaction按钮,会出现类似下图:
确保 SetupDemo 显示在 Transaction Type 下拉列表中,然后单击 Submit 按钮。成功执行交易后,您会看到一条告知您结果的简短通知消息。
在左侧 ASSETS 窗格中选择 Grower,它的所有实例都将出现在右侧。
测试模型
让我们测试一下以下场景:
Ⅰ.IoT 温度传感器提供了以下读数(单位为摄氏度):
5
7
1
4
Ⅱ.货物已收到。
在 Playground 中,区块链是在浏览器的本地存储中维护的,但无论区块链位于何处,执行的交易代码都是相同的
要在 Playground 中模拟此过程:
要在 Playground 中模拟货物接收,可在 Playground 中运行 ShipmentReceived 交易,确保提供了货物的 ID,并单击 Submit。
如果打开浏览器控制台,则会看到相应的输出信息。
参考链接中‘视频:测试模型,查看交易’部分视频演示可自行观看。
安装node.js
安装 Node.js 的最简单方法是使用 nvm,也就是 Node Version Manager。顾名思义,nvm 用于管理安装在您的计算机上的 Node 版本。nvm安装自行搜索。
安装完成后即可使用nvm安装node.js。
在命令行输入:
nvm install 8.11.1
来安装 Node.js 的8.11.1版本,版本可自行指定,此处使用8.11.1。
在等待安装完成后使用node -v验证node.js
安装node.js时会同时安装npm(Node Package Manager),npm版本也可以使用npm -v查看版本,此处使用的是5.8.0版本。
安装 Composer 命令行接口 (CLI)
您会使用该命令行接口 (CLI) 创建、部署和更新业务网络,以及执行与您的区块链网络相关的其他功能。
要安装Composer CLI,可到命令行输入此命令:
npm install -g --save composer-cli@0.19.1
通常在通过 npm 安装 Node.js 包时,仅能在已安装它的目录树内使用它。 指定 -g 选项会告诉 npm 对该包进行全局安装,这使得它可用于计算机上的所有 Node.js 项目。--save选项会同时安装相关依赖包。@0.19.1指定安装0.19.1版本,不指定则安装最新版。
验证 composer-cli 已正确安装。从命令行输入:composer -v命令,版本号将作为输出出现。
安装 Composer REST Server
npm install -g --save composer-rest-server@0.19.1
安装完成后使用
npm view composer-rest-server version
命令查看版本验证是否成功。
需要注意的是,composer-cli和composer-rest-sercer默认依赖的grpc版本可能为1.12.*,但是在第三部分,及本文的四中,如果grpc为1.12.*会出现如下错误图所示错误,但是在1.10.1中正常:
Error: Connection is not in the READY state
因此需要手动修改grpc版本为1.10.1,具体操作如下:
首先查看本地npm全局安装的包:
npm list -g –depth 0
删除多余以及版本不正确的包,命令如下,其余类似:
npm uninstall -g grcp
删除完成之后如下:
然后安装指定版本grpc包:
npm install -g --save grpc@1.10.1
安装完成后找到npm安装的包的位置,本机为~/.nvm/versions/node/v8.11.1/lib/node_modules,在该目录下为所有npm安装的包,如下:
打开composer-cli文件夹,查看composer-cli/node_modules/grpc目录下package.json文件,如果前两行版本为grpc@1.10.1则可跳过后面的步骤,否则返回到composer-cli目录下(切记不是composer-cli/node_modules/grpc目录),编辑其中的package.json文件,在其中dependencies标签下添加"grpc": "1.10.1",结果类似下图(json格式,请注意行末逗号):
添加后保存并退出,然后在该目录执行:npm install命令,
再次查看composer-cli/node_modules/grpc目录下package.json文件,版本已经变为1.10.1。
对composer-rest-sercer包执行相同的操作,使composer-rest-sercer/node_modules/grpc目录下package.json文件中前两行版本也为grpc@1.10.1。
修改完成后继续执行后面的操作或者在四之前进行修改。
安装 VSCode(非必须)
VSCode 是一个来自 Microsoft 的开源编辑器。执行 Hyperledger Composer 开发不需要安装 VSCode,但是Hyperledger Composer 有一个用于 VSCode 的扩展,您可以轻松地安装和启用它。它能够顺利集成 Git,还为 Composer 业务网络模型文件提供了语法突出显示功能。如果安装完成后可在插件管理中安装Hyperledger Composer扩展。
在计算机上选择将使用Hyperledger Composer和网络模型的位置。例如,本文使用 ~/HyperledgerComposer 作为Composer根目录,并在使用的 Bash shell 中设置一个环境变量:
export COMPOSER_ROOT=~/HyperledgerComposer
如果是使用命令行设置,则每次重新链接都需要重新设置,因此也可以直接在配置文件中设置。
导航到您的 $COMPOSER_ROOT 目录(cd $COMPOSER_ROOT),即刚刚设置的composer根目录,然后输入此命令:
git clone https://github.com/makotogo/developerWorks.git
下载完成后,使用 Node.js 包管理器 (npm) 运行一次构建,然后执行代码中提供的单元测试。执行以下两条命令:
cd $COMPOSER_ROOT/developerWorks/perishable-network
npm install && npm test
以上两行命令首先导航到 perishable-network 代码所在的目录。然后运行 npm install,这会设置本地 Node.js 环境(即 perishable-network 的本地环境)。然后运行 npm test,在最后部分如果输出类似于以下内容,这表明测试成功完成:
Payout: 1500
Grower: farmer@email.com new balance: 4000
Importer: supermarket@email.com new balance: -4000
✓ should apply penalty for min temperature violation (81ms)
Adding temperature 11 to shipment SHIP_001
Received at: Wed Nov 01 2017 10:58:12 GMT-0500 (CDT)
Contract arrivalDateTime: Thu Nov 02 2017 10:58:12 GMT-0500 (CDT)
Lowest temp reading: 1
Highest temp reading: 11
Min temp penalty: 0.2
Max temp penalty: 0.30000000000000004
Payout: 999.9999999999998
Grower: farmer@email.com new balance: 5000
Importer: supermarket@email.com new balance: -5000
✓ should apply penalty for max temperature violation (74ms)
3 passing (1s)
Perishable Goods 网络将对一个业务网络进行建模,其中包括:一个种植者、一个航运商和一个进口商。
修改网络定义
以下内容可以直接复制粘贴,修改后的解决方案应类似于 developerWorks/iot-perishable-network 目录中的解决方案。可以使用此模型作为参考。
要添加 GPS 传感器,需要对模型做一些更改。启动 VSCode,打开 Perishable Goods 网络的根目录$COMPOSER_ROOT/developerWorks/perishable-network。打开位于 models 目录中的名为 perishable.cto 的模型文件。
将一个表示罗盘上的主要位置的新 enum 添加到 enum ShipmentStatus 下方 :
/**
* Directions of the compass
*/
enum CompassDirection {
o N
o S
o E
o W
}
方向中的 N 表示北方、S 表示南方,等等。限制输入来表示一组 GPS 坐标的数据很重要,这个 enum 用于限制可输入模型中的值,以确保它们有效。
每次获得一个 GPS 读数,都会将它作为一个事务记录到区块链中,这意味着您需要向模型中添加一个针对它的事务。在 TemperatureReading 事务下方添加一个新的 GpsReading 事务:
/**
* A GPS reading for a shipment.E.g. received from a device
* within a shipping container
*/
transaction GpsReading extends ShipmentTransaction {
o String readingTime
o String readingDate
o String latitude
o CompassDirection latitudeDir
o String longitude
o CompassDirection longitudeDir
}
在获取 GPS 读数时需要包含一些参数,以及经纬度。此信息是作为参数提供给事务的。
接下来,要让事务能够将 GPS 读数存储在区块链中,该信息需要包含在一个区块链资产中。 因为从船运集装箱获取的 GPS 读数在概念上是一批货物的一部分,所以将该读数添加到 Shipment 资产中是合情合理的(就像 TemperatureReading 一样)。将下面突出显示的行(第 7 行)添加到 Shipment 资产中:
asset Shipment identified by shipmentId {
o String shipmentId
o ProductType type
o ShipmentStatus status
o Long unitCount
o TemperatureReading[] temperatureReadings optional
o GpsReading[] gpsReadings optional
--> Contract contract
}
最后,向模型添加两个事件:一个表示违反温度阈值,另一个表示集装箱船到达目标港口:
/**
* An event - when the temperature goes outside the agreed-upon boundaries
*/
event TemperatureThresholdEvent {
o String message
o Double temperature
--> Shipment shipment
}
/**
* An event - when the ship arrives at the port
*/
event ShipmentInPortEvent {
o String message
--> Shipment shipment
}
添加链代码
现在已对 GPS 传感器和用于将 GPS 读数添加到模型的事务进行建模。现在需要编写 JavaScript 链代码来处理区块链的更新。打开 lib/logic.js。您需要对此文件执行一些更改。
首先,向 temperatureReading 函数添加代码来处理 TemperatureReading 事务。将该方法的全部内容替换为下面这个方法,为方便参考,突出显示了添加的行:
function temperatureReading(temperatureReading) {
var shipment = temperatureReading.shipment;
var NS = "org.acme.shipping.perishable";
var contract = shipment.contract;
var factory = getFactory();
console.log('Adding temperature ' + temperatureReading.centigrade + ' to shipment ' + shipment.$identifier);
if (shipment.temperatureReadings) {
shipment.temperatureReadings.push(temperatureReading);
} else {
shipment.temperatureReadings = [temperatureReading];
}
if (temperatureReading.centigrade < contract.minTemperature ||
temperatureReading.centigrade > contract.maxTemperature) {
var temperatureEvent = factory.newEvent(NS, 'TemperatureThresholdEvent');
temperatureEvent.shipment = shipment;
temperatureEvent.temperature = temperatureReading.centigrade;
temperatureEvent.message = 'Temperature threshold violated! Emitting TemperatureEvent for shipment: ' + shipment.$identifier;
emit(temperatureEvent);
}
return getAssetRegistry(NS + '.Shipment')
.then(function (shipmentRegistry) {
// add the temp reading to the shipment
return shipmentRegistry.update(shipment);
});
}
此代码参照合同规定检查了当前温度读数,如果超过了最低或最高温度限制,则会发出一个 TemperatureThresholdEvent 事件。
接下来,添加一个新函数来处理 GpsReading 事务。
备注:同时添加注释块很重要。它包含您将需要的两个重要注释(@param 和 @transaction)。
/**
* A GPS reading has been received for a shipment
* @param {org.acme.shipping.perishable.GpsReading} gpsReading - the GpsReading transaction
* @transaction
*/
function gpsReading(gpsReading) {
var factory = getFactory();
var NS = "org.acme.shipping.perishable";
var shipment = gpsReading.shipment;
var PORT_OF_NEW_YORK = '/LAT:40.6840N/LONG:74.0062W';
var latLong = '/LAT:'+ gpsReading.latitude + gpsReading.latitudeDir + '/LONG:'+
gpsReading.longitude + gpsReading.longitudeDir;
if (shipment.gpsReadings) {
shipment.gpsReadings.push(gpsReading);
} else {
shipment.gpsReadings = [gpsReading];
}
if (latLong == PORT_OF_NEW_YORK) {
var shipmentInPortEvent = factory.newEvent(NS, 'ShipmentInPortEvent');
shipmentInPortEvent.shipment = shipment;
var message = 'Shipment has reached the destination port of ' + PORT_OF_NEW_YORK;
shipmentInPortEvent.message = message;
emit(shipmentInPortEvent);
}
return getAssetRegistry(NS + '.Shipment')
.then(function (shipmentRegistry) {
// add the temp reading to the shipment
return shipmentRegistry.update(shipment);
});
}
该事务的链代码将此 GPS 读数存储在 Shipment 资产中的 GpsReading 数组中。然后,它会检查此 GPS 读数是否与目标港口对应,如果是,则发出 ShipmentInPort 事件。最后,使用 Shipment 的当前状态更新区块链。
添加 Cucumber 功能测试
总结一下,在之前的构建中向模型添加了一个事务,以及两个新事件。现在需要对更改进行单元测试,确保它们工作正常。Hyperledger Composer 团队推荐使用 Cucumber 对 Composer 业务模型进行单元测试。
在 features 文件夹中创建一个名为 iot-perishable.feature 的新文件,并在 VSCode 中打开它。文中将简单解释一下您需要添加的每一节。在“使用 Cucumber 执行单元测试”小节中,我将更全面地解释 Cucumber。但是首先,让我们执行一些相关工作。
首先,告诉 Cucumber 您想测试的特性,以及需要在每个单元测试之前执行的任何后台(设置)。将以下代码添加到您的空 iot-perishable.feature 文件中。
Feature: IoT Perishable Network
Background:
Given I have deployed the business network definition ..
And I have added the following participants
"""
[
{"$class":"org.acme.shipping.perishable.Grower", "email":"grower@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"USA"}, "accountBalance":0},
{"$class":"org.acme.shipping.perishable.Importer", "email":"supermarket@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"UK"}, "accountBalance":0},
{"$class":"org.acme.shipping.perishable.Shipper", "email":"shipper@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"Panama"}, "accountBalance":0}
]
"""
And I have added the following asset of type org.acme.shipping.perishable.Contract
| contractId | grower | shipper | importer | arrivalDateTime | unitPrice | minTemperature | maxTemperature | minPenaltyFactor | maxPenaltyFactor |
| CON_001 | grower@email.com | supermarket@email.com | supermarket@email.com | 10/26/2018 00:00 | 0.5 | 2 | 10 | 0.2 | 0.1 |
And I have added the following asset of type org.acme.shipping.perishable.Shipment
| shipmentId | type | status | unitCount | contract |
| SHIP_001 | BANANAS | IN_TRANSIT | 5000 | CON_001 |
When I submit the following transactions of type org.acme.shipping.perishable.TemperatureReading
| shipment | centigrade |
| SHIP_001 | 4 |
| SHIP_001 | 5 |
| SHIP_001 | 10 |
现在需要添加一些称为场景 (Scenario) 的单元测试。将场景添加到 iot-perishable.feature 文件中的 Background 块下方。
Scenario: When the temperature range is within the agreed-upon boundaries
When I submit the following transaction of type org.acme.shipping.perishable.ShipmentReceived
| shipment |
| SHIP_001 |
Then I should have the following participants
"""
[
{"$class":"org.acme.shipping.perishable.Grower", "email":"grower@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"USA"}, "accountBalance":2500},
{"$class":"org.acme.shipping.perishable.Importer", "email":"supermarket@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"UK"}, "accountBalance":-2500},
{"$class":"org.acme.shipping.perishable.Shipper", "email":"shipper@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"Panama"}, "accountBalance":0}
]
"""
此场景确保在货物集装箱中的温度在协商的限制内时,为种植者支付了足额的费用。
现在添加一个场景:超出了最低温度阈值(2 摄氏度) 2 度。
Scenario: When the low/min temperature threshold is breached by 2 degrees C
Given I submit the following transaction of type org.acme.shipping.perishable.TemperatureReading
| shipment | centigrade |
| SHIP_001 | 0 |
When I submit the following transaction of type org.acme.shipping.perishable.ShipmentReceived
| shipment |
| SHIP_001 |
Then I should have the following participants
"""
[
{"$class":"org.acme.shipping.perishable.Grower", "email":"grower@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"USA"}, "accountBalance":500},
{"$class":"org.acme.shipping.perishable.Importer", "email":"supermarket@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"UK"}, "accountBalance":-500},
{"$class":"org.acme.shipping.perishable.Shipper", "email":"shipper@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"Panama"}, "accountBalance":0}
]
"""
在此场景中,最低温度下降到 0 摄氏度,针对低于阈值的每摄氏度,向种植者收取罚金。
现在添加一个场景:超出最高温度阈值 2 摄氏度。
Scenario: When the hi/max temperature threshold is breached by 2 degrees C
Given I submit the following transaction of type org.acme.shipping.perishable.TemperatureReading
| shipment | centigrade |
| SHIP_001 | 12 |
When I submit the following transaction of type org.acme.shipping.perishable.ShipmentReceived
| shipment |
| SHIP_001 |
Then I should have the following participants
"""
[
{"$class":"org.acme.shipping.perishable.Grower", "email":"grower@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"USA"}, "accountBalance":1500},
{"$class":"org.acme.shipping.perishable.Importer", "email":"supermarket@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"UK"}, "accountBalance":-1500},
{"$class":"org.acme.shipping.perishable.Shipper", "email":"shipper@email.com", "address":{"$class":"org.acme.shipping.perishable.Address", "country":"Panama"}, "accountBalance":0}
]
"""
在此场景中,最高温度超过了 10 摄氏度,针对高于阈值的每摄氏度,向种植者收取罚金。
最后,向模型中添加 3 个场景(两个 TemperatureThresholdEvent 和一个 ShipmentInPortEvent),如下所示。
Scenario: Test TemperatureThresholdEvent is emitted when the min temperature threshold is violated
When I submit the following transactions of type org.acme.shipping.perishable.TemperatureReading
| shipment | centigrade |
| SHIP_001 | 0 |
Then I should have received the following event of type org.acme.shipping.perishable.TemperatureThresholdEvent
| message | temperature | shipment |
| Temperature threshold violated! Emitting TemperatureEvent for shipment: SHIP_001 | 0 | SHIP_001 |
Scenario: Test TemperatureThresholdEvent is emitted when the max temperature threshold is violated
When I submit the following transactions of type org.acme.shipping.perishable.TemperatureReading
| shipment | centigrade |
| SHIP_001 | 11 |
Then I should have received the following event of type org.acme.shipping.perishable.TemperatureThresholdEvent
| message | temperature | shipment |
| Temperature threshold violated! Emitting TemperatureEvent for shipment: SHIP_001 | 11 | SHIP_001 |
Scenario: Test ShipmentInPortEvent is emitted when GpsReading indicates arrival at destination port
When I submit the following transaction of type org.acme.shipping.perishable.GpsReading
| shipment | readingTime | readingDate | latitude | latitudeDir | longitude | longitudeDir |
| SHIP_001 | 120000 | 20171025 | 40.6840 | N | 74.0062 | W |
Then I should have received the following event of type org.acme.shipping.perishable.ShipmentInPortEvent
| message | shipment |
| Shipment has reached the destination port of /LAT:40.6840N/LONG:74.0062W | SHIP_001 |
最后,需要修改 package.json,使它看起来类似下面的清单。突出显示了需要修改(第 18 行)和添加(第 41 和 42 行)的行。
{
"engines": {
"composer": "^0.15.0"
},
"name": "perishable-network",
"version": "0.1.11",
"description": "Shipping Perishable Goods Business Network",
"networkImage": "https://github.com/makotogo/developerWorks/perishable-network/networkimage.svg",
"networkImageanimated": "https://github.com/makotogo/developerWorks/perishable-network/networkimageanimated.svg",
"scripts": {
"prepublish": "mkdirp ./dist && composer archive create --sourceType dir --sourceName .-a ./dist/perishable-network.bna",
"pretest": "npm run lint",
"lint": "eslint .",
"postlint": "npm run licchk",
"licchk": "license-check",
"postlicchk": "npm run doc",
"doc": "jsdoc --pedantic --recurse -c jsdoc.json",
"test": "mocha -t 0 --recursive && cucumber-js",
"deploy": "./scripts/deploy.sh"
},
"repository": {
"type": "git",
"url": "https://github.com/makotogo/developerWorks.git"
},
"keywords": [
"shipping",
"goods",
"perishable",
"composer",
"composer-network",
"iot"
],
"author": "Hyperledger Composer",
"license": "Apache-2.0",
"devDependencies": {
"browserfs": "^1.2.0",
"chai": "^3.5.0",
"composer-admin": "^0.14.0-0",
"composer-cli": "^0.14.0-0",
"composer-client": "^0.14.0-0",
"composer-connector-embedded": "^0.14.0-0",
"composer-cucumber-steps": "^0.14.0-0",
"cucumber": "^2.2.0",
"eslint": "^3.6.1",
"istanbul": "^0.4.5",
"jsdoc": "^3.4.1",
"license-check": "^1.1.5",
"mkdirp": "^0.5.1",
"mocha": "^3.2.0",
"moment": "^2.17.1"
},
"license-check-config": {
"src": [
"**/*.js",
"!./coverage/**/*",
"!./node_modules/**/*",
"!./out/**/*",
"!./scripts/**/*"
],
"path": "header.txt",
"blocking": true,
"logInfo": false,
"logError": true
}
}
请注意,向 package.json 添加了两个新 Node 模块(上面的第 41 和 42 行)。要安装它们,需要在命令行(当前目录)运行npm install命令。
运行单元测试
现在,从命令行执行 npm test 来运行单元测试。将会产生许多输出,但这一次,除了 Mocha 测试之外,您还会看到每个 Cucumber 特性场景的一个输出块。Cucumber 功能测试的开头类似于下面这段代码。输出的最后几行类似于下面这段代码,这表明单元测试通过了。
.
✔ When I submit the following transactions of type org.acme.shipping.perishable.TemperatureReading
| shipment | centigrade |
| SHIP_001 | 4 |
| SHIP_001 | 5 |
| SHIP_001 | 10 |
✔ When I submit the following transaction of type org.acme.shipping.perishable.GpsReading
| shipment | readingTime | readingDate | latitude | latitudeDir | longitude | longitudeDir |
| SHIP_001 | 120000 | 20171025 | 40.6840 | N | 74.0062 | W |
✔ Then I should have received the following event of type org.acme.shipping.perishable.ShipmentInPortEvent
| message | shipment |
| Shipment has reached the destination port of /LAT:40.6840N/LONG:74.0062W | SHIP_001 |
6 scenarios (6 passed)
44 steps (44 passed)
0m02.788s
此部分以及更深入地探索如何使用 Cucumber 执行单元测试参考链接中相应部分
Hyperledger Fabric是一个为业务用途构建区块链应用程序的框架,而您已经知道,Hyperledger Composer是一个配套工具,它使得构建在Hyperledger Fabric上运行的区块链应用程序变得更容易。
现在,将在自己的计算机上安装并运行Hyperledger Fabric,使用Composer命令行接口 (CLI) 与之交互。
获取 Hyperledger Fabric
首先,在您的计算机上创建一个您想在其中执行本地 Hyperledger Composer 开发的目录。本文中继续使用的是第三部分第二个小标题创建的目录,即~/HyperledgerComposer,
现在,使用 curl 命令将 fabric-dev-servers.zip 分发文件下载到您的 Composer 根目录,并解压它。命令序列如下所示(假设 ~/HyperledgerComposer 是本示例的根目录):
mkdir ~/HyperledgerComposer
export COMPOSER_ROOT=~/HyperledgerComposer
以上两步如果之前已经完成可忽略
cd $COMPOSER_ROOT;
mkdir fabric-dev-servers && cd fabric-dev-servers;
curl -O https://raw.githubusercontent.com/hyperledger/composer-tools/master/packages/fabric-dev-servers/fabric-dev-servers.zip;
unzip fabric-dev-servers.zip;
启动 Hyperledger Fabric
备注:在继续后面的操作之前,请确保 Docker 正在运行。
cd $COMPOSER_ROOT/fabric-dev-servers;
./downloadFabric.sh;
./startFabric.sh;
./createPeerAdminCard.sh;
运行downloadFabric.sh视网络情况或许会花费较长时间,该命令会获取所有必要的 Docker 映像。
第二个命令会启动本地 Hyperledger Fabric。
最后一个命令将为 Fabric 管理员(即 PeerAdmin)发放一个 ID 卡。
createPeerAdminCard.sh 脚本的输出类似下图:
记下卡名称,因为您需要使用它来执行本教程中的所有 CLI 命令。
只需运行 createPeerAdminCard.sh 脚本一次。从现在开始,无论任何时候启动 Hyperledger Fabric,只需像下面这样运行startFabric.sh 脚本即可:
cd $COMPOSER_ROOT/fabric-dev-servers
./startFabric.sh
该脚本运行完成后,Hyperledger Fabric 就会在您的计算机上运行。 要关闭本地 Hyperledger Fabric,请运行 stopFabric.sh 脚本。暂时不需要关闭,请让Hyperledger Fabric 保持运行。
部署到 Hyperledger Fabric
在第二部分,克隆了来自 GitHub 的 developerWorks 项目,并修改了 Perishable Goods 网络。developerWorks/iot-perishable-network目录中提供了该网络的一个已完成的版本。本教程的剩余部分将会使用该网络。
要将iot-perishable-network部署到本地Fabric,需要使用Composer CLI并执行这一系列命令:
进入目录:
cd $COMPOSER_ROOT/developerWorks/iot-perishable-network
运行构建(这一步完成后会在目录中生成一个dist目录,包含iot-perishable-network.bna文件):
npm install
测试:
npm test
部署示例业务网络iot-perishable-network,"composer network install" 命令会部署指定的 .bna 文件到 Fabric 网络。.bna 文件包括了这个业务网络的 Assets 模型、交易事务逻辑、访问控制规则等定义,但它并不能直接在 Fabric 上运行。.bna 文件是由 Composer 生成的,它是用 Composer 提供支持的一系列建模语言、规范定义的业务网络定义,我们必须将它先安装在 Fabric Peer 节点上。然后才可以在这个节点上启动运行这个业务网络。
参数 -c (--card) 应指定为在上一步骤中生成 PeerAdmin Card 文件。
参数 -a (--archiveFile) 应指定为将要部署的业务网络文件包。
composer network install --card PeerAdmin@hlfv1 --archiveFile ./dist/iot-perishable-network.bna
启动业务网络,"composer network start" 用指定的 Card 启动这个网络;同时会生成一个当前业务网络的管理员 Card 文件,即此示例中的 networkadmin.card。
composer network start --networkName iot-perishable-network --networkVersion 0.1.12 --networkAdmin admin --networkAdminEnrollSecret adminpw --card PeerAdmin@hlfv1 --file networkadmin.card
导入 tutorial-network 管理员 Card
composer card import -f networkadmin.card
查看导入的 Card 文件
composer card list
确认 tutorial-network 安装成功
composer network ping --card admin@iot-perishable-network
如果此时提示错误信息:Error: Connection is not in the READY state请返回三中安装composer-cli之后查看相应解决办法。
启动 REST Server,生成 REST 接口。在生成 REST 接口之前,确保 Hyperledger Fabric 正在运行且 iot-perishable-network 已部署(否则会没有连接目标)。
composer-rest-server
REST 服务器需要知道如何向 Hyperledger Fabric 执行身份验证,以便与业务网络进行通信。您需要提供一个 ID 卡来实现此目的(第 2 行),比如本教程前面的 admin@iot-perishable-network ID 卡。
命名空间有助于避免名称冲突。在 iot-perishable-network 中,这不是什么大问题,因为只有少量资产、参与者和事务。我认为始终使用命名空间是个不错的主意(第 3 行)。测试包含大量参与者、资产和事务的真实网络非常困难;使用命名空间有助于避免与名称冲突相关的麻烦。
使用 REST 接口执行测试时,暂时无需担心身份验证(第 4 行)、事件和 WebSocket(第 5 行)或 TLS 安全性(第 6 行)。但是,如果您决定部署 REST 服务器作为生产区块链解决方案的一部分,一定要查阅这里或本教程末尾处的相关主题中的链接。
下一次您想使用相同选项来启动 REST 服务器时,只需使用显示的命令(第 9 行)并跳过身份验证的交互步骤!
composer-rest-server -c admin@iot-perishable-network -n never
现在可以在本机上使用图中标注的链接http://localhost:3000/explorer访问区块链网络。
到这里,我们就成功地通过 Hyperledger Composer 安装了 Hyperledger Fabric,并部署、启动了第一个区块链业务网络iot-perishable-network。
要使用 REST 接口,请打开浏览器并访问上图中第 18 行上给出的地址。您将看到类似下面这样的信息:
其余操作请查看参考链接中相关部分资料。一下不再赘述。
END