Fabric1.0 架构相比0.6更关注于隐私性和系统伸缩性。
交易仅在相关方节点进行传递和处理,chaincode也只在相关方节点上进行部署和调用,每个节点只存放与自己相关的交易和状态,相比于0.6版本架构,所有交易都传播给验证节点,并在验证节点上执行,隐私性得到很大提高。
不同的chaincode可以在不同的相关节点上执行,进而实现了整个系统分区并行执行,相比于0.6架构所有验证节点都执行交易验证,这样可以保证整体系统性能的高伸缩性,满足高吞吐量需求。
那么Fabric1.0在架构上是如何做到的呢?
一、架构概览
Fabric1.0架构将原来作为共识主体的验证节点的职责切分成两部分,背书节点和共识服务。
将 验证和共识角色分离,交易的验证从共识系统中剥离,由背书节点进行交易验证和背书,而分离了验证功能的共识系统变成了纯技术的共识服务,同具体的 chaincode业务执行无关,这样可以把基于整个共识系统(所有验证节点,chaincode,PBFT算法)的安全假设,分解到对若干具体 chaincode的安全假设和对共识技术服务的信任,共识服务只做技术上的全序消息广播组包和送达,无关任何业务交易,这样可按使用场景实现插件式服务 提供,比如集中式,分布式或抗恶意式实现,共识部分成为可替换的技术服务,满足组件插件式设计需求。
不同 chaincode可以指定不交叉的一组背书节点进行交易验证和背书,交易验证可能涉及到chaincode的高负载运算,从共识上分离出来,可使其不在 整个区块链系统的关键路径上,并且可由专门的硬件节点进行chaincode运算,从而提高系统整体的交易并发量。这个思路同以太坊正在着手的横向 sharding扩容(分片共识处理)类似,另一个方式是通过增大block size纵向扩容。这个思路也是R3-Corda设立公证人服务进行共识,而交易在相关方之间进行流转验证类似。
上 图显示了两个不同的chaincode并行进行背书和共识处理的过程。对于chaincode CC1,其应用调用CC1的请求节点进行状态迁移处理①,请求节点执行本地chaincode CC1的调用,将本次请求需要设定的最终状态,执行过程所用到依赖状态都记录下来,形成交易建议,为了区分状态的历史变化,1.0引入了状态版本的概念, 对状态变化的历史进行记录,交易建议中涵盖了本次交易需要修改的状态key值,新的value值,以及变化所依赖的状态key值和当前版本值,交易建议被 发往CC1在部署时指定的一组背书节点列表②,背书节点也执行CC1的方法调用,对交易建议进行验证,看看是否建议的状态修改和状态依赖是否与本背书节点 实际运算的结果一致,如果不一致,可以很容易识别出当前状态版本是否已经过时了,如果一致加上本背书节点签名反馈给请求节点。请求节点会收集这些背书节点 反馈,满足chaincode预先设定的背书策略即认为交易建议获得足额背书,chaincode在部署时会指定背书策略,如7个背书节点中的5个背书节 点给出了背书签名即认为满足背书要求,或者为每个背书节点指定了权重或stake,如果背书签名达到所有权重值的50%以上即认为满足背书要求,形如 PoS,满足了背书策略的交易建议由请求节点发往共识服务节点集群③。共识服务为每个chaincode提供通讯通道,所有提交节点和背书节点都连到这个 通讯通道上,每个节点可以向通道广播消息也可以接收通道发来的其他节点广播的消息,通道的作用就是保证所有的消息全序广播,每个消息被分配唯一的广播序列 号,就如同微信上的聊天群,每个加入群的人都可以在这个群上收发消息,微信通道保证所有发出的消息其他人都可以送达,但是有一个不同就是广播的消息会包括 上一个序号消息的哈希值,这样每个节点就维护了一个完整的全序消息的哈希链,所有在同一个通讯通道上的节点收到消息的一致性,完整性得以保证,任何共识服 务在通讯通道上的消息广播不会重复,不凭空产生,也不会发生跳跃,为了提高通道效率,共识服务会收集一段期间内的消息组成一个报文批次,按批次送达各个订 阅节点④。每个节点在收到共识服务的批次报文后,对批次内的每个全序交易消息进行验证,这时只需进行密码学验证和背书策略验证和状态版本依赖验证,如果验 证通过,这笔交易即为合法交易,节点会依据交易指示执行本地状态的更新。
基于以上架构设计和实现流程,实现了不同chaincode的执行分离,不同的共识通道的分离,交易验证和共识的分离,分离了CPU密集型(交易验证)和 IO密集型(共识服务)节点以便针对性采用专用硬件,最大限度拆解了共识交易达成的耦合度,降低系统串行度提高并行度,提升了系统可用性的同时也同时提高了系统性能,满足系统高伸缩性的设计目标。
再 来看看系统的安全性,区块链系统一个很重要的问题就是防止“双花 Double-Spent”,如果请求节点将背书过的具有相同状态依赖的交易建议提交给共识服务两次,共识服务会分配两个序列号给这两个交易并送达各个节 点,节点进行本地状态版本依赖验证时,先接受的交易由于已经commit,本地状态已经新增了一个版本,后来的相同交易由于依赖了一个过时的版本,不会通 过状态版本依赖验证,而作为非法交易被丢弃。这里我个人觉得需要从系统层面增加一个重放DoS攻击的防范,虽然系统最终是安全的,但是如果共识服务不对这 种重放交易进行拒绝,会降低整个系统的性能,当然许可链的使用场景下这种重发DoS的可能性也极大降低。
隐私性上来 看,不同的chaincode关联主体只知道自己chaincode相关交易和执行交易验证,共识服务只接收相关主体的广播请求和执行对相关主体的消息送 达,节点只记录与其相关的chaincode的状态。另外,chaincode可设定为保密,系统依据部署时设定的保密级别,执行通讯消息加密,使用背书 节点的公钥进行chaincode私钥的分发,背书节点使用chaincode私钥获得实际payload明文进行chaincode的执行和交易验证。
二、数据模型
共 识服务按批次序号送达各个相关节点全序的交易消息,每个节点进行哈希链批次验证,确保本地当前批次为最新,如果不是最新的,向相邻节点请求缺少的批次,这 种从共识服务获得的批次交易消息以批次为单位组成了原始账本(Raw Ledger)哈希链,节点对交易进行背书策略验证和状态版本依赖验证,验证通过的交易为合法交易,节点按照合法交易的指示执行本地状态存储(Key- Value Store,KVS)的更新。
KVS保存了chaincode状态的键值对(Key-Value)映射 关系,比较特殊的是,“值”具有“版本”的概念,具体来讲,Key指向了一组带有版本序号的值。KVS中的状态可以依据不同的chaincode进行分 区,chaincode只能更新属于本chaincode的键值对,但是可以读取其他chaincode的状态(对于属于保密chaincode的值是加 密值,如果节点拥有分发的chaincode私钥即可解密),这可以允许跨chaincode的交易执行。
对状态KVS的更新的历史(即所有合法交易执行更新)会被记录下来,一个批次内所有合法交易都被有序记录在一个block上,以区块链的形式保存成有效账本(Validated Ledger),batchno和blockno一一对应。
对 于原始账本(Raw Ledger)哈希链由于包括非法交易,随着时间推移可以对历史记录进行裁剪以减少数据量,1.0引入基于有效账本的检查点(checkpoint)机 制,节点可每隔设定的区块数向其他节点广播检查点消息,把自己当前有效账本的blockno和blockhash以及自己的签名广播给其他节点,其他节点 将其与自己的有效账本blockno和blockhash进行比对,如果一致,可以回复自己的签名,请求者收集到符合检查点策略的签名后,减掉直到 blockno所有的原始账本batch记录。每个节点可以定义自己的检查点策略,如定义本地策略“只要是A节点的确认即认为符合”,或者全局策略“克服 拜占庭恶意失效的2f个节点确认才认为符合”。
检查点除了可以降低节点数据量存储外,当有新的节点加入到相同的通道时,还可以大量减少其从头开始构建原始账本和有效账本的时间成本。如果新加入的节点的检查点策略同某个节点的检查点策略一致,新节点可直接从那个节点的检查点开始同步后续的原始账本。
小结:
Fabric1.0 架构定位为许可链的实际,将原先验证节点所承担的交易验证和共识算法职责分离到背书节点和共识服务提供者,背书节点只对相关的chaincode进行验证 和背书,共识蜕变成了一种保证交易全局时序的技术服务。不论是隐私上,系统安全上,还是系统整体伸缩性上新的架构都提供了更好的支持。
针 对共识,还想补充一点个人见解,共识机制要达成的从根本上讲就是一种保证所有节点都认可的一致性状态时序,许可链的设计只需满足一致的状态时序即 可,Fabric1.0基于通道对所有交易消息进行排序并全序广播相关节点,R3 Corda则是使用公证人节点对“双方有效共识”交易进行唯一性验证防止双花以确保交易时序,但是公有链则额外需要能促使大家都努力维护这个状态时序的机 制设计,如比特币PoW在100个区块后才得到挖矿奖励,PoS的保证金奖罚机制,并且与此同时,还需存在一个完全随机性的技术设计,以确保任意一个节点 很难连续采到几个区块来控制整个网络,这样像比特币的6个区块确认才有存在价值:-)