深度学习
排序服务给客户端和Peer节点提供了一个共享通信通道(Communication Channel),用来实现交易的广播服务。客户端连接到通道(Channel)上,在通道上广播的消息会最终发送给通道内所有的Peer节点。通道支持 消息的原子广播(Atomic Broadcast),通道给所有相连的Peer节点输出相同的消息,并且有相同的逻辑顺序。这种原子通信保证也叫全序广播(Total-order Broadcast)。
排序服务支持多通道(Multi-channel),类似Kafka消息系统的主题(Toptics)。客户端连 接到一个指定的通道上,就可以发送或者获取消息了。通道是相互隔离的,客户端连接到一个通道是不知道其他通道的存在的,但是客户端可以连接到多个通道。为 简单起见,在本章后面的部分,除非明确提到的其他情况,否则我们都假设排序服务是由单个通道和主题组成的。
图6-2所示为一个多通道的示例,基于SDK开发的应用程序或者命令行程序通过gRPC通道给排序服务提交背书节 点以模拟执行后的交易,排序服务会根据交易信息里提案的请求头确定通道信息,添加到对应的队列中进行排序,生成区块后广播给加入了这个通道的节点。比如节 点1会收到通道1和通道N的区块信息,节点2会收到通道1、通道2和通道N的区块信息,节点N会收到通道2和通道N的区块信息。没有加入通道中的节点是接 收不到这个通道的区块信息的,比如节点1收不到通道2的区块信息,节点N收不到通道1的区块信息。
图6-2 多通道示例
每个通道在节点上都有一个关联的账本,节点2在3个通道上,本地会对应有3个账本数据,账本存储结构参考上一章的 介绍。在区块链网络的所有节点上都存在的账本称为系统账本,反之称为子账本。从数据隔离角度看,两个通道上的节点完全一样是没有意义的,有多个系统账本也 是没有意义的。由于排序服务能接收到所有链的交易信息,所以数据隔离是对节点来说的,并不针对排序服务节点(Ordering Service Nodes,OSN)。如果业务上希望交易信息的内容对排序服务也保密,可以对交易信息进行哈希或者加密,避免传输明文信息。
6.2.1 排序服务的初始化
排序服务是由多个排序节点组成的,在每个排序节点启动的时候需要有一个创世区块(Genesis Glock)。创世区块包含的信息有:
·排序节点信息及其MSP信息(管理员证书、根证书和TLS根证书);
·组织信息及其MSP信息(管理员证书、根证书和TLS根证书);
·共识算法类型;
·区块配置信息;
·访问控制策略。
创世区块是通过configtxgen工具生成的,还有一个工具configtxlator可以实现区块和JSON格式之间的相互转换,下面是一个创世区块转换成JSON后的格式,包含的信息概要如下所示:
{
"data": {
"data": [
{
"payload": {
"data": {
"config": {
"channel_group": {
"groups": {
"Consortiums": {
"groups": {
"SampleConsortium": {
"groups": {
"Org1MSP": {...
},
"Org2MSP": {...
}
},
"mod_policy": "/Channel/
Orderer/Admins",
"values": {...
}
}
},
"mod_policy": "/Channel/Orderer/
Admins",
"policies": {...
}
},
"Orderer": {
"groups": {
"OrdererOrg": {...
}
},
"mod_policy": "Admins",
"policies": {...
},
"values": {
"BatchSize": {
"mod_policy": "Admins",
"value": {
"absolute_max_bytes":
102760448,
"max_message_count": 10,
"preferred_max_bytes":
524288
}
},
"BatchTimeout": {
"mod_policy": "Admins",
"value": {
"timeout": "2s"
}
},
"ChannelRestrictions": {
"mod_policy": "Admins"
},
"ConsensusType": {
"mod_policy": "Admins",
"value": {
"type": "solo"
}
}
}
}
},
"mod_policy": "Admins",
"policies": {...
},
"values": {
"BlockDataHashingStructure": {
"mod_policy": "Admins",
"value": {
"width": 4294967295
}
},
"HashingAlgorithm": {
"mod_policy": "Admins",
"value": {
"name": "SHA256"
}
},
"OrdererAddresses": {
"mod_policy": "/Channel/Orderer/
Admins",
"value": {
"addresses": [
"orderer.example.com:7050"
]
}
}
}
}
}
},
"header": {...
}
}
}
]
},
"header": {
"data_hash": "etbznpwMod/5MUv9j3Ul9fo8fWj6WYd+0PFWFx2c2X8="
},
"metadata": {...
}
}
其中,…表示信息省略了。
6.2.2 通道的创建
应用程序可以通过SDK或者命令行向排序服务发起创建通道的请求,提交的内容是通道配置交易(Channel Configuration Transaction)。通道配置交易需要由工具configtxgen生成,详细步骤在第2章已经详细介绍过。以下是一个通道配置交易通过工具 configtxlator转换成JSON格式的示例:
{
"payload": {
"data": {
"config_update": {
"channel_id": "mychannel",
"read_set": {
"groups": {
"Application": {
"groups": {
"Org1MSP": {},
"Org2MSP": {}
}
}
},
"values": {
"Consortium": {
"value": {
"name": "SampleConsortium"
}
}
}
},
"write_set": {
"groups": {
"Application": {
"groups": {
"Org1MSP": {},
"Org2MSP": {}
},
"mod_policy": "Admins",
"policies": {
"Admins": {
"mod_policy": "Admins",
"policy": {
"type": 3,
"value": {
"rule": "MAJORITY",
"sub_policy": "Admins"
}
}
},
"Readers": {
"mod_policy": "Admins",
"policy": {
"type": 3,
"value": {
"sub_policy": "Readers"
}
}
},
"Writers": {
"mod_policy": "Admins",
"policy": {
"type": 3,
"value": {
"sub_policy": "Writers"
}
}
}
},
"version": "1"
}
},
"values": {
"Consortium": {
"value": {
"name": "SampleConsortium"
}
}
}
}
}
},
"header": {
"channel_header": {
"channel_id": "mychannel",
"timestamp": "2017-08-22T18:53:29.000Z",
"tx_id": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca49599
1b7852b855",
"type": 2
}
}
}
}
排序服务接收到创建通道的请求,会检查是否是配置交易。检查的方法是查看通道头ChannelHeader的类型 是否为HeaderType_CONFIG_UPDATE(新建通道和更新通道配置的类型都是这个类型),然后排序服务节点重新生成一个配置交易,修改交 易类型为HeaderType_CONFIG,内容除了包含write_set里的Aplication,还会包含系统链里的Orderer和 Consortium,新生成的交易会利用接收消息的排序服务节点的私钥重新进行签名,然后添加到系统链的交易消息队列中进行处理。
每个链(包括系统链)有一个协程专门处理消息队列中的消息,按消息队列的顺序进行排序。系统链增加了 newSystemChainFilter的消息过滤器,在排序的过程中会检查系统链中的消息是否满足过滤器的条件,检查的结果可能是转发、拒绝或者接 收,接收消息的同时返回系统链的提交器systemChainCommitter。交易切割形成区块后,在区块写入系统账本之前会调用提交器创建一个新的 链,在新的链上创建一个包含配置交易的创世区块。新的链会在多账本管理器multiLedger处注册,当接收到这个链上的交易请求时,排序服务节点会分 发给这个链来处理。这样,排序服务节点就有了多链的处理逻辑,给不同链的交易划分了不同的通道,实现了数据的隔离。
应用程序发起了创建通道的请求,创建成功后返回这个链的创世区块。新链的创世区块如下:
{
"data": {
"data": [
{
"payload": {
"data": {
"config": {
"channel_group": {
"groups": {
"Application": {
"groups": {
"Org1MSP": {...
},
"Org2MSP": {...
}
},
"mod_policy": "Admins",
"policies": {...
},
"version": "1"
},
"Orderer": {...
}
},
"policies": {...
},
"values": {...
}
},
"sequence": "1"
},
"last_update": {
"payload": {
"data": {
"config_update": {
"channel_id": "mychannel",
"read_set": {..
},
"write_set": {...
}
},
"signatures": [...
]
},
"header": {...
}
},
"signature": "MEUCIQDoU1ZwztKkRhp5f0X2aWef7xQ73P7rqu
MrGGx7EcRNNQIge2inBpxbGHkQ83lyHoMdA7eciNPmX3+QwCLbzOgkUpU="
}
},
"header": {
"channel_header": {
"channel_id": "mychannel",
"timestamp": "2017-08-31T09:24:31.000Z",
"type": 1
},
"signature_header": {...
}
}
},
"signature": "MEQCIA/fOYvcOou5pkHtjtiG3eV4f67z4D/
Myusxu3qAHAdAAiB0j/ekiakdHkbOBM9uuR2bzYjVBrKuoK1UaJ1ZuWkm8Q=="
}
]
},
"header": {...
},
"metadata": {...
}
}
新链的创世区块包含了通道配置交易的内容,扩展了从系统链上保存的组织信息、排序节点服务信息等,这样节点可以根据这个创世区块确定新链的标识、排序服务节点地址等,而不用访问排序服务的系统链。
6.2.3 通道的更新
通道的配置是可以更新的,包括通道组织、组织MSP、访问控制策略、排序服务配置等。通道更新需要线下确定好需要修改的配置项,离线修改后通过SDK或者CLI发送给排序服务节点,详细的过程如图6-3所示。
从图6-3可以看到,通道配置的修改同样需要利用configtxlator服务,详细的使用方法参考附录B的内容。
发送给排序服务的交易请求类型为HeaderType_CONFIG_UPDATE,排序服务节点接收到配置更新 交易请求后会重新创建一个类型为HeaderType_CONFIG的信封,添加到被修改通道的交易队列里。每个链都一些过滤器规则,若检测到是类型是 HeaderType_CONFIG就提交给configManager来处理。
利用排序服务生成的配置区块,也会通过排序服务建立好gRPC连接的主节点(orgLeader)广播给通道内的 其他节点。记账节点接收到配置区块以后,账本提交器(LedgerCommitter)在提交到账本之前会检查ChannelHeader的类型,如果是 HeaderType_CONFIG就确认是配置区块,从区块里获取链编号,更新本地节点这个链的配置区块为最新收到的区块。
图6-3 利用configtxlator构造通道更新的请求
6.2.4 通道的加入
应用程序通过SDK或者命令行给节点发送包含通道创世区块的JoinChain请求,请求的类型是 HeaderType_CONFIG。节点加入链的JoinChain请求是由系统链码CSCC处理的。节点会校验创世区块的合法性(包括内容完整性), 比如是否包含应用相关的配置项,还会对提交者的身份进行认证和权限检查。配置交易是需要应用程序用提交者的私钥进行签名的,身份认证需要确认请求头是否包 含有效的提交者身份信息,再验证配置交易请求是否是该提交者签名的。然后是权限检查,包括两个方面。
1)是否有权限向节点提交请求:即检查提交者的MSP是否与本地MSP相同。
2)是否满足加入通道请求的策略:提交加入通道请求是需要有管理员权限的,管理员的证书配置在节点的$CORE_PEER_MSPCONFIGPATH/admincerts目录下。
权限检查会在节点本地创建以请求头里channel_header的channel_id为标识的链,节点的本地 配置是由主节点(orgLeader)或者选举为主节点后主动和创世区块里设置的排序服务节点建立连接,接收排序服务广播的新区块,再在组织内部节点同 步;节点若不是主节点就从组织内部其他节点上同步,详细的过程参见上一章的相关内容。
6.2.5 通道的查询
通道信息是节点本地维护的,有一个值为chain的映射表(list map[string]*chain),在节点启动或者有加入通道等操作的时候更新这个映射表。映射表的键就是通道名称,遍历就能返回节点加入的所有通 道。这个映射表只能通过系统链码CSCC查询,命令行的方式是:
peer channel list
应用程序也可以通过SDK发送请求,比如fabric-sdk-go提供的接口 QueryChannels(peer Peer)(*pb.ChannelQueryResponse,error)可以查询指定节点加入的通道。命令行和SDK的方式都是发送相同的请求,即 构造一个调用CSCC的GetChannels调用请求。查询通道信息是需要权限的,权限的策略配置是在配置区块里的,一般的读取权限是只要成为这个组织 的成员就可以了。通过权限检查返回的是由本地节点维护的已加入通道的名称数组。
通道的配置也是可以查询的,比如获取排序服务节点。节点内部查询配置区块是通过调用系统链码CSCC的GetConfigBlock获取的,同样会检查是否有权限查询,通过检查会返回由本地维护的最新配置区块。
应用程序和命令行是怎么从账本里找到最新的配置区块呢?实际上,每个区块的元数据里都有最新配置区块的索引,所以 需要先给排序服务发送SeekPosition_Newest请求以获取最新的区块,从区块里解析出 BlockMetadataIndex_LAST_CONFIG以获取配置区块高度,根据区块高度获取指定的配置区块。需要说明的是,最新的配置区块都是 全量的,如果通道的配置信息更新过,更新的内容都会更新到最新的配置区块里,获取最新的配置区块就能查询最新的配置信息了。
命令行获取通道配置的命令:
peer channel fetch config config_block.pb -o $OSN_IP:$OSN_PORT -c $CHANNEL_ID
其中:OSN_IP和OSN_PORT是排序服务节点的地址和端口,CHANNEL_ID是通道编号。config_block.pb是配置区块文件,如果不提供这个参数,则默认生成的配置区块文件是$CHANNEL_ID.block。
通道上的交易处理和智能合约参考上一章的相关部分。截止到目前的版本,通道创建以后还不能终止或者删除,也没有提供功能让节点退出一个通道。
来源:我是码农,转载请保留出处和链接!
本文链接:http://www.54manong.com/?id=1063
微信号:qq444848023 QQ号:444848023
加入【我是码农】QQ群:864689844(加群验证:我是码农)
全站首页 | 数据结构 | 区块链| 大数据 | 机器学习 | 物联网和云计算 | 面试笔试
var cnzz_protocol = (("https:" == document.location.protocol) ? "https://" : "http://");document.write(unescape("%3Cspan id='cnzz_stat_icon_1276413723'%3E%3C/span%3E%3Cscript src='" + cnzz_protocol + "s23.cnzz.com/z_stat.php%3Fid%3D1276413723%26show%3Dpic1' type='text/javascript'%3E%3C/script%3E"));本站资源大部分来自互联网,版权归原作者所有!
评论专区