本文基于Hyperledger Fabric 1.4版本。

官方文档地址:传送门

动态添加一个组织到Fabric网络中也是一个比较重要的功能。官方文档写的已经很详细了,有能力的尽量还是看官方文档,本文只是根据官方文档进行整理同时兼翻译。

1.前提条件


这个不再解释了,前提条件自然是搭建Fabric的环境了并跑通官方的例子,具体的看这里.

2.启动网络


还是以官方的byfn为例好了,不多说,对Fabric有一定了解的都能明白,不明白的看上面文档:

./byfn.sh up
#或者是
./byfn.sh up -s couchdb
#区别不大,只不过换了一个数据库而已,对本文内容没多少关系

动态添加组织官方脚本自动化操作就简单执行以下命令:

./eyfn.sh up

本文重点不在这里,因为自动化操作省略了所有的内容,固然简单,但是仍然不懂其中过程。所以本文的重点还是下一部分,手动地一步一步完成动态增加组织。

3手动添加组织到网络中

byfn网络中的节点为:

  • Order -> orderer.example.com
  • Org1 -> peer0.org1.example.com
  • Org1 -> peer1.org1.example.com
  • Org2 -> peer0.org2.example.com
  • Org2 -> peer1.org2.example.com

而我们要添加的为:

  • Org3 -> peer0.org3.example.com
  • Org3 -> peer1.org3.example.com

在这里,我们假设工作目录在$GOPATH/.../fabric-samples/first-network文件夹。上面的五个节点也通过

./byfn.sh up

命令成功启动。

Fabric网络的启动过程总的来说没有几步(锚节点那部分先省略掉,对本文没有影响):

  1. 为每一个节点生成证书文件
  2. 生成系统通道的创世区块(也是配置文件)
  3. 生成通道配置文件
  4. 启动节点
  5. 根据通道配置文件创建通道生成应用通道创世区块
  6. 加入通道
  7. ...

根据这个流程来考虑动态增加节点:

  • 首先为每一个节点生成证书文件是肯定要做的。
  • 第二步生成创世区块(系统通道配置文件)是不需要的
  • 第三步生成应用通道配置文件需要变为更新应用通道配置文件
  • 第四步启动节点步骤不变
  • 第五步创建通道也不需要了,直接到第六步加入通道
  • ...(网络启动之后的步骤最后再说)

既然分析完了,我们只要按照步骤完成就可以了。

3.1生成证书文件

怎么生成证书文件呢,这个直接使用官方的文件就可以了,当然有定制化需求的请自行修改。文件在工作目录下的org3-artifacts文件夹下的org3-crypto.yaml文件。

这一步比较简单,直接执行命令行工具就可以了,当然对Fabric CA比较熟悉的也可以采用手动生成证书的方法,本文为了简便,直接使用工具生成:

cd org3-artifacts
cryptogen generate --config=./org3-crypto.yaml

完成之后在org3-artifacts目录下生成一个crypto-config文件夹。里面就是需要添加的新组织的证书文件。

如果网络开启TLS的话,在多机环境下还需要将OrdererTLS根证书拷贝一份过来用于之后的与Orderer节点进行通信,而单机环境下也可以直接将OrdererTLS根证书挂载到之后需要启动的Org3的容器内部。而本文采用和官方文档相同的方法,直接拷贝文件:

cd ../ && cp -r crypto-config/ordererOrganizations org3-artifacts/crypto-config/

3.2更新通道配置文件

接下来第三步:更新通道配置文件,可以分为以下步骤:

  1. 获取网络中当前通道之前最新的配置区块
  2. 把需要更新的内容添加进去
  3. 把最新的配置文件更新到网络中

3.2.1获取最新的配置区块

看一下第一步获取网络中之前最新的配置区块,如何获取呢,自然是通过网络中现有的节点进行获取,并且使从peer节点向Orderer节点发起通信获取配置区块。

首先进入cli容器:

docker exec -it cli bash

配置需要的环境变量:

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

如果操作中途退出了cli容器,那么再次进入时都需要重新配置环境变量.

接下来获取之前最新的配置区块:

peer channel fetch config config_block.pb -o orderer.example.com:7050 -c $CHANNEL_NAME --tls --cafile $ORDERER_CA
  • peer channel fetch: 从指定的通道获取具体的区块并写入文件。
  • config :指定获取的区块是配置区块.(Fabric网络中区块类型可分为普通交易区块和配置区块)
  • config_block.pb:将配置区块写入到这个文件中
  • -o :指定向具体的排序节点发起通信
  • -c:指定通道名称
  • --tls:如果开启了TLS则需要指定这个参数
  • --cafile:TLS根证书文件

执行完毕后命令行会打印这些信息:

 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
UTC [cli.common] readBlock -> INFO 002 Received block: 4
UTC [cli.common] readBlock -> INFO 003 Received block: 2
UTC [channelCmd] fetch -> INFO 004 Retrieving last config block: 2

可以看到mychannel通道中共生成了5个区块(创世区块序号为0).但是最新的配置区块序号为2:

  1. 配置区块0:创世区块
  2. 配置区块1:组织一的锚节点更新
  3. 配置区块2:组织二的锚节点更新
  4. 普通区块3:实例化链码
  5. 普通区块4:调用链码

而本文获取到了最新的配置区块也是是区块2,并将该区块写入到了config_block.pb文件中。

3.2.2将配置信息添加到配置文件中

我们已经获取到了最新的配置文件,接下来如何更新它呢,因为区块内容是编码过的,而且还包括区块头,元数据以及签名等信息,对更新配置是用不到的。所以需要先将区块进行解码成我们可读的文件,而且为了简单化,可以将不相关的区块头等信息去掉(当然不去掉也没有问题)。

这里用到了两个工具:Fabric官方的命令行工具configtxlator,以及jq工具:

configtxlator工具可以帮助我们进行编解码转换

jq工具和Linux中的grep,awk命令较为相似,都是对数据进行处理的(当然不使用这个工具也没什么问题,只不过需要手动修改数据而已)。

接下来就是将区块信息解码去除不相关的信息后并以json格式保存到文件中:

configtxlator proto_decode --input config_block.pb --type common.Block | jq .data.data[0].payload.data.config > config.json
  • proto_decode :解码操作
  • --input:需要解码的文件作为输入
  • --type:输入文件的类型

解码后通过jq工具提取需要的数据并保存到了config.json文件中。

接下来呢,就是将组织三的配置信息写到这里面,组织三的配置信息呢?我们还没有生成它,之前只是为组织三生成了证书文件。所以我们还需要生成组织三的配置信息。

同样的,用于生成配置信息的源文件官方也给了,在工作目录下的org3-artifacts文件夹下的configtx.yaml文件。

因为上一步我们将通道内的最新的配置文件转换为了json格式,所以这里我们也需要将这个文件内的配置信息转换为json格式:

#打开新的终端进入以下目录中
cd $GOPATH/.../fabric-samples/first-network/org3-argifacts/
#指定配置文件所在路径 或者是通过-configPath路径指定
export FABRIC_CFG_PATH=$PWD
#直接通过工具将配置信息写到org3.json文件中。
configtxgen -printOrg Org3MSP > ../channel-artifacts/org3.json

现在让我们回到之前的终端继续操作,将刚刚生成的org3.json文件添加到config.json文件中,通过jq工具:

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

这一行命令就是将org3.json这个文件添加到config.json文件的channel_group->groups->Application->groups->Org3MSP下,并保存到modified_config.json文件。

接下来就是获取原始配置文件和新的配置文件的不同点了,官方文档的意思是只保留组织3的定义以及一个指向组织1与组织2的高级指针,因为没有必要连同之前的配置文件一起更新,所以只需要一个指针指向原配置(个人理解)。

具体的操作方法是将上面两个json文件编码回去,然后使用configtxlator工具进行比较更新。

操作命令:

  • 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
  • 计算两个文件的差异并输出到org3_update.pb文件:
# --original 指定原配置文件   --updated 指定新配置文件
configtxlator compute_update --channel_id $CHANNEL_NAME --original config.pb --updated modified_config.pb --output org3_update.pb

接下来还需要做一件事,就是封装一个更新配置的文件,将org3_update.pb写进去,毕竟向Fabric添加组织需要更新Fabric的配置,自然是需要将配置文件按照Fabric规定的文件类型封装好才能更新网络。

然后封装配置信息又会涉及到一些额外的信息,说简单点就是Fabric规定的文件类型的标识符之类的,所以需要我们再次解码,然后添加这些额外的信息进去:

configtxlator proto_decode --input org3_update.pb --type common.ConfigUpdate | jq . > org3_update.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 proto_encode --input org3_update_in_envelope.json --type common.Envelope --output org3_update_in_envelope.pb

3.2.3更新应用通道配置文件

配置更新消息已经处理好了,接下来就是更新到网络中了。在此时,新添加的组织信息还没有更新进去,所以还是需要使用之前的组织将配置进行更新,首先就是需要带有Admin身份的多数节点进行签名(策略这块以后再讲),所以需要每个组织中各一个节点进行签名,首先是peer0.org1,由于之前打开的cli容器默认身份就是peer0.org1,所以不需要配置环境变量直接进行签名:

peer channel signconfigtx -f org3_update_in_envelope.pb

接下来是组织二的节点:

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:9051

实际上我们只需要进行配置文件更新就行了,因为在配置更新操作中如果没有签名默认会先进行签名的:

peer channel update -f org3_update_in_envelope.pb -c $CHANNEL_NAME -o orderer.example.com:7050 --tls --cafile $ORDERER_CA

如果命令行日志打印出一下内容说明更新通道配置成功:

UTC [channelCmd] update -> INFO 002 Successfully submitted channel update

在此时,区块5将会生成并写到每一个节点的账本,比如我们查看peer0.org1的日志信息,可以看到以下内容:

#打开一个新的命令行
docker logs -f peer0.org1.example.com
##日志内容
UTC [gossip.privdata] StoreBlock -> INFO 07c [mychannel] Received block [5] from buffer
...
UTC [gossip.gossip] JoinChan -> INFO 07d Joining gossip network of channel mychannel with 3 organizations
...
UTC [committer.txvalidator] Validate -> INFO 082 [mychannel] Validated block [5] in 238ms
...
UTC [kvledger] CommitWithPvtData -> INFO 08b [mychannel] Committed block [5] with 1 transaction(s) in 238ms
...

3.4启动节点并加入通道

到这里,组织三的信息已经更新到网络中了,所以我们可以启动组织三的节点了:

docker-compose -f docker-compose-org3.yaml up -d

启动成功后进入组织三的cli容器:

docker exec -it Org3cli bash

第一步还是配置环境变量,还记得一开始我们将排序节点的根证书复制的那一步吧,现在就派上用场了:

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

没问题的话就可以进行加入通道了,如果加入通道呢,肯定是需要创世区块了,所以需要从排序节点处获取它:

#这里不能用peer channel fetch config ... 否则获取到的是刚生产的区块5,只有使用创世区块才能加入通道
peer channel fetch 0 mychannel.block -o orderer.example.com:7050 -c $CHANNEL_NAME --tls --cafile $ORDERER_CA
###命令行打印出一下内容
UTC [cli.common] readBlock -> INFO 002 Received block: 0

最后加入通道:

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

3.5测试

一切都没有问题,就差测试链码能不能用了。

首先这里注意一点,在新的组织添加进通道之前,链码的背书策略并没有涉及到新的组织,所以之前的链码对于新的组织是不能使用的,包括查询,调用以及更新操作。但是安装链码是可以用的(前提是版本和链码名称不能全部相同),所以我们需要通过之前的组织更新链码,并制定背书策略将新的组织添加进来。

切换到组织一的节点:

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/
## 更新背书策略将新的组织添加进来
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')"
#测试一下更新是否成功
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
## Query Result: 90

切换回组织三的节点容器:

docker exec -it Org3cli bash
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

安装链码:

peer chaincode install -n mycc -v 2.0 -p github.com/chaincode/chaincode_example02/go/

安装完测试一下:

peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
# Query Result: 90

查询没问题,调用一下试试:

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

没问题了,到这里我们成功将组织三动态添加到网络中了。

3.5更新组织三的锚节点

锚节点说简单点就是用于跨组织通信的。初始的跨组织通信启动信息需要通过锚节点的设置提供。在最后一小部分,说明一下如何更新组织三的锚节点。

和前面的步骤相似:

  1. 获取最新的配置区块
  2. 更新配置信息
  3. 将更新后的配置信息更新到链上。

3.5.1获取最新的配置区块

#还是之前的组织三的CLI容器,并且环境变量$CHANNEL_NAME,$ORDERER_CA需要提前配置好
peer channel fetch config config_block.pb -o orderer.example.com:7050 -c $CHANNEL_NAME --tls --cafile $ORDERER_CA
  • 解码配置信息为JSON格式,并去除用不到的信息:
configtxlator proto_decode --input config_block.pb --type common.Block | jq .data.data[0].payload.data.config > 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
  • 将原有的配置信息与新的配置信息编码为common.Config格式:
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 $CHANNEL_NAME --original config.pb --updated modified_anchor_config.pb --output anchor_update.pb
  • 再次解码:
configtxlator proto_decode --input anchor_update.pb --type common.ConfigUpdate | jq . > anchor_update.json
  • 添加头部信息:
echo '{"payload":{"header":{"channel_header":{"channel_id":"'$CHANNEL_NAME'", "type":2}},"data":{"config_update":'$(cat anchor_update.json)'}}}' | jq . > anchor_update_in_envelope.json
  • 编码为Fabric可读的配置文件类型:
configtxlator proto_encode --input anchor_update_in_envelope.json --type common.Envelope --output anchor_update_in_envelope.pb
  • 配置文件写完了,更新上去:
peer channel update -f anchor_update_in_envelope.pb -c $CHANNEL_NAME -o orderer.example.com:7050 --tls --cafile $ORDERER_CA

到这里锚节点更新完了,剩下的自行测试。

Hyperledger Fabric 动态增加组织到网络中的更多相关文章

  1. Fabric动态增加组织【资料】

    Fabric在启动之前需要生成Orderer的创世区块和channel的配置区块.也就是说在Fabric网络启动之前我们就必须定好了有哪些Org,而当Fabric已经跑起来之后,想要增加Org却是很麻 ...

  2. Hyperledger Fabric动态配置Raft节点

    Hyperledger Fabric动态配置Raft节点 最近看官方文档发现新的共识算法etcdRaft允许动态添加或删除排序节点,所以也花了一天时间操作了以下,写篇文章把整个过程记录一下. 初始网络 ...

  3. Hyperledger Fabric无排序组织以Raft协议启动多个Orderer服务、TLS组织运行维护Orderer服务

    前言 在实验Hyperledger Fabric无排序组织以Raft协议启动多个Orderer服务.多组织共同运行维护Orderer服务中,我们已经完成了让普通组织运行维护 Orderer 服务,但是 ...

  4. Fabric进阶(三)—— 使用SDK动态增加组织

    在fabric网络运行过程中动态追加新的组织是相当复杂的,网上的资料也十分匮乏,大多是基于first-network这样的简单示例,而且是使用启动cli容器的方法来增加组织,几乎没有针对实际应用的解决 ...

  5. Hyperledger Fabric无排序组织以Raft共识算法启动多个Orderer服务、多组织共同运行维护Orderer服务

    前言 在Hyperledger Fabric无系统通道启动及通道的创建和删除中,我们已经完成了以无系统通道的方式启动 Hyperledger Fabric 网络,并将链码安装到指定通道.但目前为止,实 ...

  6. 菜鸟系列Fabric——Fabric 动态添加组织(7)

    Fabric 网络动态添加组织 1.环境准备 如果存在fabric网络环境可不执行,若不存在可以安装下列进行准备 下载fabric-sample,fabric https://github.com/h ...

  7. OSI7层封包解包动态图-数据在网络中的传输过程.gif

  8. 【干货干货】hyperledger fabric 之动态添加组织/修改配置 (Fabric-java-sdk) 下

    我们接着上一节来讲: 在熟悉动态增加组织或修改配置的步骤后,我们就可以使用java的api来完成动态增加组织或修改配置了: 废话不多说,直接上干货: 1,预制条件 org3的证书以及组织3的MSP详情 ...

  9. Fedora 25-64位操作系统中安装配置Hyperledger Fabric过程

    安装过程参照Hyperledger Fabric的官方文档,文档地址:http://hyperledger-fabric.readthedocs.io/en/latest/prereqs.html 0 ...

随机推荐

  1. 考试T1护花

    传送门 这题的提议似乎有什么问题,只要约翰选好了要抓那头牛,他就不会吃草了,站在原地傻等? 这题就是贪心,但在用cmp中比较单位时间吃草数量时,要用double型,不然可能会有点一样... 还有就是主 ...

  2. Consul安装集群搭建

    1 consul的安装和配置 1.1 consul agent 命令介绍 下载consul_1.0.0_linux_amd64.zip解压,里面只有一个consul可执行文件,其中,consul最常用 ...

  3. phpexcel导出数字带E的解决方法

    phpexcel导出数字带E的解决方法 excel之所以带E 是因为按照数字格式来显示了(数字过长的时候) 数字左边或者右边加空格就变成字符串了 那么excel就会按照字符串格式来显示了 就不会带E了

  4. transformer模型简介

    Transformer模型由<Attention is All You Need>提出,有一个完整的Encoder-Decoder框架,其主要由attention(注意力)机制构成.论文地 ...

  5. django 之创建自己的模板(使用案例)

    Django 创建自己的模板篇(实例) 此处需要创建模板,主要是对自己的模板进行扩展: 一般是扩展模板的tag和filter两个功能.可以用来创建你自己的tag和filter功能库. 创建模板库 分为 ...

  6. C++中对C的扩展学习新增语法——强制类型转换

    类型转换:主要进行指针类型转换,因为在C++中,不同类型指针不允许隐式转换,任何一个程序中如果出现了大量的类型转换,说明该程序不是太好的程序. 注意事项: 不同类型指针不允许隐式转换: void* 类 ...

  7. php如何在mysql里批量插入数据

    假如说我有这样一个表,我想往这个表里面插入大量数据 CREATE TABLE IF NOT EXISTS `user_info` ( `id` int(11) NOT NULL AUTO_INCREM ...

  8. 力扣(LeetCode)两整数之和 个人题解

    不使用运算符 + 和 - ​​​​​​​,计算两整数 ​​​​​​​a .b ​​​​​​​之和. 示例 1: 输入: a = 1, b = 2 输出: 3 示例 2: 输入: a = -2, b = ...

  9. 领扣(LeetCode)设计哈希映射 个人题解

    不使用任何内建的哈希表库设计一个哈希映射 具体地说,你的设计应该包含以下的功能 put(key, value):向哈希映射中插入(键,值)的数值对.如果键对应的值已经存在,更新这个值. get(key ...

  10. gitbook怎么操作

    首先我先说一下什么是GitBook,它和Git没半毛钱关系,定义如下: GitBook 是一个基于 Node.js 的命令行工具,支持 Markdown 和 AsciiDoc 两种语法格式,可以输出 ...