本文介绍在 Ubuntu 18.04 中安装 Fabric, 并对 官方文档中的一个小案例(Using the Fabric test network)进行测试。javascript
目的: 初步了解 Fabric 网络的执行步骤,调用,以及经过阅读样例链码,了解如何写链码html
做为初学者,文中描述可能有不当,但愿看到的人可以及时指出,你们一块儿学习。java
找到 GoPath
所在的文件,若是根据上面的安装来,GOPATH=$HOME/go
, 在这个目录下打开终端,输入node
curl -sSL https://bit.ly/2ysbOFE | bash -s
也能够用下面命令下载指定版本(以 fabric_version = 2.2.0,fabric-ca_version = 1.4.8 为例)linux
curl -sSL https://bit.ly/2ysbOFE | bash -s -- <fabric_version> <fabric-ca_version> curl -sSL https://bit.ly/2ysbOFE | bash -s -- 2.2.0 1.4.8
Note!!!-------若是下载过程当中因为网络问题出现错误,能够从新输入命令进行下载,已经下载的镜像会自动跳过,不会重复下载。算法
下载成功后会打印出全部的 hyperledger docker images
,或者终端输入docker images
也将出现如下结果docker
===> List out hyperledger docker images hyperledger/fabric-ca 1.4 152b9082adf6 2 weeks ago 158MB hyperledger/fabric-ca 1.4.8 152b9082adf6 2 weeks ago 158MB hyperledger/fabric-ca latest 152b9082adf6 2 weeks ago 158MB hyperledger/fabric-tools 2.2 5eb2356665e7 5 weeks ago 519MB hyperledger/fabric-tools 2.2.0 5eb2356665e7 5 weeks ago 519MB hyperledger/fabric-tools latest 5eb2356665e7 5 weeks ago 519MB hyperledger/fabric-peer 2.2 760f304a3282 5 weeks ago 54.9MB hyperledger/fabric-peer 2.2.0 760f304a3282 5 weeks ago 54.9MB hyperledger/fabric-peer latest 760f304a3282 5 weeks ago 54.9MB hyperledger/fabric-orderer 2.2 5fb8e97da88d 5 weeks ago 38.4MB hyperledger/fabric-orderer 2.2.0 5fb8e97da88d 5 weeks ago 38.4MB hyperledger/fabric-orderer latest 5fb8e97da88d 5 weeks ago 38.4MB hyperledger/fabric-ccenv 2.2 aac435a5d3f1 5 weeks ago 586MB hyperledger/fabric-ccenv 2.2.0 aac435a5d3f1 5 weeks ago 586MB hyperledger/fabric-ccenv latest aac435a5d3f1 5 weeks ago 586MB hyperledger/fabric-baseos 2.2 aa2bdf8013af 5 weeks ago 6.85MB hyperledger/fabric-baseos 2.2.0 aa2bdf8013af 5 weeks ago 6.85MB hyperledger/fabric-baseos latest aa2bdf8013af 5 weeks ago 6.85MB
在终端输入如下命令设置环境变量typescript
gedit ./.bashrc # 在下面添加如下命令, 路径根据本身的GoPath 以及 fabric-samples 路径。 export PATH=/home/faddei/go/fabric-samples/bin:$PATH
保存后退出,shell
# 激活环境变量 source ./.bashrc
查看是否配置好ubuntu
peer version
出现如下即为安装成功,版本根据本身下载的指定版本,可能会有所不一样
peer: Version: 2.2.0 Commit SHA: 5ea85bc54 Go version: go1.14.4 OS/Arch: linux/amd64 Chaincode: Base Docker Label: org.hyperledger.fabric Docker Namespace: hyperledger
测试脚本所在的位置 /home/faddei/go/fabric-samples
以你本身的路径为准, cd 进入这个文件夹
cd ~/go/fabric-samples/test-network/
查看脚本的使用方法
faddei@ubuntu:~/go/fabric-samples/test-network$ ./network.sh
打印结果以下:
Usage: network.sh <Mode> [Flags] Modes: up - bring up fabric orderer and peer nodes. No channel is created up createChannel - bring up fabric network with one channel createChannel - create and join a channel after the network is created deployCC - deploy the asset transfer basic chaincode on the channel or specify down - clear the network with docker-compose down restart - restart the network Flags: Used with network.sh up, network.sh createChannel: -ca <use CAs> - create Certificate Authorities to generate the crypto material -c <channel name> - channel name to use (defaults to "mychannel") -s <dbtype> - the database backend to use: goleveldb (default) or couchdb -r <max retry> - CLI times out after certain number of attempts (defaults to 5) -d <delay> - delay duration in seconds (defaults to 3) -i <imagetag> - the tag to be used to launch the network (defaults to "latest") -cai <ca_imagetag> - the image tag to be used for CA (defaults to "latest") -verbose - verbose mode Used with network.sh deployCC -c <channel name> - deploy chaincode to channel -ccn <name> - the short name of the chaincode to deploy: basic (default),ledger, private, sbe, secured -ccl <language> - the programming language of the chaincode to deploy: go (default), java, javascript, typescript -ccv <version> - chaincode version. 1.0 (default) -ccs <sequence> - chaincode definition sequence. Must be an integer, 1 (default), 2, 3, etc -ccp <path> - Optional, path to the chaincode. When provided the -ccn will be used as the deployed name and not the short name of the known chaincodes. -ccep <policy> - Optional, chaincode endorsement policy, using signature policy syntax. The default policy requires an endorsement from Org1 and Org2 -cccg <collection-config> - Optional, path to a private data collections configuration file -cci <fcn name> - Optional, chaincode init required function to invoke. When provided this function will be invoked after deployment of the chaincode and will define the chaincode as initialization required. -h - print this message Possible Mode and flag combinations up -ca -c -r -d -s -i -verbose up createChannel -ca -c -r -d -s -i -verbose createChannel -c -r -d -verbose deployCC -ccn -ccl -ccv -ccs -ccp -cci -r -d -verbose Taking all defaults: network.sh up Examples: network.sh up createChannel -ca -c mychannel -s couchdb -i 2.0.0 network.sh createChannel -c channelName network.sh deployCC -ccn basic -ccl javascript network.sh deployCC -ccn mychaincode -ccp ./user/mychaincode -ccv 1 -ccl javascript
了解了脚本的使用方法以后,在启动项目脚本以前,先 执行下面的命令将 以前运行过的容器清除掉若是有的话。(Note, up 以前 记住 要 down 一下)
./network.sh down
确保你所在当前路径是正确的即 ~/go/fabric-samples/test-network
,以本身的为准
接下来启动网络
./network.sh up
这个命令会建立一个包含 两个 peer 节点和一个 order 节点的 Fabric 网络。若是这个命令成功运行,终端上将会显示如下日志
Creating network "net_test" with the default driver Creating volume "net_orderer.example.com" with default driver Creating volume "net_peer0.org1.example.com" with default driver Creating volume "net_peer0.org2.example.com" with default driver Creating peer0.org1.example.com ... done Creating orderer.example.com ... done Creating peer0.org2.example.com ... done CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9eea87fad9bc hyperledger/fabric-orderer:latest "orderer" 3 seconds ago Up Less than a second 0.0.0.0:7050->7050/tcp orderer.example.com b0662814ecfe hyperledger/fabric-peer:latest "peer node start" 3 seconds ago Up Less than a second 7051/tcp, 0.0.0.0:9051->9051/tcp peer0.org2.example.com b256cee7e51f hyperledger/fabric-peer:latest "peer node start" 3 seconds ago Up Less than a second 0.0.0.0:7051->7051/tcp peer0.org1.example.com
继续进行以前,先看一下 Fabric 网络的组成
docker ps -a
结果以下
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 9eea87fad9bc hyperledger/fabric-orderer:latest "orderer" 41 seconds ago Up 39 seconds 0.0.0.0:7050->7050/tcp orderer.example.com b0662814ecfe hyperledger/fabric-peer:latest "peer node start" 41 seconds ago Up 38 seconds 7051/tcp, 0.0.0.0:9051->9051/tcp peer0.org2.example.com b256cee7e51f hyperledger/fabric-peer:latest "peer node start" 41 seconds ago Up 38 seconds 0.0.0.0:7051->7051/tcp peer0.org1.example.com
Peer :
每个须要与 Fabric 网络交互的节点或用户都须要属于必定的组织,也即联盟中的一个成员。 这个测试网络有两个联盟(consortium)成员, org1 和 org2。 这个网络也包含一个 维持 Fabric 网络中排序服务的 order 组织
peer 节点是 Fabric 网络中重要的组成部分, peer 节点存储 区块链中的帐本,并在交易被写进帐本以前验证交易的合法性。 同时 peer 节点还运行包含着用来管理区块链账本中资产的商业逻辑的智能合约。
Fabric 网络中的节点都须要属于联盟中的一个成员,在这个测试网络中,每个组织操做一个 peer 节点,
peer0.org1.example.com
和peer0.org2.example.com
Order:
每个 Fabric 网络中都包含一个排序服务。 虽然 peer 节点验证交易的合法性并将包含交易的区块写进区块链中, 可是他们没法决定 交易的顺序,也没法将他们包含进新的区块中。在一个分布式网络中,peer 节点可能距离十分遥远,当一个交易被建立的时候,这些peer 节点没有一个共识。所以,对交易的顺序达成一致将是一个很是大的花销。
排序服务容许peer 节点专一于验证交易并将交易提交到帐本中。在排序节点从客户端接收到以背书的交易以后,它们就交易的顺序达成一致,而后将其添加到块中。而后这些区块将被分发到 peer 节点, 这些peer节点将区块添加到区块链帐本中。排序节点还操做定义Fabric网络容量的系统通道,例如如何建立区块而且决定节点使用哪一个版本的Fabric。系统通道定义了哪些组织是联盟的成员。
这个 sample 网络 使用由排序组织提供的单节点的 Raft 排序服务。 真实的网络可能使用由一个或多个排序组织提供的多个排序节点。不一样的排序节点将使用 Raft 共识算法来就整个网络的事务顺序达成一致。
建立一个通道
如今可使用脚原本为 org1 和 org2 之间的交易来建立一个 Fabric 通道。 通道是特定网络成员之间通讯的私有层。通道只能被邀请到通道的组织使用,而且对网络的其余成员不可见。每个通道都有一个独立的区块链帐本。
使用如下脚本建立通道(建立通道的名称默认为 “mychannel”, 可使用 -c 指定名称)
./network.sh createChannel
若是命令执行成功,终端日志中会出现如下结果
========= Channel successfully joined ===========
在通道中部署链码
建立好通道以后,就可使用智能合约与通道帐本交互。智能合约包含管理区块链帐本上资产的业务逻辑。由网络成员运行的应用程序可以调用智能合约来建立,改变,以及转移资产。同时也能够调用智能合约来查询帐本中的数据
为了确保交易是有效的,使用智能合约建立的交易一般须要由多个组织签署,并提交给通道帐本。多重签名对于 Fabric 的信任模型来讲是不可或缺的。要求对一笔交易进行多重背书,能够防止一个通道上的组织篡改peer的帐本,或使用未经赞成的业务逻辑。为了签署交易,每一个组织须要在其peer 节点上调用并执行智能契约,而后由对等方签署事务的输出。为了签署交易,每一个组织须要在其peer上调用并执行智能合约,而后由peer签署交易的输出。若是输出是一致的,而且有足够多的组织签署,交易能够提交到总帐。指定通道上须要执行智能合约的集合组织的策略称为背书策略,该策略为每一个链码设置,做为链码定义的一部分。
在 Fabric 中,智能合约以被称为链码的包部署在网络中。
使用下面的命令在通道中部署链码
# 我指定的是Java, 能够本身选择 go (default), java, javascript, typescript ./network.sh deployCC -ccl java
指定 Java 这里可能有一个坑:
Could not unzip /home/faddei/.gradle/wrapper/dists/gradle-6.5.1-bin/1m5048aptkfynhbvolwgr4ej9/gradle-6.5.1-bin.zip to /home/faddei/.gradle/wrapper/dists/gradle-6.5.1-bin/1m5048aptkfynhbvolwgr4ej9. Reason: error in opening zip file Exception in thread "main" java.util.zip.ZipException: error in opening zip file at java.util.zip.ZipFile.open(Native Method) at java.util.zip.ZipFile.<init>(ZipFile.java:225) at java.util.zip.ZipFile.<init>(ZipFile.java:155) at java.util.zip.ZipFile.<init>(ZipFile.java:169) at org.gradle.wrapper.Install.unzip(Install.java:219) at org.gradle.wrapper.Install.access$600(Install.java:27) at org.gradle.wrapper.Install$1.call(Install.java:75) at org.gradle.wrapper.Install$1.call(Install.java:48) at org.gradle.wrapper.ExclusiveFileAccessManager.access(ExclusiveFileAccessManager.java:69) at org.gradle.wrapper.Install.createDist(Install.java:48) at org.gradle.wrapper.WrapperExecutor.execute(WrapperExecutor.java:107) at org.gradle.wrapper.GradleWrapperMain.main(GradleWrapperMain.java:63)
解决方法,从 gradle 官网下载 https://gradle.org/releases/
上面的 6.5.1 版本到指定文件下,而后手动解压缩到 to 后面的那个文件加下。从新运行命令,成功部署。
经过链码与网络交互
成功部署完链码以后,可使用 peer CLI 来与 Fabric 网络进行交互。 peer CLI 容许调用已经部署好的智能合约,更新通道,或者从 CLI 安装部署新的智能合约。
添加环境变量
# 由于第二步已经在 ~/.bashrc 文件下设置过该环境变量,因此若是 在终端中 输入 peer version 有结果显示的话,下面这个命令能够跳过 # 若是没有 就要设置一下 export PATH=${PWD}/../bin:$PATH
同时也须要设置 FABRIC_CFG_PATH
指向 core.yaml
export FABRIC_CFG_PATH=$PWD/../config/
设置容许操做 peer CLI 做为 org1 的环境变量
# 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/Admin@org1.example.com/msp export CORE_PEER_ADDRESS=localhost:7051
接下来开始与智能合约进行交互
使用下面的命令初始化帐本中的资产
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n basic --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":"InitLedger","Args":[]}'
若是成功的话,终端日志中会打印以下:
-> INFO 001 Chaincode invoke successful. result: status:200
如今能够从 CLI 中查询帐本。
# 下面命令获取所有资产 peer chaincode query -C mychannel -n basic -c '{"Args":["GetAllAssets"]}'
成功的话会输出这样一串字符串。
[ {"ID": "asset1", "color": "blue", "size": 5, "owner": "Tomoko", "appraisedValue": 300}, {"ID": "asset2", "color": "red", "size": 5, "owner": "Brad", "appraisedValue": 400}, {"ID": "asset3", "color": "green", "size": 10, "owner": "Jin Soo", "appraisedValue": 500}, {"ID": "asset4", "color": "yellow", "size": 10, "owner": "Max", "appraisedValue": 600}, {"ID": "asset5", "color": "black", "size": 15, "owner": "Adriana", "appraisedValue": 700}, {"ID": "asset6", "color": "white", "size": 15, "owner": "Michel", "appraisedValue": 800} ]
使用下面的命令转移资产
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n basic --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":"TransferAsset","Args":["asset6","Christopher"]}'
执行成功会有下面的日志, 说明 asset6 已经被成功转移到 Christopher 名下
-> INFO 001 Chaincode invoke successful. result: status:200 payload:"{\"owner\":\"Christopher\",\"color\":\"white\",\"size\":15,\"appraisedValue\":700,\"assetID\":\"asset6\"}"
由于 asset-transfer (basic) chaincode
的背书策略要求 org1 和 org2 共同签署, 因此链码调用命令须要使用 --peerAddresses
标志同时指向 peer0.org1.example.com
和 peer0.org2.example.com
由于 网络启用了 TLS ,命令还须要使用 --tlsRootCertFiles
标志来为每一个节点引用 TLS 整数。
查询asset6的的状态
peer chaincode query -C mychannel -n basic -c '{"Args":["ReadAsset","asset6"]}'
结果以下:
{"owner":"Christopher","color":"white","size":15,"appraisedValue":700,"assetID":"asset6"}
上面是对 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/Admin@org2.example.com/msp export CORE_PEER_ADDRESS=localhost:9051
查询 asset6 的状态,结果同上
关闭网络
./network.sh down
该命令将中止并删除节点和链码容器,删除组织密码材料,并从你的Docker注册表中删除链码图像。