Fabric官方案例first-network
Table of Contents
准备
注: 使用的版本为1.1.0
下载源代码
git clone https://github.com/hyperledger/fabric-samples.git cd fabric-samples # 如果想切换到其他版本, 则输入以下命令. 我直接使用主分支的版本, 因此不切换 git checkout {TAG}
下载工具
想要运行这里的官方案例, 需要准备一些工具. 你可以使用脚本下载, 如果编译过Fabric的, 也可以选另一种方式, 因为如果编译过, 已经有很多镜像文件了, 不需要使用脚本重新下载.
使用脚本下载
可以直接执行以下命令:
# 能翻墙 curl -sSL https://goo.gl/6wtTN5 | bash -s 1.1.0 # 不能翻墙 curl -sSL https://raw.githubusercontent.com/hyperledger/fabric/master/scripts/bootstrap.sh | bash -s 1.1.0
也可以直接到这个网站, 将脚本复制下来, 放在 fabric-samples
根目录下的 bootstrap.sh
中, 这个文件要自己创建.
# 让其可执行 chmod +x ./bootstrap.sh ./bootstrap.sh
编译过Fabric的
如果有根据编译所说的进行编译过, 可以先打开 bootstrap.sh
, 在里面查找 dockerFabricPull()
方法, 将该方法以后(包括该方法)的内容全部注释. 添加两句:
echo ${ARCH} echo ${VERSION} ./bootstrap.sh
查看输出, 根据输出的信息用浏览器到以下两个网站去下载. (终端的curl太慢了)
下载完后解压到 fabric-samples/bin/
目录下, 如果没有 bin目录
, 则创建一个. 这里的工具, 有几个也可以在 fabric/build/docker/bin
里面找到, 直接复制过去也行.
一键运行
cd first-network # 生成配置 ./byfn.sh -m generate # 启动网络 ./byfn.sh -m up # 关闭网络 ./byfn.sh -m down
如果成功, 可以看到类似下面两个图中的内容.
手动运行
cryptogen工具
cryptogen工具为网络节点生成证书信息(x509证书). 这些证书是节点身份的代表, 它们使得我们可以在网络中交易时进行签名/验证身份.
cryptogen工具根据 crypto-config.yaml
文件里的配置进行工具, 这个文件包含了网络拓扑, 并且使得我们可以为Organizations和属于Organizations的节点生成证书与密钥. 每个Organization都有唯一的根证书(ca-cert), 它将组件(peers, orders)绑定到Organization. 通过为每个Organization颁发唯一的CA证书, 我们可以模仿一个典型的区块链网络, 这个网络中的成员将使用自己的数字证书获取授权. Hyperledger Fabric中的交易和通信, 都是通过存储在 keystore
中的实体的私钥签名, 然后使用公钥进行身份验证.
去掉 crypto-config.yaml
中的注释部分, 可以清楚地看清其内容.
sed '/#/d' crypto-config.yaml > cryp.yaml emacs cryp.yaml
可以看到, 里面的内容如下:
crypto-config.yaml
中的 count
表示Organization中的 peer
的数量.
还要注意 OrdererOrgs 下的 Name, Domain, Specs 这些字段. 网络实体的命名规则为: {Hostname}.{Domain}
因此, Orderer节点的命名为 orderer.example.com, MSP ID为Orderer.
使用 cryptogen
生成的数字证书和密钥信息保存在 crypto-config
文件夹中.
configtxgen工具(配置交易生成器)
configtxgen会生成4个配置信息:
- orderer genesis block
- channel configuration transaction
- 两个 anchor peer transactions
其中, orderer block是Orderer Service的创世区块. Channel configuration transaction文件在Channel创建的时候广播给Order. Anchor peer transactions指定了每个Organization在此Channel上的代表节点.
configtxgen的配置文件是 configtx.yaml
. 去掉其中的注释可以看得更清晰些.
该配置文件定义了3个成员: 一个Ordering Service组织(Organization) OrdererOrg, 两个节点组织 Org1 和 Org2, 每个组织由2个Peer组成. 每个组织还指定了Anchor Peer(peer0.org1.example.com和peer0.org2.example.com). 还为每个成员指定了MSP文件夹, 用来存储每个组织在orderer genesis block中指定的根证书, 有了这些证书, 任意和Ordering service通信的节点都可以对其数字签名进行验证.
使用工具
其实怎么去使用这些工具, 在一键式脚本 byfn.sh
中都有写明. 如根据 crypto-config.yaml
中的配置来生成用于相关数字证书, 可以查看 generateCerts()
中的写法.
手动执行, 可加深了解.
创建数字证书:
../bin/cryptogen generate --config=./crypto-config.yaml
生成的数字证书存放在 crypto-config
文件夹中.
生成Ordering Service的创世区块:
设置环境变量 FABRIC_CFG_PATH
, 告诉configtxgen工具, 要到哪里去寻找配置文件 configtx.yaml
:
export FABRIC_CFG_PATH=${PWD} ../bin/configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block
这样, Ordering Service的创世区块就生成了, 放在 channel-artifacts
目录中.
创建Channel配置交易:
export CHANNEL_NAME=mychannel && ../bin/configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID $CHANNEL_NAME
创建Channel上Org1的anchor peer:
../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP
创建Channel上Org2的anchor peer:
../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org2MSP
到此为止, 我们有了Channel, Org1, Org2, Org1的anchor peer, Org2的anchor peer
启动网络
我们使用docker-compose脚本来启动网络, 该脚本使用之前下载的镜像文件, 通过 genesis.block
引导Orderer.
docker-compose -f docker-compose-cli.yaml up -d
如果不使用 -d
, 则日志会实时显示, 这样需要新开一个终端做接下来的工作. 使用了 -d
就表示后台执行.
启动CLI容器, CLI容器主要用来发送一些管理命令.
docker start cli
设置环境变量
为了能在 peer0.org1.example.com
上执行下面的CLI命令, 需要先配置几个环境变量, 这些环境变量已经默认在CLI容器里设置好了, 可以直接使用. 但是, 如果想发送命令到其他的Peers或Orderer中使用, 则需要相应的设置对应的环境变量.
# Environment variables for PEER0 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
我们可以使用configtxgen工具来创建Channel.
首先进行CLI容器:
docker exec -it cli bash
之前, 我们使用configtxgen创建了Channel的配置交易channel.tx, 现在将它作为参数传递给Orderer, 作为创建Channel请求的一部分.
创建Channel的命令包含一些参数. -c
表示Channel名字, -f
表示Channel配置交易, 这边是channel.tx, 当然你也可以挂载你自己的配置交易, 名字也可以不一样, --cafile
允许我们验证TLS握手, 参数为证书根路径.
注: 不使用SSL/TLS的HTTP通信, 就是不加密的通信. SSL/TSL协议的基本过程为:
- Client向Server索要并验证公钥
- 双方协商生成"对话密钥"
- 双方采用"对话密钥"进行加密
前两步就是握手阶段.
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
该命令返回一个创世区块, 我们准备把它加入到Channel. 在CLI容器当前目录下, 会生成一个mychannel.block的区块. 如图所示:
将 peer0.org1.example.com 加到 channel 中:
peer channel join -b mychannel.block
如果要将其他节点加入Channel, 需要修改相应的环境变量. 这边以加入 peer0.org2.example.com 到Channel为例.
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 peer channel join -b mychannel.block
注意, 这会改掉原有的环境变量. 如果全部写在一行去执行, 则不会改变默认的环境变量.
关于Channel.
在Fabric中, Channel是很重要的概念. 一个Peer要想与另一个Peer发生交易, 必须处于同一个Channel中, 账本与Channel也是一对一的关系. Channel需要使用 peer channel ...
这样的命令进行维护.
create(Channel在Orderer结点内部): peer channel create -o orderer.example.com:7050 -c mychannel -f ./channel.tx
join(加入一个Channel): peer channel join -b mychannel.block
update(更新channel的某Org的配置): peer channel update -o orderer.example.com:7050 -c mychannel -f ./Org1MSPanchors.tx
Channel分成System Channel和Application Channel. 通过 peer channel ...
命令维护的都是Application Channel. 对Application Channel发起维护命令的Peer节点, 必须是提交的配置文件中所配置的Org中的一员, 提交的配置文件一般为 channel.tx, mychannel.block, Org1MSPanchors.tx. 本质的意思是说, 该Peer节点要持有该组织所颁发的证书.
create, join, update 三个命令, 都使用了配置文件.
- channel.tx: 这是创建Application Channel的配置文件. channel.tx由configtxgen工具根据指定的profile从configtx.yaml中读取配置数据, profile指的是configtx.yaml中Profiles项下定义的某一个配置项. configtx.yaml文件规定了Channel中包含哪些组织, 创建Channel的命令会根据configtx.yaml生成配置信息, 导入到channel.tx中.
- mychannel.block: 它是Application Channel的创世区块. 通过
peer channel create
生成. channel.tx只是配置原型, 在create过程中, 会根据System Channel的配置进行详细填补, 最后生成一个block. 要想加入Application Channel, 就要先获取这个Channel的genesis block. - Org1MSPanchors.tx: 更新组织的配置文件, 由configtxgen工具根据Org ID从configtx.yaml中指定的profile项生成.
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP
是指从configtx.yaml的Profiles下的TwoOrgsChannel项中获取Org ID为Org1MSP的组织的配置数据, 更新mychannel后, 把获取生成的配置数据导入到./Org1MSPanchors.tx文件中.
更新锚节点
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.example.com:
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 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的安装与初始化
应用程序通过Chaincode与BlockChain交互. 因此, 我们要在每个Peer上安装Chaincode来执行交易, 并在Channel中对其实例化.
将Go语言编写的Chaincode放在Peer的文件系统中:
peer chaincode install -n mycc -v 1.0 -p github.com/chaincode/chaincode_example02/go/
将Node.js语言编写的Chaincode放在Peer的文件系统中:
peer chaincode install -n mycc -v 1.0 -l node -p /opt/gopath/src/github.com/chaincode/chaincode_example02/node/
然后, 在Channel上进行实例化. 实例化会先初始化Chaincode, 为Chaincode设置背书策略, 为目标Peer启动Chaincode容器. -P
参数指定了在Chaincode上, 一个交易被认可所需要的背书级别.
如果策略是 =-P "OR ('Org0MSP.peer','Org1MSP.peer')"=, 表示Org1或Org2中的Peer认可, 就认可该交易. 如果把OR改成AND, 就表示需要两个都认可, 交易才会被认可.
实例化Go语言的Chaincode:
peer chaincode instantiate -o orderer.example.com:7050 --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 -C $CHANNEL_NAME -n mycc -v 1.0 -c '{"Args":["init","a", "100", "b","200"]}' -P "OR ('Org1MSP.peer','Org2MSP.peer')"
实例化Node.js语言的Chaincode:
peer chaincode instantiate -o orderer.example.com:7050 --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 -C $CHANNEL_NAME -n mycc -l node -v 1.0 -c '{"Args":["init","a", "100", "b","200"]}' -P "OR ('Org1MSP.peer','Org2MSP.peer')"
查询
假设我们要查询 a
的值, 以确认Chaincode是否已实例化, state DB是否已填充. 查询的语法如下:
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
查询结果如下图所示:
调用
假设我们要从 a
里面减去10给 b
.
peer chaincode invoke -o orderer.example.com:7050 --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 -C $CHANNEL_NAME -n mycc -c '{"Args":["invoke","a","b","10"]}'
此时, 再次查询 a
的值, 应该会从100变为90.
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
背后的原理
以上所说的步骤, 就是 script.sh
文件中的 ./byfn.sh up
. 现在, 使用 ./byfn.sh down
来关闭它们.
总结一下, 主要步骤包含以下几点:
script.sh
被拷贝到CLI容器中.script.sh
使用设定的Channel名字和Channel的配置文件channel.tx
作为参数执行createChannel
命令.createChannel
输出创世区块, 以channel_name.block
命名. 该区块保存在Peer的文件系统里, 包含了channel.tx
所指定的Channel的配置信息.joinChannel
被执行. 它使用channel_name.block
作为输入, 将四个Peer节点加入到Channel, 并建立一个以channel_name.block
为起始块的链.- 现在的Channel = 2 * Org = 4 * Peer. 其中, Org1 = peer0.org1.example.com + peer1.org1.example.com, Org2 = peer0.org2.example.com + peer1.org2.example.com
- 将Org1MSPanchor.tx, Org2MSPanchor.tx, Channel作为参数给Ordering Service, 更新Org1MSP的Anchor Peer(peer0.org1.example.com)和Org2MSP的Anchor Peer(peer0.org2.example.com).
- 在peer0.org2.example.com上实例化Chaincode, 实例化过程将添加Chaincode到Channel上, 并启动Peer节点对应的容器, 初始化和Chaincode有关的键值对. 在这边, 初始化的值为["a", "100", "b", "200"]. 实例化后会启动一个名为
dev-peer0.org2.example.com-mycc-1.0
的容器. - 实例化过程还会以背书策略为参数.
- 在peer0.org1.example.com上查询
a
的值. 之前, Chaincode已经安装在peer0.org1.example.com上了, 因此查询操作会启动一个名为dev-peer0.org1.example.com-mycc-1.0
的容器. - 在peer0.org1.example.com上执行转账.
- 发送查询到peer1.org2.example.com. 这时会启动第3个容器
dev-peer1.org2.example.com-mycc-1.0
.
总结
要想对账本进行操作, 需要先在Peer上安装Chaincode. Chaincode容器在需要时(如查询)才会启动. Channel中每个Peer都有账本的副本, 存储了不可改变的, 序列化的记录区块和State Database用于保存当前的Fabric状态. 没有安装Chaincode的Peer也会同步账本.
查看日志
CLI容器的日志:
docker logs -f cli
Chaincode的日志:
docker logs dev-peer0.org2.example.com-mycc-1.0
CouchDB
状态数据库使用goleveldb或CouchDB. 默认为goleveldb.
数据持久化
如果要在Peer容器中进行数据持久化, 可以将docker容器内相应的目录挂载到宿主机器的一个目录中. 如, 添加下面的内容到 docker-compose-base.yaml
的Peer的约定中:
volumes: - /var/hyperledger/peer0:/var/hyperledger/production
Generated by Emacs 25.x(Org mode 8.x)
Copyright © 2014 - Pinvon - Powered by EGO