title: Hyperledger fabri 部署网络(单机环境)
tags: Hyperledger, fabric ,Blockchain
安装预置环境
下载项目
首先我们需要配置好Hyperledger Fabric
开发环境,然后下载并安装Hyperledger Fabric Samples
。你会注意到fabric-samples
文件夹中包含了许多示例。我们将使用first-network
这个例子。
你如果你不知道环境配置和Samlpes
的下载安装,可以看我之前的文章:
使用脚本自动部署
Hyperledger Fabric Samples
提供一个完全注释的脚本byfn.sh
,利用这些Docker镜像可以快速引导一个由4个代表2个不同组织的peer节点以及一个排序服务节点的Hyperledger fabric网络。它还将启动一个容器来运行一个将peer节点加入channel、部署实例化链码服务以及驱动已经部署的链码执行交易的脚本。
为了使用byfn.sh
我们先切换到 first-network
目录
```cd /home/go/src/fabric-samples/first-network`
1.查看byfn.sh
帮助文档
./byfn.sh -h
注意:如果你选择不提供channel名称,则脚本将使用默认名称mychannel
- 生成配置
第一步先生成成我们各种网络实体的所有证书和密钥。
./byfn.sh -m generate -i 1.0.0
注意:1.0.0是镜像标签 ,使用 -i可以指定标签,如果不指定默认标签为
latest
, 下面命令中的1.0.0类同。
- 启动网络
现在我们开始使用命令启动网络
./byfn.sh -m up -i 1.0.0
- 关闭网络
当然我们也可以关闭网络,使用下面的命令会将关闭你的容器,移除加密材料和4个配置信息,并且从Docker仓库删除chaincode镜像
./byfn.sh -m down -i 1.0.0
使用工具手动部署
了解工具
- 证书生成器
fabric使用cryptogen
工具,读取描述了网络的拓扑结构crypto-config.yaml
的配置文件,来为网络中的实体生成证书(certificates)。这些证书是身份的代表,它们允许在我们的网络实体进行交流和交易时进行签名/验证身份验证。
通过对每个组织分配唯一的CA证书,每个链成员通过自己的证书获取权限。Hyperledger Fabric中的交易和通信是通过存储在keystore中的实体的私钥签名,然后通过公钥手段进行验证(signcerts)。
crypto-config.yaml
文件里的count
参数用来指指定每个组织中peer
的数量。
有兴趣的小伙伴可以自己看本机的
crypto-config.yaml
文件。
- 配置交易生成器
`configtxgen是Hyperledger Fabric提供的用于通道配置的实用程序,主要生成以下3种文件:
-
order genesis block
:排序服务(ordering service)的创世区块。 -
channel configuration transaction
: 通道配置交易,会在channel创建时广播给orderer。 - 以及两个
anchor peer transactions
:指定通道上两个组织的锚节点(Anchor Peer)。
Configtxgen使用一个包含简单网络的定义的configtx.yaml
文件。该文件还指定了一个SampleConsortium
的联盟,2个节点组织构成。
请注意,我们SampleConsortium在系统级配置文件中定义,然后由我们的通道级配置文件引用。渠道存在于一个联盟的范围内,所有联盟必须在整个网络的范围内定义。
手动生成配置文件
我们可以用configtxgen
和cryptogen
命令来手动生成证书/密钥和各种配置文件。
注意:
cryptogen
和configtxgen
都是需要我们手动编译生成的,并且存放在$GOPATH/bin/
如何生成,可以查看我之前的文章
https://blog.csdn.net/yang731227/article/details/83868333
- 生成证书
首先我们运行crytyogen
工具,我们的二进制文件位于bin 目录中. 我们可以通过修改crypto-config.yaml
文件来生成我们需要的证书。
首先进入存放crypto-config.yaml
的目录
cd fabric-samples/first-network
然后执行工具生成证书
$GOPATH/bin/cryptogen generate --config=./crypto-config.yaml
执行命令返回信息:
org1.example.com
org2.example.com
执行命令后,证书和密钥(也就是MSP material)将输出到crypto-config目录中,里面是各个组织的安全文件。
- 生成创世区块
接下来,我们需要告诉configtxgen
去哪找到需要的配置文件configtx.yaml
,所以我们先先设置一个环境变量。
必须在fabric-samples/first-network
目录下使用
export FABRIC_CFG_PATH=$PWD
然后,我们将调用configtxgen
工具去创建orderer genesis block
$GOPATH/bin/configtxgen -profile TwoOrgsOrdererGenesis -channelID byfn-sys-channel -outputBlock ./channel-artifacts/genesis.block
注意: orderer genesis块和我们即将创建的后续工件将输出到channel-artifacts该项目根目录的目录中。上述命令中的channelID是系统通道的名称。
- 创建channel transaction配置(channel.tx)
接下来,我们需要创建channel transaction配置。执行命令前需要设置$CHANNEL_NAME
环境变量。
export CHANNEL_NAME=mychannel`
$GOPATH/bin/configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID $CHANNEL_NAME`
接下来,在我们创建的channel上定义两个Anchor Peer
节点 Org1
和Org2
。执行命令为:
$GOPATH/bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP`
$GOPATH/bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org2MSP `
order genesis block 和 channel transaction artifacts都将输出到channel-artifacts目录下。最终目录包含4个文件:genesis.block,channel.tx,Org1MSPanchors.tx和Org2MSPanchors.tx。
启动网络
注意:如果你之前使用 byfn.sh脚本开启了网络,请确保在继续操作之前已关闭测试网络。
我们将利用docker-compose
脚本来启动我们的区块链网络。docker-compose文件利用我们之前下载的镜像,并用以前生成的genesis.block来引导orderer。
在运行之前,需要修改docker-compose-cli.yaml
文件,使用#
注释掉下面的代码:
#command: /bin/bash -c './scripts/script.sh ${CHANNEL_NAME} ${DELAY}; sleep $TIMEOUT'
该行代码会使cli容器运行的时候自动运行脚本script.sh,会进行创建channel,加入节点等等一系列操作,此时如果再进行手动执行,并把CHANNEL_NAME
设置为mychannel
,就会出现channel名称重复问题,从而报错 Error: got unexpected status: BAD_REQUEST
。
1.运行docker-compose
命令启动网络:
docker-compose -f docker-compose-cli.yaml up -d
CLI容器处于空闲状态时只会会停留1000秒。你可以使用以下命令再次启动它:
docker start cli
2.设置环境变量
下面是peer0.org1.example.com
的环境变量。每当在CLI命令中需要执行节点操作时,都要确认当前处于哪个节点下。
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
CLI容器针对peer0.org1.example.com
操作所需要的环境变量已经设置好了,但如果需要对其他peer或者orderer节点进行操作,则需要提供这些变量值。
例如,要切换至peer1.org1
节点,就需要将peer0.org1.example.com
在环境变量中进行替换。同理,如果切换到其他节点,需要对应的修改环境变量。
3.创建&加入信道
我们使用configtxgen工具创建channel transaction配置 。你可以重复使用相同或不同的configtx.yaml文件,在你的网络创建其他的信道。
我首先进入CLI容器中:
docker exec -it cli bash
如果执行成功,你将看到下列信息:opt/gopath/src/github.com/hyperledger/fabric/peer#
我们使用-c标志指定channel的名字,-f标志指定channel配置文件。在这个例子中它是channel.tx,当然你也可以使用不同的名称,挂载你自己的channel配置。再一次,我们将在CLI容器里设置了CHANNEL_NAME
环境变量,所以不需要明确传递这个参数。
export CHANNEL_NAME=mychannel
peer channel create -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
注意:-- cafile会作为命令的一部分。这是orderer的root cert的本地路径,允许我们去验证TLS握手。
此命令返回一个创世区块<channel-ID.block>
,我们将使用它加入信道。它包含了channel.tx
中的配置信息。如果你没有修改过channel.tx
文件中默认的通道名称,上面的命令会返回mychannel.block
。
现在让我们将peer0.org1.example.com
加入channel。
peer channel join -b mychannel.block
前面我们说过,当需要加入其他节点的时候,需要设置环境变量
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
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
我们继续加入peer0.org2.example.com
:
peer channel join -b mychannel.block
你可以修改环境变量来让别的节点加入信道,这里我就不演示了。
- 更新锚节点(anchor peers)
我最后添加到节点是peer1.org2.example.com
,所以执行完成后我们的命令行现在处于peer1.org2
下。而现在我们需要为Org1设置锚节点peer0.org1
,所以命令行需要先切回到peer0.org1
:
设置当前操作节点为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=peer0.org1.example.com:7051
然后更新Org1锚节点为peer0.org1
:
peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/Org1MSPanchors.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
接下来为Org2设置锚节点peer0.org2
设置当前操作节点为peer0.org2
:
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
然后更新Org2锚节点为peer0.org2
:
peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/Org2MSPanchors.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
安装和实例化链码
我们将利用一个现有的简单链码,应用程序和区块链账本会相互影响通过chaincode
。因此,我们需要在每个会执行以及背书我们交易的peer节点安装chaincode
,然后在信道上实例化chaincode
。
chaincode 支持很多语言,如Gland ,Node.js ,Java 。
安装
在这里我们使用Golang版本的,现在我们来安装下
peer chaincode install -n mycc -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02
接下来,在信道上实例化chaincode。这将初始化信道上的链码,设置链码的背书策略,为目标peer节点启动一个chaincode容器注意-P
参数。这是我们需要指定的当这个chaincode的交易需要被验证的时侯的背书策略。
在下面的命令中,你会注意到我们指定-P "OR ('Org0MSP.member','Org1MSP.member')"
作为背书策略。这意味着我们需要Org1或者Org2组织中的其中一个的节点的背书即可(即只有一个背书)。如果我们改变语法为AND那么我们就需要2个背书者。
peer chaincode instantiate -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n mycc -v 1.0 -c '{"Args":["init","a", "100", "b","200"]}' -P "OR ('Org1MSP.member','Org2MSP.member')"
实例化
现在我们来进行实战
1.查询(Query)
让我们查询一下a的值,以确保链码被正确实例化,state DB被填充。查询的语法如下:
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
2.调用(Invoke)
现在让我们从a账户转10到b账户。这个交易将创建一个新的区块并更新state DB。调用语法如:
peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n mycc -c '{"Args":["invoke","a","b","10"]}'
3.我们再次查询
让我们确认下我们之前的调用被正确地执行了。我们初始化了a的值为100,在上一次调用的时侯转移了10给b。因此,查询a应该展示90。查询的语法如下:
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
运行过程分析
以下是通过./byfn.sh -m up启动网络时,运行script.sh脚本所进行步骤
script.sh
脚本被拷贝到CLI容器中。这个脚本驱动了使用提供的channel name以及信道配置的channel.tx文件的createChannel
命令。createChannel
命令的产出是一个创世区块-<your_channel_name>.block
-这个创世区块被存储在peer节点的文件系统中同时包含了在channel.tx的信道配置。joinChannel
命令被4个peer节点执行,作为之前产生的genesis block的输入。这个命令介绍了peer节点加入<your_channel_name>
以及利用<your_channel_name>.block
去创建一条链。现在我们有了由4个peer节点以及2个组织构成的信道。这是我们的
TwoOrgsChannel
配置文件。peer0.org1.example.com
和peer1.org1.example.com
属于Org1;peer0.org2.example.com
和peer1.org2.example.com
属于Org2这些关系是通过crypto-config.yaml定义的,MSP路径在docker-compose文件中被指定。
Org1MSP(
peer0.org1.example.com
)和Org2MSP(peer0.org2.example.com
)的anchor peers将在后续被更新。我们通过携带channel的名字传递Org1MSPanchors.tx
和Org2MSPanchors.tx
配置到排序服务来实现anchor peer的更新。一个链码-
chaincode_example02
被安装在peer0.org1.example.com
和peer0.org2.example.com
这个链码在
peer0.org2.example.com
被实例化。实例化过程将链码添加到信道上,并启动peer节点对应的容器,并且初始化和链码服务有关的键值对。示例的初始化的值是[”a“,”100“,”b“,”200“]
。实例化的结果是一个名为dev-peer0.org2.example.com-mycc-1.0
的容器启动了。实例化过程同样为背书策略传递相关参数。策略被定义为
-P "OR ('Org1MSP.member','Org2MSP.member')"
,意思是任何交易必须被Org1或者Org2背书。一个针对
a
的查询发往peer0.org1.example.com
。链码服务已经被安装在了peer0.org1.example.com
,因此这次查询将启动一个名为dev-peer0.org1.example.com-mycc-1.0
的容器。查询的结果也将被返回。没有写操作出现,因此查询的结果的值将为100
。一次
invoke
被发往peer0.org1.example.com
,从a
转移10
到b
。然后链码服务被安装到
peer1.org2.example.com
一个
query
请求被发往peer1.org2.example.com
用于查询a
的值。这将启动第三个链码服务名为dev-peer1.org2.example.com-mycc-1.0
。返回a
的值为90,正确地反映了之前的交易,a
的值被转移了10。
有疑问加站长微信联系(非本文作者)