Hyperledger Fabric 1.2系列 -- 将组织添
前提条件
请看上篇内容的配置: 通过脚本方式将组织添加进通道
介绍
我们将向first-network
网络添加一个新的Org3
组织,原本该网络内存在着Org1
和Org2
两个组织。
确认关闭网络
请确认你已经将网络关闭。如果你执行过eyfn.sh
脚本,请关闭网络。
./byfn.sh down
这将关闭网络,删除所有的容器,撤销org3相关的内容。
开始
设置日志级别
将cli
和Org3cli
容器的日志级别设定为DEBUG
。
对于cli
容器可以修改/first-network/docker-compose-cli.yaml
文件来设置。例如:
cli:
container_name: cli
image: hyperledger/fabric-tools:$IMAGE_TAG
tty: true
stdin_open: true
environment:
- GOPATH=/opt/gopath
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_LOGGING_LEVEL=DEBUG
# - CORE_LOGGING_LEVEL=INFO
- CORE_PEER_ID=cli
对于Org3cli
容器,通过修改/first-network/docker-compose-org3.yaml
文件来设置。例如:
Org3cli:
container_name: Org3cli
image: hyperledger/fabric-tools:$IMAGE_TAG
tty: true
stdin_open: true
environment:
- GOPATH=/opt/gopath
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
#- CORE_LOGGING_LEVEL=INFO
- CORE_LOGGING_LEVEL=DEBUG
- CORE_PEER_ID=Org3cli
启动网络
生成证书及MSP等内容:
./byfn.sh generate
启动网络:
./byfn.sh up
你将会看到:
2018-10-12 09:04:26.859 UTC [msp/identity] Sign -> DEBU 046 Sign: digest: 2B28A4F9085F9AB6F93C54E5E6C099740FD7862F14B6268DFA3F5F7A6CCBE2A6
90
===================== Query successful on peer1.org2 on channel 'mychannel' =====================
========= All GOOD, BYFN execution completed ===========
_____ _ _ ____
| ____| | \ | | | _ \
| _| | \| | | | | |
| |___ | |\ | | |_| |
|_____| |_| \_| |____/
接下来我们将要手动添加Org3。
生成Org3 加密材料
进入first-network
目录下的org3-artifacts
:
cd org3-artifacts
这里有两个配置文件:
VirtualBox:~/code/fabric/src/fabric-samples/first-network/org3-artifacts$ ls
configtx.yaml org3-crypto.yaml
首先为Org3生成加密材料:
VirtualBox:~/code/fabric/src/fabric-samples/first-network/org3-artifacts$ cryptogen generate --config=./org3-crypto.yaml
org3.example.com
这个命令会读取org3-crypto.yaml
文件,并利用cryptogen
工具为Org3
组织的两个 peer 生成秘钥和证书。并存放在当前目录的crypto-config
文件夹下。
确保你已经将二进制文件添加环境变量下。可以参考上一篇内容添加。
使用configtxgen
工具,读取configtx.yaml
文件生成org3.json
文件,并存放在/first-network/channel-artifacts/
目录下。
export FABRIC_CFG_PATH=$PWD && configtxgen -printOrg Org3MSP > ../channel-artifacts/org3.json
这个文件包含了Org3
的策略定义,已经base64
编码格式的三个重要证书:管理员用户证书(稍后充当Org3的管理员),CA根证书和TLS根目录证书。在稍后的步骤中,我们会将此JSON文件附加到通道配置。
最后,我们要将Orderer Org
的MSP
材料移植到Org3
的 crypto-config
目录中。 我们需要特别关注的是Orderer
的TLS
根证书,它将允许Org3
实体与网络对等节点之间的安全通信。
cd ../ && cp -r crypto-config/ordererOrganizations org3-artifacts/crypto-config/
准备CLI环境
配置翻译工具configtxlator
可以简化Fabric网络中的配置任务,可以在不同的等效数据格式之间轻松转换(比如:在 protobufs 和 JSON 之间)。
首先,进入 CLI 容器。在这个容器中,我们可以访问crypto-config
目录中的两个组织和Orderer组织的MSP资料。
docker exec -it cli bash
导出ORDERER_CA
和 CHANNEL_NAME
变量:
export 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 && export CHANNEL_NAME=mychannel
检查时候设置成功:
echo $ORDERER_CA && echo $CHANNEL_NAME
如果你重新启动了 CLI 容器,你就需要重新导出
ORDERER_CA
和CHANNEL_NAME
获取配置
获取channel的配置块
我们需要获取配置的最新版本,因为通道配置元素是版本化的。版本控制可以防止重复或重放配置更改。此外,还有助于确保并发性(比如说删除通道中的某个组织,版本控制有助于防止删除两个组织,不仅仅是要删除的组织)。
peer channel fetch config config_block.pb -o orderer.example.com:7050 -c $CHANNEL_NAME --tls --cafile $ORDERER_CA
此命令将二进制 protobuf 通道配置块保存到config_block.pb
。
当你执行完peer channel fetch
后,请注意打印信息的最后一行。
2018-10-15 07:31:44.191 UTC [cli/common] readBlock -> INFO 048 Received block: 2
这里告诉我们mychannel
的最新配置块实际上是块2,而不是创世块。默认情况下,该命令返回目标通道的最新配置块,在本例中为第三个块。这是因为 BYFN 脚本定义了两个组织的锚节点,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
这里会生成一个 config.json 的 JSON 文件。
你可以研究一下这个文件,它揭示了底层配置结构和可以进行的其他类型的通道更新。
jq命令允许直接在命令行下对JSON进行操作,包括分片、过滤、转换等。详细的介绍可以参考:https://blog.csdn.net/u011641885/article/details/45559031
添加 Org3 加密资料
我们将再次使用jq
工具来配置ORG3。将org3.json
附加到通道的应用程序组字段,输出为modified_config.json
。
jq -s '.[0] * {"channel_group":{"groups":{"Application":{"groups": {"Org3MSP":.[1]}}}}}' config.json ./channel-artifacts/org3.json > modified_config.json
现在,在CLI容器中,我们有了两个JSON文件,config.json 和 modified_config.json。 config.json文件中仅包含 Org1 和 Org2 相关配置,而modified
文件包含所有三个Orgs
的配置。此时,我们只需重新编码这两个JSON文件并计算增量即可。
首先, 转换 config.json 回一个名为 protobuf 的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
用来计算这两个配置protobuf之间的增量。此命令将输出一个名为的新protobuf二进制文件org3_update.pb
:
configtxlator compute_update --channel_id $CHANNEL_NAME --original config.pb --updated modified_config.pb --output org3_update.pb
这个新的配置org3_update.pb
包含了 Org3 、 Org1 和 Org2的内容。我们没有包含 Org1 和 Org2 的 MSP和修改策略信息,是因为这些数据已经存在于通道的创世区块中了。因此我们只需要两种配置间的增量。
将org3_update.pb
转化成org3_update.json
:
configtxlator proto_decode --input org3_update.pb --type common.ConfigUpdate | jq . > org3_update.json
现在我们有了一个JSON格式的更新文件org3_update.json
,我们需要将原来剥离的标题字段增加上。并命名文件为org3_update_in_envelope.json
:
echo '{"payload":{"header":{"channel_header":{"channel_id":"mychannel", "type":2}},"data":{"config_update":'$(cat org3_update.json)'}}}' | jq . > org3_update_in_envelope.json
我们再次使用configtxlator
工具,将org3_update_in_envelope.json
文件转化成protobuf格式的org3_update_in_envelope.pb
文件:
configtxlator proto_encode --input org3_update_in_envelope.json --type common.Envelope --output org3_update_in_envelope.pb
签名并提交配置更新
在我们的 CLI 容器中,存在了一个protobuf 格式的org3_update_in_envelope.pb
文件。在将配置写入到账本前,我们需要用Admin用户进行签名。我们通道的应用组策略默认是MAJORITY
,也就是需要大多数存在的组织管理员来进行签名。由于我们只有Org1 和 Org2 两个组织,因此我们需要他们的共同签名。如果没有他们共同的签名,排序服务会拒绝该交易的发生。
我们先让Org1的管理员进行签名。由于CLI容器是由Org1 MSP信息来引导启动的,所以我们可以直接使用peer channel signconfigtx
命令进行签名。
peer channel signconfigtx -f org3_update_in_envelope.pb
你会看到如下信息:
2018-10-15 09:50:08.824 UTC [msp/identity] Sign -> DEBU 03f Sign: plaintext: 0AF1060A1508021A0608D0C591DE0522...34F5CE5B01E9A6728D8AAB754FF9B771
2018-10-15 09:50:08.824 UTC [msp/identity] Sign -> DEBU 040 Sign: digest: F8CB98C85AA8ADD71B834E3ED813D589591DAC75BAFB71F64CF8C786628A8973
最后一步是切换CLI容器的身份为Org2 Admin用户,我们通过导出特定的四个环境变量来达到目的。导出Org2的环境变量:
export CORE_PEER_LOCALMSPID="Org2MSP"
export 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
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=peer0.org2.example.com:7051
最后我们执行peer channel update
命令。这个命令会自动将Org2的签名附着在上面,我们不需要再手动执行签名操作了。
排序服务的更新操作会进行一系列的系统签名和策略检查。会输出一些流式日志,你可以分析他们。打开一个新的终端,输入
docker logs -f orderer.example.com
发送更新调用:
peer channel update -f org3_update_in_envelope.pb -c $CHANNEL_NAME -o orderer.example.com:7050 --tls --cafile $ORDERER_CA
你将会看到如下消息摘要:
2018-10-15 10:02:02.417 UTC [channelCmd] update -> INFO 04d Successfully submitted channel update
我们重新打开一个终端,输入docker logs -f peer0.org1.example.com
来查看日志信息。
通道更新成功之后,会产生一个新的区块-block 5,并在所以的节点上广播。如果你还记得0-2区块是通道初始化配置,3 和 4 是mycc 链码的实例化和调用。块5是关于Org3的最新通道配置。
如果要检查其内容,请按照演示过程获取和解码配置块。
配置领导者选举
此事例默认是动态的领导者选举,在
peer-base.yaml
文件中配置的。
新加入的节点使用创世区块来进行配置,不会包含有关在通道配置更新中添加的组织的信息。因此,新的peer 不能使用gossip 服务,因为他们没有办法验证其他peer发送的区块的有效性,直到他们获得将组织添加到channel的配置事务。因此,新加入的peer 必须具有以下配置中的一个,以便他们从orderer服务接收区块。
- 静态领导模式:
CORE_PEER_GOSSIP_USELEADERELECTION=false
CORE_PEER_GOSSIP_ORGLEADER=true
对于新添加到通道的peer节点,此配置必须相同。
- 动态选举模式:
CORE_PEER_GOSSIP_USELEADERELECTION=true
CORE_PEER_GOSSIP_ORGLEADER=false
将Org3加入通道
此时,通道的配置已经包含了我们新的组织Org3。意味着与其关联的对等节点现在可以加入mychannel
。
首先,启动Org3的节点和特定的CLI容器。
打开一个新的终端,从first-network
目录中启动 Org3 docker compose:
docker-compose -f docker-compose-org3.yaml up -d
下面进入Org3cli 容器:
docker exec -it Org3cli bash
就像我们使用初始CLI容器一样,导出两个关键的环境变量:ORDERER_CA和CHANNEL_NAME:
export 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 && export CHANNEL_NAME=mychannel
检查是否配置正确:
echo $ORDERER_CA && echo $CHANNEL_NAME
现在我们向排序服务询问创世块。由于我们成功的频道更新,排序服务能够验证Org3的有效性。如果Org3的配置没有被更新,则排序服务会拒绝此请求。
你也可以打开一个新的终端来查看排序服务节点的日志信息
使用peer channel fetch
命令来检索区块:
peer channel fetch 0 mychannel.block -o orderer.example.com:7050 -c $CHANNEL_NAME --tls --cafile $ORDERER_CA
注意,我们使用0
表示我们想要第0个区块,也就是创世区块。如果我们只是简单的使用peer channel fetch config
命令,我们会收到第5个区块,也就是Org3配置更新的区块。我们也就没有办法获取后续区块了。所以我们应该指定参数0
。
使用peer channel join
命令来加入创世区块。
peer channel join -b mychannel.block
如果你想加入Org3的第二个节点,就要导出TLS
和ADDRESS
变量,并且执行peer channel join command
命令。
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org3.example.com/peers/peer1.org3.example.com/tls/ca.crt && export CORE_PEER_ADDRESS=peer1.org3.example.com:7051
peer channel join -b mychannel.block
升级并调用chaincode
最后一个难题是增加链码的版本并认可Org3的策略。由于要升级链码的版本,所以我们可以放弃之前低版本的链码。所以我们关注升级Org3的链码。
进入Org3 CLI 容器,执行:
peer chaincode install -n mycc -v 2.0 -p github.com/chaincode/chaincode_example02/go/
如果想在Org3组织的第二个节点上安装链码,你需要修改相应的环境变量。这个操作不是必须的。你只需要在背书节点或者负责通信的主节点上安装链码即可。
现在我们回到 CLI 容器并在Org1和Org2的节点上安装新版本链码(注意:不是Org3cli容器了)。 之前我们在CLI 容器中修改了环境变量,使用的是Org2管理员身份提交的频道更新事务,因此我们再执行下面命令的时候,代表的是peer0.Org2
。
如果你不确定当前CLI 具体代表的Org1 还是 Org2 。你可以在CLI 容器内部输入
env | grep CORE_PEER_LOCALMSPID
来查看。同样需要查看一下是否指定了ORDERER_CA
和CHANNEL_NAME
这两个环境变量。
安装链码:
peer chaincode install -n mycc -v 2.0 -p github.com/chaincode/chaincode_example02/go/
切换环境变量,作为peer0.org1
身份:
export CORE_PEER_LOCALMSPID="Org1MSP"
export 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
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
然后重新执行安装链码命令:
peer chaincode install -n mycc -v 2.0 -p github.com/chaincode/chaincode_example02/go/
现在我们准备升级链码。我们并没有对链码的源代码进行修改,只是在mychannel
的mycc
上增加了Org3的背书策略。
支持链码实例化策略的身份,同样也支持链码的升级操作。默认是组织的管理员。
调用链码升级命令
peer chaincode upgrade -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -v 2.0 -c '{"Args":["init","a","90","b","210"]}' -P "OR ('Org1MSP.peer','Org2MSP.peer','Org3MSP.peer')"
上面的命令中。v
指定新的链码版本,并且链码升级时的背书策略也做了改变-P "OR ('Org1MSP.peer','Org2MSP.peer','Org3MSP.peer')"
, 增加了Org3的内容。用c
参数表示调用的函数和参数。
与实例化链码一样,链码升级同样调用init
方法,可以传递参数。
升级调用会将心产生的区块-块6,添加到账本,并允许Org3节点在背书阶段执行交易。
我们进入Org3cli 容器来查询a
的结果。这个过程可能需要一会儿时间,因为会构建一个新的chaincode容器。
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
将会返回90
现在我们调用invoke
将 a
向b
转移10
。
peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -c '{"Args":["invoke","a","b","10"]}'
最后我们再查询一下a
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
你将会得到80
。
总结
手动添加组织,我们进行了如下步骤:
- 生成新组织的加密材料
- 进入cli 容器,通过
peer channel fetch
命令获取通道的配置,并生成protobuf格式的config_block.pb
文件。 - 使用
configtxlator
工具将protobuf 格式的config_block.pb
文件转化成 JSON 文件,并删除一些头部信息。 - 向生成的JSON 文件中添加进新组织的内容。
- 将两个JSON 文件转化为两个protobuf 格式的文件。
- 使用
configtxlator
工具来计算两个protobuf文件的增量,并生成一个新的protobuf二进制文件。 - 将新生成的protobuf二进制文件,转化成json文件。
- 向这个json文件添加进原本删除掉的头部信息。
- 再将该json文件转化成一个新的protobuf文件。
- 使用管理员身份执行
peer channel signconfigtx
来对这个新的protobuf文件进行签名。 - 切换为另一个组织的管理员来进行签名。
- 发送
peer channel update
命令,来进行更新调用。 - 配置新组织的动态选举规则
- 启动新组织的Cli容器,导出
ORDERER_CA
和CHANNEL_NAME
环境变量 - 执行
peer channel fetch
来获取创世区块。 - 使用
peer channel join
命令来加入区块。 - 在新的组织容器中执行
peer chaincode install
安装链码 - 进入原来的CLI容器,安装链码。切换环境变量到另一个组织管理员,来安装链码。
- 调用
peer chaincode upgrade
命令,来升级链码。并指定新的背书策略。 - 之后就可以进入新组织的容器内部,进行链码调用了。
我只能说,这一顿操作,真的很复杂。