linux系统版本:CentOS Linux release 7.2.1511 (Core)
构建您的第一个网络(BYFN)场景提供了一个由两个组织组成的示例Hyperledger Fabric网络,每个组织都有两个peer节点,以及一个“solo”ordering服务。
(1)先决条件
- 安装curl
- 安装docker & docker compose,Docker 版本要求 17.06.2-ce or greater
我本机的docker 版本是Docker version 17.09.0-ce, build afdb6d4
docker-compose version 1.16.1, build 6d1ac219
- 安装go语言,版本1.9.x or greater
- 安装node.js和npm
- python 2.7
The Fabric Node.js SDK requires an iteration of Python 2.7 in order
for
npm install
operations to complete successfully
cd
first
-
network
curl
-
sSL
https
:
//
goo
.
gl
/
Q3YRTi
|
bash 如果这个命令不能成功执行的话,就先去下载好对应的脚本,然后再执行,执行好后会发现当前目录多了一个bin目录,目录里面有:
cryptogen,
configtxgen,
configtxlator, and
peer
然后把这个bin目录添加到系统的环境变量中去
(2)官网提供了两种方法创建网络:
- 懒人方法,一键运行脚本
cd
first
-
network
./
byfn
.
sh
-
m
generate
./
byfn
.
sh
-
m
up
./
byfn
.
sh
-
m
down
- 逐步运行命令
用
cryptogen来为网络中的实体生成加密材料(证书),这些证书是身份的代表,它们允许在我们的实体进行交流和交易时进行签名/验证身份验证。
证书是如何工作的:
cryptogen工具读取包含网络拓扑的
crypto-config.yaml配置文件来生成相关证书,并允许我们为组织和属于这些组织的组件生成一组证书和密钥。每个组织都配置了一个唯一的根证书(ca-cert),它将特定组件(peer node和ordering node)绑定到该组织。通过为每个组织分配唯一的CA证书,我们正在模仿一个典型的网络,参与会员将使用自己的证书授权。 Hyperledger Fabric中的交易和通信由实体的私钥(keystore)签名,然后通过公钥(signcerts)进行验证。
我们运行完
cryptogen
这个工具后, 生成的证书和秘钥会保存在一个名为
crypto-config
的文件夹里面
configtxgen tool
用来创建4个配置文件:
- orderer genesis block,
- channel channel configuration transaction,
- and two anchor peer transactions - one for each Peer Org.
order block是用于ordering服务的创世纪块,
channel transaction文件在通道创建时广播给orderer。
anchor peer transactions, 按照名称可能得出的提示,
anchor peer transactions在此通道上指定每个组织的锚点peer。
configtxgen
tool是如何工作的?
Configtxgen 工具读取 -
configtx.yaml
- 这个配置文件,这个配置文件包含一个简单网络的定义。有3个会员 - 一个 Orderer Org (
OrdererOrg
) 和2个 Peer Orgs (
Org1
&
Org2
) ,这两个Org分别管理着两个peer,这个文件也指定了一个 组合-
SampleConsortium
- ,包含了两个Peer Orgs.
注意:sampleConsortium被定义在system-level profile中,接下来被channel-level profile引用。Channels存在在consortium的范围内,所有的consortium都在network的范围内。
你会看到这个文件有两个不同的头部,一个是给-
TwoOrgsOrdererGenesis
- 用,另一个是给通道用-
TwoOrgsChannel
.
这两个头部很重要,因为会作为创建上面4个配置文件的参数给传递出去。
这个配置文件还有两个附加的定义是值得我们注意的:
Org(peer0.org1.example.com & peer0.org2.example.com)的anchor节点,另外一个就是指向每个成员的MSP目录的位置,基于此,我们可以将每个Org的根证书存放在orderer Genesis block中,这是一个很重要的概念。现在任意network entity与ordering service通信时就能对其数字签名进行验证。
可以通过configtxgen and cryptogen手动生成证书/密钥以及各项配置文件。同样,可以参考byfn.sh脚本实现。
可以参考byfn.sh脚本中的generateCerts函数用来生成证书(这些证书被定义在crypto-config.yaml中的网络配置所使用)所需要的命令。为了方便起见,我们提供一个参考如下。
首先,先跑起来cryptogen工具,我们的二进制文件都在bin目录下,因此我们需要cd到tool所在的目录下.
../bin/cryptogen generate --config=./crypto-config.yaml
接下来,我们会告诉configtxgen工具去哪找到需要调用的configtx.yaml文件。
首先,我们需要设置一个环境变量,用于告知configtxgen根据去哪找configtx.yaml配置文件。接下来,我们调用configtxgen工具创建orderer Genesis block
export FABRIC_CFG_PATH=
$PWD..
/bin/configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block
接着,我们创建channel transaction artifact(channel.tx)。然后,确保替换$CHANNEL_NAME
export CHANNEL_NAME=
mychannel
..
/bin/configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID $CHANNEL_NAME
接着,我们在我们正在创建的channel上定义Org1的anchor节点。然后,确保替换$CHANNEL_NAME
../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP
然后,我们在相同的channel上定义Org2的anchor节点。
../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org2MSP
我们利用docker-compose脚本来启动我们的network。docker-compose文件引用了我们之前下载的镜像,并使用前面生成的genesis block来引导orderer。
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/
peer# command:
/bin/bash -c
‘./scripts/script.sh ${CHANNEL_NAME}; sleep $TIMEOUT‘
volumes ---------docker-compose-cli.yaml
如果没有注释掉上面的命令的话,在network启动的时候,其将执行所有的CLI命令,然后就会导致文章末尾中的错误。
启动network,注意$CHANNEL_NAME,<pick_a_value>自己设定
CHANNEL_NAME=$CHANNEL_NAME TIMEOUT=<pick_a_value> docker-compose -f docker-compose-cli.yaml up -d
对于以下针对peer0.org1.example.com的CLI命令,我们需要使用以下给出的四个环境变量来介绍我们的命令。这些peer0.org1.example.com变量都被包含在CLI容器里,因此我们可以不用传递的操作它们。然而!,如果你想发送calls到其他peers或者orderer,你需要根据情况提供这些变量。打开docker-compose-base.yaml并查看具体的路径信息
# Environment variables
for
PEER0CORE_PEER_MSPCONFIGPATH
=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/
mspCORE_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
docker exec -it cli bash
请回忆下我们使用configtxgen工具生成channel配置artifact-channel.tx。我们将把artifact作为创建channel的请求的一部分发送给orderer。
注意到在接下来的命令中我们发送了-- cafile作为命令的一部分。这个是orderer证书的本地路径,使得我们可以验证TLS握手。
我们使用-c flag 标注出我们的channel名称,用-f flag标注出我们的channel 配置transaction。在本例中是channel.tx,然而你可以使用不同的名称用于挂载配置transaction。使用下面创建channel的语句的时候注意channel-name。
export CHANNEL_NAME=
mychannel
peer channel create
-o orderer.example.com:
7050
-c $CHANNEL_NAME -f ./channel-artifacts/channel.tx --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
上述命令返回了一个genesis block- <channel-ID.block> -我们可以通过这个id进入到channel。它包含channel.tx中指定的配置信息,创建成功后有如下输出:
接下来的操作都需要在CLI容器中进行,在操作peer0.org1.example.com之外的peer时,需要记得相关环境变量的命令。
接下来我们把peer0.org1.example.com加入到channel中去,channel-ID.block是之前生成的,这里我的是mychannel.block。
peer channel join
-b <channel-ID.block>
你可把其他的peer加入到该channel上,但是需要设置上述的四个环境变量。
我们这里只是使用已经存在的chaincode。
application通过chaincode与blockchain ledger进行交互。我们把chaincode安装到execute与endorse我们transaction的peer上,接下来在channel上初始化chaincode。
首先,安装sample go代码到4个peer之一的peer上。以下命令把chaincode的源代码放到了peer节点的文件系统上。
peer
chaincode
install
-
n
mycc
-
v
1.0
-
p
github
.
com
/
hyperledger
/
fabric
/
examples
/
chaincode
/
go
/
chaincode_example02
接下来,在channel上实例化chaincode。这将在channel上初始化chaincode,同时设置chaincode的endorsement的策略,然后在目标peer上启动chaincode容器。请注意-P参数,我们通过设置这个参数,来指定transaction的endorsement的需求level,用于验证chaincode。
在下面的命令,我们定义了endorsement策略为-P "OR (‘Org0MSP.member‘,‘Org1MSP.member‘)"。这表示我们需要隶属于Org1或者Org2的peer进行“endorsement”(也就是说,只有一个endorsement)。如果把or改为and则说明我们需要两个endorsement
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')"
首先查询a的值,确保chaincode已经正常的实例化,同时确保state DB已经被填充
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
让我们从a账户转移10个到b账户,这个命令将会创建新的block同时更新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"]}'
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
- script.sh脚本在CLI容器内部执行,该脚本执行了createChannel命令,提供了channel名称,同时使用channel.tx进行channel配置
- createChannel的输出是一个genesis block,使用channel名称命名的block,例如mychannel.block,该block在peers的文件系统上存储,该block包括channel.tx指定的channel配置信息。
- 加入channel的命令对所有4个peer进行执行,把之前生成的genesis block作为输入。这个join命令使得peers加入mychannel里面,同时创建了一个以mychannel.block作为开始的chain。
- 接着,我们拥有了由4个peer,两个organization组成的channel。这都在我们TwoOrgsChannel profile.里面。
- peer0.org1.example.com 与 peer1.org1.example.com 隶属于 Org1; peer0.org2.example.com 以及 peer1.org2.example.com 隶属于 Org2。这些关系在crypto-config.yaml中定义,同时在我们的docker compose中指定了MSP的路径。
- Org1MSP (peer0.org1.example.com) 以及 Org2MSP (peer0.org2.example.com)的anchor节点接下来被更新了。我们基于建立的channel把Org1MSPanchors.tx 与 Org2MSPanchors.tx 的artifacts,发送给orderering service,以实现上述的更新。
- chaincode_example02被安装在了peer0.org1.example.com 与 peer0.org2.example.com
- 接着chaincode在peer0.org2.example.com被实例化。实例化把chaincode加到channel上,并启动目标peer的容器,接着初始化chaincode有关的键-值对( [“a”,”100” “b”,”200”])。实例化的过程导致了dev-peer0.org2.example.com-zeychaincode-1.0的启动。
- 实例化需要有endorsement策略的参数,这里设置为-P "OR (‘Org1MSP.member‘,‘Org2MSP.member‘)",表示任意transaction必须被Org1 或者 Org2的一个peer进行endorsed。
- 接下来把对“a”的查询发送给peer0.org1.example.com,即在peer0.org1.example.com查询a的值。chaincode之前已经安装在了peer0.org1.example.com上,因此这个查询将会针对Org1 peer0 启动一个容器(dev-peer0.org1.example.com-zeychaincode-1.0),然后查询结果得到返回,没有任何写的操作发生,因此返回值是100
- 接着调用请求发送给peer0.org1.example.com,把10个从a转移到b。
- 然后chaincode在peer1.org2.example.com进行安装。
- 然后一个查询a的余额的请求发送到peer1.org2.example.com。这个启动了第三个chaincode容器(dev-peer1.org2.example.com-mycc-1.0),90被返回。正确的反应了上述transaction,a的值被改为了10。
Error: Got unexpected status: BAD_REQUEST
原因是存在同名的channel