fabric1.0与0.6相比改动较大,解决了不少痛点问题。第一:动态增加节点功能 第二:分链结构,容易实现spv 第三:策略管理(过滤器)机制,增加权限控制。 第四:提高高可用性HA(此词来自于殷舒~若使用不当和我没关系~~)增加kafka集群。第五:支持合约升级,有利于后期维护。第六:将ca功能拆分,ca证书分发的过程可以单独处理。第七:模块分割,结构清晰,各模块分工明确。
fabric1.0整体流程是客户端通过grpc连接peer的endorser server,endorser server仿真智能合约,仿真结果签名后返回客户端,客户端通过Broadcast将返回结果发送至orderer,orderer处理数据将结果交给kafka集群,orderer切割kafka交易成块,orderer将切割的block信息通过Deliver发送给commiter peer,committer peer之间通过gossip来实现一致性,commit peer 存储到db中。
fabric1.0管理不是以chaincode为处理单元,而是以chainID分割,也就是说以链为单位进行处理。fabric1.0以channel为载体,peer节点与orderer通信前提是搭建channel,而且每个channel只能承载一条链chainid,每个chainid 可以承载多个智能合约。(多个智能合约用一条链,ledger数据也是在一起?)这种思想有利于动态增加节点,peer节点关心的chainid可以直接向orderer进行订阅(join channel)。
fabric0.6处理交易信息都是由peer节点进行处理,而在1.0里交易由endorser server接收后,都是要交给system chaincode处理。目前一共由五个系统级chaincode,他们分别是:
cscc:负责joinchannel/config update等
escc:负责对传入数据进行签名(msp管理)
lccc:负责deploy invoke
vscc:负责签名验证/策略验证(这里如何进行策略验证?)
qscc:负责ledger查询
这五个系统级应用绑定在chainID:test_id 上,这五个又分成chainlessCC chainCC,例如cscc用于joinchannel没有数据需要单独存储所以是ChainlessCC,escc执行合约产生的数据需要保存所以是ChainCC,形象说endorser peer节点搭建合约仿真环境的时候,需要考虑是否要给其流出存储接口,合约产生的数据都提交到这个接口,合约结束后统计数据内容。
Peer节点Ledger:
类型:state存储/block存储/ledgerProvider/index
statedb:用于存储世界状态可选:leveldb couchdb
blockdb:存储block信息,leveldb
indexdb:存储块号索引 txid,leveldb
ledgerProviderdb:属于管理db,记录整个peer一共由多少chainID ledger
/**************************************************
Ledger工程描述(可跳过):
init期间创建“openedLedgers”的map表,key:chainID,value:PeerLedger实例对象。PeerLedger数据结构由三个重要成员变量:statedb操作句柄/blockdb+indexed操作句柄/ledgerProviderdb操作句柄。所以每个chainID在创建的时候都要创建chainID-PeerLedger操作句柄。在初始化期间创建ledgerProvider对象,该对象是各Ledgerdb的总句柄,chainID—PeerLedger的分配就是由ledgerProvider管理。
***************************************************/
Orderer节点ledger:
类型:block存储db
可选file ram两种方式
/**************************************************
Ledger工程描述(可跳过):
Orderer是以chainID为单位进行ledger存储,其方式与Peer 节点非常相似,map中key为chainID,value:能够对block进行操作的ReadWrite对象/以及便于查找的链表指针(ram方式是采用的链表方式存储)为什么不采用数组而采用链表呢?这里是因为其要维护一个动态的临时block组,当block数量过多的时候要从低块号删除block,数组删除后不好填补空间。
**************************************************/
通信方式:
客户端通过endorser grpc访问endorser peer
客户端通过Broadcast访问orderer
orderer通过Deliver访问commuter peer
ordererManager:多链管理员
所有由客户端发起创建的chainID,ordererManager负责管理所有有关chainID的操作。GetChain(),newChain(),以及生成该chain的策略方案,Chain相应的数据库操作等
PS:ProposeChain的函数配置创建前先提交了kafka,这里思考可能是因为其他命令都是先交给kafka后直接存储,而配置文件的提交orderer必须在本地操作,先要生成对象,这里目的性还不清晰。
/****************************************************
ordererManager工程描述(可跳过):
ordererManager数据结构{
chains map key:chainID value:chainSupport
ledger:数据库访问句柄
consenter:solo/kafka 操作句柄
}
ledger consenter 好理解,chainSupport主要是生成策略方案/配置管理/过滤器管理/kafka通信/签名及认证/数据库操作(policyManager/sharedconfigManager/ledgerManager)
****************************************************/
过滤器Filter:
过滤器在orderer模块创建chainID时配置的Filter,过滤器包括判断batch大小是否在规定范围内/policy检测/config检测是否通过等。过滤器都在什么地方使用?solo是在生成block前进行检测,例如如果该tx是配置,则在进行config检测时发现没有该配置,也就是说这是一条创建ChainID的操作,则调用ordererManager来创建chainID
创建channel流程:
由于合约要依附chainID,chainID要依附channel,创建channel是首先要做的。
1)客户端发起create channel操作,客户端封装自己的Item,例如:本地证书/策略项。个人看的版本还没有支持外接参数导入(以后可能会支持自定义配置),消息封装签名。
2)将消息通过broadcast发送给orderer节点,本地创建Deliver client连接到orderer
3)orderer节点消息解析出chainID,ordererManager检测是否存在该chainID发现不存在后,检测提交的是否是chainID配置项,检测配置项是否满足规则,交给kafka。
4)kafka消费者将该tx信息使用过滤器进行过滤,过滤器发现这是chainID配置项,则交给ordererManager进行创建配置操作,然后将信息存储到orderer本地块里
5)块存储过程中利用通道将block信息通过Deliver发送给客户端
所以chainID的第一个块一定是配置块,但最终配置块不一定是第一块,当发起config更新时第一块不再具有意义。
join channel流程:
客户端建立channel后,其他peer节点如果对该chainID关心,则可以订阅该channel
假设peer0对某chainID关心
1)客户端封装报文结构,包括:需要访问的chaincodeName:cscc 访问的方法:JoinChaincode chainID配置块内容:first block
2)客户端创建endorser client 链接peer0 endorser服务
3)peer0检测消息真实性以及判断访问的chaincodeID是否是系统chaincode
4)将报文数据传递给cscc,cscc在本地创建first block保存chainID配置块,同时与orderer建立Deliver通信。
5)peer0返回status信息
6)客户端检测status
这里peer0的作用是希望做commit peer,结果其还是需要endorser的功能,这种情况下没有做到节点分开。
(kafka集群是否与orderer节点分离,目前看还是在一起的)
deploy流程:
1)客户端封装报文结构,包括:需要访问的chaincodeName:lccc 访问的方法:deploy 签名:xxx
2)客户端创建endorser client 链接peer0 endorser服务
3)peer0检测消息真实性后发送lccc,执行部署操作,返回数据
4)peer0将lccc返回数据,送入escc进行签名,将签名结果返回客户端
5)客户端验证返回数据真实性后,签名通过broadcast发送给orderer。
策略机制分类:
orderer接受消息的策略机制
orderer建立chainID的策略机制
chaincode执行的策略机制
chaincode部署的策略机制
这几个策略机制个人理解实现还不完全,目前情况是只支持Sign一中策略,也就是通过签名个数来执行策略,而且一直在改动,个人分析的版本还不支持-p 来指定chaincode策略,fabric也在持续更新,下面是未来得及整理的某一个版本的策略部分,选看:
chain的创建 join 以及后续的应用部署/调用/查询,都是在这个chain上,chain所应用的策略很重要。
明确:这些管理都是在orderer上做的
1.configManager如何管理配置?
configManager时policyManager sharedManager的汇总,负责对policyManager sharedManager的消息录入/分析/整理。有个policyProviderMap的key value key是各种策略类型(签名策略/配置策略/order item策略),value是一个PolicyProvider对象,例如签名策略的value是具有getPolicy与验证是否符合policy的能力的对象。
2.policyManager如何管理?
multiledger创建policyManager结构体:
policyManagerImpl{
providers 负责newPolicy
policies 负责记录各种策略,并提供验证策略的方法(Evaluate)
}
创建configHandlerMap的map,key:configuration_policy value:policyManagerImpl
调用policyManagerImpl的beginHandlers方法 processConfig方法 commitHandlers方法
实际程序处理的时候是对configManager整体解析config,内部调用各自configtype的beginHandlers等interface方法,这里为了清晰,单独提取policyManager。
首先检测配置编号是否正确,检测新的策略是否满足旧的策略限制,满足旧的策略就更新
举例:chain:test_id
mini——config:
Item1:
{
type: configItem_orderer
key: consensusType
value:solo
}
Item2:
{
type:configItem_orderer
key: batchSizeKey
Value: {maxMessagecount, AbsoluteMaxBytes, PreferredMaxBytes}
}
Item3:
{
type:configItem_orderer
key:BatchTimeoutKey
value:{timeout}
}
Item4:
{
type:configItem_orderer
key:IngressPolicyNamesKey
value:AcceptAllPolicyKey
}
Item5:
{
type:configItem_orderer
key:EgressPolicyNamesKey
value:AccessAllPolicyKey
}
Item6:
{
type:configItem_Policy
key:NewConfigurationItemPolicyKey
value:Policy{
type:Policy_signature
Policy:RejectAllPolicy{
version:0
Identities:nil
Policy{
SignturePolicy{
Noutof(N=1,SignPolicy{nil})
}
}
}
}
}
Item6代表从nil个policy条件中满足1个,则验证通过,由于sign policy=nil,所以一定是拒绝的,RejectAllPolicy
Item7:
{
type:configItem_Policy
key: AcceptAllPolicyKey
Policy:同上,刚好相反N=0
}
System-config:
Item1:
{
type:config_orderer
key:chainCreationPolicyNamesKey
Value:DefaultChainCreationPolicyNames
}
Item2:
{
type:config_orderer
key:KafkaBrokerkey
value:一个代理的IP地址Brokers
}
上述创建了一个配置,该配置是block0,应用到chainid=test_id上
根据配置创建该chainID的policyManager sharedConfigManager
policyProviderMap[Policy_signature] = NewPolicyProvider
policyProviderMap[config_policy] = policyManager
policyProviderMap[config_orderer] = sharedConfigManager
调用interface Handler BeginConfig() RollbackConfig() CommitConfig() ProposeConfig()将配置项解析
解析是否存在oldconfig,如果存在检查ModificationPolicy,调用其Evaluate判断可否update策略,这个ModificationPolicy如果未定义,则采用key:NewConfigurationItemPolicyKey,如果注意发现,该配置一旦解析完成存储,下次则不可以更改这个配置,因为我们配置的是Policy:RejectAllPolicy
其中NewPolicy函数返回的是一个函数,evaluation函数。
分析evaluation这个函数指针:
SignaturePolicy分成from/signed by,两部分。from负责统计满足多少policy可以算通过,signed by是用来计算签名的,可以指定签名人来验证数据。其结构可以递归
from signby
signby
signby
from signby
singby
singly
目前应该只支持签名策略。
策略管理在何处使用?
更新config的时候
invoke/query的时候
sharedconfig:所有itemtype=orderer配置内容在这
问题:这种多少人签名通过的Policy外界如何配置
创建一个新的chain,以上内容策略是如何定义的??????????
peer节点
Item1:
{
type:“ConfigurationItemMSP”
key: mapKey
value: 各种证书
}
Item2:
{
type:ConfigurationItem_peer
key:AnchorPeerConfItemKey
value:ip:port
}
Item3:
{
type:configuration_orderer
Key:creationPolicyKey
value:{
AcceptAllPolicy
Hash(allItem)
}
}
广播到orderer后,交给multimanager管理调用ProposeChain(),orderer检测了Key:creationPolicyKey是否是系统中已经配置的支持的创建chain方式,目前只是支持AcceptAllPolicy,在orderer处理创建channel的时候都是找sqschain来处理的。那几个manager例如:policyManager sharedConfigManager,这里policyManager未执行策略