启动环境
在开始本博客之前,请确保已安装对应版本的二进制工具、镜像以及git clone fabric-samples
cd fabric-samples/test-network
如果之前启动过test-network下的network.sh脚本,执行以下命令清除之前的环境。
./network.sh down
使用脚本启动测试网络(默认通道mychannel):
./network.sh up createChannel
如果命令无误,shell窗口最后会打印:========= Channel successfully joined ===========
使用脚本添加Org3
执行脚本,会看到生成Org3的证书,创建Org3组织定义,然后通道配置被更新、签名、提交到通道。
cd addOrg3
./addOrg3.sh up
如果命令无误,shell窗口最后会打印:
========= Finished adding Org3 to your test network! =========
手动执行命令添加Org3到通道
前一节我们使用官方提供的脚本,自动帮我们完成各种操作,为了更好地理解执行过程,本节我们尝试手动执行各种命令。
清除先前的环境
./addOrg3.sh down
返回原目录,再次构建两组织的fabric网络
cd ..
./network.sh up createChannel
生成Org3的证书
这里我们使用cryptogen 生成组织三Peer节点的证书,cryptogen根据addOrg3/org3-crypto.yaml生成证书。
cd addOrg3
../../bin/cryptogen generate --config=org3-crypto.yaml --output="../organizations"
命令执行完会在test-network/organizations/peerOrganizations看到Org3的证书,生成完证书之后,我们可以使用configtxgen打印出Org3的定义,使用的是当前目录(fabric-samples/test-network/addOrg3)下的configtx.yaml文件。
export FABRIC_CFG_PATH=$PWD
../../bin/configtxgen -printOrg Org3MSP > ../organizations/peerOrganizations/org3.example.com/org3.json
上面的命令创建一个JSON文件org3.json并将其写入test-network / organizations / peerOrganizations / org3.example.com文件夹。 组织定义包含Org3的策略定义以及以base64格式编码的三个重要证书:CA证书、TLS证书、admin用户证书
启动Org3的节点及Cli
docker-compose -f docker/docker-compose-org3.yaml up -d
命令执行成功后,将会启动Peer:peer0.org3.example.com容器和Org3CLI容器。
准备Cli环境
进入容器
docker exec -it Org3cli bash
设置变量
export ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
export CHANNEL_NAME=mychannel
获取配置
我们需要获取最新版本的通道配置,由于Org3不是通道成员,因此我们这里使用Org1(或使用Org2)管理员身份进行操作。
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
获取最新的配置
peer channel fetch config config_block.pb -o orderer.example.com:7050 -c $CHANNEL_NAME --tls --cafile $ORDERER_CA
上面命令将二进制protobuf通道配置块保存到config_block.pb(名称和文件扩展名可任意设置),输出结果:
通过上面截图,我们可以得知mychannel的最新配置块是块2(块号为2,也就是第三个块),而不是创世块。 这是因为测试网络脚本network.sh更新了Org1和Org2的锚节点。
block 0: 创世块
block 1: Org1 锚节点更新
block 2: Org2 锚节点更新
通道配置块转换成JSON
现在,我们将使用configtxlator工具将此通道配置块解码为JSON格式。 我们还必须删除所有与我们要进行的更改无关的标题,元数据,创建者签名等。 我们通过jq工具完成此任务:
configtxlator proto_decode --input config_block.pb --type common.Block | jq .data.data[0].payload.data.config > config.json
上面命令为我们提供了经过精简的JSON对象config.json,它将作为配置更新的基准。
添加Org3的证书
我们将再次使用jq工具将Org3配置定义org3.json添加到application groups字段中,并输出经过修改的config.json。
jq -s '.[0] * {"channel_group":{"groups":{"Application":{"groups": {"Org3MSP":.[1]}}}}}' config.json ./organizations/peerOrganizations/org3.example.com/org3.json > modified_config.json
将config.json转换为config.pb:
configtxlator proto_encode --input config.json --type common.Config --output config.pb
将modified_config.json编码为modified_config.pb:
configtxlator proto_encode --input modified_config.json --type common.Config --output modified_config.pb
使用configtxlator计算这两个配置协议之间的差异。 此命令将输出一个新的名为org3_update.pb的protobuf二进制文件:
configtxlator compute_update --channel_id $CHANNEL_NAME --original config.pb --updated modified_config.pb --output org3_update.pb
org3_update.pb里面包含了Org3的定义以及指向Org1、Org2的高级指针,即增量更新,原有配置尽量不做更改。org3_update.pb转换为json文件:
configtxlator proto_decode --input org3_update.pb --type common.ConfigUpdate | jq . > org3_update.json
增加头字段,生成新的文件org3_update_in_envelope.json
echo '{"payload":{"header":{"channel_header":{"channel_id":"'$CHANNEL_NAME'", "type":2}},"data":{"config_update":'$(cat org3_update.json)'}}}' | jq . > org3_update_in_envelope.json
转换为Fabric所需的完整protobuf格式。 我们将最终更新对象命名为org3_update_in_envelope.pb:
configtxlator proto_encode --input org3_update_in_envelope.json --type common.Envelope --output org3_update_in_envelope.pb
签名并提交配置更新
在将配置写入账本之前,我们需要来自Admin用户的签名。通道修改策略(mod_policy)为默认值“ MAJORITY”,即大多数现有的组织管理员来对其进行签名。 因为我们只有两个组织 Org1和Org2 ,大多数是两个,所以我们都需要它们进行签名。
由于先前我们登陆身份为Org1的管理员,这里我们先以Org1的身份进行签名:
peer channel signconfigtx -f org3_update_in_envelope.pb
切换身份为Org2的管理员:
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=peer0.org2.example.com:9051
执行peer channel update命令(Org2的签名附加到调用中)
peer channel update -f org3_update_in_envelope.pb -c $CHANNEL_NAME -o orderer.example.com:7050 --tls --cafile $ORDERER_CA
如果执行成功,会返回一个新的块:block3。过程中也可以再开一个shell监控日志:
docker logs -f peer0.org1.example.com
Org3加入通道
切换到Org3的admin
export CORE_PEER_LOCALMSPID="Org3MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/organizations/peerOrganizations/org3.example.com/users/Admin@org3.example.com/msp
export CORE_PEER_ADDRESS=peer0.org3.example.com:11051
我们必须从区块0开始,注意此处不是block3
peer channel fetch 0 mychannel.block -o orderer.example.com:7050 -c $CHANNEL_NAME --tls --cafile $ORDERER_CA
加入通道
peer channel join -b mychannel.block
配置Leader选举
分为静态配置和动态选举。
静态配置(所有Peer节点均在yaml文件中进行如下配置)
CORE_PEER_GOSSIP_USELEADERELECTION=false
CORE_PEER_GOSSIP_ORGLEADER=true
动态选举
CORE_PEER_GOSSIP_USELEADERELECTION=true
CORE_PEER_GOSSIP_ORGLEADER=false
由于新增加的组织Peer获取不到原有的成员视图,因此此选项类似于静态配置,刚开始每个Peer都宣称自己是Leader,当通道配置更新后,则仅有一个活跃的Leader。
完成链码周期2.0
此处我们需要再打开一个shell窗口,利用官方脚本为Org1和Org2的Peer部署链码fabar:
cd fabric-samples/test-network
./network.sh deployCC
可以留意到在checkcommitreadiness时,已经变成三个组织。我们可以通过以下步骤给Org3部署Fabcar链码,以下命令在test-network目录执行,无需在Org3CLI容器中执行:
export PATH=${PWD}/../bin:${PWD}:$PATH
export FABRIC_CFG_PATH=$PWD/../config/
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org3MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org3.example.com/users/Admin@org3.example.com/msp
export CORE_PEER_ADDRESS=localhost:11051
打包链码:
peer lifecycle chaincode package fabcar.tar.gz --path ../chaincode/fabcar/go/ --lang golang --label fabcar_1
安装链码:
peer lifecycle chaincode install fabcar.tar.gz
Org3需要像Org1和Org2那样同意链码定义,因此需要先获取Package ID
peer lifecycle chaincode queryinstalled
Package ID: fabcar_1:aca5cf806d53b8860e3bc4234af8fe9a017e7082d98108e07ffc7ea36dbc2e07, Label: fabcar_1
同意链码定义
export CC_PACKAGE_ID=fabcar_1:aca5cf806d53b8860e3bc4234af8fe9a017e7082d98108e07ffc7ea36dbc2e07
peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 1 --init-required --package-id $CC_PACKAGE_ID --sequence 1 --tls true --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
查询已提交的链码定义
peer lifecycle chaincode querycommitted --channelID mychannel --name fabcar --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
由于我们使用的是默认的背书策略,即大多数组织认可。之前我们需要Org1与Org2两个的同意,现在我们需要Org1、Org2、Org3中的任意两个同意即可。
等待一段时间,Org3节点链码容器启动可能需要一定的时间。如下图,peer0.org3.example.com对应的链码容器已启动:
在peer0.org3.example.com节点查询
peer chaincode query -C mychannel -n fabcar -c '{"Args":["queryAllCars"]}'
在peer0.org3.example.com节点invoke:
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls true --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n fabcar --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:11051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt -c '{"function":"createCar","Args":["CAR11","Honda","Accord","Black","Tom"]}'
在peer0.org3.example.com节点查询
peer chaincode query -C mychannel -n fabcar -c '{"Args":["queryAllCars"]}'
结论
虽然过程中较为复杂,但是最终的逻辑是一步一步得到一个以protobuf二进制格式表示的增量对象,然后获取必要数量的管理员签名以满足通道更新策略。过程中使用了configtxlator和jq工具以及Peer channel命令。