1.0前期硬件资源准备
1.1硬件环境整理
准备虚机:分别分配2G内存、2核CPU、20G硬盘资源,网络连接方式为仅主机模式,为使用方便,统一设置root密码为root,普通用户名对应的密码为123456。
主机名 IP 使用情况 备注
p1 192.168.11.130 ZK1、Kafka1、Orderer1、Peer1
p2 192.168.11.133 ZK2、Kafka2、Orderer2、Peer2
p3 192.168.11.131 ZK3、Kafka3、Orderer3、Peer3
p4 192.168.11.132 Kafka4、Peer4、Peer4
1.2虚拟机网络配置
为了实现主机与虚拟机的Linux系统互连,可以对虚拟机进行设置,达到目的。
VMware的网络连接模式有三种:
1、仅主机模式:也就是host_only,这种模式仅仅只让虚拟机与本地物理机通信,不可以上网;
2、NAT模式:这种模式保留仅主机模式的功能下,还能让主机上网;
3、桥接模式:直接让虚拟机使用本地主机的网卡上网。
使用“仅主机模式”,简单的实现虚拟机与本地物理机器通信,只用修改VMnet1就可以。
第一步:
打开VMware菜单,【虚拟机】–【设置】,选择网络适配器的网络链接,我们使用仅主机模式。
第二步:
打开VMware,菜单【编辑】–【虚拟网络编辑器】
第三步:
打开VMware中安装的centos,将ip地址设置到和VMnet1处于同一个网段。
打开ifcfg-ens33,默认是动态获取IP地址,可以手动设置如下(记得在root用户下):
第四步:
重启网卡,使用命令systemctl restart network,然后查看本地的IP地址,就可以实现互联。
第五步:配置host文件
配置主机host:
将配置发送到其他主机(同时在其他主机上配置):
第六步:为了后期复制文件方便,我们需要设置机器间的免密
2、同理,分别设置p2、p3、p4免密。
第七步:配置虚拟机外网连接
1、保证VMware Network Adapter VMnet1是启用状态
2、将可以连接外网的连接共享属性设置成如下图所示
3、将VMware Network Adapter VMnet1的IP地址设置成与本机IP不同的网段即可
4、linux网络配置如下,同样保持一致
5.通过文件配置如下
6、测试网络连接
7、按照上述步骤分别检查4台机器的网络连接状态。
2.0Fabric入门
2.1先决条件
2.1.1Linux系统内核升级
升级Linux内核
yum update -y
查看内核版本
cat /proc/version
查看系统版本
cat /etc/issue
2.1.2安装git
yum install git
查看git版本
git version
2.1.3安装cURL
在Linux中curl是一个利用URL规则在命令行下工作的文件传输工具,可以说是一款很强大的http命令行工具。它支持文件的上传和下载,是综合传输工具,但按传统,习惯称url为下载工具。具体参考连接
https://www.cnblogs.com/duhuo/p/5695256.html
2.1.4安装docker和docker compose
卸载旧版本
首先需要对服务器进行清理, 如果之前安装过Docker , 需要先执行卸载操作,具体命令
如下:
sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-selinux docker-engine-selinux docker-engine
安装Docker CE
安装yum-utils提供的yum-config-manager,device-mapper-persistent-data和lvm2
sudo yum install yum-utils device-mapper-persistent-data lvm2
使用下面的命令来设置稳定存储库:
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
可以选择性地启用edge 和测试存储库,这些存储库包含在Docker 中,在默认情况下是禁用的。具体执行命令如下:
sudo yum-config-manager --enable docker-ce-edge
sudo yum-config-manager --enable docker-ce-test
也可以通过使用禁用标志来运行yum-config-manager 命令, 以禁用edge 或测试存储库。
要重新启用它, 可以使用-enable 标志。下面的命令禁用edge 存储库:
yum-config-manager --disable docker-ce-edge
最后, 可执行如下命令安装最新版本的Docker CE :
yum install docker-ce -y
还能通过如下命令安装指定版本的Docker CE :
yum install docker-ce -
执行查询Docke r 版本号, 看是否安装成功:
docker --version
Docker启动及常用命令
Docker CE 安装完成后, 需要启动它并设置为开机启动。
Docker 启动命令如下:
service docker start
Docker 开机自启动命令如下:
chkconfig docker on
Docker 常用命令如下。
杀死所有正在运行的容器:
docker kill $(docker ps -a -q)
删除所有己经停止的容器:
docker rm $(docker ps -a -q)
删除所有镜像:
docker rmi $(docker images -q)
强制删除所有镜像:
docker rmi -f $(docker images -q)
Docker-Compose 安装
Compose 是定义和运行多容器Docker 应用程序的工具,可以使用YAML 文件来配置应用服务。然后, 通过单个命令可以从配置中创建井启动所有服务。
要了解更多关于组合的特性,请参阅特性列表:
https://docs.docker.com/compose/overview/#features
使用Compose 基本上是一个三步骤的过程:
( 1 )用Dockerfile 定义应用程序的环境,这样它可以在任何地方复制。
(2 )通过docker-compose. yml 在服务中定义所启动的各个应用,这些应用将在相互隔离的环境中同时运行。
(3 )运行docke r-compose up ,启动Co mpo se 并运行整个应用程序。
在线安装Docker-Compose
安装Docker-Compose 需要服务器支持curl 命令,如果服务器不支持curl , 需要执行如下操作安装c url 依赖:
yum install curl
通过https://github.com/docker/compose/releases 网址,可以查看Docker Compose 最新发行版的动向。
执行如下操作下载Docke r Compose :
curl -L https://github.com/docker/compose/releases/download/1.23.2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
该下载目录为/usr/local/bin/docker-compose,且权限己经给出, 再执行docker-compose -version 检查版本号,或许会有如下提示:
-bash: /usr/bin/docker-compose: No such file or directory
如果出现上述提示, 则执行以下操作:
cp /usr/local/bin/docker-compose /usr/bin
将docker-compose 复制到/usr/ bin 目录下,再次执行:
docker-compose --version
正常情况下会打印docker-compose 的版本信息,如下所示:
docker-compose version 1.20.0-rc1, build 86428af
2.1.5 Go 语言环境安装
go1.13.X及以上版本
下载go语言包
wget https://studygolang.com/dl/golang/go1.14.linux-amd64.tar.gz
tar -C /usr/local -zxvf go1.14.linux-amd64.tar.gz
tar解压时遇到解压的部分文件丢失,从Windows上解压完再复制到虚拟机上,需要赋予go执行权限
chmod a+x /usr/local/go/bin/go
Go语言环境变量
考虑到以后将会在Go 语言中编写链码程序,有两个环境变量需要正确设置: 可以将这些设置永久地保存在适当的启动文件中。
修改/etc/profile 文件使其永久性生效,并对所有系统用户生效,在文件末尾加上如下两行代码:
export PATH=$PATH:/usr/local/go/bin
export GOPATH=/opt/gopath
生效配置文件
source /etc/profile
使其修改生效。随后可通过下述命令查看是否添加成功:
echo $PATH
最后,可通过如下命令查看当前Go 版本的信息:
go version
将go文件夹复制到其他机器
[root@p1 local]# scp -r go root@p2:/usr/local/
[root@p1 apps]# scp /etc/profile root@p2:/etc
[root@p1 local]# scp -r go root@p3:/usr/local/
[root@p1 apps]# scp /etc/profile root@p3:/etc
[root@p1 local]# scp -r go root@p4:/usr/local/
[root@p1 apps]# scp /etc/profile root@p4:/etc
[root@p1 apps]# ssh p2
[root@p2 ~]# source /etc/profile
[root@p1 apps]# ssh p3
[root@p3 ~]# source /etc/profile
[root@p1 apps]# ssh p4
[root@p4 ~]# source /etc/profile
2.1.6安装node.js
下载node-v13.11.0-linux-x64.tar.xz,并传送至虚拟机的/usr/local目录下,
解压node-v13.11.0-linux-x64.tar.xz
[root@p3 local]#tar xf node-v13.11.0-linux-x64.tar.xz
重命名下:
[root@p3 local]#mv node-v13.11.0-linux-x64 nodejs
建立软连接:
[root@p3 local]# ln -s /usr/local/nodejs/bin/npm /usr/local/bin/
[root@p3 local]# ln -s /usr/local/nodejs/bin/node /usr/local/bin/
查看版本号:
[root@p3 local]# npm -v
6.13.7
[root@p3 local]# node -v
v13.11.0
同理部署其他机器环境。
2.1.7安装python
根据官网介绍,Fabric Node.js SDK 需要 Python 2.7 进行相关操作。检查版本:
python --version
2.2fabric源码安装
下载项目到go目录并checkout到1.1分支
创建文件夹:
mkdir -p $GOPATH/src/github.com/hyperledger
进入文件夹:
cd $GOPATH/src/github.com/hyperledger
下载fabric:
git clone https://github.com/hyperledger/fabric.git
网速度太慢可以更换下载源,https://gitee.com/hbhssl/fabric.git
可以在码云上导入源码再clone到本地
2.2.1测试网络
确定机器上要放置Fabric-samples 存储库的位置,然后在终端窗口中输入该目录,我选取的是/opt/gopath/src/github.com/hyperledger。
如果要使用最新的生产版本,请省略所有版本标识符。
curl -sSL https://bit.ly/2ysbOFE | bash -s
或者
curl -sSL https : //raw.githubusercontent.com/hyperledger/fabric/master/scripts/bootstrap.sh | bash -s -- 2.0.0 1.4.4 0.4.18
下载指定版本:
curl -sSL https://bit.ly/2ysbOFE | bash -s --
例:
curl -sSL https://bit.ly/2ysbOFE | bash -s -- 2.0.0 1.4.4 0.4.18
将下载好的工具类添加到path中:
export PATH=/bin:$PATH
例:
export PATH=/opt/gopath/src/github.com/hyperledger/fabric-samples/bin:$PATH
建立测试网络
test-network在fabric-samples存储库目录中找到用于启动网络的脚本。使用以下命令导航到测试网络目录:
cd fabric-samples/test-network
从test-network目录内部,运行以下命令以从以前的运行中删除所有容器或工件:
./network.sh down
手动删除所有docker镜像
docker rm $(docker ps -a | grep "hyperledger/*" | awk "{print $1}") -f
清除以前的网络,提供全新的环境:
docker network prune
然后,您可以通过发出以下命令来启动网络:
./network.sh up
命令创建一个由两个对等节点(一个订购节点)组成的结构网络。您在运行时不会创建任何渠道,尽管我们将在以后的步骤中实现。如果命令成功完成,您将看到正在创建的节点的日志:
测试网络的组成部分
部署测试网络后,您可能需要一些时间来检查其组件。运行以下命令以列出计算机上运行的所有Docker容器。您应该看到该network.sh脚本创建的三个节点:
docker ps -a
建立通道
使用network.sh脚本在Org1和Org2之间创建频道,并将其对等方加入该频道。运行以下命令以使用默认名称创建频道mychannel:
./network.sh createChannel
命令成功执行,您将在日志中看到以下消息:
您也可以使用channel标志创建具有自定义名称的频道。例如,以下命令将创建一个名为的通道channel1:
./network.sh createChannel -c channel1
通道标志还允许您通过指定不同的通道名称来创建多个通道。创建mychannel或后channel1,您可以使用以下命令创建另一个名为的频道channel2:
./network.sh createChannel -c channel2
如果要一步一步建立网络并创建频道,可以将up和createChannel模式一起使用:
./network.sh up createChannel
在通道上启动链码
使用以下命令在频道上启动链码:
./network.sh deployCC
启动成功后在日志中看到以下汽车清单:
备注:
[root@p1 test-network]# ./network.sh deployCC
deploying chaincode on channel 'mychannel'
Vendoring Go dependencies ...
/opt/gopath/src/github.com/hyperledger/fabric-samples/chaincode/fabcar/go /opt/gopath/src/github.com/hyperledger/fabric-samples/test-network
/opt/gopath/src/github.com/hyperledger/fabric-samples/test-network
Finished vendoring Go dependencies
Using organization 1
++ peer lifecycle chaincode package fabcar.tar.gz --path ../chaincode/fabcar/go/ --lang golang --label fabcar_1
++ res=1
++ set +x
Error: failed to normalize chaincode path: 'go list' failed with: go tool asm: fork/exec /usr/local/go/pkg/tool/linux_amd64/asm: permission denied: exit status 1
!!!!!!!!!!!!!!! Chaincode packaging on peer0.org1 has failed !!!!!!!!!!!!!!!!
ERROR !!! Deploying chaincode failed
遇到以上问题是go配置过程中存在权限问题,赋权即可
[root@p1 test-network]# chmod -R 777 /usr/local/go
与网络互动
启动测试网络后,可以使用peerCLI与网络进行交互。peerCLI允许您从CLI调用已部署的智能合约,更新通道或安装和部署新的智能合约。
在test-network目录进行操作,使用以下命令将这些二进制文件添加到您的CLI路径
export PATH=${PWD}/../bin:${PWD}:$PATH
设置FABRIC_CFG_PATH指向存储库中的core.yaml文件fabric-samples:
export FABRIC_CFG_PATH=$PWD/../config/
设置环境变量,以允许您以peer Org1的形式操作CLI:
# Environment variables for Org1
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=localhost:7051
运行以下命令以获取已添加到通道分类帐中的汽车的列表:
peer chaincode query -C mychannel -n fabcar -c '{"Args":["queryAllCars"]}'
命令成功执行,则在运行脚本时,可以看到与日志中打印的汽车相同的列表:
当网络成员要转移或更改分类帐上的资产时,将调用链码。使用以下命令通过调用fabcar链码来更改分类帐中汽车的所有者:
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls true --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n fabcar --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"changeCarOwner","Args":["CAR9","Dave"]}'
命令成功,看到以下响应:
由于fabcar链码的背书策略要求事务由Org1和Org2签名,因此chaincode invoke命令需要既针对目标 peer0.org1.example.com又peer0.org2.example.com使用–peerAddresses 标志。由于已为网络启用TLS,因此该命令还需要使用该–tlsRootCertFiles标志为每个对等方引用TLS证书。
调用链代码后,我们可以使用另一个查询来查看该调用如何更改了区块链分类账上的资产。由于我们已经查询过Org1对等体,因此我们可以借此机会查询Org2对等体上运行的链码。设置以下环境变量以作为Org2进行操作:
# Environment variables for Org2
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=localhost:9051
查询在以下位置运行的fabcar链码peer0.org2.example.com:
peer chaincode query -C mychannel -n fabcar -c '{"Args":["queryAllCars"]}'
结果将显示"CAR9"已转移到Dave:
[{"Key":"CAR0", "Record":{"make":"Toyota","model":"Prius","colour":"blue","owner":"Tomoko"}},{"Key":"CAR1", "Record":{"make":"Ford","model":"Mustang","colour":"red","owner":"Brad"}},{"Key":"CAR2", "Record":{"make":"Hyundai","model":"Tucson","colour":"green","owner":"Jin Soo"}},{"Key":"CAR3", "Record":{"make":"Volkswagen","model":"Passat","colour":"yellow","owner":"Max"}},{"Key":"CAR4", "Record":{"make":"Tesla","model":"S","colour":"black","owner":"Adriana"}},{"Key":"CAR5", "Record":{"make":"Peugeot","model":"205","colour":"purple","owner":"Michel"}},{"Key":"CAR6", "Record":{"make":"Chery","model":"S22L","colour":"white","owner":"Aarav"}},{"Key":"CAR7", "Record":{"make":"Fiat","model":"Punto","colour":"violet","owner":"Pari"}},{"Key":"CAR8", "Record":{"make":"Tata","model":"Nano","colour":"indigo","owner":"Valeria"}},{"Key":"CAR9", "Record":{"make":"Holden","model":"Barina","colour":"brown","owner":"Dave"}}]
中断网络
使用完测试网络后,可以使用以下命令关闭网络:
./network.sh down
该命令将停止并删除节点和链码容器,删除组织加密材料,并从Docker注册表中移除链码映像。该命令还会从以前的运行中删除通道工件和docker卷,从而在遇到任何问题时允许您再次运行。./network.sh up
与证书颁发机构建立网络
运行以下命令以关闭所有正在运行的网络:
./network.sh down
然后,您可以使用CA标志启动网络:
./network.sh up -ca
运行成功后:
2.2.2开发应用程序-商业票据
先决条件
必备条件:node版本:8.9.0及以上;docker版本:18.06及以上
实用工具:VSCode:1.28及以上;NVM(node version manager)
安装NVM
[root@p1 p1]# git clone git://github.com/creationix/nvm.git ~/nvm
正克隆到 '/root/nvm'...
remote: Enumerating objects: 9, done.
remote: Counting objects: 100% (9/9), done.
remote: Compressing objects: 100% (8/8), done.
remote: Total 7694 (delta 1), reused 4 (delta 1), pack-reused 7685
接收对象中: 100% (7694/7694), 2.62 MiB | 236.00 KiB/s, done.
处理 delta 中: 100% (4865/4865), done.
[root@p1 p1]# command -v nvm
[root@p1 p1]# cd ~/nvm/
[root@p1 nvm]# command -v nvm
[root@p1 nvm]# echo "source ~/nvm/nvm.sh" >> ~/.bashrc
[root@p1 nvm]# source ~/.bashrc
[root@p1 nvm]# nvm list-remote
iojs-v1.0.0
iojs-v1.0.1
启动测试网络并使用商业票据目录中提供的脚本创建频道。转到commercial-paper目录fabric-samples:
cd fabric-samples/commercial-paper
然后使用脚本启动测试网络:
./network-starter.sh
如果命令成功执行,您将在日志中看到正在创建的测试网络。您可以使用以下命令查看在本地计算机上运行的Fabric节点:docker ps
[root@p1 commercial-paper]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e71c26ae5b0d hyperledger/fabric-peer:amd64-2.0.0 "peer node start" 51 seconds ago Up 49 seconds 7051/tcp, 0.0.0.0:9051->9051/tcp peer0.org2.example.com
14385bbf7601 hyperledger/fabric-peer:amd64-2.0.0 "peer node start" 51 seconds ago Up 49 seconds 0.0.0.0:7051->7051/tcp peer0.org1.example.com
d351ca080a3e hyperledger/fabric-orderer:amd64-2.0.0 "orderer" 53 seconds ago Up 51 seconds 0.0.0.0:7050->7050/tcp orderer.example.com
eaecd78a0449 hyperledger/fabric-couchdb "tini -- /docker-ent…" 53 seconds ago Up 51 seconds 4369/tcp, 9100/tcp, 0.0.0.0:5984->5984/tcp couchdb0
231c320876ec hyperledger/fabric-couchdb "tini -- /docker-ent…" 53 seconds ago Up 51 seconds 4369/tcp, 9100/tcp, 0.0.0.0:7984->5984/tcp couchdb1
对等端 节点 容器 组织 雇员
Org1 peer0.org1.example.com f98791ffa664 DigiBank Balaji
Org2 peer0.org2.example.com 78abb5575932 MagnetoCorp Isabella
Org1对等点CouchDB数据库 couchdb0 3624bddc453a DigiBank
Org2对等点CouchDB数据库 couchdb1 706481a0fed1 MagnetoCorp
Order orderer.example.com d1d4f45b10e3
这些容器都构成一个 名为的Docker网络net_test。您可以使用以下命令查看网络:docker network
[root@p1 commercial-paper]# docker network inspect net_test
[
{
"Name": "net_test",
"Id": "dd33aca5a020694d86a5a78f26e1497b5292caa65b7e64aa0046b97d5cd62e01",
"Created": "2020-04-01T14:17:04.910883091+08:00",
"Scope": "local",
"Driver": "bridge",
"EnableIPv6": false,
"IPAM": {
"Driver": "default",
"Options": null,
"Config": [
{
"Subnet": "172.20.0.0/16",
"Gateway": "172.20.0.1"
}
]
},
"Internal": false,
"Attachable": false,
"Ingress": false,
"ConfigFrom": {
"Network": ""
},
"ConfigOnly": false,
"Containers": {
"3624bddc453a64427db1ca727b4067859fa5fd8b5ec1cdbef0a390fc4f52f0ec": {
"Name": "couchdb0",
"EndpointID": "178b94184377b6b031b4775fbd079df3e4c01baf31984ebff761709975b8f226",
"MacAddress": "02:42:ac:14:00:04",
"IPv4Address": "172.20.0.4/16",
"IPv6Address": ""
},
"706481a0fed13e3f226dd06bd67cfb22f3efbc2edb40e604e98645cba017a9b2": {
"Name": "couchdb1",
"EndpointID": "72bed54d83e4d170f3594c3c73683924ba6f4e477f1d5a5167de178dd2f12c24",
"MacAddress": "02:42:ac:14:00:03",
"IPv4Address": "172.20.0.3/16",
"IPv6Address": ""
},
"78abb5575932dd704df8555df4144126ffab8617d231639c1a05fb9908ad9bdc": {
"Name": "peer0.org2.example.com",
"EndpointID": "3b684c8035874ac005370b6bff4108af71925a4a429d7156412b965f904a8ff7",
"MacAddress": "02:42:ac:14:00:05",
"IPv4Address": "172.20.0.5/16",
"IPv6Address": ""
},
"d1d4f45b10e3620057d0b9b9e18585570aa3c37ae5912f34595ebca83098de76": {
"Name": "orderer.example.com",
"EndpointID": "5583465ee920cfddaf5592e949b16306a1cb8561bc38a47f6ecc44ae9807b31f",
"MacAddress": "02:42:ac:14:00:02",
"IPv4Address": "172.20.0.2/16",
"IPv6Address": ""
},
"f98791ffa664a1bfeef6b608a95019f691b1c480f692e638a57095bd167d414d": {
"Name": "peer0.org1.example.com",
"EndpointID": "9154602ebabebc76fe83ad582dc8ca2ac72eb15f3db8b75ab2616ca7b617d8e8",
"MacAddress": "02:42:ac:14:00:06",
"IPv4Address": "172.20.0.6/16",
"IPv6Address": ""
}
},
"Options": {},
"Labels": {}
}
]
作为MagnetoCorp监视网络
在fabric-samples存储库中打开一个新窗口,并使用以下命令切换到MagnetoCorp目录:
cd commercial-paper/organization/magnetocorp
为方便查看日志,可以安装logspout工具,该工具将不同的输出流收集到一个位置,从而可以轻松地从单个窗口查看正在发生的情况。
为方便代码编辑,选用vscode。
在MagnetoCorp目录中,运行以下命令以运行 monitordocker.sh 脚本并启动logspout与PaperNet相关的容器的工具net_test:
[root@p1 magnetocorp]# ./configuration/cli/monitordocker.sh net_test
成功后:
[root@p1 cli]# ./monitordocker.sh net_test
Starting monitoring on all containers on the network net_test
3cb93b55cc12a71ea9899673527d81bee537a003d97230bb3d6397a1e412e368
curl: (56) Recv failure: Connection reset by peer
现在,该窗口将显示本教程其余部分中Docker容器的输出,因此继续并打开另一个命令窗口。我们要做的下一步是检查MagnetoCorp将用于向商业票据发行的智能合约。
遇到以下问题:
[root@p1 cli]# ./monitordocker.sh net_test
Starting monitoring on all containers on the network net_test
WARNING: IPv4 forwarding is disabled. Networking will not work.
1c1855c7ded0f3a52178fadd98f5ba53873dabb07fdb498b01b52d68d825df5f
curl: (56) Recv failure: Connection reset by peer
解决方法:
[root@p1 cli]# vim /usr/lib/sysctl.d/00-system.conf
添加如下代码:
net.ipv4.ip_forward=1
重启network服务:
[root@p1 cli]# systemctl restart network
检查商业票据智能合约
issue,buy并且redeem是在商业票据智能合同心脏的三个功能。应用程序使用它来提交交易,这些交易相应地在分类账上发行,购买和赎回商业票据。我们的下一个任务是检查智能合约。
在fabric-samples目录中打开一个新终端,然后切换到MagnetoCorp文件夹以充当MagnetoCorp开发人员。然后,您可以contract使用选择的编辑器(在本教程中为VS Code)在目录中查看智能合约:【非root用户下进行code操作】。在lib文件夹目录中,您将看到papercontract.js文件-其中包含商业票据智能合约!
将智能合约部署到渠道
在papercontract被应用程序调用之前,必须将其安装到测试网络的适当对等节点上,然后使用Fabric链码生命周期在通道上进行定义。Fabric链码生命周期允许多个组织在将链码部署到通道之前就链码的参数达成一致。因此,我们需要以MagnetoCorp和DigiBank的管理员身份安装和批准链码。
MagnetoCorp管理员将的副本安装papercontract到MagnetoCorp对等方。
智能合约是应用程序开发的重点,并且包含在称为chaincode的Hyperledger Fabric工件中。可以在单个链码中定义一个或多个智能合约,安装链码将允许PaperNet中的不同组织使用它们。这意味着只有管理员才需要担心链码。其他人都可以根据智能合约进行思考。
以MagnetoCorp的形式安装和批准智能合约
以MagnetoCorp管理员的身份安装和批准智能合约。确保您正在该magnetocorp文件夹中进行操作。MagnetoCorp管理员可以使用peerCLI 与PaperNet进行交互。但是,管理员需要在命令窗口中设置某些环境变量,以使用正确的peer二进制集,将命令发送到MagnetoCorp对等方的地址,并使用正确的加密材料对请求进行签名。您可以使用示例提供的脚本在命令窗口中设置环境变量。在magnetocorp目录中运行以下命令:
source magnetocorp.sh
您将在窗口中看到环境变量的完整列表。现在,我们可以使用此命令窗口以MagnetoCorp管理员的身份与PaperNet进行交互。
第一步是安装papercontract智能合约。可以使用以下命令将智能合约打包为链码 。在MagnetoCorp管理员的命令窗口中,运行以下命令来创建chaincode包:peer lifecycle chaincode package
(magnetocorp admin)$ peer lifecycle chaincode package cp.tar.gz --lang node --path ./contract --label cp_0
MagnetoCorp管理员现在可以使用以下命令在MagnetoCorp对等方上安装链码:peer lifecycle chaincode install
(magnetocorp admin)$ peer lifecycle chaincode install cp.tar.gz
如果命令成功执行,您将在终端上看到类似于以下内容的消息:
[root@p1 magnetocorp]# peer lifecycle chaincode install cp.tar.gz
2020-04-01 14:29:30.105 CST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response:
2020-04-01 14:29:30.114 CST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: cp_0:5190287c1ce48b1147206e66d5e7e7d968708719aea167dcbaa824101af3b40c
[root@p1 magnetocorp]#
[root@p1 magnetocorp]# source magnetocorp.sh
Using organization 2
Using organization 2
export CORE_PEER_ADDRESS="localhost:9051"
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_MSPCONFIGPATH="/opt/gopath/src/github.com/hyperledger/fabric-samples/test-network/organizations/peerOrganizations/org2.example.com/users/[email protected]/msp"
export CORE_PEER_TLS_ENABLED="true"
export CORE_PEER_TLS_ROOTCERT_FILE="/opt/gopath/src/github.com/hyperledger/fabric-samples/test-network/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt"
export FABRIC_CFG_PATH="/opt/gopath/src/github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp/../../../config"
export ORDERER_CA="/opt/gopath/src/github.com/hyperledger/fabric-samples/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem"
export PATH="/opt/gopath/src/github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp/../../../bin:/opt/gopath/src/github.com/hyperledger/fabric-samples/test-network:/root/.sdkman/candidates/java/current/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/usr/local/go/bin:/usr/local/jdk8/bin:/usr/local/maven/bin:/home/p1/.nvm/nvm.sh:/home/p1/.local/bin:/home/p1/bin"
export PEER0_ORG1_CA="/opt/gopath/src/github.com/hyperledger/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt"
export PEER0_ORG2_CA="/opt/gopath/src/github.com/hyperledger/fabric-samples/test-network/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt"
export PEER0_ORG3_CA="/opt/gopath/src/github.com/hyperledger/fabric-samples/test-network/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt"
export PEER_PARMS="--peerAddresses localhost:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric-samples/test-network/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt"
rm:是否删除普通文件 "/tmp/env.orig"?
[root@p1 magnetocorp]#
[root@p1 magnetocorp]#
[root@p1 magnetocorp]#
[root@p1 magnetocorp]# peer lifecycle chaincode package cp.tar.gz --lang node --path ./contract --label cp_0
[root@p1 magnetocorp]# peer lifecycle chaincode install cp.tar.gz
2020-04-01 14:29:30.105 CST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response:
2020-04-01 14:29:30.114 CST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: cp_0:5190287c1ce48b1147206e66d5e7e7d968708719aea167dcbaa824101af3b40c
[root@p1 magnetocorp]#
由于MagnetoCorp管理员已将CORE_PEER_ADDRESS=localhost:9051其命令设置为peer0.org2.example.com,因此 表示该对象已成功安装。INFO 001 Installed remotely…``papercontract
安装智能合约后,我们需要批准链码定义为papercontractMagnetoCorp。第一步是找到我们安装在对等方上的链码的packageID。我们可以使用以下命令查询packageID :peer lifecycle chaincode queryinstalled
[root@p1 magnetocorp]# peer lifecycle chaincode queryinstalled
Installed chaincodes on peer:
Package ID: cp_0:5190287c1ce48b1147206e66d5e7e7d968708719aea167dcbaa824101af3b40c, Label: cp_0
下一步将需要包ID,因此我们将其保存为环境变量。软件包ID可能对于所有用户而言都不相同,因此您需要使用从命令窗口返回的软件包ID来完成此步骤。
[root@p1 magnetocorp]# export PACKAGE_ID=cp_0:5190287c1ce48b1147206e66d5e7e7d968708719aea167dcbaa824101af3b40c
管理员现在可以使用以下命令批准MagnetoCorp的链码定义 :peer lifecycle chaincode approveformyorg
[root@p1 magnetocorp]# peer lifecycle chaincode approveformyorg --orderer localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name papercontract -v 0 --package-id $PACKAGE_ID --sequence 1 --tls --cafile $ORDERER_CA
2020-04-01 14:44:19.022 CST [chaincodeCmd] ClientWait -> INFO 001 txid [fcef4e37aed66f2d8ed5f81bc4e2e2a5fd93cadaae9fce5ecfe3a4945cfa6ca8] committed with status (VALID) at
[root@p1 magnetocorp]#
作为DigiBank安装并批准智能合约
默认情况下,结构链代码生命周期需要通道上的大多数组织才能将链代码定义成功提交到通道。这意味着我们需要批准papernet链码为MagnetoCorp和DigiBank,以从2中获得必需的多数。在中打开一个新的终端窗口,导航到目录/opt/gopath/src/github.com/hyperledger/fabric-samples/commercial-paper/organization/magnetocorp。
使用DigiBank文件夹中的脚本设置环境变量,使您可以充当DigiBank管理员:
source digibank.sh
我们现在可以安装并批准papercontract为DigiBank。运行以下命令来打包链码:
(digibank admin)$ peer lifecycle chaincode package cp.tar.gz --lang node --path ./contract --label cp_0
管理员现在可以在DigiBank对等方上安装链码了:
(digibank admin)$ peer lifecycle chaincode install cp.tar.gz
然后,我们需要查询并保存刚刚安装的链码的packageID:
(digibank admin)$ peer lifecycle chaincode queryinstalled
将程序包ID保存为环境变量。使用从控制台返回的程序包ID完成此步骤。
export PACKAGE_ID=cp_0:ffda93e26b183e231b7e9d5051e1ee7ca47fbf24f00a8376ec54120b1a2a335c
Digibank管理员现在可以批准以下链代码的定义papercontract:
(digibank admin)$ peer lifecycle chaincode approveformyorg --orderer localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name papercontract -v 0 --package-id $PACKAGE_ID --sequence 1 --tls --cafile $ORDERER_CA
以上步骤的完整操作过程如下:
[root@p1 p1]# cd /opt/gopath/src/github.com/hyperledger/fabric-samples/commercial-paper/organization/digibank/
[root@p1 digibank]# ll
总用量 4
drwxr-xr-x. 2 root root 117 3月 26 14:50 application
drwxr-xr-x. 4 root root 119 3月 26 14:50 application-java
drwxr-xr-x. 3 root root 17 3月 26 14:50 configuration
drwxr-xr-x. 5 root root 163 3月 26 14:50 contract
drwxr-xr-x. 4 root root 91 3月 26 14:50 contract-go
drwxr-xr-x. 4 root root 153 3月 26 14:50 contract-java
-rwxr-xr-x. 1 root root 738 3月 26 14:50 digibank.sh
drwxr-xr-x. 2 root root 50 3月 26 16:39 gateway
[root@p1 digibank]# source digibank.sh
Using organization 1
Using organization 1
export CORE_PEER_ADDRESS="localhost:7051"
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_MSPCONFIGPATH="/opt/gopath/src/github.com/hyperledger/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/users/[email protected]/msp"
export CORE_PEER_TLS_ENABLED="true"
export CORE_PEER_TLS_ROOTCERT_FILE="/opt/gopath/src/github.com/hyperledger/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt"
export FABRIC_CFG_PATH="/opt/gopath/src/github.com/hyperledger/fabric-samples/commercial-paper/organization/digibank/../../../config"
export ORDERER_CA="/opt/gopath/src/github.com/hyperledger/fabric-samples/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem"
export PATH="/opt/gopath/src/github.com/hyperledger/fabric-samples/commercial-paper/organization/digibank/../../../bin:/opt/gopath/src/github.com/hyperledger/fabric-samples/test-network:/root/.sdkman/candidates/java/current/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/usr/local/go/bin:/usr/local/jdk8/bin:/usr/local/maven/bin:/home/p1/.nvm/nvm.sh:/home/p1/.local/bin:/home/p1/bin"
export PEER0_ORG1_CA="/opt/gopath/src/github.com/hyperledger/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt"
export PEER0_ORG2_CA="/opt/gopath/src/github.com/hyperledger/fabric-samples/test-network/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt"
export PEER0_ORG3_CA="/opt/gopath/src/github.com/hyperledger/fabric-samples/test-network/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt"
export PEER_PARMS="--peerAddresses localhost:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric-samples/test-network/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt"
rm:是否删除普通文件 "/tmp/env.orig"?
[root@p1 digibank]#
[root@p1 digibank]#
[root@p1 digibank]# peer lifecycle chaincode package cp.tar.gz --lang node --path ./contract --label cp_0
[root@p1 digibank]# peer lifecycle chaincode install cp.tar.gz
2020-04-01 14:53:01.789 CST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response:
2020-04-01 14:53:01.789 CST [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: cp_0:46eb5e8fae138e4ba37621951bc4a77ef9efad45a8da5aa57b0b3ac817214594
[root@p1 digibank]#
[root@p1 digibank]#
[root@p1 digibank]# peer lifecycle chaincode queryinstalled
Installed chaincodes on peer:
Package ID: cp_0:46eb5e8fae138e4ba37621951bc4a77ef9efad45a8da5aa57b0b3ac817214594, Label: cp_0
[root@p1 digibank]# export PACKAGE_ID=cp_0:46eb5e8fae138e4ba37621951bc4a77ef9efad45a8da5aa57b0b3ac817214594
[root@p1 digibank]# peer lifecycle chaincode approveformyorg --orderer localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name papercontract -v 0 --package-id $PACKAGE_ID --sequence 1 --tls --cafile $ORDERER_CA
2020-04-01 14:54:53.696 CST [chaincodeCmd] ClientWait -> INFO 001 txid [166979b110b2fc48e1612775e1bb937bbf80e2aefff3d33ca93456052921ef72] committed with status (VALID) at
将链码定义提交给通道
DigiBank和MagnetoCorp都已批准了papernet链码,我们将需要大多数(2之2)来将链码定义提交给渠道。一旦在通道上成功定义了链码,链码中的 CommercialPaper智能合约papercontract就可以由通道上的客户端应用程序调用。由于任何一个组织都可以将链码提交给渠道,因此我们将继续以DigiBank管理员身份进行操作:
DigiBank管理员将链码的定义提交papercontract到通道后,将创建一个新的Docker链码容器,以papercontract在两个PaperNet对等体上运行
DigiBank管理员使用命令将链码定义提交到:peer lifecycle chaincode commitpapercontract
mychannel
[root@p1 digibank]# peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --peerAddresses localhost:7051 --tlsRootCertFiles ${PEER0_ORG1_CA} --peerAddresses localhost:9051 --tlsRootCertFiles ${PEER0_ORG2_CA} --channelID mychannel --name papercontract -v 0 --sequence 1 --tls --cafile $ORDERER_CA --waitForEvent
2020-04-01 14:57:36.642 CST [chaincodeCmd] ClientWait -> INFO 001 txid [029d759bd82de1740ed76728047e96a91efac7eb1f28de538dd765030f858b70] committed with status (VALID) at localhost:9051
2020-04-01 14:57:36.725 CST [chaincodeCmd] ClientWait -> INFO 002 txid [029d759bd82de1740ed76728047e96a91efac7eb1f28de538dd765030f858b70] committed with status (VALID) at localhost:7051
[root@p1 digibank]#
链码容器将在链码定义提交到通道后启动。您可以使用该命令查看 在两个对等方上都启动的容器。docker ps``papercontract
[root@p1 digibank]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
522d8ce4e992 dev-peer0.org2.example.com-cp_0-5190287c1ce48b1147206e66d5e7e7d968708719aea167dcbaa824101af3b40c-e07b3b06d71856bbf3231a90f87ad03cdf794073bb87c25b588394a6cc3bf823 "docker-entrypoint.s…" About a minute ago Up About a minute dev-peer0.org2.example.com-cp_0-5190287c1ce48b1147206e66d5e7e7d968708719aea167dcbaa824101af3b40c
d06b016497f9 dev-peer0.org1.example.com-cp_0-46eb5e8fae138e4ba37621951bc4a77ef9efad45a8da5aa57b0b3ac817214594-724a34ef3af63e0cb26768193198f7a571f3f1ccf691374e09b75f2986f1e63d "docker-entrypoint.s…" About a minute ago Up About a minute dev-peer0.org1.example.com-cp_0-46eb5e8fae138e4ba37621951bc4a77ef9efad45a8da5aa57b0b3ac817214594
4272461910da gliderlabs/logspout "/bin/logspout" 36 minutes ago Up 36 minutes 127.0.0.1:8000->80/tcp logspout
f98791ffa664 hyperledger/fabric-peer:amd64-2.0.0 "peer node start" 41 minutes ago Up 41 minutes 0.0.0.0:7051->7051/tcp peer0.org1.example.com
78abb5575932 hyperledger/fabric-peer:amd64-2.0.0 "peer node start" 41 minutes ago Up 41 minutes 7051/tcp, 0.0.0.0:9051->9051/tcp peer0.org2.example.com
d1d4f45b10e3 hyperledger/fabric-orderer:amd64-2.0.0 "orderer" 41 minutes ago Up 41 minutes 0.0.0.0:7050->7050/tcp orderer.example.com
3624bddc453a hyperledger/fabric-couchdb "tini -- /docker-ent…" 41 minutes ago Up 41 minutes 4369/tcp, 9100/tcp, 0.0.0.0:5984->5984/tcp couchdb0
706481a0fed1 hyperledger/fabric-couchdb "tini -- /docker-ent…" 41 minutes ago Up 41 minutes 4369/tcp, 9100/tcp, 0.0.0.0:7984->5984/tcp couchdb1
[root@p1 digibank]#
应用结构
papercontractMagnetoCorp的应用程序调用其中包含的智能合约issue.js。伊莎贝拉(Isabella)使用该应用程序向发行商业票据的总账提交交易00001。让我们快速检查一下issue应用程序如何工作。
网关允许应用程序专注于事务的生成,提交和响应。它协调不同网络组件之间的交易建议,订购和通知处理。
因为该issue应用程序代表Isabella提交事务,所以它首先从她的钱包中检索Isabella的X.509证书,该证书 可能存储在本地文件系统或硬件安全模块 HSM中。然后,issue 应用程序可以利用网关在通道上提交事务。Hyperledger Fabric SDK提供了 网关抽象,因此应用程序可以在将网络交互委派给网关的同时专注于应用程序逻辑。网关和钱包使编写Hyperledger Fabric应用程序变得很简单。
因此,让我们检查一下issueIsabella将要使用的应用程序。为她打开一个单独的终端窗口,然后fabric-samples找到MagnetoCorp /application文件夹:
(isabella)$ cd commercial-paper/organization/magnetocorp/application/
(isabella)$ ls
addToWallet.js issue.js package.json
addToWallet.js是Isabella将用于将其身份加载到她的钱包中的程序,issue.js并将通过使用该身份00001代表MagnetoCorp 创建商业票据papercontract。
转到包含MagnetoCorp应用程序副本的目录 issue.js,然后使用代码编辑器进行检查:
(isabella)$ cd commercial-paper/organization/magnetocorp/application
(isabella)$ code issue.js
检查该目录;它包含问题应用程序及其所有依赖项。
请注意以下关键程序行issue.js:
随时检查目录中的其他文件/application以了解其issue.js工作原理,并在应用程序主题中详细阅读其实现方式。
应用程序依赖
该issue.js应用程序是用JavaScript编写的,旨在在作为PaperNet网络客户端的Node.js环境中运行。按照惯例,MagnetoCorp的应用程序建立在许多外部节点程序包上-以提高开发质量和速度。考虑一下issue.js包括js-yaml 包处理YAML网关连接配置文件,或fabric-network 包访问的Gateway 和Wallet类:
const yaml = require('js-yaml');
const { Wallets, Gateway } = require('fabric-network');
必须使用以下命令将这些软件包从npm下载到本地文件系统。按照惯例,必须将软件包安装到相对于应用程序的目录中,以便在运行时使用。npm install``/node_modules
检查package.json文件以查看如何issue.js标识要下载的软件包及其确切版本:
"dependencies": {
"fabric-network": "~1.4.0",
"fabric-client": "~1.4.0",
"js-yaml": "^3.12.0"
},
npm版本控制功能非常强大;您可以在此处了解更多信息 。
让我们使用命令安装这些软件包-这可能需要一分钟才能完成:npm install
上图为执行前后结果对比。
检查node_modules目录以查看已安装的软件包。有很多,因为js-yaml和fabric-network本身是基于其他npm软件包构建的!有用的是,该package-lock.json 文件标识了所安装的确切版本,如果您想精确地复制环境,这可以证明是无价的。测试,诊断问题或交付经过验证的应用程序。
钱包
伊莎贝拉几乎准备issue.js发行MagnetoCorp商业票据 00001; 剩下要做的一项任务!由于issue.js代表伊莎贝拉(Isabella)并因此代表MagnetoCorp,它将使用她钱包中的身份来 反映这些事实。现在,我们需要执行此一次性活动,向她的钱包添加适当的X.509凭据。
在Isabella的终端窗口中,运行addToWallet.js程序以将身份信息添加到她的钱包:
(isabella)$ node addToWallet.js
done
addToWallet.js是一个简单的文件复制程序,您可以随时检查。它将身份从测试网络样本移至Isabella的钱包。让我们关注该程序的结果-用来向PaperNet提交交易的钱包内容:
(isabella)$ ls ../identity/user/isabella/wallet/
isabella.id
Isabella可以在她的钱包中存储多个身份,尽管在我们的示例中,她仅使用一个。该wallet文件夹包含一个isabella.id文件,该文件提供Isabella连接到网络所需的信息。伊莎贝拉(Isabella)使用的其他身份将拥有自己的文件。您可以打开此文件以查看issue.js将在JSON文件中代表Isabella使用的身份信息。为了清楚起见,已对输出进行格式化。
(isabella)$ cat ../identity/user/isabella/wallet/*
{
"credentials": {
"certificate": "-----BEGIN CERTIFICATE-----\nMIICKTCCAdCgAwIBAgIQWKwvLG+sqeO3LwwQK6avZDAKBggqhkjOPQQDAjBzMQsw\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy\nYW5jaXNjbzEZMBcGA1UEChMQb3JnMi5leGFtcGxlLmNvbTEcMBoGA1UEAxMTY2Eu\nb3JnMi5leGFtcGxlLmNvbTAeFw0yMDAyMDQxOTA5MDBaFw0zMDAyMDExOTA5MDBa\nMGwxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T\nYW4gRnJhbmNpc2NvMQ8wDQYDVQQLEwZjbGllbnQxHzAdBgNVBAMMFlVzZXIxQG9y\nZzIuZXhhbXBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAT4TnTblx0k\ngfqX+NN7F76Me33VTq3K2NUWZRreoJzq6bAuvdDR+iFvVPKXbdORnVvRSATcXsYl\nt20yU7n/53dbo00wSzAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADArBgNV\nHSMEJDAigCDOCdm4irsZFU3D6Hak4+84QRg1N43iwg8w1V6DRhgLyDAKBggqhkjO\nPQQDAgNHADBEAiBhzKix1KJcbUy9ey5ulWHRUMbqdVCNHe/mRtUdaJagIgIgYpbZ\nXf0CSiTXIWOJIsswN4Jp+ZxkJfFVmXndqKqz+VM=\n-----END CERTIFICATE-----\n",
"privateKey": "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQggs55vQg2oXi8gNi8\nNidE8Fy5zenohArDq3FGJD8cKU2hRANCAAT4TnTblx0kgfqX+NN7F76Me33VTq3K\n2NUWZRreoJzq6bAuvdDR+iFvVPKXbdORnVvRSATcXsYlt20yU7n/53db\n-----END PRIVATE KEY-----\n"
},
"mspId": "Org2MSP",
"type": "X.509",
"version": 1
}
在文件中,您会注意到以下内容:
您可以在此处了解有关证书的更多信息。实际上,证书文件还包含某些特定于Fabric的元数据,例如Isabella的组织和角色-在wallet主题中了解更多。
发行申请
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。
如您所见,为了实现这一点,应用程序调用issue中的CommercialPaper智能合约中定义的交易papercontract.js。MagnetoCorp管理员已在网络中安装并实例化了该文件。这是智能合约,它通过Fabric API与分类帐进行交互,最著名的是putState()和getState(),将新的商业票据表示为世界状态内的向量状态。我们将看到智能载体中也定义了buy和redeem事务随后如何操纵此向量状态。
底层的Fabric SDK一直都在处理交易认可,订购和通知过程,从而使应用程序的逻辑简单明了;SDK使用网关提取网络详细信息和 connectionOptions来声明更高级的处理策略,例如事务重试。
现在,让我们关注MagnetoCorp 00001的生命周期,将重点转移到DigiBank的一名员工Balaji,他将使用DigiBank应用程序购买该商业票据。
Digibank应用
Balaji使用DigiBank的buy应用程序向分类帐提交交易,分类帐将商业票据的所有权00001从MagnetoCorp转移到DigiBank。该CommercialPaper智能合同是一样的,通过MagnetoCorp的应用程序使用,然而该交易不同,这一次-这是buy不是issue。让我们检查DigiBank的应用程序如何工作。
打开Balaji的单独终端窗口。在中fabric-samples,转到包含应用程序的DigiBank应用程序目录,buy.js然后使用编辑器将其打开:
(balaji)$ cd commercial-paper/organization/digibank/application/
(balaji)$ code buy.js
如您所见,此目录同时包含Balaji将使用的buy和redeem应用程序。
DigiBank的商业票据目录包含buy.js和redeem.js 应用程序。
DigiBank的buy.js应用程序在结构上issue.js与MagnetoCorp的应用程序非常相似,但 有两个重要区别:
随时检查目录中的其他文件application以了解应用程序如何工作,并详细阅读buy.js应用程序主题中如何实现。
以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 [email protected]
(...)
added 738 packages in 46.701s
在Balaji的命令窗口中,运行addToWallet.js程序以将身份添加到他的钱包:
(balaji)$ node addToWallet.js
done
该addToWallet.js程序已将的身份信息添加balaji到他的钱包,该信息将被用来向buy.js并redeem.js提交交易 PaperNet。
与Isabella一样,Balaji可以在他的钱包中存储多个身份,尽管在我们的示例中,他仅使用一个。他对应的id文件digibank/identity/user/balaji/wallet/balaji.id与Isabella的文件 非常相似-请随时检查。
购买申请
Balaji现在可以buy.js用来提交一笔交易,该交易会将MagnetoCorp商业票据00001的所有权转让给DigiBank。
buy在Balaji的窗口中运行该应用程序:
(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调用了智能合约中buy定义的交易,该 交易使用和 Fabric API 在世界范围内CommercialPaper更新了商业票据。如您所见,购买和发行商业票据的应用程序逻辑与智能合约逻辑非常相似。00001putState()
getState()
兑换申请
商业票据00001生命周期中的最后一笔交易是DigiBank用MagnetoCorp赎回的。Balaji用于redeem.js提交交易以执行智能合约中的兑换逻辑。
redeem在Balaji的窗口中运行事务:
(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调用中redeem定义的交易时如何成功赎回商业票据00001 CommercialPaper。再次,它更新00001了世界范围内的商业票据,以反映所有权归还给票据发行人MagnetoCorp。
清理
完成使用《商业票据》教程后,您可以使用脚本来清理环境。使用命令窗口导航回到商业票据样本的根目录:
cd fabric-samples/commercial-paper
然后,您可以使用以下命令关闭网络:
./network-clean.sh
除logspout工具外,此命令还将关闭对等方,CouchDB容器和网络的订购节点。它还将删除我们为Isabella和Balaji创建的身份。请注意,分类账上的所有数据都将丢失。如果您想再次阅读本教程,则将从一个干净的初始状态开始。
2.3在结构中使用私有数据
参考网址:https://hyperledger-fabric.readthedocs.io/en/latest/private_data_tutorial.html
3.fabric-sdk-java
3.1java环境安装
首先需要卸载openjdk,查看已安装的jdk
--查看已安装的jdk:
[root@p1 p1]# rpm -qa|grep jdk
--卸载
[root@localhost ~]# yum -y remove java*
--查看版本
[root@localhost ~]# java -version
安装
--解压文件、重命名,复制到软件安装目录
[root@p1 apps]# tar -zxvf jdk-8u221-linux-x64.tar.gz
[root@p1 apps]# mv jdk1.8.0_221 jdk8
[root@p1 apps]# cp -r jdk8/ /usr/local/
--配置环境变量
[root@p1 apps]# vim /etc/profile
--将以下内容复制到文件中保存退出
#JAVA1.8
export JAVA_HOME=/usr/local/jdk8
export PATH=$PATH:$JAVA_HOME/bin
export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
--将以上内容复制到文件中保存退出
[root@p1 apps]# source /etc/profile
[root@p1 apps]# java -version
java version "1.8.0_221"
Java(TM) SE Runtime Environment (build 1.8.0_221-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.221-b11, mixed mode)
3.2maven环境安装
下载安装包、重命名、配置环境变量
[root@p1 apps]# ls
fabric go1.14.linux-amd64.tar.gz jdk8 nodejs
go hbhssl-fabric-master.zip jdk-8u221-linux-x64.tar.gz node-v13.11.0-linux-x64.tar.xz
[root@p1 apps]# wget http://mirrors.hust.edu.cn/apache/maven/maven-3/3.1.1/binaries/apache-maven-3.1.1-bin.tar.gz
--2020-03-27 09:49:06-- http://mirrors.hust.edu.cn/apache/maven/maven-3/3.1.1/binaries/apache-maven-3.1.1-bin.tar.gz
正在解析主机 mirrors.hust.edu.cn (mirrors.hust.edu.cn)... 202.114.18.160
正在连接 mirrors.hust.edu.cn (mirrors.hust.edu.cn)|202.114.18.160|:80... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度:5494427 (5.2M) [application/octet-stream]
正在保存至: “apache-maven-3.1.1-bin.tar.gz”
100%[=============================================================================================>] 5,494,427 4.38MB/s 用时 1.2s
2020-03-27 09:49:07 (4.38 MB/s) - 已保存 “apache-maven-3.1.1-bin.tar.gz” [5494427/5494427])
[root@p1 apps]# ls
apache-maven-3.1.1-bin.tar.gz go1.14.linux-amd64.tar.gz jdk-8u221-linux-x64.tar.gz
fabric hbhssl-fabric-master.zip nodejs
go jdk8 node-v13.11.0-linux-x64.tar.xz
[root@p1 apps]# tar zxf apache-maven-3.1.1-bin.tar.gz
[root@p1 apps]# ls
apache-maven-3.1.1 fabric go1.14.linux-amd64.tar.gz jdk8 nodejs
apache-maven-3.1.1-bin.tar.gz go hbhssl-fabric-master.zip jdk-8u221-linux-x64.tar.gz node-v13.11.0-linux-x64.tar.xz
[root@p1 apps]# mv apache-maven-3.1.1 maven
[root@p1 apps]# ls
apache-maven-3.1.1-bin.tar.gz go1.14.linux-amd64.tar.gz jdk-8u221-linux-x64.tar.gz node-v13.11.0-linux-x64.tar.xz
fabric hbhssl-fabric-master.zip maven
go jdk8 nodejs
[root@p1 apps]# cp -r maven/ /usr/local/
[root@p1 apps]# cd /usr/local/
[root@p1 local]# ls
bin etc games go include jdk8 lib lib64 libexec maven nodejs sbin share src
[root@p1 local]# vim /etc/profile
--将以下内容复制到文件中
#maven
export M2_HOME=/usr/local/maven
export PATH=$PATH:$JAVA_HOME/bin:$M2_HOME/bin
--将以上内容复制到文件中
[root@p1 local]# source /etc/profile
/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/usr/local/go/bin:/home/p1/.local/bin:/home/p1/bin:/usr/local/jdk8/bin
[root@p1 local]# mvn -v
Apache Maven 3.1.1 (0728685237757ffbf44136acec0402957f723d9a; 2013-09-17 23:22:22+0800)
Maven home: /usr/local/maven
Java version: 1.8.0_221, vendor: Oracle Corporation
Java home: /usr/local/jdk8/jre
Default locale: zh_CN, platform encoding: UTF-8
OS name: "linux", version: "3.10.0-1062.18.1.el7.x86_64", arch: "amd64", family: "unix"
4.0blockchain-explorer
1、blockchain-explorer/app/persistence/postgreSQL/db目录下执行./createdb.sh
[root@host-192-100-36-247 blockchain-explorer]# cd app/persistence/postgreSQL/db
[root@host-192-100-36-247 blockchain-explorer]# ./createdb.sh
2、进入blockchain-explorer目录,执行npm install --unsafe-perm下载依赖文件夹node_modules
[root@host-192-100-36-247 blockchain-explorer]# npm install --unsafe-perm
3、接下来进入blockchain-explorer/ cd app/test/ 目录下执行npm install下载对应的依赖模块:
[root@host-192-100-36-247 blockchain-explorer]# cd app/test/
[root@host-192-100-36-247 test]# npm install
4、test目录下执行npm run test
[root@host-192-100-36-247 test]# npm run test
5、接下来进入blockchain-explorer/client目录,执行npm install下载相关依赖模块:
[root@host-192-100-36-247 test]# cd ..
[root@host-192-100-36-247 app]# cd ../..
[root@host-192-100-36-247 hyperledger]# cd blockchain-explorer/client/
[root@host-192-100-36-247 client]# npm install
6、当前目录下执行npm test – -u --coverage
[root@host-192-100-36-247 client]# npm test -- -u --coverage
7、可以看到所有的测试都通过了。接下来运行 npm run build命令
[root@host-192-100-36-247 client]# npm run build
运行完会在当前目录下生成build和coverage两个文件夹
8、
5.智能合约部署
1、herocu