教程 - 商业票据 (Commercial Paper)
本教程将向你展示如何安装和使用商业票据 (Commercial Paper) 示例应用程序和智能合约。这是一个面向任务的主题,因此强调了以上概念中的过程。当你想更详细地了解这些概念时,可以阅读 开发应用程序 主题。
image在本教程中,MagnetoCorp 和 DigiBank 这两个组织使用 Hyperledger Fabric 区块链网络 PaperNet 彼此进行商业票据交易。
建立基本网络后,你将担任 MagnetoCorp 员工 Isabella 的代表,他将代表该公司发行商业票据。然后,你将转而担任 DigiBank 员工 Balaji 的角色,他将购买此商业票据,保留一段时间,然后与 MagnetoCorp 赎回以获取少量利润。
你将分别在不同的组织中充当开发人员,终端用户和管理员的角色,执行以下步骤旨在帮助你了解作为两个不同的组织独立工作,但要根据 Hyperledger Fabric 网络中共同商定的规则进行协作。
- 设置网络并下载示例
- 创建一个网络
- 了解智能合约的结构
- 作为组织 MagnetoCorp 来安装和实例化智能合约
- 了解 MagnetoCorp 应用程序的结构,包括其依赖项
- 配置和使用钱包和身份
- 运行 MagnetoCorp 应用程序以发行商业票据
- 了解第二家组织 Digibank 如何在其应用程序中使用智能合约
- 作为 Digibank,运行购买和赎回商业票据的应用程序
本教程已经在 MacOS 和 Ubuntu 上进行了测试,并且可以在其他 Linux 发行版上使用。Windows 版本正在开发中。
1. 先决条件
在开始之前,你必须安装本教程所需的一些必备技术。我们将这些限制降至最低,以便你可以快速上手。
你必须安装以下技术:
- Node 8.9.0 或更高版本。Node 是一个 JavaScript 运行时,可用于运行应用程序和智能合约。建议你使用 Node 的长期支持 (Long Term Support, LTS) 版本。在 此处 安装 Node。
- Docker 18.06 或更高版本。Docker 帮助开发人员和管理员创建用于构建和运行应用程序和智能合约的标准环境。Hyperledger Fabric 是作为一组 Docker 镜像提供的,PaperNet 智能合约将在 Docker 容器中运行。在 此处 安装 Docker。
你会发现安装以下技术会有所帮助:
- 源代码编辑器,例如 Visual Studio Code 1.28 或更高版本。VS Code 将帮助你开发和测试你的应用程序和智能合约。在 此处 安装 VS Code。
提供了许多出色的代码编辑器,包括 Atom,Sublime Text 和 Brackets。
随着对应用程序和智能合约开发的经验越来越丰富,安装以下技术可能会有所帮助。初次运行本教程时,无需安装它们:
- Node 版本管理器。NVM (Node Version Manager) 可帮助你轻松地在不同版本的 Node 之间切换 - 如果你同时从事多个项目,这将非常有用。在 此处 安装 NVM。
2. 下载示例
商业票据教程是 Hyperledger Fabric 示例 之一,该示例存储在公共 GitHub 仓库中,称为 fabric-samples。在你的计算机上运行教程时,你的第一个任务是下载 fabric-samples 仓库。
image将 fabric-samples GitHub 仓库下载到本地计算机。
GOPATH 是否已设置:
$ env
...
GOPATH=/Users/username/go
NVM_BIN=/Users/username/.nvm/versions/node/v8.11.2/bin
NVM_IOJS_ORG_MIRROR=https://iojs.org/dist
...
如果未设置 $GOPATH,请使用以下 指令。
现在,你可以创建一个相对于 $GOPATH 的目录,将在其中安装 fabric-samples:
$ mkdir -p $GOPATH/src/github.com/hyperledger/
$ cd $GOPATH/src/github.com/hyperledger/
使用 git clone 命令将 fabric-samples 仓库复制到以下位置:
$ git clone https://github.com/hyperledger/fabric-samples.git
随时检查 fabric-samples 的目录结构:
$ cd fabric-samples
$ ls
CODE_OF_CONDUCT.md balance-transfer fabric-ca
CONTRIBUTING.md basic-network first-network
Jenkinsfile chaincode high-throughput
LICENSE chaincode-docker-devmode scripts
MAINTAINERS.md commercial-paper README.md
fabcar
请注意 commercial-paper
目录,这是我们的示例所在的目录!
你现在已经完成了教程的第一阶段!在继续操作时,你将打开多个命令窗口,这些窗口将为不同的用户和组件打开。例如:
- 代表 Isabella 和 Balaji 运行应用程序,他们将彼此进行商业票据交易
- 代表 MagnetoCorp 和 DigiBank 的管理员发出命令,包括安装和实例化智能合约
- 显示对端节点,交易排序器和 CA 日志输出
我们将在你应该从特定命令窗口运行命令时明确说明,例如:
(isabella)$ ls
表示你应该在 Isabella 的窗口中运行 ls 命令。
3. 创建网络
本教程当前使用基础网络。它将很快更新为更好地反映 PaperNet 的多组织结构的配置。目前,该网络足以向你展示如何开发应用程序和智能合约。
imageHyperledger Fabric 基础网络包括一个对端节点及其账本数据库,一个交易排序器和一个证书颁发机构 (Certificate Authority, CA)。这些组件中的每一个都作为 docker 容器运行。
对端节点,帐本,交易排序器和 CA 均在各自的 docker 容器中运行。在生产环境中,组织通常使用与其他系统共享的现有 CA。它们不是专用于 Fabric 网络的。
你可以使用 fabric-samples\basic-network 目录中包含的命令和配置来管理基础网络。让我们使用 start.sh shell 脚本在本地计算机上启动网络:
$ cd fabric-samples/basic-network
$ sudo ./start.sh
docker-compose -f docker-compose.yml up -d ca.example.com orderer.example.com peer0.org1.example.com couchdb
Creating network "net_basic" with the default driver
Pulling ca.example.com (hyperledger/fabric-ca:)...
latest: Pulling from hyperledger/fabric-ca
3b37166ec614: Pull complete
504facff238f: Pull complete
(...)
Pulling orderer.example.com (hyperledger/fabric-orderer:)...
latest: Pulling from hyperledger/fabric-orderer
3b37166ec614: Already exists
504facff238f: Already exists
(...)
Pulling couchdb (hyperledger/fabric-couchdb:)...
latest: Pulling from hyperledger/fabric-couchdb
3b37166ec614: Already exists
504facff238f: Already exists
(...)
Pulling peer0.org1.example.com (hyperledger/fabric-peer:)...
latest: Pulling from hyperledger/fabric-peer
3b37166ec614: Already exists
504facff238f: Already exists
(...)
Creating orderer.example.com ... done
Creating couchdb ... done
Creating ca.example.com ... done
Creating peer0.org1.example.com ... done
(...)
2018-11-07 13:47:31.634 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2018-11-07 13:47:31.730 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel
请注意 docker-compose -f docker-compose.yml up -d ca.example.com ...
命令如何从 DockerHub 中提取四个 Hyperledger Fabric 容器镜像,然后启动它们。这些容器具有适用于这些 Hyperledger Fabric 组件的软件的最新版本。欢迎浏览 basic-network
目录 - 在本教程中,我们将使用其中的大部分内容。
你可以使用 docker ps 命令列出运行基础网络组件的 Docker 容器:
$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ada3d078989b hyperledger/fabric-peer "peer node start" About a minute ago Up About a minute 0.0.0.0:7051->7051/tcp, 0.0.0.0:7053->7053/tcp peer0.org1.example.com
1fa1fd107bfb hyperledger/fabric-orderer "orderer" About a minute ago Up About a minute 0.0.0.0:7050->7050/tcp orderer.example.com
53fe614274f7 hyperledger/fabric-couchdb "tini -- /docker-ent…" About a minute ago Up About a minute 4369/tcp, 9100/tcp, 0.0.0.0:5984->5984/tcp couchdb
469201085a20 hyperledger/fabric-ca "sh -c 'fabric-ca-se…" About a minute ago Up About a minute 0.0.0.0:7054->7054/tcp ca.example.com
查看是否可以将这些容器映射到基础网络 (你可能需要水平滚动以查找信息):
- 对端节点
peer0.org1.example.com
在容器ada3d078989b
中运行 - 交易排序器
orderer.example.com
正在容器1fa1fd107bfb
中运行 - 在容器
53fe614274f7
中正在运行 CouchDB 数据库couchdb
- CA
ca.example.com
正在容器469201085a20
中运行
这些容器都形成了一个名为 net_basic
的 docker 网络。你可以使用 docker network
命令查看网络:
$ sudo docker network inspect net_basic
{
"Name": "net_basic",
"Id": "62e9d37d00a0eda6c6301a76022c695f8e01258edaba6f65e876166164466ee5",
"Created": "2018-11-07T13:46:30.4992927Z",
"Containers": {
"1fa1fd107bfbe61522e4a26a57c2178d82b2918d5d423e7ee626c79b8a233624": {
"Name": "orderer.example.com",
"IPv4Address": "172.20.0.4/16",
},
"469201085a20b6a8f476d1ac993abce3103e59e3a23b9125032b77b02b715f2c": {
"Name": "ca.example.com",
"IPv4Address": "172.20.0.2/16",
},
"53fe614274f7a40392210f980b53b421e242484dd3deac52bbfe49cb636ce720": {
"Name": "couchdb",
"IPv4Address": "172.20.0.3/16",
},
"ada3d078989b568c6e060fa7bf62301b4bf55bed8ac1c938d514c81c42d8727a": {
"Name": "peer0.org1.example.com",
"IPv4Address": "172.20.0.5/16",
}
},
"Labels": {}
}
查看这四个容器如何成为一个 docker 网络的一部分,如何使用不同的 IP 地址。(为清楚起见,我们将输出缩写。)
回顾一下:你已经从 GitHub 下载了 Hyperledger Fabric 示例仓库,并且基础网络已在本地计算机上运行。现在,让我们开始扮演 MagnetoCorp 的角色,他希望买卖商业票据。
4. 担任 MagnetoCorp 角色
要监视 PaperNet 的 MagnetoCorp 组件,管理员可以使用 logspout
工具 查看一组 Docker 容器的聚合输出。它将不同的输出流收集到一个位置,从而可以轻松地从一个窗口查看正在发生的事情。例如,这对于安装智能合约的管理员或调用智能合约的开发人员确实很有帮助。
现在,让我们以 MagnetoCorp 管理员的身份监视 PaperNet。在 fabric-samples
目录中打开一个新窗口,找到并运行 monitordocker.sh
脚本以启动与 docker 网络 net_basic
关联的 PaperNet docker 容器的 logspout 工具:
(magnetocorp admin)$ cd commercial-paper/organization/magnetocorp/configuration/cli/
(magnetocorp admin)$ sudo ./monitordocker.sh net_basic
...
latest: Pulling from gliderlabs/logspout
4fe2ade4980c: Pull complete
decca452f519: Pull complete
(...)
Starting monitoring on all containers on the network net_basic
b7f3586e5d0233de5a454df369b8eadab0613886fc9877529587345fc01a3582
请注意,如果 Monitordocker.sh 中的默认端口已在使用中,则可以将端口号传递给上述命令。
(magnetocorp admin)$ ./monitordocker.sh net_basic <port_number>
现在,该窗口将显示 docker 容器的输出,因此让我们启动另一个终端窗口,该窗口将允许 MagnetoCorp 管理员与网络进行交互。
imageMagnetoCorp 管理员通过 Docker 容器与网络进行交互。
为了与 PaperNet 进行交互,MagnetoCorp 管理员需要使用 Hyperledger Fabric peer
命令。方便地,这些都可以在 hyperledger/fabric-tools
docker 镜像 中预先构建。
让我们使用 docker-compose
命令 为管理员启动一个特定于 MagnetoCorp 的 Docker 容器:
(magnetocorp admin)$ cd commercial-paper/organization/magnetocorp/configuration/cli/
(magnetocorp admin)$ sudo docker-compose -f docker-compose.yml up -d cliMagnetoCorp
Pulling cliMagnetoCorp (hyperledger/fabric-tools:)...
latest: Pulling from hyperledger/fabric-tools
3b37166ec614: Already exists
(...)
Digest: sha256:058cff3b378c1f3ebe35d56deb7bf33171bf19b327d91b452991509b8e9c7870
Status: Downloaded newer image for hyperledger/fabric-tools:latest
Creating cliMagnetoCorp ... done
再次,查看如何从 Docker Hub 检索 hyperledger/fabric-tools
docker 镜像并将其添加到网络:
(magnetocorp admin)$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
562a88b25149 hyperledger/fabric-tools "/bin/bash" About a minute ago Up About a minute cliMagnetoCorp
b7f3586e5d02 gliderlabs/logspout "/bin/logspout" 7 minutes ago Up 7 minutes 127.0.0.1:8000->80/tcp logspout
ada3d078989b hyperledger/fabric-peer "peer node start" 29 minutes ago Up 29 minutes 0.0.0.0:7051->7051/tcp, 0.0.0.0:7053->7053/tcp peer0.org1.example.com
1fa1fd107bfb hyperledger/fabric-orderer "orderer" 29 minutes ago Up 29 minutes 0.0.0.0:7050->7050/tcp orderer.example.com
53fe614274f7 hyperledger/fabric-couchdb "tini -- /docker-ent…" 29 minutes ago Up 29 minutes 4369/tcp, 9100/tcp, 0.0.0.0:5984->5984/tcp couchdb
469201085a20 hyperledger/fabric-ca "sh -c 'fabric-ca-se…" 29 minutes ago Up 29 minutes 0.0.0.0:7054->7054/tcp ca.example.com
MagnetoCorp 管理员将使用容器 562a88b25149
中的命令行与 PaperNet 进行交互。还要注意日志记录容器 b7f3586e5d02
;这是为 monitordocker.sh
命令捕获所有其他 docker 容器的输出。
现在,让我们使用此命令行以 MagnetoCorp 管理员的身份与 PaperNet 进行交互。
5. 智能合约
发行 (issue
),购买 (buy
) 和赎回 (redeem
) 是 PaperNet 智能合约的三个核心功能。应用程序使用它来提交交易,这些交易相应地在账本上发行,购买和赎回商业票据。我们的下一个任务是检查智能合约。
打开一个新的终端窗口,代表 MagnetoCorp 开发人员,然后转到包含 MagnetoCorp 智能合约副本的目录,以便使用你选择的编辑器进行查 (本教程中的 VS 代码):
(magnetocorp developer)$ cd commercial-paper/organization/magnetocorp/contract
(magnetocorp developer)$ ls .
在文件夹的 lib
目录中,你将看到 papercontract.js
文件 - 该文件包含商业票据智能合约!
一个示例代码编辑器,在 papercontract.js
中显示商业票据智能合约。
papercontract.js
是一个 JavaScript 程序,旨在在 node.js 环境中运行。请注意以下关键程序行:
-
const { Contract, Context } = require('fabric-contract-api');
该声明将智能合约广泛使用的两个关键 Hyperledger Fabric 类纳入了范围 -
Contract
和Context
。你可以在fabric-shim
JSDOCS 中了解有关这些类的更多信息。 -
class CommercialPaperContract extends Contract {
这基于内置的 Fabric
Contract
类定义了智能合约类CommercialPaperContract
。在此类中定义了实现发行 (issue
),购买 (buy
) 和赎回 (redeem
) 商业票据的关键交易的方法。 -
async issue(ctx, issuer, paperNumber, issueDateTime, maturityDateTime...) {
此方法为 PaperNet 定义了商业票据发行 (
issue
) 交易。传递给此方法的参数将用于创建新的商业票据。在智能合约中找到并检查购买 (
buy
) 和赎回 (redeem
) 交易。 -
let paper = CommercialPaper.createInstance(issuer, paperNumber, issueDateTime...);
在发行 (
issue
) 交易中,此语句使用带有提供的交易输入的CommercialPaper
类在内存中创建新的商业票据。检查购买 (buy
) 和赎回 (redeem
) 交易,以了解它们如何类似地使用此类。 -
await ctx.paperList.addPaper(paper);
该语句使用
ctx.paperList
将新的商业票据添加到帐本中,ctx.paperList
是在智能合约上下文CommercialPaperContext
初始化时创建的PaperList
类的实例。再次,检查购买 (buy
) 和赎回 (redeem
) 方法,以了解它们如何使用此类。 -
return paper.toBuffer();
该语句返回一个二进制缓冲区作为发行 (
issue
) 交易的响应,由智能合约的调用者进行处理。
随时检查 contract
目录中的其他文件,以了解智能合约的工作原理,并详细阅读智能合约 主题 中 papercontract.js
的设计方式。
6. 安装合约
在应用程序可以调用 papercontract
之前,必须将它安装到 PaperNet 中的相应对端节点上。MagnetoCorp 和 DigiBank 管理员能够将 papercontract
安装到他们各自具有权限的对端节点上。
MagnetoCorp 管理员将 papercontract
的副本安装到 MagnetoCorp 对端节点。
智能合约是应用程序开发的重点,并且包含在称为 链码 的 Hyperledger Fabric 构件中。可以在单个链码中定义一个或多个智能合约,安装链码将允许 PaperNet 中的不同组织使用它们。这意味着只有管理员才需要担心链码。其他人都可以根据智能合约进行思考。
MagnetoCorp 管理员使用 peer chaincode install
命令将 papercontract
智能合约从其本地计算机的文件系统复制到目标对端节点 Docker 容器内的文件系统。一旦将智能合约安装到对端节点并在通道上实例化,便可以由应用程序调用 papercontract
,并通过 putState() 和 getState() Fabric API与账本数据库进行交互。检查 ledger-api\statelist.js
中的 StateList
类如何使用这些 API。
现在,以 MagnetoCorp 管理员的身份安装 papercontract
。在 MagnetoCorp 管理员的命令窗口中,使用 docker exec
命令在 cliMagnetCorp
容器中运行 peer chaincode install
命令:
(magnetocorp admin)$ sudo docker exec cliMagnetoCorp peer chaincode install -n papercontract -v 0 -p /opt/gopath/src/github.com/contract -l node
2018-11-07 14:21:48.400 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-11-07 14:21:48.400 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
2018-11-07 14:21:48.466 UTC [chaincodeCmd] install -> INFO 003 Installed remotely response:<status:200 payload:"OK" >
cliMagnetCorp
容器已将 CORE_PEER_ADDRESS=peer0.org1.example.com:7051
设置为将其命令定向到 peer0.org1.example.com
,并且 INFO 003 Installed remotely ...
表示该对端节点已成功安装 papercontract
。目前,MagnetoCorp 管理员只需在单个 MagentoCorp 对端节点上安装 papercontract
副本。
请注意,peer chaincode install
命令如何相对于 cliMagnetoCorp
容器的文件系统 /opt/gopath/src/github.com/contract
指定智能合约路径 -p
。该路径已通过 magnetocorp/configuration/cli/docker-compose.yml
文件映射到本地文件系统路径 .../organization/magnetocorp/contract
:
volumes:
- ...
- ./../../../../organization/magnetocorp:/opt/gopath/src/github.com/
- ...
了解 volume
指令如何将 organization/magnetocorp
映射到 /opt/gopath/src/github.com/
,以提供此容器访问你的本地文件系统的位置,该目录中保存了 MagnetoCorp 的 papercontract
智能合约副本。
你可以在 此处 阅读有关 docker compose
的更多信息,并在 此处 阅读 peer chaincode install
命令。
7. 实例化合约
现在,已将包含 CommercialPaper
智能合约的 papercontract
链码安装在所需的 PaperNet 对端节点上,管理员可以将其提供给不同的网络通道使用,从而可以由连接到这些通道的应用程序调用。因为我们使用的是 PaperNet 的基础网络配置,所以我们只会在单个网络通道 mychannel
中提供 papercontract
。
MagnetoCorp 管理员实例化包含智能合约的 papercontract
链码。将创建一个新的 docker chaincode 容器以运行 papercontract
。
MagnetoCorp 管理员使用 peer chaincode instantiate
命令来实例化 mychannel
上的 papercontract
:
(magnetocorp admin)$ sudo docker exec cliMagnetoCorp peer chaincode instantiate -n papercontract -v 0 -l node -c '{"Args":["org.papernet.commercialpaper:instantiate"]}' -C mychannel -P "AND ('Org1MSP.member')"
2018-11-07 14:22:11.162 UTC [chaincodeCmd] InitCmdFactory -> INFO 001 Retrieved channel (mychannel) orderer endpoint: orderer.example.com:7050
2018-11-07 14:22:11.163 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default escc
2018-11-07 14:22:11.163 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 003 Using default vscc
-P
是 instantiate
中最重要的参数之一。它指定了 papercontract
的 背书策略,描述了在确定交易有效之前必须背书 (执行和签名) 交易的一组组织。所有交易 (无论有效还是无效) 都将记录在 账本区块链 上,但是只有有效交易才能更新 世界状态。
通过传递,请参见 instantiate
如何传递交易排序器地址 orderer.example.com:7050
。这是因为它另外将实例化交易提交给交易排序器,它会将交易包含在下一个区块中并将其分发给已加入 mychannel
的所有对端节点,从而使任何对端节点都可以在其自己的隔离链码容器中执行链码。请注意,对于 papercontract
,instantiate
只需要发布一次,即使它通常安装在许多对端节点上。
查看如何使用 docker ps
命令启动纸质 papercontract
:
(magnetocorp admin)$ sudo docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4fac1b91bfda dev-peer0.org1.example.com-papercontract-0-d96... "/bin/sh -c 'cd /usr…" 2 minutes ago Up 2 minutes dev-peer0.org1.example.com-papercontract-0
请注意,该容器的名称为 dev-peer0.org1.example.com-papercontract-0-d96...
,以指示哪个对端节点启动了该容器,以及该容器运行的是 papertract
版本 0
。
现在,我们已经建立并运行了基本的 PaperNet,并已安装并实例化了 paperContract
,现在我们将注意力转向发行商业票据的 MagnetoCorp 应用程序。
8. 应用程序结构
papercontract
中包含的智能合约由 MagnetoCorp 的应用程序 issue.js
调用。Isabella (伊莎贝拉) 使用此应用程序将交易提交到帐本,该帐本将发行商业票据 00001
。让我们快速检查一下发行 (issue
) 程序的工作方式。
网关 (gateway) 允许应用程序专注于交易的生成,提交和响应。它协调不同网络组件之间的交易提案,交易排序和通知处理。
由于 issue
应用程序代表 Isabella 提交交易,因此首先要从她的 钱包 中检索 Isabella 的 X.509 证书,该证书可能存储在本地文件系统或硬件安全模块 (Hardware Security Module, HSM) 中。然后,issue
应用程序能够利用网关在通道上提交交易。 Hyperledger Fabric SDK 提供了 网关 抽象,因此应用程序可以在将网络交互委托给网关的同时专注于应用程序逻辑。网关和钱包使编写 Hyperledger Fabric 应用程序变得很简单。
因此,让我们检查一下Isabella将要使用的问题应用程序。为她打开一个单独的终端窗口,然后在Fabric-samples中找到MagnetoCorp / application文件夹:
因此,让我们检查一下 Isabella 将要使用的 issue
应用程序。为她打开一个单独的终端窗口,然后在 fabric-samples
中找到 MagnetoCorp /application
文件夹:
(magnetocorp user)$ cd commercial-paper/organization/magnetocorp/application/
(magnetocorp user)$ ls
addToWallet.js issue.js package.json
Isabella 将使用 addToWallet.js
程序将 Isabella 的身份加载到她的钱包中,issue.js
将通过调用 papercontract
使用此身份代表 MagnetoCorp 创建商业票据 00001
。
转到包含 MagnetoCorp 应用程序 issue.js
副本的目录,然后使用代码编辑器进行检查:
(magnetocorp user)$ cd commercial-paper/organization/magnetocorp/application
(magnetocorp user)$ code issue.js
检查此目录;它包含 issue
应用程序及其所有依赖项。
一个代码编辑器,显示商业票据应用程序目录的内容。
请注意 issue.js
中的以下关键程序行:
-
const { FileSystemWallet, Gateway } = require('fabric-network');
该声明将两个关键的 Hyperledger Fabric SDK 类引入了作用域 -
Wallet
和Gateway
。由于 Isabella 的 X.509 证书位于本地文件系统中,因此该应用程序使用FileSystemWallet
。 -
const wallet = new FileSystemWallet('../identity/user/isabella/wallet');
该语句标识该应用程序在连接到区块链网络通道时将使用 isabella 钱包。该应用程序将选择 isabella 钱包中的特定身份。(钱包必须已经装有 Isabella 的 X.509 证书,这就是
addToWallet.js
所做的。) -
await gateway.connect(connectionProfile, connectionOptions);
这行代码使用由
connectionProfile
标识的网关 (使用 ConnectionOptions 中引用的身份) 连接到网络。请参阅如何分别将
../gateway/networkConnection.yaml
和User1@org1.example.com
用于这些值。 -
const network = await gateway.getNetwork('mychannel');
这会将应用程序连接到网络通道
mychannel
,在该通道papercontract
先前已实例化。 -
const contract = await network.getContract('papercontract', 'org.papernet.comm...');
该语句使应用程序可访问
papercontract
中由命名空间org.papernet.commercialpaper
定义的智能合约。一旦应用程序发布了 getContract,它就可以提交在其中实现的任何交易。 -
const issueResponse = await contract.submitTransaction('issue', 'MagnetoCorp', '00001'...);
这行代码使用智能合约中定义的发行 (
issue
) 交易将交易提交到网络。MagnetoCorp
,00001
… 是发行交易用于创建新商业票据的值。 -
let paper = CommercialPaper.fromBuffer(issueResponse);
该语句处理来自发行 (
issue
) 交易的响应。需要将响应从缓冲区反序列化为paper
(可以由应用程序正确解释的CommercialPaper
对象)。
随时检查 /application
目录中的其他文件,以了解 issue.js
的工作方式,并在应用程序 主题 中详细阅读它的实现方式。
9. 应用程序依赖
issue.js
应用程序是用 JavaScript 编写的,旨在在作为 PaperNet 网络客户端的 node.js 环境中运行。按照惯例,MagnetoCorp 的应用程序建立在许多外部 node 程序包上 – 以提高开发质量和速度。请考虑 issue.js
如何包括用于处理 YAML 网关连接配置文件的 js-yaml
程序包,或用于访问 Gateway 和 Wallet 类的 fabric-network
程序包:
const yaml = require('js-yaml');
const { FileSystemWallet, Gateway } = require('fabric-network');
必须使用 npm install
命令将这些软件包从 npm 下载到本地文件系统。按照约定,必须将软件包安装到相对于应用程序的 /node_modules
目录中,以便在运行时使用。
检查 package.json
文件,查看 issue.js
如何识别要下载的软件包及其确切版本:
"dependencies": {
"fabric-network": "^1.4.0-beta",
"fabric-client": "^1.4.0-beta",
"js-yaml": "^3.12.0"
},
npm 版本控制功能非常强大;你可以在 这里 读更多关于它的内容。
让我们使用 npm install
命令安装这些软件包 - 这可能需要一分钟才能完成:
(magnetocorp user)$ npm install
( ) extract:lodash: sill extract ansi-styles@3.2.1
(...)
added 738 packages in 46.701s
查看此命令如何更新目录:
(magnetocorp user)$ ls
addToWallet.js node_modules package.json
issue.js package-lock.json
检查 node_modules
目录以查看已安装的软件包。有很多,因为 js-yaml
和 fabric-network
本身是建立在其他 npm 软件包上的!有用的是,package-lock.json
文件可以标识安装的确切版本,如果你想精确地复制环境,则可以证明它的价值。以测试,诊断问题或交付经过验证的应用程序。
10. 钱包
Isabella 几乎可以运行 issue.js
发行 MagnetoCorp 商业票据 00001;剩下要做的一项任务!由于 issue.js
代表 Isabella 并因此代表 MagnetoCorp,它将使用其钱包中的身份来反映这些事实。现在,我们需要执行这一一次性活动,向她的钱包添加适当的 X.509 凭据。
在 Isabella 的终端窗口中,运行 addToWallet.js
程序以向她的钱包添加身份信息:
(isabella)$ node addToWallet.js
done
Isabella 可以在她的钱包中存储多个身份,尽管在我们的示例中,她仅使用一个身份 - User1@org.example.com
。该身份当前与基础网络相关联,而不是与更现实的 PaperNet 配置相关联 - 我们将尽快更新本教程。
addToWallet.js
是一个简单的文件复制程序,你可以随时检查。它将身份从基础网络示例转移到 Isabella 的钱包。让我们关注这个程序的结果 – 钱包中的内容,这些内容将用于向 PaperNet 提交交易:
(isabella)$ ls ../identity/user/isabella/wallet/
User1@org1.example.com
查看目录结构如何映射 User1@org1.example.com
身份 - Isabella 使用的其他身份将拥有自己的文件夹。在此目录中,你将找到 issue.js
代表 isabella 使用的身份信息:
(isabella)$ ls ../identity/user/isabella/wallet/User1@org1.example.com
User1@org1.example.com c75bd6911a...-priv c75bd6911a...-pub
注意:
- 私钥
c75bd6911a...-priv
用于代表 Isabella 签署交易,但并未在她的直接控制范围之外分发。 - 公钥
c75bd6911a...-pub
,该密钥以密码方式链接到 Isabella 的私钥。这完全包含在 Isabella 的 X.509 证书中。 - 证书
User1@org.example.com
,其中包含 Isabella 的公钥以及证书颁发机构在创建证书时添加的其他 X.509 属性。该证书已分发到网络,以便不同的参与者在不同的时间可以通过密码验证由 Isabella 的私钥创建的信息。
在 此处 了解有关证书的更多信息。实际上,证书文件还包含一些特定于 Fabric 的元数据,例如 Isabella 的组织和角色 - 在 wallet 主题中了解更多。
11. 发行应用程序
Isabella 现在可以使用 issue.js
提交将发行 MagnetoCorp 商业票据 00001 的交易:
(isabella)$ node issue.js
Connect to Fabric gateway.
Use network channel: mychannel.
Use org.papernet.commercialpaper smart contract.
Submit commercial paper issue transaction.
Process issue transaction response.{"class":"org.papernet.commercialpaper","key":"\"MagnetoCorp\":\"00001\"","currentState":1,"issuer":"MagnetoCorp","paperNumber":"00001","issueDateTime":"2020-05-31","maturityDateTime":"2020-11-30","faceValue":"5000000","owner":"MagnetoCorp"}
MagnetoCorp commercial paper : 00001 successfully issued for value 5000000
Transaction complete.
Disconnect from Fabric gateway.
Issue program complete.
node
命令初始化一个 node.js 环境,并运行 issue.js
。从程序输出中我们可以看到,发行了面值为 500 万美元的 MagnetoCorp 商业票据 00001。
如你所见,为实现此目的,该应用程序调用 papercontract.js
中 CommercialPaper
智能合约中定义的 issue
交易。MagnetoCorp 管理员已在网络中安装并实例化了该文件。这是智能合约,它通过 Fabric API 与帐本进行交互,最著名的是 putState()
和 getState()
,以将新的商业票据表示为世界状态内的向量状态。我们将看到随后如何通过智能合约中定义的购买 (buy
) 和赎回 (redeem
) 交易来操纵此向量状态。
底层的 Fabric SDK 一直都在处理交易背书,交易排序和通知流程,使应用程序的逻辑变得简单明了;SDK使用 gateway 抽象网络详细信息和 connectionOptions 来声明更高级的处理策略,例如交易重试。
现在,让我们关注 MagnetoCorp 00001
的生命周期,将重点转移到将购买商业票据的 DigiBank。
12. 担任 DigiBank 角色
现在,MagnetoCorp 已发行了商业票据 00001
,现在让我们切换上下文,以 DigiBank 的雇员的身份与 PaperNet 进行交互。首先,我们将以管理员身份创建一个配置为与 PaperNet 进行交互的控制台。然后,最终用户 Balaji 将使用 Digibank 的购买 (buy
) 应用程序购买商业票据 00001
,将其转移到生命周期的下一个阶段。
DigiBank 管理员和应用程序与 PaperNet 网络交互。
由于本教程当前使用 PaperNet 的基础网络,因此网络配置非常简单。管理员使用类似于 MagnetoCorp 的控制台,但为 Digibank 的文件系统配置了控制台。同样,Digibank 最终用户将使用与 MagnetoCorp 应用程序调用相同智能合约的应用程序,尽管它们包含 Digibank 特定的逻辑和配置。无论是哪个应用程序调用它们,智能合约都可以捕获共享的业务流程,而账本则可以存储共享的业务数据。
让我们打开一个单独的终端,以使 DigiBank 管理员可以与 PaperNet 进行交互。在 fabric-samples
中:
(digibank admin)$ cd commercial-paper/organization/digibank/configuration/cli/
(digibank admin)$ sudo docker-compose -f docker-compose.yml up -d cliDigiBank
(...)
Creating cliDigiBank ... done
现在,此 Docker 容器可供 Digibank 管理员与网络交互:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORT NAMES
858c2d2961d4 hyperledger/fabric-tools "/bin/bash" 18 seconds ago Up 18 seconds cliDigiBank
在本教程中,你将使用名为 cliDigiBank
的命令行容器代表 DigiBank 与网络进行交互。我们并未显示所有的 Docker 容器,在现实世界中,DigiBank 用户只会看到他们有权访问的网络组件 (对端节点,交易排序器,CA)。
由于 PaperNet 网络配置非常简单,因此 Digibank 的管理员现在在本教程中不需要做什么工作。让我们把注意力转向 Balaji。
13. DigiBank 应用程序
Balaji 使用 DigiBank 的购买 (buy
) 应用程序将交易提交到帐本,该帐本将商业票据 00001
的所有权从 MagnetoCorp 转移到 DigiBank。CommercialPaper
智能合约与 MagnetoCorp 的应用程序使用的合约相同,但是这次交易有所不同 – 是购买 (buy
) 而不是发行 (issue
)。让我们研究一下 DigiBank 应用程序的工作方式。
打开 Balaji 的单独终端窗口。在 fabric-samples
中,切换到包含应用程序 buy.js
的 DigiBank 应用程序目录,然后使用编辑器将其打开:
(balaji)$ cd commercial-paper/organization/digibank/application/
(balaji)$ code buy.js
如你所见,此目录包含 Balaji 将使用的购买 (buy
) 和赎回 (redeem
) 应用程序。
DigiBank 的商业票据目录,其中包含 buy.js
和 redeem.js
应用程序。
DigiBank 的 buy.js
应用程序的结构与 MagnetoCorp 的 issue.js
相似,但有两个重要区别:
- 身份 (Identity):该用户是 DigiBank 用户 Balaji,而不是 MagnetoCorp 的 Isabella
const wallet = new FileSystemWallet('../identity/user/balaji/wallet');`
查看应用程序在连接到 PaperNet 网络通道时如何使用 balaji 钱包。`buy.js` 在 balaji 钱包中选择一个特定的身份。
- 交易 (Transaction):被调用的交易是买入 (
buy
) 而非发行 (issue
)
`const buyResponse = await contract.submitTransaction('buy', 'MagnetoCorp', '00001'...);`
提交了具有 `MagnetoCorp`,`00001` … 值的购买 (`buy`) 交易,由 `CommercialPaper` 智能合约类使用该交易将商业票据 `00001` 的所有权转让给 DigiBank。
随时检查应用程序目录中的其他文件,以了解应用程序的工作方式,并详细阅读应用程序 主题 中的 buy.js
的实现方式。
14. 以 DigiBank 身份运行
购买和赎回商业票据的 DigiBank 应用程序的结构与 MagnetoCorp 的发行应用程序非常相似。因此,让我们安装它们的依赖项并设置 Balaji 的钱包,以便他可以使用这些应用程序购买和赎回商业票据。
与 MagnetoCorp 一样,Digibank 必须使用 npm install
命令安装所需的应用程序包,这又需要很短的时间才能完成。
在 DigiBank 管理员窗口中,安装应用程序依赖项:
(digibank admin)$ cd commercial-paper/organization/digibank/application/
(digibank admin)$ npm install
( ) extract:lodash: sill extract ansi-styles@3.2.1
(...)
added 738 packages in 46.701s
在 Balaji 的终端窗口中,运行 addToWallet.js
程序以向其钱包添加身份信息:
(balaji)$ node addToWallet.js
done
addToWallet.js
程序已在他的钱包中添加了 balaji 的身份信息,buy.js
和 redeem.js
将使用该信息来向 PaperNet 提交交易。
与 Isabella 一样,Balaji 可以在他的钱包中存储多个身份,尽管在我们的示例中,他仅使用一个身份 – Admin@org.example.com
。他对应的钱包结构 digibank/identity/user/balaji/wallet/Admin@org1.example.com
所包含的钱包与伊莎贝拉的钱包非常相似 - 请随时进行检查。
15. 购买应用程序
Balaji 现在可以使用 buy.js
提交交易,该交易会将 MagnetoCorp 商业票据 00001
的所有权转让给 DigiBank。
在 Balaji 的窗口中运行购买 (buy
) 应用程序:
(balaji)$ node buy.js
Connect to Fabric gateway.
Use network channel: mychannel.
Use org.papernet.commercialpaper smart contract.
Submit commercial paper buy transaction.
Process buy transaction response.
MagnetoCorp commercial paper : 00001 successfully purchased by DigiBank
Transaction complete.
Disconnect from Fabric gateway.
Buy program complete.
你可以看到程序输出,Balaji 代表 DigiBank 成功购买了 MagnetoCorp 商业票据 00001
。buy.js
调用了 CommercialPaper
智能合约中定义的购买 (buy
) 交易,该合约使用 putState()
和 getState()
Fabric API 在世界状态更新了商业票据 00001
。如你所见,购买和发行商业票据的应用程序逻辑与智能合约逻辑非常相似。
16. 赎回应用程序
商业票据 00001
生命周期中的最后一笔交易是 DigiBank 用 MagnetoCorp 赎回它。Balaji 使用 redeem.js
提交交易以执行智能合约中的赎回逻辑。
在 Balaji 的窗口中运行赎回 (redeem
) 交易:
(balaji)$ node redeem.js
Connect to Fabric gateway.
Use network channel: mychannel.
Use org.papernet.commercialpaper smart contract.
Submit commercial paper redeem transaction.
Process redeem transaction response.
MagnetoCorp commercial paper : 00001 successfully redeemed with MagnetoCorp
Transaction complete.
Disconnect from Fabric gateway.
Redeem program complete.
再次,看看当 redeem.js
调用 CommercialPaper
中定义的赎回 (redeem
) 交易时,商业票据 00001
是如何成功赎回的。再次,它更新了世界状态的商业票据 00001
,以反映所有权归还给票据发行人 MagnetoCorp。
17. 进一步阅读
为了更详细地了解本教程中显示的应用程序和智能合约的工作原理,你会发现阅读 开发应用程序 很有帮助。本主题将为你提供有关商业票据方案,PaperNet 商业网络,其参与者以及他们使用的应用程序和智能合约如何工作的更详细说明。
也可以随时使用此示例开始创建自己的应用程序和智能合约!
Reference
- Docs » Tutorials » Commercial paper tutorial, https://hyperledger-fabric.readthedocs.io/en/release-1.4/tutorial/commercial_paper.html
- Docs » Developing Applications, https://hyperledger-fabric.readthedocs.io/en/release-1.4/developapps/developing_applications.html
- https://nodejs.org/en/
- https://www.docker.com/get-started
- https://code.visualstudio.com/
- https://github.com/nvm-sh/nvm
- https://github.com/hyperledger/fabric-samples
- https://github.com/
- https://github.com/golang/go/wiki/SettingGOPATH
- https://hub.docker.com/
- https://docs.docker.com/network/
- https://github.com/gliderlabs/logspout#logspout
- https://hub.docker.com/r/hyperledger/fabric-tools/
- https://docs.docker.com/compose/
- Hyperledger Fabric Node.js Contract and Shim, https://fabric-shim.github.io/release-1.4/index.html
- Docs » Developing Applications » Smart Contract Processing, https://hyperledger-fabric.readthedocs.io/en/release-1.4/developapps/smartcontract.html
- Docs » Tutorials » Chaincode Tutorials, https://hyperledger-fabric.readthedocs.io/en/release-1.4/chaincode.html
- https://docs.docker.com/compose/
- Docs » Commands Reference » peer chaincode, https://hyperledger-fabric.readthedocs.io/en/release-1.4/commands/peerchaincode.html
- Docs » Operations Guides » Endorsement policies, https://hyperledger-fabric.readthedocs.io/en/release-1.4/endorsement-policies.html
- https://hyperledger-fabric.readthedocs.io/en/release-1.4/ledger/ledger.html#blockchain
- https://hyperledger-fabric.readthedocs.io/en/release-1.4/ledger/ledger.html#world-state
- Docs » Developing Applications » Application design elements » Wallet, https://hyperledger-fabric.readthedocs.io/en/release-1.4/developapps/wallet.html
- Docs » Developing Applications » Application design elements » Gateway, https://hyperledger-fabric.readthedocs.io/en/release-1.4/developapps/gateway.html
- Docs » Developing Applications » Application, https://hyperledger-fabric.readthedocs.io/en/release-1.4/developapps/application.html
- https://www.npmjs.com/
- https://docs.npmjs.com/getting-started/semantic-versioning
- https://hyperledger-fabric.readthedocs.io/en/release-1.4/identity/identity.html#digital-certificates
- Docs » Developing Applications » Application design elements » Wallet, https://hyperledger-fabric.readthedocs.io/en/release-1.4/developapps/wallet.html
- Docs » Developing Applications » Application design elements » Gateway, https://hyperledger-fabric.readthedocs.io/en/release-1.4/developapps/gateway.html
- Docs » Developing Applications » Application, https://hyperledger-fabric.readthedocs.io/en/release-1.4/developapps/application.html
- Docs » Developing Applications, https://hyperledger-fabric.readthedocs.io/en/release-1.4/developapps/developing_applications.html
项目源代码
项目源代码会逐步上传到 Github,地址为 https://github.com/windstamp。
Contributor
- Windstamp, https://github.com/windstamp
网友评论