本文适用于linux环境。
先放文档地址:
官方文档:http://hyperledger-fabric.readthedocs.io/en/latest/
中文文档:https://hyperledgercn.github.io/hyperledgerDocs/
一、准备条件
需要安装的软件:git、cURL、docker和docker-compose、go语言、nodejs和npm、python,网上有好多教程,自行安装。
下面来下载Fabric需要的镜像(在gopath/src/github.com/hyperledger/目录下):
(注:如果已经下载了fabric的镜像,但是没有fabric-samples这个文件夹,可以单独下载,放在本地任意目录都行,地址https://github.com/hyperledger/fabric-samples 本文使用的fabric1.1版本,下载这个样例时版本一定要和你使用的镜像的版本一致,要不。。。都是泪)
curl -sSL https://goo.gl/6wtTN5 | bash
这条命令是从这个地址上下载一个脚本,然后执行脚本的命令进行下载(地址可能会变,可以参考官方文档)
这是会有个fabric-simples文件夹,进入。
设置环境变量:
sudo gedit ~/.bashrc
然后在最后一行加入:
export PATH=$PATH:/home/zhj/project/gopath/src/github.com/hyperledger/test/fabric-samples/bin
将里面的路径换成你自己的安装路径。
现在需下载的环境已经准备好,下面以first-network这个文件夹进行搭建第一个Fabric网络。
二、部署网络
本部分利用已下载的自带脚本自动执行所有操作,包括搭建起一个Fabric网络,其中包括一个order和四个分别属于两个组织的peer;加入channel;部署执行chaincode。
1、生成所有秘钥和证书
cd first-network/
./byfn.sh -m generate
第一步生成我们各种网络实体的所有证书和密钥,genesis block用于引导排序服务,以及配置Channel所需要的一组交易配置集合 。
2、启动网络
./byfn.sh -m up
来看一下输出日志的主要事件(省略中间大部分输出):
===================== Channel "mychannel" is created successfully =====================
===================== peer0.org1 joined on the channel "mychannel" =====================
===================== peer1.org1 joined on the channel "mychannel" =====================
===================== peer0.org2 joined on the channel "mychannel" =====================
===================== peer1.org2 joined on the channel "mychannel" =====================
===================== Anchor peers for org "Org1MSP" on "mychannel" is updated successfully =====================
===================== Anchor peers for org "Org2MSP" on "mychannel" is updated successfully =====================
===================== Chaincode is installed on peer0.org1 =====================
===================== Chaincode is installed on peer0.org2 =====================
===================== Chaincode Instantiation on peer0.org2 on channel 'mychannel' is successful =====================
===================== Query on peer0.org1 on channel 'mychannel' is successful =====================
===================== Invoke transaction on peer0.org1 on channel 'mychannel' is successful =====================
===================== Chaincode is installed on peer1.org2 =====================
===================== Query on peer1.org2 on channel 'mychannel' is successful =====================
可以看到,先创建了一个channel,然后将四个peer节点分别加入channel中,再设置两个组织的锚节点。
(下面进行chaincode操作,chaincode的要实现的是:初始化两个账户a和b,分别拥有100和200的余额,可以执行查询、转账操作)
在两个锚节点上分别安装chaincode,在channel上实例化chaincode,然后开始对chaincode进行操作:在组织1的锚节点上执行查询操作,调用转账操作;在组织2的peer1上安装chaincode并执行查询操作。可以看到peer0.org1对chaincode执行修改操作后,在peer1.org2节点可以看到修改后的结果。
3、关闭网络
./byfn.sh -m down
包括关闭容器,移除加密材料和4个配置信息,并且从Docker仓库删除chaincode镜像。
以上是通过example自带的脚本来自动执行所有的操作,仔细研究每一步的话,可以查看脚本中的内容。下面通过手动配置的方法来实现以上的各功能。
三、手动配置网络
1、手动生成配置文件
(1)生成证书、秘钥
cryptogen generate --config=./crypto-config.yaml
使用cryptogen工具根据crypto-config.yaml配置文件生成各种网络实体的加密材料(x509证书)。这些证书是身份的代表,它们允许在我们的网络实体进行交流和交易时进行签名/验证身份验证。执行tree crypto-config操作,可以看到生成了ordererOrganizations 和peerOrganizations两个组织,其中peerOrganizations中包含org1.example.com和org2.example.com两个组织。
每个组织都配置了唯一的根证书(ca-cert),它将特定组件(peers和orders)绑定到该组织。通过为每一个组织分配唯一的CA证书,我们正在模仿一个经典的网络,这个网络中的成员将使用自己的证书颁发机构。Hyperledger Fabric中的交易和通信是通过存储在keystore中的实体的私钥签名,然后通过公钥手段进行验证(signcerts)。
(2)配置交易生成器
configtxgen tool用于创建4个配置工作: order的genesis block, channel的channel configuration transaction, * 以及两个anchor peer transactions一个对应一个Peer组织。order block是一个ordering service的创世区块,channel transaction文件在Channel创建的时侯广播给order。anchor peer transactions,正如名称所示,指定了每个组织在此channel上的Anchor peer。
Configtxgen使用一个包含示例网络的configtx.yaml文件。有3个成员:一个排序服务组织OrdererOrg以及两个节点组织(Org1&Org2),每个组织管理和持有2个peer节点。该文件还指定了一个SampleConsortium的联盟,由上述2个节点组织构成。下面进行配置
生成order的genesis block:
export FABRIC_CFG_PATH=$PWD
configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block
创建channel transaction的配置:
export CHANNEL_NAME=mychannel
configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID $CHANNEL_NAME
在通道上定义org1和org2的锚节点:
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org2MSP
以上生成的配置都放在了channel-artifacts/这个文件夹中,查看一下现在包含的文件:tree channel-artifacts/
channel-artifacts/
├── channel.tx
├── genesis.block
├── Org1MSPanchors.tx
└── Org2MSPanchors.tx
查看排序创世区块和通道创世区块的命令分别是:
configtxgen -profile TwoOrgsOrdererGenesis -inspectBlock ./channel-artifacts/genesis.block
configtxgen -profile TwoOrgsOrdererGenesis -inspectChannelCreateTx ./channel-artifacts/channel.tx
会以json格式解析给出区块的内容.
2、启动网络
使用docker-compose根据配置文件来启动网络(配置文件不只是docker-compose-cli.yaml,还包括order节点和peer节点的配置,详见这篇文章):
CHANNEL_NAME=$CHANNEL_NAME TIMEOUT=10 docker-compose -f docker-compose-cli.yaml up -d
其中cli充当客户端的作用,cli和peer连接,将指令发送给peer节点上执行。默认是peer0.org1节点。
3、创建并加入channel
加入cli容器:
docker exec -it cli bash
如果显示下面这样,说明成功:
root@0d83760ad1aa:/opt/gopath/src/github.com/hyperledger/fabric/peer#
将节点切换到peer0.org1:
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
CORE_PEER_ADDRESS=peer0.org1.example.com:7051
CORE_PEER_LOCALMSPID="Org1MSP"
CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
下面进行创建channel,应该与前面创建的channel配置保持一样的channel名字
export CHANNEL_NAME=mychannel
ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
peer channel create -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA
使用-c标志指定channel的名字,-f标志指定配置交易,在这个例子中它是channel.tx。
这时可以看到目录中多了一个创世区块mychannel.block,它包含了channel.tx的配置信息,我们使用它加入channel。
下面加入peer0.org1的通道,进行链码的相关配置:
peer channel join -b mychannel.block
现在已经加入peer0.org1的通道,下面将其他三个节点也加入通道中:
CORE_PEER_LOCALMSPID="Org1MSP"
CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
CORE_PEER_ADDRESS=peer1.org1.example.com:7051
peer channel join -b mychannel.block
CORE_PEER_LOCALMSPID="Org2MSP"
CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
CORE_PEER_ADDRESS=peer0.org2.example.com:7051
peer channel join -b mychannel.block
CORE_PEER_LOCALMSPID="Org2MSP"
CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
CORE_PEER_ADDRESS=peer1.org2.example.com:7051
peer channel join -b mychannel.block
更新锚节点:
CORE_PEER_LOCALMSPID="Org1MSP"
CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
CORE_PEER_ADDRESS=peer0.org1.example.com:7051
peer channel update -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/Org1MSPanchors.tx --tls true --cafile $ORDERER_CA
CORE_PEER_LOCALMSPID="Org2MSP"
CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
CORE_PEER_ADDRESS=peer0.org2.example.com:7051
peer channel update -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/Org2MSPanchors.tx --tls true --cafile $ORDERER_CA
4、安装和实例化链码
下面安装和实例化链码都是在节点peer0.org1上操作的,应先切换到该节点,切换方法上面有。
在每个会执行并背书交易的节点上安装chaincode,并在通道上实例化。注意:每个相关节点都需要安装一遍,在通道上实例化只需要一次即可。
这里安装一个已经下载好的链码,在我cli的容器中位置是:/opt/gopath/src/github.com/chaincode/chaincode_example02/go,可能不太一样,自己找一下。
peer chaincode install -n mycc -v 1.0 -p github.com/chaincode/chaincode_example02/go
下面在通道上实例化链码,需要指定背书策略:
peer chaincode instantiate -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -v 1.0 -c '{"Args":["init","a", "100", "b","200"]}' -P "OR ('Org1MSP.member','Org2MSP.member')"
其中-c '{"Args":["init","a", "100", "b","200"]}'是初始化链码,-P "OR ('Org1MSP.member','Org2MSP.member')"是指定背书策略,即两个组织中任何一个节点背书即可
5、执行链码
先执行查询操作,我们在上一步初始化的时候,将a的值设为100,b的值设为200,现在查询一下a的值:
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
返回结果为:
2018-06-15 03:21:12.859 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-06-15 03:21:12.859 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
Query Result: 100
2018-06-15 03:21:12.863 UTC [main] main -> INFO 003 Exiting.....
可以看到查询结果为100.下面进行修改操作,从a给b转账10:
peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -c '{"Args":["invoke","a","b","10"]}'
然后在执行查询操作可以看到a的值变为90,b的值变为210
现在切换到peer1.org2节点上执行查询操作:
安装chaincode并执行查询操作:
peer chaincode install -n mycc -v 1.0 -p github.com/chaincode/chaincode_example02/go/
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","b"]}'
可以看到查询结果a是90,b是210.
6、查看日志,清除操作
所有操作已执行完,执行exit退出cli通道,使用docker logs [name]命令可以查看相关通道的日志,如
docker logs dev-peer0.org1.example.com-mycc-1.0可得到结果:
ex02 Init
Aval = 100, Bval = 200
ex02 Invoke
Query Response:{"Name":"a","Amount":"100"}
ex02 Invoke
Aval = 90, Bval = 210
下面清理操作:
./byfn.sh -m down
所有的通道和链码镜像等都被清除。