对Hyperledger Fabric的研究也已经有一段时间啦,趁这几天有时间,对自己所理解的知识进行一下汇总,同时也希望能帮助到他人。
随着IBM Fabric 1.1预发行版本的发布,更加稳定高效的区块链网络也随之而来,也为我们开发人员带来了学习区块链更好的机会。内心OS(据说IBM在1.1正式版本发布后会有相应的技术支持哦,有点小期待)
我们既然获取到了fabric的源码,所以也可以轻松的获取到这些工具。我们只需要进入到fabric源码的根目录下然后执行如下命令就可以相应的生成下面两个工具:
make cryptogen
运行后系统返回:
build/bin/cryptogen
CGO_CFLAGS=” ” GOBIN=/root/gopath/src/github.com/hyperledger/fabric/build/bin go install -tags “experimental” -ldflags “-X github.com/hyperledger/fabric/common/tools/cryptogen/metadata.Version=1.1.1-snapshot-dfce53705” github.com/hyperledger/fabric/common/tools/cryptogen
Binary available as build/bin/cryptogen
make configtxgen
运行后系统返回:
build/bin/configtxgen
CGO_CFLAGS=” ” GOBIN=/root/gopath/src/github.com/hyperledger/fabric/build/bin go install -tags “experimental nopkcs11” -ldflags “-X github.com/hyperledger/fabric/common/tools/configtxgen/metadata.Version=1.1.1-snapshot-dfce53705” github.com/hyperledger/fabric/common/tools/configtxgen
Binary available as build/bin/configtxgen
由于我们这是测试环境,并没有启动CA认证节点,我们需要通过配置crypto-config.yaml文件来控制cryptogen工具生成相应的公私钥和证书。
我们可以查看源码下examples/e2e_cli/crypto-config.yaml(Org1)文件来分析
Name: Org1
Domain: org1.example.com
Template:
Count: 2
Users:
Count: 1
Name和Domain的话是组织的名字和域名,在生成证书时会包含相应的信息。
Template是我们需要为这个组织生成几套公私钥。也就是说Org1组织下会有两个peer节点(peer0、peer1)
Users是我们需要生成几套证书,也就是每一个peer节点下有一个普通用户(不包括Admin用户)
配置好上述文件后可以通过如下命令来生成公私钥和证书,生成的公私钥和证书存放在crypto-config文件夹下。
cd examples/e2e_cli/
../../build/bin/cryptogen generate --config=./crypto-config.yaml
该configtxgen命令允许用户创建和检查通道配置相关的工件。生成的工件的内容由内容决定configtx.yaml。也就是说我们需要配置configtx文件。
同样的我们可以先配置examples/e2e_cli/configtx.yaml这个文件
生成创世区块
../../build/bin/configtxgen -outputBlock genesis_block.pb -profile SampleSingleMSPSoloV1_1 -channelID orderer-system-channel
生成Channel配置区块
../../build/bin/configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID mychannel
锚节点的更新
../../build/bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP
../../build/bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP
最终生成的文件都在channel-artifacts文件夹下应该有四个文件:channel.tx、genesis.block 、Org1MSPanchors.tx、Org2MSPanchors.tx。
前面我们通过fabric提供的两个工具cryptogen、configtxgen相继生成了fabric运行所需要的公私钥、证书和创世区块等。接下来我们就可以配置docker-compose来控制fabric的启动环境了,此文件位于base文件夹下。
首先来配置Orderer:
Orderer的配置是在base/docker-compose-base.yaml文件中,以下是我们截取的Orderer的相关配置:
orderer.example.com:
container_name: orderer.example.com
image: hyperledger/fabric-orderer
environment:
- ORDERER_GENERAL_LOGLEVEL=debug
- ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
- ORDERER_GENERAL_GENESISMETHOD=file
- ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block
- ORDERER_GENERAL_LOCALMSPID=OrdererMSP
- ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp
# enabled TLS
- ORDERER_GENERAL_TLS_ENABLED=true
- ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key
- ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt
- ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]
working_dir: /opt/gopath/src/github.com/hyperledger/fabric
command: orderer
volumes:
- ../channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
- ../crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp:/var/hyperledger/orderer/msp
- ../crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/:/var/hyperledger/orderer/tls
ports:
- 7050:7050
我们较为关注的是之前配置的创世区块文件,也就是如下配置
ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block
在volumes: 下,就是我们主机到docker的映射
../channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
另外的配置主要是TL,Log等,最后暴露出服务端口7050。我们可以根据自己的需要进行相应的改动
接下来我们来配置peer:
peer的配置是在base/docker-compose-base.yaml中,然后指定到peer-base.yaml文件中,以下是我们截取的peer的相关配置:
peer-base:
image: hyperledger/fabric-peer
environment:
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock # the following setting starts chaincode containers on the same
# bridge network as the peers
# https://docs.docker.com/compose/networking/
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=e2ecli_default
#- CORE_LOGGING_LEVEL=ERROR
- CORE_LOGGING_LEVEL=DEBUG
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_GOSSIP_USELEADERELECTION=true
- CORE_PEER_GOSSIP_ORGLEADER=false
- CORE_PEER_PROFILE_ENABLED=true
- CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key
- CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: peer node start
peer0.org1.example.com:
container_name: peer0.org1.example.com
extends:
file: peer-base.yaml
service: peer-base
environment:
- CORE_PEER_ID=peer0.org1.example.com
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051
- CORE_PEER_CHAINCODELISTENADDRESS=peer0.org1.example.com:7052
- CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.example.com:7051
- CORE_PEER_LOCALMSPID=Org1MSP
volumes:
- /var/run/:/host/var/run/
- ../crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp:/etc/hyperledger/fabric/msp
- ../crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls:/etc/hyperledger/fabric/tls
ports:
- 7051:7051
- 7052:7052
- 7053:7053
在peer的配置中主要是为peer分配各种服务的地址和端口,以及各种TLS和MSP信息等
配置CLI:
CLI在Fabric网络中扮演了客户端的角色,在测试过程中我们可以把CLI当成SDK来使用,简化了我们的开发过程。CLI和Peer想连,把指令发送给相应的peer来执行。CLI的配置在docker-compose-cli.yaml文件中。让我们来看看其中的奥妙:
cli:
container_name: cli
image: hyperledger/fabric-tools
tty: true
environment:
- GOPATH=/opt/gopath
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_LOGGING_LEVEL=DEBUG
- CORE_PEER_ID=cli
- CORE_PEER_ADDRESS=peer0.org1.example.com:7051
- CORE_PEER_LOCALMSPID=Org1MSP
- CORE_PEER_TLS_ENABLED=true
- CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt
- CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key
- 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/[email protected]/msp
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
command: /bin/bash -c ‘./scripts/script.sh CHANNELNAME;sleep C H A N N E L N A M E ; s l e e p TIMEOUT’
volumes:
- /var/run/:/host/var/run/
- ../chaincode/go/:/opt/gopath/src/github.com/hyperledger/fabric/examples/chaincode/go
- ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
- ./scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/
- ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
depends_on:
- orderer.example.com
- peer0.org1.example.com
- peer1.org1.example.com
- peer0.org2.example.com
- peer1.org2.example.com
从这个配置中我们可以发现CLI启动时默认启动了peer0.org1.example.com,并且启用了TLS,并以admin的身份连接到peer。可以看到command中启动了./scripts/script.sh这个脚本,这个脚本完成了fabric环境的初始化和chaincode的安装以及运行,具体这个脚本的内容在后面会有相应的介绍。还有一点值得注意的是在volumns中的../chaincode/go/:/opt/gopath/src/github.com/hyperledger/fabric/examples/chaincode/go也就是说docker容器的chaincode是由本地环境下chaincode/go/目录所映射的,所以以后我们要开发自己的chaincode时可以直接将chaincode放入此目录中。
在上面的./scripts/script.sh脚本默认是自动运行的,然而在测试过程中我们并不希望它自动运行,所以我们需要把这一行命令给注释掉。
鉴于之前我们的配置将所以的配置完成后,我们可以通过如下命令来启动docker容器:
docker-compose -f docker-compose-cli.yaml up -d
-f参数表示通过加载之后的文件来启动容器
-d参数表示docker容器可以进入后台运行,不会随着我们的终端的关闭而关闭
随后执行docker -ps可以看到如下的结构:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
df7f3d468e8c hyperledger/fabric-tools “/bin/bash” 11 minutes ago Up 11 minutes cli
0bb2aa5e2982 hyperledger/fabric-orderer “orderer” 11 minutes ago Up 11 minutes 0.0.0.0:7050->7050/tcp orderer.example.com
2e5a2a34297b hyperledger/fabric-kafka “/docker-entrypoint.…” 11 minutes ago Up 11 minutes 9093/tcp, 0.0.0.0:32780->9092/tcp kafka3
f559d2c74610 hyperledger/fabric-kafka “/docker-entrypoint.…” 11 minutes ago Up 11 minutes 9093/tcp, 0.0.0.0:32779->9092/tcp kafka1
384b103b15ce hyperledger/fabric-kafka “/docker-entrypoint.…” 11 minutes ago Up 11 minutes 9093/tcp, 0.0.0.0:32778->9092/tcp kafka0
380353352c92 hyperledger/fabric-kafka “/docker-entrypoint.…” 11 minutes ago Up 11 minutes 9093/tcp, 0.0.0.0:32777->9092/tcp kafka2
89bc2e9eb7d7 hyperledger/fabric-zookeeper “/docker-entrypoint.…” 11 minutes ago Up 11 minutes 0.0.0.0:32776->2181/tcp, 0.0.0.0:32775->2888/tcp, 0.0.0.0:32773->3888/tcp zookeeper2
92bfcdcaf1de hyperledger/fabric-zookeeper “/docker-entrypoint.…” 11 minutes ago Up 11 minutes 0.0.0.0:32774->2181/tcp, 0.0.0.0:32772->2888/tcp, 0.0.0.0:32771->3888/tcp zookeeper0
d66f7681ea42 hyperledger/fabric-zookeeper “/docker-entrypoint.…” 11 minutes ago Up 11 minutes 0.0.0.0:32770->2181/tcp, 0.0.0.0:32769->2888/tcp, 0.0.0.0:32768->3888/tcp zookeeper1
f5554fbbf974 hyperledger/fabric-peer “peer node start” 11 minutes ago Up 11 minutes 0.0.0.0:10051->7051/tcp, 0.0.0.0:10052->7052/tcp, 0.0.0.0:10053->7053/tcp peer1.org2.example.com
2c97d371a736 hyperledger/fabric-peer “peer node start” 11 minutes ago Up 11 minutes 0.0.0.0:9051->7051/tcp, 0.0.0.0:9052->7052/tcp, 0.0.0.0:9053->7053/tcp peer0.org2.example.com
cc030248055a hyperledger/fabric-peer “peer node start” 11 minutes ago Up 11 minutes 0.0.0.0:8051->7051/tcp, 0.0.0.0:8052->7052/tcp, 0.0.0.0:8053->7053/tcp peer1.org1.example.com
3d98b098b7f2 hyperledger/fabric-peer “peer node start” 11 minutes ago Up 11 minutes 0.0.0.0:7051-7053->7051-7053/tcp
可以看出来我们启动了1个order+4个peer+1个cli,还有kafka和zookeeper等容器,kafka是fabric提供的两种共识算法(solo,kafka)的其中一个,可以查看docker-compose-cli.yaml文件中的order配置选项默认是启动了kafka共识算法、zookeeper容器的话主要是用于对order进行热备的,提高了整个系统的容错性,此次测试没有针对热备对配置文件进行修改。
之前启动了1个cli容器,现在我们需要进入到这个容器中去
docker exec -it cli bash
创建channel的命令是peer channel create
,由于我们之前的配置文件对channel的命名为mychannel,所以我们这里创建channel时也需要指定为这个名字,要不然会出现错误。创建channel时是要以order节点为环境创建,所以我们要指定order节点的证书:
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
添加完后执行下一步命令生成channel
peer channel create -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/channel.tx --tls true --cafile $ORDERER_CA
命令执行完毕后,后两行为:
2018-05-22 07:30:56.195 UTC [channelCmd] readBlock -> DEBU 034 Received block: 0
2018-05-22 07:30:56.195 UTC [main] main -> INFO 035 Exiting…..
随之系统会在当前目录下生成一个mychannel.block文件,这个文件是其他节点加入这个channel所必须要使用的。
之前我们有提到,cli容器默认连接到的就是org1组织下的peer0节点,所以我们首先将这个peer加入到channel:
peer channel join -b mychannel.block
之后系统返回,后两行为:
2018-05-22 07:40:33.147 UTC [channelCmd] executeJoin -> INFO 006 Successfully submitted proposal to join channel
2018-05-22 07:40:33.147 UTC [main] main -> INFO 007 Exiting…..
之后我们需要将其他的org1组织下的peer1和org2组织下的peer0/peer1加入到我们的channel中来,我们应该如何操作呢?当然是改变一下当前cli容器的环境了,这个对同行来说应该不陌生。
笔者这里仅提供一下org1的peer1的示例,org2下的peer0/peer1需要各位看官自行搞定啦:
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/[email protected]/msp
CORE_PEER_ADDRESS=peer1.org1.example.com:7051
环境修改
peer channel join -b mychannel.block
加入channel
关于锚节点的定义官方给出了在一个channel上可以被所有其他peer发现的peer,channel上的每个成员都有一个anchor Peer(或多个anchor peer 来防止单点故障),允许属于不同成员的peer发现chnnel上的所有现有peer的定义,下面我们来将对org1和org2的锚节点进行更新:
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/[email protected]/msp
CORE_PEER_ADDRESS=peer0.org1.example.com:7051
org1环境配置
peer channel update -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/Org1MSPanchors.tx --tls true --cafile $ORDERER_CA
org1锚节点更新
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/[email protected]/msp
CORE_PEER_ADDRESS=peer0.org2.example.com:7051
org2环境配置
peer channel update -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/Org2MSPanchors.tx --tls true --cafile $ORDERER_CA
org2锚节点更新
之前的步骤让我们将整个fabric的网络已经channel配置完成了,接下来就需要我们来进行chaincode的安装与运行了,这里我们选择的是example02,它可以实现两个用户之前的转账。
首先安装链上代码:
如果某个peer希望使用我们的chaincode(example02)进行对我们创建的fabric网络进行操作的话,就必须先安装我们的链上代码。也就是说如果这两个org下的四个peer想要都可以对我们构建的fabric区块进行操作的话,需要逐个安装。我们先在org1的peer0下安装。
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/[email protected]/msp
CORE_PEER_ADDRESS=peer0.org1.example.com:7051
org1的peer0环境配置
peer chaincode install -n mycc -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02
安装链上代码
其他的节点等我们需要使用时再进行安装。
实例化链上代码
实例化链上代码主要是对peer上安装的链码赋予一个初始化的状态,如同其他框架的初始化。在实例化的过程中我们可以指定背书的政策。
peer chaincode instantiate -o orderer.example.com:7050 --tls true --cafile $ORDERER_CA -C mychannel -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "OR ('Org1MSP.member','Org2MSP.member')"
在peer0上发起一笔交易
在我们实例化链上代码的时候,初始化了a和b两个账户,a账户拥有100元,b账户拥有 200元.接下来我们试着先调用一下example02的query方法,查看一下是不是如上所说:
peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'
可以看到系统返回:
Query Result: 100
2018-05-22 09:40:39.862 UTC [main] main -> INFO 008 Exiting…..
接下来调用invoke方法,a转账给b10元:
peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile $ORDERER_CA -C mychannel -n mycc -c '{"Args":["invoke","a","b","10"]}'
接下来可以再次调用query方法查询账户中的金额是不是发生了改变。
首先配置org1下peer1节点的环境,笔者不在提供详细代码啦,上边已经给出了。接下来要先安装channel.
peer chaincode install -n mycc -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02
安装好之后是不需要再次进行初始化的哦,因为之前我们已经初始化过一次了。我们看看可不可以查询之前的交易:
peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'
系统返回:
Query Result: 90
2018-05-22 09:49:09.471 UTC [main] main -> INFO 008 Exiting…..
说明我们在同一组织的其他节点上是可以查询到交易的。接下来我们在不同的组织上查询看看可不可以呢,先切换到org2的peer0节点的环境下。然后安装链码并执行查询:
peer chaincode install -n mycc -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02
同样安装好之后我们可以查询一下:
peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'
也是可以正常返回的哦,至此说明我们基于Hyperledger Fabric的区块链网络已经搭建完成了。
由于是第一次搭建区块链网络,其中也遇到了不少的坑,不过最后还是搭建完成了,写这篇文章第一是对自己在搭建过程中遇到的知识进行一下总结,第二也使自己对其中的一些理解更加深刻,第三也是最为重要的一点,希望同行在看到这篇文章时能够有所帮助。其中有哪些地方写的不对或者不好的,还希望大家多多指正。