如何用Python&Fabric打造区块链“淘宝”商城



  • 原创: kou 区块链大本营
    链接:https://mp.weixin.qq.com/s/u02QzDaN6zEmo1myWMwf7g

    作者 | Haardik
    编译 | kou、Guoxi

    你能学到什么?

    通过学习本教程,你将学会创建一个具有交易数字资产(球星卡)功能的区块链网络,在这其中,拥有棒球、足球和板球球星卡的不同交易方之间能够进行互相交易。

    为实现上述功能,你需要做:

    建立一个 REST API 服务器,以帮助执行客户端调用;
    编写一个 Angular 4 应用程序;
    调用 REST API,实现 Angular 4 与区块链网络的交互。

    最终效果图是这样的...

    0_1539647917213_92213086-5630-4453-a8e7-e1e5ecba4737-image.png
    通过前后端交互,球星卡成功交易

    本教程共6部分,根据自己需要,选择跳读吧,准备好了吗?开始!

    Hyperledger Fabric 及相关应用程序简介
    安装依赖包、工具和 Fabric 运行环境 Fabric runtime
    创建和部署区块链业务网络
    测试区块链业务网络
    生成 REST API 服务器
    生成调用 REST API 的 Angular 应用程序

    1、Hyperledger Fabric及相关应用程序简介

    0_1539648051578_f338c103-6319-4ad5-919d-1d78962427f8-image.png
    Hyperledger开发环境概述

    Hyperledger Fabric 是一个开源的区块链框架,可以用来创建私有区块链(许可区块链)业务网络,在网络中每个成员的身份和角色都被其他成员所知。

    我们要构建的区块链网络将以 Fabric 作为后端,客户端应用程序作为前端。目前软件开发工具包(SDK)支持使用 Node.js 和 Java 来构建客户端应用程序,未来很快就会支持 Python 和 Golang。

    Hyperledger Composer 是一组基于 JavaScript 的工具和脚本,可简化Hyperledger Fabric 网络的创建过程。通过这些工具,我们可以生成区块链的业务网络存档(business network archive,BNA)。

    Composer 包含以下3个组件:
    业务网络存档(BNA)
    Composer Playground(用户界面)
    Composer REST 服务器

    业务网络存档 - Composer 允许用户打包不同的文件并生成一个存档,存档可以在 Fabric 中部署为区块链业务网络。要生成这个存档,需要以下4个文件:

    网络模型 - 网络中所存资源的说明。这些资源包括资产,参与者和交易。我们稍后会详细讲述它们的细节。
    业务逻辑 - 交易功能的逻辑。
    访问控制 - 定义网络中不同参与者权限的各种规则,包括但不限于定义参与者可以控制的资产。
    查询文件(可选的) - 可以在网络上运行的一组查询操作,我们可以简单地将其理解为 SQL 的查询功能。

    Composer Playground 是一个基于 Web 的用户界面,主要用于区块链业务网络的建模和测试。Playground 使用浏览器的本地存储来模拟区块链网络,因此它非常适合简单的概念证明建模。

    同时,如果用户在本地运行了 Fabric 运行环境并在其中部署了区块链网络,此时 Playground 可以用来与区块链网络进行交互。在这种情况下,Playground 并没有模拟区块链网络,而是直接与本地 Fabric 运行环境通信。

    Composer REST 服务器是一个允许用户根据业务网络定义生成相应 REST API 服务器的工具。生成的 REST API 供客户端应用程序使用,帮助用户在区块链网络中整合非区块链的应用程序。

    2、安装依赖包,工具和Fabric运行环境

    1)安装依赖包

    在深度了解了将要建立的区块链网络后,现在你可以动手开发了。但在开始编程前,请确保你的系统上已安装了所需的依赖包。

    Hyperledger 官方文档中列出的依赖包有以下4个:

    Docker Engine 和 Docker Compose
    Node.js 和 NPM
    Git
    Python 2.7.x

    Hyperledger 贴心地为 Ubuntu 用户提供了一个 bash 脚本,用来简化安装依赖包的过程。因而 Ubuntu 用户只需要在终端中运行以下命令:

    1curl -O https://hyperledger.github.io/composer/latest/prereqs-ubuntu.sh
    2chmod u+x prereqs-ubuntu.sh
    3./prereqs-ubuntu.sh

    而 Mac 用户必须手动安装上述工具,一定确保不落下任何一个依赖包,防止出现 bug。

    2)安装工具来简化开发过程

    在终端运行以下命令,并确保在运行 npm 命令时没有使用管理员权限 sudo。

    1npm install -g composer-cli
    2npm install -g composer-rest-server
    3npm install -g composer-playground
    4npm install -g yo generator-hyperledger-composer

    composer-cli 是唯一必不可少的依赖包,其余的并不是核心组件,但在接下来的开发中它们非常有用。

    3)安装本地 Hyperledger Fabric 运行环境

    1mkdir ~/fabric-dev-servers
    2cd ~/fabric-dev-servers
    3curl -O https://raw.githubusercontent.com/hyperledger/composer-
    4tools/master/packages/fabric-dev-servers/fabric-dev-servers.tar.gz
    5tar -xvf fabric-dev-servers.tar.gz
    6export FABRIC_VERSION=hlfv12
    7./downloadFabric.sh
    8./startFabric.sh
    9./createPeerAdminCard.sh

    上面的代码执行了怎样的操作呢?首先,我们新建了一个目录 fabric-dev-servers,接下来我们进入到目录中,下载并解压安装了 Hyperledger Fabric 所需的工具。

    在 export 命令中我们指定了所需的 Fabric 版本,本教程使用的是1.2版本,因此参数为 hlfv12。然后,我们执行脚本下载 Fabric 运行环境并启动。

    最后一个脚本中生成一个 PeerAdmin 卡。类似于现实生活中的身份证,Fabric 网络中的参与者都有业务网络访问卡。

    Fabric 是区块链的底层,PeerAdmin 业务网络访问卡的持有者可以在此 Fabric 运行环境中部署、删除和管理区块链业务网络。

    如果一切顺利,你应该会看到这样的输出:

    0_1539648292234_1aa4e19b-1205-44ed-a8a5-2df340bdde4a-image.png
    此外,如果你输入显示目录下列表的命令 ls,输出应该如下:

    0_1539648357445_5b70d573-a389-4e64-81ad-f99d4ac436b9-image.png
    以上,我们只是下载并启动了本地 Fabric 区块链网络。如果你想要关停区块链网络,只需运行脚本 ./stopFabric.sh。在开发会话(development session)结束时,你应该运行脚本 ./teardownFabric.sh。

    注意:这个本地运行环境可能会经常开启、停止和测试完成后回收数据(tear down)以满足开发需要。如果想让这个运行环境持续运行,那么你需要在开发环境之外部署区块链网络。比如,可部署到 Kubernetes 容器或 IBM Blockchain 等托管平台中。

    3、创建和部署区块链业务网络

    还记得你刚才安装的依赖包 yo 和 generator-hyperledger-composer 吗?

    yo 提供了一个生成器生态系统,该生成器是一个使用 yo 命令运行的插件,用于为项目设置样板应用程序。

    generator-hyperledger-composer 是我们将使用的 yo 生成器,它包含了用于生成样板业务网络的规范。

    1)生成区块链业务网络

    在所选目录中打开终端并输入 yo hyperledger-composer:
    0_1539648425164_67d91bd2-c806-4319-997e-779c1fef77a7-image.png

    正常情况下系统会输出如下的交互式设置界面,在其中选择 Business Network 并将其命名为 cards-trading-network,如下所示:
    0_1539648452816_f5db2c71-ba91-443b-b6be-7bc9c802f676-image.png

    2)业务网络建模

    确定网络中存在的资源是建立业务网络的第一步,也是最重要的一步。在我们的模型中共有以下4种资源:

    资产
    参与者
    交易
    事件

    在球星卡交易网络 cards-trading-network 中,我们定义资产类型为球星卡 TradingCard,参与者类型为交易者 Trader,交易类型为交易卡片 TradeCard,事件类型为交易事件 TradeNotification。

    模型构建完毕后,你需要在代码中实现它,在代码编辑器中打开模型文件 org.example.biznet.cto,删除其中除去命名空间声明之外的所有代码(后续会重写它)。

    1/**
    2 * The asset participants will be trading.
    3 * Each card has certain properties such as name,
    4 * description, and type which can
    5 * be used for the frontend application
    6 /
    7asset TradingCard identified by cardId {
    8 o String cardId
    9 o String cardName
    10 o String cardDescription
    11 o GameType cardType default="Baseball" // If no value is provided, it takes the default value
    12 o Boolean forTrade
    13}
    14
    15/
    *
    16 * Enumerated types are used to specify a type
    17 * which can have 1 or N possible values, and nothing else.
    18 */
    19enum GameType {
    20 o Baseball
    21 o Football
    22 o Cricket
    23}

    上述代码制定了资产球星卡 TradingCard 的规范。

    区块链网络中所有资产和参与者都需要被指定用于区分的唯一标识符,在代码中我们使用的是 cardId。

    此外,我们还定义了一个枚举对象 GameType cardType,它基于枚举器。枚举对象用于在N个可能的类型中选取一个类型,但选项不能超出这N个类型。在我们的示例中,球星卡 TradingCard 的类型,定义为棒球 Baseball、足球 Football 或板球 Cricket 的任一种。

    接下来,还要指定参与者 Trader 的资源类型,在模型文件中添加以下代码:

    1/**
    2 * The participant model for a Trader
    3 */
    4participant Trader identified by traderId {
    5 o String traderId
    6 o String traderName
    7}

    上述代码相对简单且易于理解,在其中我们定义了一个参与者类型 Trader,由它们的唯一 traderId 进行标识。

    现在,你需要添加对球星卡 TradingCard 的引用,用以指出每张球星卡的持有者,从而确定了区块链中的资产归属。为此,请在 TradingCard 资产中添加一行代码:

    1--> Trader owner

    更新后的代码如下所示:

    1asset TradingCard identified by cardId {
    2 o String cardId
    3 o String cardName
    4 o String cardDescription
    5 o GameType cardType default="Baseball" // If no value is provided, it takes the default value
    6 o Boolean forTrade
    7 --> Trader owner
    8}

    你可能会好奇“-->”这个符号的作用是什么。

    --> 是一个关系指针,它和符号 o 是我们区分拥有数字资产以及资源类型之间关系的工具。由于交易者 Trader 一定是网络的参与者,所以当你想直接引用该交易者 Trader 时,可以用符号 -->。

    最后,在模型文件中添加以下代码,来指定创建交易和发起事件所需的参数。

    1/**
    2 * A transaction which allows Traders to buy other
    3 * Traders' cards if they're available for trade
    4 /
    5transaction TradeCard {
    6 --> TradingCard card
    7 --> Trader newOwner
    8}
    9
    10/
    *
    11 * A notification event to be emitted whenever
    12 * any card is traded
    13 */
    14event TradeNotification {
    15 --> TradingCard card
    16}

    3)添加交易逻辑

    要在交易球星卡函数 TradeCard 中添加交易逻辑,你需要新建一个表示逻辑的Javascript文件,具体而言就是在项目的文件夹中创建一个名为 lib 的新目录,并使用以下代码创建一个名为 logic.js 的新文件:

    1/**
    2 * Buy card transaction
    3 * @param {org.example.biznet.TradeCard} trade
    4 * @transaction
    5 */
    6async function buyCard(trade) {
    7 if (trade.card.forTrade) {
    8 // If card is available for trade
    9 trade.card.owner = trade.newOwner;
    10 return getAssetRegistry("org.example.biznet.TradingCard")
    11 .then(assetRegistry => {
    12 return assetRegistry.update(trade.card); // Update the network registry
    13 })
    14 .then(() => {
    15 let event = getFactory().newEvent(
    16 "org.example.biznet",
    17 "TradeNotification"
    18 ); // Get a reference to the event specified in the modeling language
    19 event.card = trade.card;
    20 emit(event); // Fire off the event
    21 });
    22 }
    23}

    注意:函数上面注释中的装饰器(decorator)非常重要,如果没有装饰器 @param {org.example.biznet.TradingCard}trade,函数就无法确定从模型文件中引用哪个交易 Transaction。

    此外,确保函数末尾的参数是你在函数调用中传递的参数。

    上述代码(forTrade == true)检查了指定的球星卡是否设置为待交易,若是,则会更新球星卡的所有者。然后,它会触发该卡的 TradeNotification 事件。

    4)定义权限和访问规则

    在 permissions.acl 中添加新规则,以便参与者访问自己的资源。

    这里的权限和访问规则都已简化,在实际生产中,权限和访问规则十分严格。

    1rule AllParticipantsHaveAccessToAllResources {
    2 description: "Allow all participants to have access to all resources and make transactions"
    3 participant: "ANY"
    4 operation: ALL
    5 resource: "org.example.biznet.*"
    6 action: ALLOW
    7}

    5)生成业务网络存档(BNA)

    到现在所有的代码编写任务都已完成,接下来你要为区块链业务网络创建一个存档文件,以便将其部署到本地 Fabric 运行环境上。为此,你需要在项目目录中打开终端并输入以下内容:

    1composer archive create --sourceType dir --sourceName

    这条命令告诉 Hyperledger Composer,你想在当前根文件夹目录中构建一个区块链业务网络存档。

    区块链业务网络存档的名称和版本号来自 package.json文件。如果要更改代码,一定要记住更改版本号,以部署能够升级现有业务网络的唯一存档。

    6)安装和部署区块链业务网络存档文件

    我们可以使用 PeerAdmin 用户将网络安装和部署到本地 Fabric 运行环境中,要安装业务网络,需输入以下代码:

    1composer network install --archiveFile cards-trading-
    2network@0.0.1.bna --card PeerAdmin@hlfv1
    bingo!

    要部署业务网络,请输入:

    1composer network start --networkName cards-trading-network --
    2networkVersion 0.0.1 --networkAdmin admin --
    3networkAdminEnrollSecret adminpw --card PeerAdmin@hlfv1 --file cards-trading-admin.card

    再一次,bingo!

    0_1539648568127_e918342e-8944-49a9-9709-0dad22854cdf-image.png
    代码中的网络名称networkName和网络版本networkVersion必须与 package.json 中所指定的名称和版本相同,否则网络将无法正常工作。

    --file 获取业务网络访问卡生成文件的名称,访问卡可由以下命令导入:

    1composer card import --file cards-trading-admin.card

    再、再一次bingo!
    0_1539648602812_38eeafb7-ac2f-4dbf-a269-7c525d105abb-image.png

    想要知道区块链网络是否已正常运行,输入以下命令:

    1composer network ping --card admin@cards-trading-network

    这里的 --card 命令用来提取网络中的管理员访问卡,以便我们通过 ping 命令检查是否能连接上区块链网络。

    如果一切顺利,你应该能看到类似的输出:

    0_1539648627071_bdb3f860-85fa-43e4-9052-c0ce478d3739-image.png
    又bingo了... 又bingo了...

    4、测试区块链业务网络

    现在区块链网络已经在 Fabric 上运行了,你可以启动 Composer Playground 与它进行交互。请在终端中输入 composer-playground ,并在浏览器中打开http://localhost:8080/,显示页面如下:

    0_1539648646871_c72ebb23-86c5-4978-ab45-75a84d97100f-image.png

    点击 admin @ cards-trading-network 之下的立即连接(Connect now),你会看到:

    0_1539648668967_1ccb5673-a672-449c-83eb-742735e6bf6a-image.png

    在“定义(Define)”页面中,你可以对代码进行更改、部署这些更改以更新区块链网络,还可以导出当前的业务网络存档。

    从顶部菜单点击进入“测试(Test)”页面,你会看到:

    0_1539648688310_b4c6f2e5-cf01-416e-9760-6b86becaec5f-image.png

    从参与者(Participants)中选择交易者(Trader),点击右上角的创建新参与者(Create New Participant),创建一个如下的新交易者(Trader):

    0_1539648710620_30d2e159-e995-43d1-83aa-38041b04af34-image.png

    重复这个过程,再多创建几个交易者(Trader)。

    本教程中,三个交易者分别为 Haardik、John 和 Tyrone。

    0_1539648735068_2e79f8ad-f294-430c-8c09-41fd9366e067-image.png

    现在你可以进入上帝模式随意地创建数字资产了。点击左侧菜单中的球星卡(TradingCard),然后点击“创建新资产(Create New Asset)”。

    请注意所有者(owner)字段的填写十分有趣,像以下这样:

    0_1539648756825_91c229ec-fb4f-4445-aa34-0ca8a1654173-image.png

    这指代了一种关系,同时这也是上文中符号 --> 的作用。我们指定了资源类型和它们的唯一标识符,所以这里就有了一个关系指针。

    填写以下信息来完成球星卡 TradingCard 的制作:

    0_1539648767908_55306333-13c7-424f-a328-77f36a8f6611-image.png

    请注意所有者(owner)字段指向交易者1号(Trader#1,也就是我刚才命名的Haardik)。重复上述过程多制作几张球星卡,将一些球星卡的是否交易属性(forTrade)设置为是(true)。

    0_1539648784955_293f7c15-d0d4-4c01-97b1-7f11e88214f7-image.png

    请注意球星卡2号(Card#2)中是否交易一项设置为是(forTrade:true)。

    接下来我们来交易这张球星卡。点击左侧的提交交易(Submit Transaction),将球星卡(Card)设置为交易球星卡2号(TradingCard#2),新所有者(newOwner)设置为交易者3号(Trader#3),如下所示:

    0_1539648802199_05749a24-2467-42d2-bbdc-449881318c3e-image.png

    点击提交(Submit),你会发现球星卡2号(Card#2)现在的所有者变成了交易者3号(Trader#3)。

    5、生成REST API服务器

    使用 Composer Playground 用户界面来进行交易看上去还挺不错的,但它并不是最佳的选项。为了给那些甚至都不了解区块链的用户无缝的使用体验,你还需要开发一个客户端软件。为此,你需要一种更好的方式与区块链业务网络进行交互。值得庆幸的是,Hyperledger 附带的 composer-rest-server 可以帮助你执行交互。

    在终端中输入 composer-rest-server,指定使用的区块链网络 admin @ cards-trading-network,选择不使用命名空间(never use namespaces),其余的使用默认选项即可。

    0_1539648828107_526fc54e-d507-4b4e-9814-2d57e6c84dfe-image.png

    打开 http://localhost:3000/explorer/,你将看到自动生成的 REST API 以文档的形式呈现出来。

    6、生成使用REST API的Angular应用程序

    还记得 yo hyperledger-composer 这个生成器吗?它不仅可以用来生成区块链业务网络,还可以创建一个使用 REST API 运行的 Angular 4 应用程序。

    要创建 Angular Web 应用程序,在终端中输入 yo hyperledger-composer,选择 Angular,选择使用卡 admin @ cards-trading-network ,连接到当前业务网络和 REST API。

    0_1539648860313_1c999ed8-4ca4-43ce-88ed-1d6873a7bf83-image.png

    这个过程将会运行 npm install,完成之后,访问 http://localhost:4200/,显示页面如下:

    0_1539648876967_f674b638-50ca-4508-9be7-2323359ef6f5-image.png

    你现在可以直接使用这个应用程序与区块链网络交互,此程序直接与区块链网络在端口3000上运行的 REST 服务器通信。

    恭喜!你使用 Hyperledger Fabric 和 Hyperledger Composer 成功创建了一个附带客户端程序的区块链业务网络。

    接下来,你可以给球星卡交易网络添加更多功能:
    给每张球星卡加入价格属性并为每个交易者加入余额属性;
    给交易者设置接受交易(forTrade)的最低价位;
    将交易网络与非区块链应用程序整合,将用户在链下购买的球星卡添加到其帐户中,以便后期在链上交易。

    已知漏洞分析:Angular Web 无法正确处理交易?

    这里存在一个 bug,就是“交易”页面上的紫色“调用(invoke)”按钮不执行任何操作。

    为解决这个问题,你需要对生成的 Angular 应用程序做一些修改。

    0_1539648911541_1ca1cc8b-dd74-4603-b54a-06238b280305-image.png

    1)按下按钮时打开一个模态(modal)

    你需要做的第一个修改就是让按钮打开模态窗口。代码中已包含所需的模态窗口,只是缺少该按钮的点击(click)属性和目标数据(data-target)属性。

    为了解决这个问题,请打开文件:

    /cards-trading-angular-app/src/app/TradeCard/TradeCard.component.html

    这里文件名与你设置的交易(transaction)名称相同。如果区块链业务网络中有多个交易(transaction),那么你必须在所有交易资源类型的HTML文件中做此更改。

    向下滚动直到文件最后,你会看到一个<button>标签,在这个标签中添加两个属性:

    1click)="resetForm();" data-target="#addTransactionModal"

    这条命令就成了这样:

    1<button type=”button” class=”btn btn-primary invokeTransactionBtn”
    2data-toggle=”modal” (click)=”resetForm();” data-
    3target=”#addTransactionModal”>Invoke</button>

    点击(click)属性将调用重置表单函数 resetForm(),该函数将所有输入字段清空,而目标数据(data-target)属性会规定在点击时打开的模态窗口。

    保存文件,打开浏览器,尝试按下调用(invoke)按钮。成功,可用了!

    0_1539648970539_f4e6e433-e57e-46de-9c18-b2be5136f664-image.png

    2)删除不必要的字段

    仅仅打开模态是不够的。

    上图中创建交易还需要填写交易ID(transactionId) 和时间戳(timestamp),然而我们并没有在模型文件中添加这些字段。

    不过,我们的区块链网络存储了这些所有交易固有的值。所以,它应该能够自己找出这些值。事实证明,它确实可以。

    不过这些是备用字段,最简单粗暴的方法莫过于直接将它们注释掉,REST API 会帮你处理剩下的工作。

    在这个文件(修改模态使用的文件)中,向上滚动查找输入字段并注释掉负责交易模态(addTransactionModal)中输入字段的 div 标签。

    0_1539648997238_31f40ead-c484-4bf3-8b2c-c98b5c8b116e-image.png

    保存文件,打开浏览器,然后点击调用(invoke)按钮,是这样的:

    0_1539649015772_a585e399-6e43-4a33-8112-7328c5f54f4d-image.png

    你现在可以通过在这些字段中传入数据来创建交易。添加一笔交易:

    0_1539649031843_c6defa15-e366-44b1-9370-b1f23d8ad7c1-image.png

    点击确认(Confirm),返回资产(Asset)页面,你将看到球星卡2号(TradingCard#2)现在属于交易者1号(Trader#1):

    0_1539649050731_de0e86f0-a098-4a49-8047-52b37de422fc-image.png

    **Congrats!**你已经在 Hyperledger Fabric上成功构建并部署了区块链业务网络。你还为该网络生成了一个 REST API 服务器,并学习了如何创建与 REST API 交互的 Web 应用程序。

    由于区块链具有价值存储特性,所以,在实际使用中还需要在安全性和用户体验上做出优化。要想打造一个区块链淘宝商城,任重而道远,就需要我们不断尝试、不断摸索了,一起加油吧!

    --【完】--

    0_1539649075054_8cced1b3-615f-4b32-9e2f-59548902fa3d-image.png



  • 楼主的帖子是属于硬核了,好难啃。期待后续有大神出来多多讨论。