Hyperledger Fabric 入门笔记(六)Fabric V2.5 测试网络进阶之网络部署


前言

本文参考官方技术文档的教程,介绍使用脚本部署测试网络背后的细节,包括三部分:
1、手动部署链码
2、手动创建通道
3、手动加入组织到通道中
这三部分内容循序渐进,有助于后续搭建自己的网络。


一、手动部署链码

1.1. 准备工作

在Hyperledger Fabric中,智能合约被打包在称为链码的包中。想要验证交易或查询账本的组织需要在其peer节点上安装链码。在连接到通道的peer节点上安装了链码之后,通道成员可以将链码部署到通道中,并使用链码中的智能合约来创建或更新通道账本上的资产。

链码通过一个称为Fabric链码生命周期的过程部署到通道中。Fabric链码生命周期允许多个组织在链码被用于创建交易之前,就如何操作链码达成一致。例如,背书策略指定了哪些组织需要执行链码来验证交易,而通道成员需要使用Fabric链码生命周期来就链码背书策略达成一致。

本节使用peer lifecycle chaincode命令将Go版本的asset-transfer-basic链码部署到Fabric测试网络的通道中。部署之前需要先启动网络并创建通道:

cd ~/hyfa/fabric-samples/test-network
./network.sh down
./network.sh up createChannel

将二进制文件和配置文件的路径加入环境变量:

export PATH=$PATH:${PWD}/../bin
export FABRIC_CFG_PATH=${PWD}/../config/

1.2. 启用Logspout(可选)

为了监控链码的日志,可以使用Logspout工具查看一组Docker容器的聚合输出。该工具将来自不同Docker容器的输出流收集到一个地方,从而可以很容易地从一个窗口中看到正在发生的事情。由于创建一些容器纯粹是为了启动链码,并且只存在很短的时间,因此从网络中收集所有日志是很有帮助的。

启动Logspout的脚本monitordocker.sh位于fabric-samples/test-network中。运行该脚本需要使用新的终端窗口,并且必须在启动网络后才能启用。

./monitordocker.sh

该脚本实际上是使用镜像文件logspout启动一个容器,镜像文件会在第一次运行脚本时自动下载。

Logspout默认收集属于网络“fabric_test”(即测试网络)的容器的输出。

Logspout成功启动后,一开始不会看到任何日志,但后续部署链码时,就会在当前终端持续输出日志。

关闭测试网络前,首先应当使用Ctrl-C终止Logspout工具。

1.3. 流程

注1:本节的全部内容等价于执行以下命令:
./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go -ccl go

注2:asset-transfer-basic链码有多个版本,详见官方技术文档。

1.3.1. 打包智能合约

1.3.1.1. 安装依赖

转到Go版本的asset-transfer-basic链码文件夹:

cd ../asset-transfer-basic/chaincode-go

在当前目录中运行以下命令:

GO111MODULE=on go mod vendor

如果命令成功,将能够在vendor文件夹中找到安装好的依赖。

回到test-network文件夹中的工作目录:

cd ../../test-network

以上内容仅在第一次部署该链码时必须,关闭测试网络不会恢复链码项目到初始状态。

1.3.1.2. 创建链码包

使用peer lifecycle chaincode package命令创建链码包:

peer lifecycle chaincode package basic.tar.gz --path ../asset-transfer-basic/chaincode-go --lang golang --label basic_1.0.1

这个命令将在当前目录中创建一个名为basic.tar.gz的包。–lang标志用于指定链码语言,–path标志提供智能合约代码的位置。–label标志用来指定一个链码标签,用来标识该链码(即,后续创建的镜像还有对应的链码容器的名称都会由该标签指定),建议标签包含链码名称和版本。

1.3.2. 安装链码包

打包智能合约后,可以在peer节点上安装链码。链码需要安装在每个为交易背书的peer节点上。

使用setOrgEnv.sh脚本设置环境变量,以Org1 admin用户操作peer CLI,其中CORE_PEER_ADDRESS用于指向Org1的peer节点peer0.org1.example.com。

export $(./setOrgEnv.sh Org1 | xargs)

使用命令peer lifecycle chaincode install在Org1的peer节点上安装链码:

peer lifecycle chaincode install basic.tar.gz

使用setOrgEnv.sh脚本设置环境变量,以Org2 admin用户操作peer CLI,其中CORE_PEER_ADDRESS用于指向Org2的peer节点peer0.org2.example.com。

export $(./setOrgEnv.sh Org2 | xargs)

使用命令peer lifecycle chaincode install在Org2的peer节点上安装链码:

peer lifecycle chaincode install basic.tar.gz

安装链码包后,peer节点将生成并返回包ID,用于在下一步中批准链码定义。本质上,安装链码包是创建链码容器对应的镜像,因此安装成功后可以使用docker images命令在本地镜像仓库查看新创建的镜像。

1.3.3. 批准链码定义

一个组织的peer节点在安装链码包之后,该组织需要批准一个链码定义。

在部署链码之前需要批准链码定义的通道成员(组织)的集合由/Channel/Application/LifecycleEndorsement策略控制。默认情况下,该策略要求大多数通道成员批准后,链码才能在通道上使用。

批准链码定义时,包ID用于将安装在peer节点上的链码与经过批准的链码定义关联起来,并允许组织使用链码来批准交易。

将包ID和测试网络的排序服务的TLS CA证书的路径设置为环境变量:

export CC_PACKAGE_ID=$(peer lifecycle chaincode calculatepackageid basic.tar.gz) && echo $CC_PACKAGE_ID
export ORDERER_CA=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

因为环境变量已经设置为以Org2 admin用户操作peer CLI,所以可以为Org2批准链码定义。链码是在组织级别批准的,因此命令只需要针对一个peer节点,随后会通过Gossip将批准分发给组织内的其他peer节点。批准链码定义使用peer lifecycle chaincode approveformyorg命令:

peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name basic --version 1.0.1 --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile $ORDERER_CA

注:这里的–version标志与创建链码包时用到的–label标志不一致时,不影响链码的使用。

接下来还需要为Org1批准链码定义。使用setOrgEnv.sh脚本设置环境变量以Org1 admin用户操作peer CLI:

export $(./setOrgEnv.sh Org1 | xargs)

使用peer lifecycle chaincode approveformyorg命令为Org1批准链码定义:

peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name basic --version 1.0.1 --package-id $CC_PACKAGE_ID --sequence 1 --tls --cafile $ORDERER_CA

本质上,批准链码定义是将链码的策略写入配置区块中并在网络中达成共识,因此成功批准链码定义后再使用peer channel getinfo命令可以发现排序服务返回的通道信息有所变化(区块高度加一)。

1.3.4. 提交链码定义到通道

在足够多的组织批准了链码定义之后,一个组织可以将链码定义提交到通道。如果大多数通道成员都批准了定义,这次提交将会成功,链码定义中同意的参数将会在通道上实现。

首先使用peer lifecycle chaincode checkcommitreadiness命令来检查通道成员是否已经批准了相同的链码定义。

peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name basic --version 1.0.1 --sequence 1 --tls --cafile $ORDERER_CA --output json

然后使用peer lifecycle chaincode commit命令由组织管理员向通道提交链码定义。

peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name basic --version 1.0.1 --sequence 1 --tls --cafile $ORDERER_CA --peerAddresses localhost:7051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt"

成功提交链码定义同样会使区块高度加一,同时链码容器将会启动并连接到对应的Peer节点上。

链码定义成功提交后可以使用peer CLI与测试网络进行交互,测试智能合约的功能,详见Hyperledger Fabric 入门笔记(九)Fabric V2.4 测试网络基础补充 - 与网络交互


二、手动部署通道

2.1. 准备工作

本节使用Fabric测试网络的运行实例来创建新通道,因为从已知的初始状态进行操作很重要。创建通道之前需要先启动网络:

cd hyfa/fabric-samples/test-network
./network.sh down
./network.sh up

通道的创建需要用到configtxgen工具和定义了通道配置的configtx.yaml文件。configtxgen工具在fabric-samples/bin文件夹中,而测试网络的configtx.yaml文件在fabric-samples/test-network/configtx文件夹中。将二进制文件和配置文件的路径加入环境变量:

export PATH=${PWD}/../bin:$PATH
export FABRIC_CFG_PATH=${PWD}/configtx

注:在fabric-samples\config文件夹中同样也有一个configtx.yaml文件,但是这个文件仅仅是一个模板,并不适用于测试网络,所以这里加入到环境变量的配置文件路径有所不同。

2.2. V2.4版本流程

Fabric V2.3版本引入了在不需要系统通道的情况下创建通道的能力。此种方式下,通道的创建是由configtxgen工具创建包含了通道创建交易的通道创世区块,然后使用osnadmin工具将该创世区块传递给排序服务来实现的。

2.2.1. 生成通道创世区块

运行以下命令为channel1创建通道创世区块:

configtxgen -profile TwoOrgsApplicationGenesis -outputBlock ./channel-artifacts/channel1.block -channelID channel1

2.2.2. 创建应用通道

有了通道生成区块就可以很容易地使用osnadmin channel join命令来创建通道。

首先设置一些环境变量,以确定测试网络中排序服务的证书位置:

export ORDERER_CA=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
export ORDERER_ADMIN_TLS_SIGN_CERT=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt
export ORDERER_ADMIN_TLS_PRIVATE_KEY=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.key

运行以下命令在排序服务上创建名为channel1的通道:

osnadmin channel join --channelID channel1 --config-block ./channel-artifacts/channel1.block -o localhost:7053 --ca-file "$ORDERER_CA" --client-cert "$ORDERER_ADMIN_TLS_SIGN_CERT" --client-key "$ORDERER_ADMIN_TLS_PRIVATE_KEY"

创建更多通道时,osnadmin channel list命令可用于查看此排序服务所属的通道。

osnadmin channel list -o localhost:7053 --ca-file "$ORDERER_CA" --client-cert "$ORDERER_ADMIN_TLS_SIGN_CERT" --client-key "$ORDERER_ADMIN_TLS_PRIVATE_KEY"

2.2.3. 将Peer节点加入到通道中

测试网络包括两个Peer组织,每个组织有一个Peer节点。通道创建后,可以使用peer CLI将Peer节点加入到通道中。peer CLI要用到配置文件core.yaml,该文件在fabric-samples/test-network/configtx路径下没有,因此需要先重新将环境变量FABRIC_CFG_PATH指向包含了core.yaml文件的路径:

export FABRIC_CFG_PATH=$PWD/../config/

作为Org1 admin操作peer CLI:

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节点加入到测试网络的通道channel1:

peer channel join -b ./channel-artifacts/channel1.block

作为Org2 admin操作peer CLI:

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节点加入到测试网络的信道channel1:

peer channel join -b ./channel-artifacts/channel1.block

2.3. V2.2版本流程

Fabric V2.2版本中,网络创建的第一个通道是系统通道。系统通道定义了组成排序服务的排序节点集合和充当排序服务管理员的组织集合。系统通道还包括属于区块链联盟的组织。当执行./network.sh up命令时,测试网络脚本已经生成了系统通道创世区块。可以在日志中找到对应命令:

configtxgen -profile TwoOrgsOrdererGenesis -channelID system-channel -outputBlock ./system-genesis-block/genesis.block

2.3.1. 生成应用通道创建交易

运行以下命令为channel1创建一个创建通道的交易:

configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel1.tx -channelID channel1

2.3.2. 创建应用通道

有了应用通道创建交易,就可以使用peer CLI将通道创建交易提交给排序服务。

将peer CLI所需配置文件的路径加入环境变量:

export FABRIC_CFG_PATH=$PWD/../config/

设置环境变量并以Org1中的admin用户身份运行peer CLI:

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

将测试网络排序服务CA证书的路径加入环境变量:

export ORDERER_CA=${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

使用以下命令创建通道:

peer channel create -o localhost:7050  --ordererTLSHostnameOverride orderer.example.com -c channel1 -f ./channel-artifacts/channel1.tx --outputBlock ./channel-artifacts/channel1.block --tls --cafile "$ORDERER_CA"

上面的命令使用-f标志提供通道创建交易文件的路径,并使用-c标志指定通道名称。-o标志用于选择将用于创建通道的排序节点。–cafile是Orderer节点的TLS证书的路径。新通道的创世区块会返回到–outputBlock标志指定的位置。

2.3.3. 将Peer节点加入到通道中

创建通道后,可以使用创世区块,通过peer channel join命令将Peer加入到该通道。如果本地没有创世区块,可以使用peer channel fetch命令从排序服务中获取。加入通道后,Peer将通过从排序服务中获取通道上的其他区块来构建区块链账本。

由于已经以Org1管理员的身份使用peer CLI提交了通道创建交易,且本地已经有了通道创世区块,因此现在可以将Org1的Peer加入到通道中。

peer channel join -b ./channel-artifacts/channel1.block

以Org2中的admin用户身份运行peer CLI:

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加入到通道中:

peer channel join -b ./channel-artifacts/channel1.block

在更现实的场景下,组织将使用peer channel fetch命令从排序服务中获取区块:

peer channel fetch 0 ./channel-artifacts/channel_org2.block -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com -c channel1 --tls --cafile "$ORDERER_CA"

该命令使用0来指定它需要获取加入通道所需的创世区块。

此外,可以使用peer channel getinfo命令验证Peer是否已加入通道:

peer channel getinfo -c channel1

该命令将列出通道的区块高度和最新区块的哈希。由于创世区块是通道上的唯一区块,因此通道的高度将为1。

2.4. 设置锚节点

一个组织将其Peer节点加入通道后,应该选择至少一个Peer节点成为锚节点,才能使用私有数据和服务发现等功能。如果可以,每个组织都应该在一个通道上设置多个锚节点以实现冗余。

每个组织的锚节点的端点信息包括在通道配置中。 每个通道成员都可以通过更新通道来指定其锚节点。下面使用configtxlator工具来更新通道配置,并为Org1和Org2选择一个锚节点。

作为Org1 admin操作peer CLI:

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 "$ORDERER_CA"

因为最新的通道配置区块是通道创世区块,所以命令从通道返回区块0。

切换到存储通道配置区块config_block.pb的channel-artifacts文件夹中:

cd channel-artifacts

现在可以开始使用configtxlator工具来开始处理通道配置。第一步是将区块从protobuf解码为可以读取和编辑的JSON对象,并去掉了不必要的块数据,只留下通道配置。

configtxlator proto_decode --input config_block.pb --type common.Block --output config_block.json
jq '.data.data[0].payload.data.config' config_block.json > config.json
cp config.json config_copy.json

使用jq工具将Org1锚节点添加到通道配置中:

jq '.channel_group.groups.Application.groups.Org1MSP.values += {"AnchorPeers":{"mod_policy": "Admins","value":{"anchor_peers": [{"host": "peer0.org1.example.com","port": 7051}]},"version": "0"}}' config_copy.json > modified_config.json

在这一步之后,我们在modified_config.JSON文件中获得了JSON格式的通道配置的更新版本。我们现在可以将原始和修改后的通道配置转换回protobuf格式,并计算它们之间的差异。

configtxlator proto_encode --input config.json --type common.Config --output config.pb
configtxlator proto_encode --input modified_config.json --type common.Config --output modified_config.pb
configtxlator compute_update --channel_id channel1 --original config.pb --updated modified_config.pb --output config_update.pb

名为config_update.pb的新protobuf包含我们需要应用于通道配置的锚节点更新。我们可以将配置更新封装在交易信封中,以创建通道配置更新交易。

configtxlator proto_decode --input config_update.pb --type common.ConfigUpdate --output config_update.json
echo '{"payload":{"header":{"channel_header":{"channel_id":"channel1", "type":2}},"data":{"config_update":'$(cat config_update.json)'}}}' | jq . > config_update_in_envelope.json
configtxlator proto_encode --input config_update_in_envelope.json --type common.Envelope --output config_update_in_envelope.pb

现在可以使用config_update_in_envelope.pb来更新通道。返回测试网络目录,使用peer channel update命令提供新的信道配置来添加锚节点。因为我们正在更新只影响Org1的通道配置的一部分,所以其他通道成员不需要批准通道更新。

cd ..
peer channel update -f channel-artifacts/config_update_in_envelope.pb -c channel1 -o localhost:7050  --ordererTLSHostnameOverride orderer.example.com --tls --cafile "$ORDERER_CA"

作为Org2 admin操作peer CLI:

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

获取最新的通道配置区块,它现在是通道上的第二个区块:

peer channel fetch config channel-artifacts/config_block.pb -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com -c channel1 --tls --cafile "$ORDERER_CA"

切换到channel-artifacts文件夹中:

cd channel-artifacts

解码并复制配置区块:

configtxlator proto_decode --input config_block.pb --type common.Block --output config_block.json
jq '.data.data[0].payload.data.config' config_block.json > config.json
cp config.json config_copy.json

使用jq工具将Org2锚节点添加到通道配置中:

jq '.channel_group.groups.Application.groups.Org2MSP.values += {"AnchorPeers":{"mod_policy": "Admins","value":{"anchor_peers": [{"host": "peer0.org2.example.com","port": 9051}]},"version": "0"}}' config_copy.json > modified_config.json

将原始和修改后的通道配置转换回protobuf格式,并计算它们之间的差异。

configtxlator proto_encode --input config.json --type common.Config --output config.pb
configtxlator proto_encode --input modified_config.json --type common.Config --output modified_config.pb
configtxlator compute_update --channel_id channel1 --original config.pb --updated modified_config.pb --output config_update.pb

将配置更新封装在交易信封中,以创建通道配置更新交易:

configtxlator proto_decode --input config_update.pb --type common.ConfigUpdate --output config_update.json
echo '{"payload":{"header":{"channel_header":{"channel_id":"channel1", "type":2}},"data":{"config_update":'$(cat config_update.json)'}}}' | jq . > config_update_in_envelope.json
configtxlator proto_encode --input config_update_in_envelope.json --type common.Envelope --output config_update_in_envelope.pb

返回测试网络目录,使用peer channel update命令提供新的信道配置来添加锚节点。

cd ..
peer channel update -f channel-artifacts/config_update_in_envelope.pb -c channel1 -o localhost:7050  --ordererTLSHostnameOverride orderer.example.com --tls --cafile "$ORDERER_CA"

最后通过运行peer channel info命令来确认通道已成功更新:

peer channel getinfo -c channel1

现在,通过在通道创世区块后添加两个通道配置区块来更新通道,通道的高度将增加到三个,散列也将更新。

2.4. 部署链码以测试通道的生成

可以通过向通道部署链码来确认通道已成功创建。使用network.sh脚本将asset-transfer-basic链码部署到该通道,然后在账本上初始化一些资产并查询:

./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-java -ccl java -c channel1
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "$ORDERER_CA" -C channel1 -n basic --peerAddresses localhost:7051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt" -c '{"function":"InitLedger","Args":[]}'
peer chaincode query -C channel1 -n basic -c '{"Args":["GetAllAssets"]}'

三、手动加入组织到通道中

3.1. 准备工作

本节通过向应用通道添加一个新组织Org3来扩展Fabric测试网络。扩展之前需要先启动网络并创建通道:

cd hyfa/fabric-samples/test-network
./network.sh down
./network.sh up createChannel -c channel1

将二进制文件的路径加入环境变量:

export PATH=${PWD}/../bin:$PATH

从test-network进入addOrg3子目录:

cd addOrg3

3.2. 流程

3.2.1. 生成加密材料并启动节点容器

使用cryptogen读取org3-crypto.yaml文件,生成Org3的加密材料:

../../bin/cryptogen generate --config=org3-crypto.yaml --output="../organizations"

为configtxgen工具指定所需的configtx.yaml文件在当前目录中,创建Org3的组织定义:

export FABRIC_CFG_PATH=$PWD
../../bin/configtxgen -printOrg Org3MSP > ../organizations/peerOrganizations/org3.example.com/org3.json

Org3的组织定义是一个名为org3.JSON 的JSON文件,包含Org3的策略定义、Org3的NodeOU定义以及以base64格式编码的CA根证书和TLS根证书,后续通过将此组织定义附加到通道配置来将Org3添加到通道中。

现在启动Org3的对等体:

export DOCKER_SOCK="${DOCKER_HOST:-/var/run/docker.sock}"
docker-compose -f compose/compose-org3.yaml -f compose/docker/docker-compose-org3.yaml up -d

3.2.2. 通道配置更新

3.2.2.1. 获取现有通道配置

返回test-network目录:

cd ..

因为Org3还不是通道的成员,所以我们需要作为另一个组织的管理员来获取通道配置:

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"
3.2.2.2. 将通道配置转换为JSON格式并修剪

进入存储通道配置区块的channel-artifacts文件夹:

cd channel-artifacts

使用configtxlator工具将此通道配置区块解码为JSON格式,去掉所有与想要进行的更改无关的标头、元数据、创建者签名等(需要在本地机器上安装jq工具):

configtxlator proto_decode --input config_block.pb --type common.Block --output config_block.json
jq ".data.data[0].payload.data.config" config_block.json > config.json
3.2.2.3. 修改通道配置

再次使用jq工具将Org3的组织定义(Org3.json)添加到通道配置中,并将输出命名为modified_config.json。

jq -s '.[0] * {"channel_group":{"groups":{"Application":{"groups": {"Org3MSP":.[1]}}}}}' config.json ../organizations/peerOrganizations/org3.example.com/org3.json > modified_config.json

现在可以将原始和修改后的通道配置转换回protobuf格式,并计算它们之间的差异。

configtxlator proto_encode --input config.json --type common.Config --output config.pb
configtxlator proto_encode --input modified_config.json --type common.Config --output modified_config.pb
configtxlator compute_update --channel_id channel1 --original config.pb --updated modified_config.pb --output org3_update.pb

这将输出一个名为org3_update.pb的新protobuf二进制文件,然后把这个对象解码为可编辑的JSON格式:

configtxlator proto_decode --input org3_update.pb --type common.ConfigUpdate --output org3_update.json

将org3_update.json封装在一个信封消息中:

echo '{"payload":{"header":{"channel_header":{"channel_id":"'channel1'", "type":2}},"data":{"config_update":'$(cat org3_update.json)'}}}' | jq . > org3_update_in_envelope.json

最后转换为protobuf格式:

configtxlator proto_encode --input org3_update_in_envelope.json --type common.Envelope --output org3_update_in_envelope.pb
3.2.2.4. 签名并提交配置更新

在将配置更新写入账本之前,需要必要的管理员用户的签名。这里需要Org1和Org2的签名。

首先作为Org1为此更新签名:

cd ..
peer channel signconfigtx -f channel-artifacts/org3_update_in_envelope.pb

设置环境变量作为Org2:

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

最后使用peer channel update命令提交更新:

peer channel update -f channel-artifacts/org3_update_in_envelope.pb -c channel1 -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem"

这里,Org2的管理员签名将自动附加,因此无需再次手动签名。

3.2.3. 将新组织的节点加入到通道中

设置环境变量作为Org3:

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的对等体可以通过创世区块或Org3加入通道后创建的快照加入通道。要通过创世区块加入,需要向排序服务请求channel1的创世区块。排序服务将验证Org3是否可以拉取创世区块并加入通道。如果Org3没有成功附加到通道配置,订购服务将拒绝此请求。
下面使用peer channel fetch命令拉取创世区块:

peer channel fetch 0 channel-artifacts/channel1.block -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"

最后使用创世区块加入通道:

peer channel join -b channel-artifacts/channel1.block

3.3. 为新组织的节点使用已有链码

可以通过在通道上安装并调用链码来确认Org3是channel1的成员。如果现有通道成员已经向通道提交了链码定义,则新组织只需批准链代码定义即可使用链代码。
首先使用network.sh脚本在通道上为Org1和Org2部署链码:

./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-java/ -ccl java -c channel1

为Org3的对等体安装链码并批准链码定义:

peer lifecycle chaincode install basic.tar.gz
peer lifecycle chaincode queryinstalled
export CC_PACKAGE_ID=...
peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" --channelID channel1 --name basic --version 1.0 --package-id $CC_PACKAGE_ID --sequence 1
peer lifecycle chaincode querycommitted --channelID channel1 --name basic

使用Org2的对等体和Org3的对等体的背书满足背书策略,初始化账本:

peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C channel1 -n basic --peerAddresses localhost:9051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.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":"InitLedger","Args":[]}'

查询链码:

peer chaincode query -C channel1 -n basic -c '{"Args":["GetAllAssets"]}'

3.4. 更新新组织的锚节点(可选)

由于Org1和Org2在通道配置中定义了锚节点,因此Org3的对等体能够与Org1和Org2的对等体建立Gossip连接。同样,像Org3这样新添加的组织也应该在通道配置中定义其锚节点,以便来自其他组织的任何新对等体都可以直接发现Org3的对等体。该过程与2.2.4节基本一致。

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"
cd channel-artifacts
configtxlator proto_decode --input config_block.pb --type common.Block --output config_block.json
jq ".data.data[0].payload.data.config" config_block.json > config.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
configtxlator proto_encode --input config.json --type common.Config --output config.pb
configtxlator proto_encode --input modified_anchor_config.json --type common.Config --output modified_anchor_config.pb
configtxlator compute_update --channel_id channel1 --original config.pb --updated modified_anchor_config.pb --output anchor_update.pb
configtxlator proto_decode --input anchor_update.pb --type common.ConfigUpdate --output anchor_update.json
echo '{"payload":{"header":{"channel_header":{"channel_id":"channel1", "type":2}},"data":{"config_update":'$(cat anchor_update.json)'}}}' | jq . > anchor_update_in_envelope.json
configtxlator proto_encode --input anchor_update_in_envelope.json --type common.Envelope --output anchor_update_in_envelope.pb
cd ..
peer channel update -f channel-artifacts/anchor_update_in_envelope.pb -c channel1 -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem"

排序服务收到配置更新请求后用更新后的配置生成一个新的配置区块。当对等体接收到新的配置区块时,它们将处理配置更新。

检查其中一个对等体的日志:

docker logs -f peer0.org1.example.com

看到下述信息则证明配置更新已成功应用。

在这里插入图片描述

3.5. 补充说明 - 主节点选举的配置

新加入的对等体使用创世区块进行引导,创世区块不包含有关在通道配置更新中添加的组织的信息。因此,新的对等体不能直接使用Gossip服务,因为它们不能验证其它对等体从各自的组织转发的区块,直到它们从排序服务获得将组织添加到通道的配置交易。

3.6. 报错

触发位置:使用docker-compose命令手动启动Org3的节点容器

错误描述:error decoding ‘volumes[1]’: invalid spec: :/host/var/run/docker.sock: empty section between colons

在这里插入图片描述

报错原因:启动测试网络节点容器的YAML文件中包含了${DOCKER_SOCK}:/host/var/run/docker.sock的映射项,当使用测试网络自带的脚本启动节点容器时,会为DOCKER_SOCK赋值,但是如果直接使用docker-compose命令手动启动节点容器,则DOCKER_SOCK为空。

解决方法:启动前设置环境变量,将DOCKER_SOCK指向/var/run/docker.sock。
export DOCKER_SOCK=“${DOCKER_HOST:-/var/run/docker.sock}”

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值