Hyperledger Fabric官方中文教程-改进笔记(十五)-从通道中删除组织
注意:
作为本教程的前提条件,应当先通过本专栏 《向通道添加一个组织》 一文中的步骤,创建一个包含三个组织的区块链网络。(你也可以查阅官网 向通道添加一个组织 )
本教程将从包含 Org1、Org2 和 Org3 的 Hyperledger Fabric 测试网络中移除 Org2。
停止 Org2 Peer
在从 Fabric 网络中移除 Org2 之前,先停止 Org2 的 peer。
docker stop peer0.org2.example.com
获取配置
我们将在本地克隆的 fabric-samples
的 test-network
子目录根目录下进行操作。
cd fabric-samples/test-network
以 Org1 管理员身份执行以下命令。
# 你可以一次性执行这些命令
export PATH=${PWD}/../bin:$PATH
export FABRIC_CFG_PATH=${PWD}/../config/
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=Org1MSP
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051
现在我们可以执行以下命令获取最新的配置区块:
peer channel fetch config channel-artifacts/config_block.pb -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com -c channel1 --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem"
该命令会将二进制 protobuf 通道配置区块保存为 config_block.pb
。请注意,文件名和扩展名的选择是任意的。但建议遵循一种约定,能够同时标识所表示的对象类型以及其编码(protobuf 或 JSON)。
当你执行 peer channel fetch
命令时,日志中会显示如下输出:
2024-03-18 14:35:27.837 CST 0001 INFO [channelCmd] InitCmdFactory -> Endorser and orderer connections initialized
2024-03-18 14:35:27.845 CST 0002 INFO [cli.common] readBlock -> Received block: 4
2024-03-18 14:35:27.845 CST 0003 INFO [channelCmd] fetch -> Retrieving last config block: 4
2024-03-18 14:35:27.848 CST 0004 INFO [cli.common] readBlock -> Received block: 4
将配置转换为 JSON 并精简
通道配置区块被存储在 channel-artifacts
文件夹中,以便将更新过程与其他制品分开。进入 channel-artifacts
文件夹来完成接下来的步骤:
cd channel-artifacts
现在我们将使用 configtxlator
工具将该通道配置区块解码为 JSON 格式(人类可读并可修改):
configtxlator proto_decode --input config_block.pb --type common.Block --output config_block.json
我们还必须去除所有与本次修改无关的头部、元数据、创建者签名等。我们通过 jq
工具来完成这一操作(你需要在本地安装 jq 工具):
jq '.data.data[0].payload.data.config' config_block.json >config.json
该命令会生成一个精简后的 JSON 对象 —— config.json
,它将作为我们配置更新的基准。
注:jq命令中的’>'会覆盖掉原来的同名文件,如果存在的话。上面的configtxlator命令也是
从通道中移除 Org2
我们将再次使用 jq
工具,把 Org2MSP
从通道的 application group 字段中删除:
jq 'del(.channel_group.groups.Application.groups.Org2MSP)' config.json > modified_config.json
从配置块中移除 Org2 加密材料
现在我们有两个需要关注的 JSON 文件 —— config.json
和 modified_config.json
。初始文件包含三个组织,而“修改后的”文件仅包含 Org1 和 Org3 的数据。此时,只需重新编码这两个 JSON 文件并计算它们之间的差异即可。
首先,把 config.json
转换为名为 config.pb
的 protobuf:
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 二进制文件,命名为 config_update.pb
:
configtxlator compute_update --channel_id channel1 --original config.pb --updated modified_config.pb --output config_update.pb
将差异对象解码为 JSON 格式:
configtxlator proto_decode --input config_update.pb --type common.ConfigUpdate --output config_update.json
现在我们得到了一个解码后的更新文件 —— config_update.json
—— 需要将其包装在一个 envelope 消息中。此步骤会重新生成我们之前去掉的 header 字段。我们将该文件命名为 config_update_in_envelope.json
:
echo '{"payload":{"header":{"channel_header":{"channel_id":"channel1", "type":2}},"data":{"config_update":'$(cat config_update.json)'}}}' | jq . > config_update_in_envelope.json
使用这个格式正确的 JSON —— config_update_in_envelope.json
—— 我们将最后一次调用 configtxlator
工具,把它转换为 Fabric 需要的完整 protobuf 格式。我们将最终的更新对象命名为 config_update_in_envelope.pb
:
configtxlator proto_encode --input config_update_in_envelope.json --type common.Envelope --output config_update_in_envelope.pb
签名并提交配置更新
在将配置写入账本之前,我们需要相关管理员用户的签名。
首先,以 Org1 的身份签署该更新 proto。回到 test-network
目录:
cd ..
导出 Org1 的环境变量:
export PATH=${PWD}/../bin:$PATH
export FABRIC_CFG_PATH=${PWD}/../config/
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=Org1MSP
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051
执行以下命令以 Org1 身份签署更新:
peer channel signconfigtx -f channel-artifacts/config_update_in_envelope.pb
导出 Org2 的环境变量:
export PATH=${PWD}/../bin:$PATH
export FABRIC_CFG_PATH=${PWD}/../config/
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID=Org2MSP
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:9051
执行以下命令以 Org2 身份签署更新:
peer channel signconfigtx -f channel-artifacts/config_update_in_envelope.pb
导出 Org3 的环境变量:
export PATH=${PWD}/../bin:$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
执行以下命令以 Org3 身份签署更新:
peer channel signconfigtx -f channel-artifacts/config_update_in_envelope.pb
现在我们最终执行 peer channel update
命令,将更新发送到通道:
peer channel update -f channel-artifacts/config_update_in_envelope.pb -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com -c channel1 --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem"
如果更新提交成功,你会看到类似以下的消息:
2024-03-18 14:40:10.761 CST 0002 INFO [channelCmd] update -> Successfully submitted channel update
现在,移除 Org2 的所有操作已经完成。你可以通过以下命令查看 peer0.org1.example.com 和 peer0.org3.example.com 的日志:
docker logs peer0.org1.example.com -f
docker logs peer0.org3.example.com -f
查看 peer 的日志时,你会看到关于 peer0.org2.example.com 的 gossip 警告信息。由于 Org2 已经从 Fabric 网络中移除,Org1 和 Org3 的 peer 无法再连接到 Org2 peer。
2024-03-18 06:40:10.811 UTC 0086 WARN [gossip.gossip] func3 -> Failed determining organization of 87333f25423a5270cddbed5078fde14056ed2899e4ce7ffc6476e81f330201d1
2024-03-18 06:40:11.108 UTC 0087 WARN [peer.gossip.sa] OrgByPeerIdentity -> Peer Identity [...] cannot be desirialized. No MSP found able to do that.
重启 Org1 Peer 和 Org3 Peer
你可以通过重启 Org1 和 Org3 的 peer 来消除这些警告。
docker stop peer0.org1.example.com
docker start peer0.org1.example.com
docker stop peer0.org3.example.com
docker start peer0.org3.example.com
更新集合定义文件(可选)
如果你的链码中使用了私有数据集合,现在应当从集合定义中移除 Org2MSP,并更新链码,因为 Org2MSP 已经不再定义在 Fabric 网络中。例如,一个集合被定义为在 Org1 和 Org2 之间保存私有数据:
[{"name": "pdc1","policy": "OR('Org1MSP.member', 'Org2MSP.member')","requiredPeerCount": 0,"maxPeerCount": 3,"blockToLive": 1000000,"memberOnlyRead": true,"memberOnlyWrite": false,"endorsementPolicy": { "signaturePolicy": "OR('Org1MSP.member', 'Org2MSP.member')" }}
]
在移除 Org2 后,应当从集合定义中移除对 Org2MSP 的引用,因此集合现在只由 Org1 持有:
[{"name": "pdc1","policy": "OR('Org1MSP.member')","requiredPeerCount": 0,"maxPeerCount": 3,"blockToLive": 1000000,"memberOnlyRead": true,"memberOnlyWrite": false,"endorsementPolicy": { "signaturePolicy": "OR('Org1MSP.member')" }}
]
将集合转移到另一个组织(可选)
如果某个已存在的集合仅由被移除的组织持有,该怎么办?例如,以下集合 pdc2 仅由 Org2 持有:
[{"name": "pdc2","policy": "OR('Org2MSP.member')","requiredPeerCount": 0,"maxPeerCount": 3,"blockToLive": 1000000,"memberOnlyRead": true,"memberOnlyWrite": false,"endorsementPolicy": { "signaturePolicy": "OR('Org2MSP.member')" }}
]
正如 更新集合定义 所述,现有的集合必须包含在集合定义文件中,因此我们不能简单地将集合从文件中移除。
如果在更新链码定义时指定了集合配置,则必须包含所有现有集合的定义。
一种替代方案是,你可以将集合转移到另一个现有组织。在本例中,我们将 pdc2 转移到 Org3:
[{"name": "pdc2","policy": "OR('Org3MSP.member')","requiredPeerCount": 0,"maxPeerCount": 3,"blockToLive": 1000000,"memberOnlyRead": true,"memberOnlyWrite": false,"endorsementPolicy": { "signaturePolicy": "OR('Org3MSP.member')" }}
]
完成转移后,Org3 的 peer 会尝试从其他 peer 获取 pdc2 的私有数据。这被称为私有数据对账。私有数据对账会基于 core.yaml 中的 peer.gossip.pvtData.reconciliationEnabled
和 peer.gossip.pvtData.reconcileSleepInterval
配置周期性发生。由于 Org2 peer 已经从 Fabric 网络中移除,Org3 peer 将无法再从 Org2 peer 获取私有数据。你会在 Org3 的日志中看到如下警告信息:
2024-03-18 06:15:51.065 UTC 0047 WARN [gossip.privdata] fetchPrivateData -> Do not know any peer in the channel (channel1) that matches the policies , aborting channel=channel1
2024-03-18 06:15:51.065 UTC 0048 ERRO [gossip.privdata] reconcile -> reconciliation error when trying to fetch missing items from different peers: Empty membership channel=channel1
2024-03-18 06:15:51.065 UTC 0049 ERRO [gossip.privdata] run -> Failed to reconcile missing private info, error: Empty membership channel=channel1
你可以在 Org3 的 peer 上配置 peer.gossip.pvtData.reconciliationEnabled=false
来停止对账并抑制错误日志。