教程 - 向通道中添加一个组织
注意
确保你已下载符合本文档版本的适当的镜像和二进制文件,即文档 Install Samples, Binaries and Docker Images 和 Prerequisites 中说明的镜像和二进制文件,本示例的版本号为 1.4.3。特别是,你的
fabric-samples
文件夹版本必须包含eyfn.sh
(“Extending Your First Network”) 脚本及其相关脚本。
本教程是对 构建你的第一个网络 (BYFN) 教程的扩展,并将演示向 BYFN 自动生成的应用程序通道 (mychannel) 添加新组织 Org3 的过程。它假定你对 BYFN 有深入的了解,包括上述实用程序的用法和功能。
尽管我们在此仅专注于新组织的集成,但是在执行其他通道配置更新 (例如,更新修改策略或更改批次大小) 时,可以采用相同的方法。要总体上了解有关频道配置更新的过程和可能性的更多信息,请查看 更新频道配置。同样值得注意的是,通道配置更新 (如此处所示) 通常是组织管理员 (而不是链码或应用程序开发人员) 的责任。
注意
在继续操作之前,请确保自动化的
byfn.sh
脚本在计算机上正确运行。如果你已将二进制文件和相关工具 (cryptogen,configtxgen 等) 导出到 PATH 变量中,则可以在不通过完全限定路径的情况下相应地修改命令。
1. 设置环境变量
我们将从你的 fabric-samples
本地克隆中 first-network
子目录的根开始进行操作。现在切换到该目录。你还需要打开一些额外的终端以方便使用。
首先,使用 byfn.sh
脚本进行整理。该命令将杀死所有活动或陈旧的 Docker 容器并删除以前生成的组件。无需关闭 Fabric 网络以执行通道配置更新任务。但是,出于本教程的考虑,我们希望从已知的初始状态进行操作。因此,让我们运行以下命令来清理以前的所有环境:
$ sudo ./byfn.sh down
现在生成默认的 BYFN 构件:
$ ./byfn.sh generate
并使用 CLI 容器中的脚本执行来启动网络:
$ sudo ./byfn.sh up
现在,你的计算机上已运行了干净的 BYFN 版本,你可以采用两种不同的方法。首先,我们提供一个带有完整注释的脚本,该脚本将执行配置交易更新以将 Org3 加入网络。
另外,我们将显示同一过程的手动版本,显示每个步骤并说明完成的步骤(由于我们向你展示了如何在此手动过程之前关闭网络,因此你还可以运行脚本,然后查看每个步骤)。
2. 通过脚本将 Org3 添加到通道
你应该在 first-network
中。要使用该脚本,只需发出以下命令:
$ sudo ./eyfn.sh up
这里的输出值得一读。你会看到添加了 Org3 加密材料,正在创建和签名配置更新,然后安装了链码以允许 Org3 执行账本查询。
如果一切顺利,你会收到以下消息:
========= All GOOD, EYFN test execution completed ===========
eyfn.sh
可以通过发出以下命令 (而不是 ./byfn.sh up
) 来与 byfn.sh
一起使用相同的 Node.js 链码和数据库选项:
$ sudo ./byfn.sh up -c testchannel -s couchdb -l node
然后
$ sudo ./eyfn.sh up -c testchannel -s couchdb -l node
注意
上面的命令中应该把
testchannel
替换为mychannel
才能成功。
对于那些想更仔细地了解此过程的人,文档的其余部分将向你展示用于进行通道更新的每个命令及其作用。
3. 手动将 Org3 添加到通道
注意
下面概述的手动步骤假定 cli 和 Org3cli 容器中的 FABRIC_LOGGING_SPEC 设置为 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
#- FABRIC_LOGGING_SPEC=INFO
- FABRIC_LOGGING_SPEC=DEBUG
对于 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
#- FABRIC_LOGGING_SPEC=INFO
- FABRIC_LOGGING_SPEC=DEBUG
如果你使用了 eyfn.sh
脚本,则需要关闭网络。可以通过发出以下命令来完成:
$ sudo ./eyfn.sh down
这将关闭网络,删除所有容器,并撤消我们添加 Org3 的操作。
当网络断开时,再次将其恢复。
$ ./byfn.sh generate
然后
$ sudo ./byfn.sh up
这将使你的网络恢复到执行 eyfn.sh
脚本之前的状态。
现在,我们准备手动添加 Org3。首先,我们需要生成 Org3 的加密材料。
4. 生成 Org3 的加密材料
在另一个终端中,从 first-network
切换到 org3-artifacts
子目录。
$ cd org3-artifacts
这里有两个感兴趣的 Yaml 文件:org3-crypto.yaml 和 configtx.yaml。首先,为 Org3 生成加密材料:
$ ../../bin/cryptogen generate --config=./org3-crypto.yaml
该命令读取我们新的加密 Yaml 文件 org3-crypto.yaml,并利用 cryptogen 生成 Org3 CA 以及绑定到此新组织的两个对端节点的密钥和证书。与 BYFN 实现一样,此加密材料将放入当前工作目录 (在我们的情况下为 org3-artifacts) 中新生成的 crypto-config 文件夹中。
现在,使用 configtxgen 实用程序以 JSON 打印出 Org3 特定的配置材料。我们将通过告诉工具在当前目录中查找它需要摄取的 configtx.yaml 文件,来为命令添加前缀。
$ export FABRIC_CFG_PATH=$PWD && ../../bin/configtxgen -printOrg Org3MSP > ../channel-artifacts/org3.json
上面的命令创建一个 JSON 文件 org3.json 并将其输出到 first-network
根目录下的 channel-artifacts
子目录中。该文件包含 Org3 的策略定义以及以 base 64 格式显示的三个重要证书:admin 用户证书 (以后将需要用作 Org3 的管理员),CA 根证书和 TLS 根证书在接下来的步骤中,我们会将这个 JSON 文件添加到通道配置中。
我们的最后一项整理工作是将 Orderer Org 的 MSP 材料移植到 Org3 crypto-config 目录中。特别是,我们与交易排序器的 TLS 根证书有关,这将使 Org3 实体与网络的交易排序节点之间的安全通信成为可能。
$ cd ../ && cp -r crypto-config/ordererOrganizations org3-artifacts/crypto-config/
现在,我们准备更新频道配置 ...
5. 准备 CLI 环境
更新过程使用配置转换器工具 configtxlator。该工具提供了独立于 SDK 的无状态 REST API。此外,它提供了 CLI,以简化结构网络中的配置任务。该工具允许在不同的等效数据表示形式/格式之间轻松转换 (在这种情况下,在 protobuf 和 JSON 之间)。此外,该工具可以基于两个通道配置之间的差异来计算配置更新交易。
首先,执行到 CLI 容器中。回想一下,该容器已经安装了 BYFN crypto-config 库,使我们可以访问两个原始对端节点组织和 Orderer Org 的 MSP 材料。自举身份是 Org1 管理员用户,这意味着我们要以 Org2 身份执行的任何步骤都需要设置 MSP 特定的环境变量。
$ sudo 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。
6. 获取配置
现在,我们有了一个 CLI 容器,其中包含两个关键环境变量 – ORDERER_CA 和 CHANNEL_NAME 已导出。让我们获取通道 mychannel 的最新配置区块。
之所以必须提取最新版本的配置,是因为通道配置元素已版本化。版本控制很重要,原因有几个。它可以防止重复或重放配置更改 (例如,使用旧的 CRL 恢复到通道配置会带来安全风险)。它还有助于确保并发性 (例如,如果要从通道中删除组织,例如,在添加新的组织之后,版本控制将有助于防止你同时删除两个组织,而不仅仅是希望删除的组织)。
$ peer channel fetch config config_block.pb -o orderer.example.com:7050 -c $CHANNEL_NAME --tls --cafile $ORDERER_CA
此命令将二进制 protobuf 通道配置区块保存到 config_block.pb。请注意,名称和文件扩展名的选择是任意的。但是,建议遵循一个约定,该约定既标识要表示的对象的类型,又标识其编码 (protobuf 或 JSON)。
当你发出 peer channel fetch
命令时,终端中有相当数量的输出。日志中的最后一行很有趣:
2017-11-07 17:17:57.383 UTC [channelCmd] readBlock -> DEBU 011 Received block: 2
这告诉我们 mychannel 的最新配置区块实际上是区块 2,而不是创世区块。缺省情况下,`peer channel fetch config 命令返回目标通道的最新配置区块,在这种情况下为第三块。这是因为 BYFN 脚本在两个单独的通道更新交易中为我们的两个组织 Org1 和 Org2 定义了锚定对端节点。
结果,我们具有以下配置顺序:
- 区块 0:创世区块
- 区块 1:Org1 锚定对端节点更新
- 区块 2:Org2 锚定对端节点更新
备注
上面官方文档关于区块的描述感觉有误,我个人的理解如下。
- 区块 1:创世区块
- 区块 2:创建通道 mychannel
- 区块 3:Org1 锚定对端节点更新
- 区块 4:Org2 锚定对端节点更新
符合下面的输出
# peer channel fetch config config_block.pb -o orderer.example.com:7050 -c $CHANNEL_NAME --tls --cafile $ORDERER_CA
2019-12-04 08:34:33.475 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2019-12-04 08:34:33.493 UTC [cli.common] readBlock -> INFO 002 Received block: 4
2019-12-04 08:34:33.498 UTC [cli.common] readBlock -> INFO 003 Received block: 2
2019-12-04 08:34:33.499 UTC [channelCmd] fetch -> INFO 004 Retrieving last config block: 2
7. 将配置转换成 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,位于 fabric-samples/first-network
文件夹中,它将作为配置更新的基准。
花一点时间在你选择的文本编辑器中 (或在浏览器中) 打开此文件。即使你已完成本教程,仍然值得研究,因为它揭示了潜在的配置结构和可以进行的其他通道更新。我们将在 更新通道配置 中更详细地讨论它们。
8. 添加 Org3 的加密材料
备注
无论你要进行哪种配置更新,到目前为止,你执行的步骤几乎都是相同的。我们选择在此教程中添加组织,因为它是你可以尝试的最复杂的通道配置更新之一。
我们将再次使用 jq
工具将 Org3 配置定义 org3.json
添加到通道的应用程序组字段 (application groups
) 中,并将输出命名为 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。初始文件仅包含 Org1 和 Org2 材料,而修改后的文件包含所有三个 Org。此时,只需重新编码这两个 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 之间的差异。此命令将输出一个新的名为 org3_update.pb 的 protobuf 二进制文件:
$ configtxlator compute_update --channel_id $CHANNEL_NAME --original config.pb --updated modified_config.pb --output org3_update.pb
这个新的 proto org3_update.pb 包含 Org3 定义以及指向 Org1 和 Org2 材料的高级指针。我们可以放弃针对 Org1 和 Org2 的大量 MSP 材料和修改策略信息,因为该数据已存在于通道的创始区块中。这样,我们只需要两个配置之间的增量。
在提交通道更新之前,我们需要执行一些最后的步骤。首先,让我们将该对象解码为可编辑的 JSON 格式,并将其命名为 org3_update.json:
$ configtxlator proto_decode --input org3_update.pb --type common.ConfigUpdate | jq . > org3_update.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
使用我们格式正确的 JSON (org3_update_in_envelope.json),我们将最后一次使用 configtxlator 工具,并将其转换为 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
9. 签名并提交配置更新
快完成了!
现在,我们的 CLI 容器中有一个 protobuf 二进制文件 org3_update_in_envelope.pb。但是,在将配置写入账本之前,我们需要来自必需的 Admin 用户的签名。我们的通道应用程序组的修改策略 (mod_policy) 设置为默认值 “MAJORITY”,这意味着我们需要大多数现有的组织管理员来对其进行签名。因为我们只有两个组织 – Org1 和 Org2 – 且大多数是两个,所以我们都需要它们进行签名。没有这两个签名,交易排序服务将因未能履行策略而拒绝交易。
首先,让我们以 Org1 Admin 身份签署此更新协议。请记住,CLI 容器是用 Org1 MSP 材料引导的,因此我们只需要发出 peer channel signconfigtx
命令:
# you can issue all of these commands at once
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/[email protected]/msp
export CORE_PEER_ADDRESS=peer0.org2.example.com:9051
最后一步是切换 CLI 容器的身份以反映 Org2 Admin 用户。为此,我们导出了四个特定于 Org2 MSP 的环境变量。
$
备注
即将到来的交易排序服务更新调用将进行一系列系统的签名和策略检查。因此,你可能会发现流式传输和检查交易排序节点的日志很有用。从另一个 shell 中,发出
sudo 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-02-24 18:56:33.499 UTC [msp/identity] Sign -> DEBU 00f Sign: digest: 3207B24E40DE2FAB87A2E42BC004FEAA1E6FDCA42977CB78C64F05A88E556ABA
你还将看到我们的配置交易的提交:
2018-02-24 18:56:33.499 UTC [channelCmd] update -> INFO 010 Successfully submitted channel update
成功的通道更新调用将新的区块 (区块 5) 返回给通道上的所有对端节点。记住,区块 0-2 是初始通道配置,而区块 3 和 4 是 mycc 链码的实例化和调用。这样,区块 5 用作 Org3 现在通道上已定义的最新通道配置。
检查 peer0.org1.example.com
的日志:
$ sudo docker logs -f peer0.org1.example.com
如果要检查其内容,请按照演示的过程来获取和解码新的配置区块。
10. 配置领导者选举
备注
包含本部分作为一般参考,以了解在初始通道配置完成后向网络添加组织时的领导者选举设置。此示例默认为动态领导者选举,该选举在
peer-base.yaml
中为网络中的所有对端节点设置。
新加入的对端节点使用创世区块引导,该创世区块不包含有关在通道配置更新中添加的组织的信息。因此,新对端节点无法利用 gossip,因为它们无法验证其他对端节点从其自己的组织转发的区块,直到他们获得将组织添加到通道的配置交易。因此,新添加的对端节点必须具有以下配置之一,以便它们从交易排序服务接收区块:
- 要使用静态领导者模式,请将对端节点配置为组织领导者:
CORE_PEER_GOSSIP_USELEADERELECTION=false
CORE_PEER_GOSSIP_ORGLEADER=true
备注
对于添加到通道的所有新对端节点,此配置必须相同。
- 要使用动态领导者选举,请将对端节点配置为使用领导者选举:
CORE_PEER_GOSSIP_USELEADERELECTION=true
CORE_PEER_GOSSIP_ORGLEADER=false
备注
由于新加入的组织的对端节点将无法形成 MSP 视图,因此此选项将类似于静态配置,因为每个对端节点都将开始宣称自己是领导者。但是,一旦他们使用将组织添加到通道的配置交易进行更新,组织将只有一位活跃的领导者。因此,如果你最终希望组织的同行利用领导者选举,则建议利用此选项。
11. 将 Org3 加入通道
至此,通道配置已更新为包括我们的新组织 Org3,这意味着与它关联的对端节点现在可以加入 mychannel。
首先,让我们启动 Org3 对端节点的容器和 Org3 特定的 CLI。
打开一个新终端,从 first-network
启动 Org3 docker compose:
$ sudo docker-compose -f docker-compose-org3.yaml up -d
这个新的 compose 文件已配置为跨我们的初始网络桥接,因此两个对端节点和 CLI 容器将能够与现有对端节点和交易排序节点进行解析。随着这三个新容器的运行,请执行到 Org3 特定的 CLI 容器中:
$ sudo 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
现在,让我们调用交易排序服务,询问 mychannel 的创始区块。由于我们成功地更新了通道,因此交易排序服务能够验证此调用所添加的 Org3 签名。如果 Org3 尚未成功添加到通道配置,则交易排序服务应拒绝此请求。
备注
同样,你可能会发现流式传输交易排序节点的日志以显示签名/验证逻辑和策略检查很有用。
使用 peer channel fetch
命令检索此区块:
$ peer channel fetch 0 mychannel.block -o orderer.example.com:7050 -c $CHANNEL_NAME --tls --cafile $ORDERER_CA
请注意,我们传递的 0 表示我们想要通道帐本中的第一个区块 (即创世区块)。如果我们简单地传递 peer channel fetch config
命令,那么我们将收到区块 5 – 已定义 Org3 的更新配置。但是,我们不能从下游区块开始帐本 - 我们必须从区块 0 开始。
发出 peer channel join
命令并传入创世区块 – mychannel.block:
$ peer channel join -b mychannel.block
如果要加入 Org3 的第二个对端节点,请导出 TLS 和 ADDRESS 变量,然后重新发出 peer channel join channel
命令:
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:12051
peer channel join -b mychannel.block
12. 更新和调用链码
最后一个难题是增加链码版本并更新背书策略以包括 Org3。由于我们知道即将进行升级,因此可以放弃安装链码版本 1的徒劳做法。我们只关注 Org3 将成为背书策略一部分的新版本,因此我们将直接跳至链码的第二版。
从 Org3 CLI:
$ peer chaincode install -n mycc -v 2.0 -p github.com/chaincode/chaincode_example02/go/
如果要在 Org3 的第二个对端节点上安装链码,请相应地修改环境变量并重新发出命令。请注意,第二次安装不是强制性的,因为你只需要在将用作背书人或与账本进行交互的对端节点上安装链码 (即仅用于查询)。在没有运行链码容器的情况下,对端节点仍将运行验证逻辑并充当提交方。
现在,跳回到原始的 CLI 容器,并在 Org1 和 Org2 对端节点上安装新版本。我们使用 Org2 管理员身份提交了通道更新调用,因此该容器仍代表 peer0.org2:
$ 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/[email protected]/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/
现在,我们准备升级链码。尚未对基础源代码进行任何修改,我们只是将 Org3 添加到通道 mychannel 上的链码 mycc 的背书策略中。
备注
任何符合链码实例化策略的身份都可以发出升级请求。默认情况下,这些标识是通道管理员。
发送调用:
$ 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
方法。如果你的链码要求将参数传递给 init
方法,那么你将需要在此处这样做。
升级调用将新的区块 (区块 6) 添加到通道的帐本中,并允许 Org3 对端节点在背书阶段执行交易。跳回到 Org3 CLI 容器并发出查询 a
的值。这将花费一些时间,因为需要为目标对端节点构建一个链码镜像,并且容器需要启动:
$ peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
我们应该看到查询结果的响应:Query Result 90
。
现在发出将 10 从 a 移到 b 的调用:
$ 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"]}'
最后查询一次:
$ peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
我们应该看到 Query Result: 80
的响应,准确反映了此链码世界状态的更新。
13. 总结
通道配置更新过程确实涉及很多,但是各个步骤都有一个逻辑方法。最终的结果是形成一个以 protobuf 二进制格式表示的增量交易对象,然后获取必要数量的管理员签名,以便通道配置更新交易满足通道的修改策略。
configtxlator 和 jq 工具以及不断增长的 peer channel
命令为我们提供了完成此任务的功能。
14. 更新通道配置以添加 Org3 的锚定对端节点 (可选)
由于 Org1 和 Org2 在通道配置中定义了锚定对端节点,因此 Org3 对端节点能够建立与 Org1 和 Org2 对端节点的 gossip 连接。同样,新添加的组织 (如 Org3) 也应在通道配置中定义其锚定对端节点,以便来自其他组织的任何新对端节点都可以直接发现 Org3 对端节点。
从 Org3 CLI 继续,我们将进行通道配置更新以定义 Org3 锚定对端节点。该过程与之前的配置更新类似,因此这次我们会更快。
和以前一样,我们将获取最新的通道配置以开始使用。在 Org3 的 CLI 容器内,使用 peer channel fetch
命令获取通道的最新配置区块。
$ peer channel fetch config config_block.pb -o orderer.example.com:7050 -c $CHANNEL_NAME --tls --cafile $ORDERER_CA
提取配置区块后,我们将其转换为 JSON 格式。为此,我们将使用 configtxlator 工具,就像之前将 Org3 添加到通道中一样。在转换它时,我们需要使用 jq 工具删除更新 Org3 以包括锚定对端节点所需的所有标头,元数据和签名。在我们继续更新通道配置之前,稍后将重新合并此信息。
$ configtxlator proto_decode --input config_block.pb --type common.Block | jq .data.data[0].payload.data.config > config.json
config.json
是经过裁剪的 JSON,代表我们将更新的最新通道配置。
再次使用 jq 工具,我们将使用我们要添加的 Org3 锚定对端节点更新配置 JSON。
$ jq '.channel_group.groups.Application.groups.Org3MSP.values += {"AnchorPeers":{"mod_policy": "Admins","value":{"anchor_peers": [{"host": "peer0.org3.example.com","port": 11051}]},"version": "0"}}' config.json > modified_anchor_config.json
现在,我们有两个 JSON 文件,一个用于当前通道配置 config.json,一个用于所需的通道配置 modified_anchor_config.json。接下来,我们将这些转换回 protobuf 格式,并计算两者之间的差异。
将 config.json 转换回 protobuf 格式为 config.pb
$ configtxlator proto_encode --input config.json --type common.Config --output config.pb
将 modified_anchor_config.json 转换为 protobuf 格式为 modified_anchor_config.pb:
$ configtxlator proto_encode --input modified_anchor_config.json --type common.Config --output modified_anchor_config.pb
计算两个 protobuf 格式的配置之间的差异。
$ configtxlator compute_update --channel_id $CHANNEL_NAME --original config.pb --updated modified_anchor_config.pb --output anchor_update.pb
现在,我们已经有了所需的通道更新,我们必须将其包装在信封消息中,以便可以正确读取它。为此,我们必须首先将 protobuf 转换回可以包装的 JSON。
我们将再次使用 configtxlator 命令将 anchor_update.pb 转换为 anchor_update.json
$ configtxlator proto_decode --input anchor_update.pb --type common.ConfigUpdate | jq . > anchor_update.json
接下来,我们将更新包装在信封消息中,还原先前剥离的标头,然后将其输出到 anchor_update_in_envelope.json
$ echo '{"payload":{"header":{"channel_header":{"channel_id":"mychannel", "type":2}},"data":{"config_update":'$(cat anchor_update.json)'}}}' | jq . > anchor_update_in_envelope.json
现在,我们已经重新合并了信封,我们需要将其转换为 protobuf,以便可以对其进行正确签名并提交给交易排序器以进行更新。
$ configtxlator proto_encode --input anchor_update_in_envelope.json --type common.Envelope --output anchor_update_in_envelope.pb
现在,更新已正确格式化,是时候签名并提交更新了。由于这只是对 Org3 的更新,因此我们只需要 Org3 在更新上签名。由于我们位于 Org3 CLI 容器中,因此无需切换 CLI 容器标识,因为它已经在使用 Org3 标识。因此,我们只能使用 peer channel update
命令,因为它也将以 Org3 管理员的身份签发更新,然后再将其提交给交易排序器。
$ peer channel update -f anchor_update_in_envelope.pb -c $CHANNEL_NAME -o orderer.example.com:7050 --tls --cafile $ORDERER_CA
交易排序器收到配置更新请求,并使用更新后的配置切割一个区块。当对端节点收到该区块时,他们将处理配置更新。
检查对端节点之一的日志。在处理来自新区块的配置交易时,你会看到 gossip 使用 Org3 的新锚定重新建立连接。这证明配置更新已成功应用!
$ docker logs -f peer0.org1.example.com
2019-06-12 17:08:57.924 UTC [gossip.gossip] learnAnchorPeers -> INFO 89a Learning about the configured anchor peers of Org1MSP for channel mychannel : [{peer0.org1.example.com 7051}]
2019-06-12 17:08:57.926 UTC [gossip.gossip] learnAnchorPeers -> INFO 89b Learning about the configured anchor peers of Org2MSP for channel mychannel : [{peer0.org2.example.com 9051}]
2019-06-12 17:08:57.926 UTC [gossip.gossip] learnAnchorPeers -> INFO 89c Learning about the configured anchor peers of Org3MSP for channel mychannel : [{peer0.org3.example.com 11051}]
恭喜,你现在进行了两次配置更新 - 一次将 Org3 添加到通道,第二次为 Org3 定义锚点。
Reference
- Docs » Tutorials » Adding an Org to a Channel, https://hyperledger-fabric.readthedocs.io/en/release-1.4/channel_update_tutorial.html
- Docs » Getting Started » Install Samples, Binaries and Docker Images, https://hyperledger-fabric.readthedocs.io/en/release-1.4/install.html
- Docs » Getting Started » Prerequisites, https://hyperledger-fabric.readthedocs.io/en/release-1.4/prereqs.html
- Docs » Tutorials » Building Your First Network, https://hyperledger-fabric.readthedocs.io/en/release-1.4/build_network.html
- Docs » Operations Guides » Updating a Channel Configuration, https://hyperledger-fabric.readthedocs.io/en/release-1.4/config_update.html
- Docs » Operations Guides » Updating a Channel Configuration, https://hyperledger-fabric.readthedocs.io/en/release-1.4/config_update.html
项目源代码
项目源代码会逐步上传到 Github,地址为 https://github.com/windstamp。
Contributor
- Windstamp, https://github.com/windstamp