Fabric 和 Sawtooth 技术分析(下)

Posted earvin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Fabric 和 Sawtooth 技术分析(下)相关的知识,希望对你有一定的参考价值。

http://blog.talkingdata.com/?p=6172

在前一篇文章(Fabric和Sawtooth技术分析(上))中,我们着重跟大家分享了 Fabric 相关的内容,在本篇文章中,我们将围绕着 Sawtooth 进行一些分析和探讨。

 

Sawtooth 结构及分析Sawtooth 是 Intel 公司推出的企业级区块链,2018年 Intel 将其贡献给 Hypherlegder 项目。本文中笔者主要从 Sawtooth 的存储结构、数据结构、网络结构方面做简要介绍。

Sawtooth

技术图片

Sawtooth 的存储结构

Sawtooth 使用名为 Radix Merkle Tree 的存储结构,它融合了 Radix Tree 和 Merkle Hash Tree 的功能,先看看这两种结构:

  • Radix Tree

Radix Tree 概念比较拗口,简单地说就记住在这个树上,任何一个叶子节点的位置和一个 01 串唯一对应,因此我们可以根据一个 01 串组成的地址确定叶节点是谁。

下图是一个 Sawtooth 所使用的 Radix Tree 对应的字符串,由70个16进制字符组成,前6位称为命名空间前缀(Namespace prefix),后边的是该前缀所对应的空间内可分配的地址范围。

技术图片

我们以 Sawtooth 预定义的一个 Transaction Family-IntegerKey 为例,注意 Sawtooth中 的 Transaction Family 相当于 Fabric 中的 chaincode 或者 Ethereum 中的 Smart Contract 。IntegerKey 的前缀(prefix)计算法方法是:hashlib.sha512(‘intkey’.encode(‘utf-8’)).hexdigest()[0:6],运算结果是 ‘1cf126’。那么,存储该 transaction family 中一个 block 的地址就是:

address = “1cf126” + hashlib.sha512(‘name’.encode(‘utf-8’)).hexdigest()[-64:]

当然,地址的构成也可以更复杂一些,比如,有个自定义 Transaction Family 的前缀是 prefix = “my-transaction-family-namespace-example”。命名空间可以进一步划分为 object-type 和 unique-object-identifier 。其中,object-type = “widget-type”,unique-object-identifier = ”unique-widget-identifier”。那么,对应的字符串就可以计算如下:

hashlib.sha256(“my-transaction-family-namespace-example”.encode(‘utf-8’)).hexdigest()[:6] + hashlib.sha256(“widget-type”.encode(‘utf-8’)).hexdigest()[:4]

+ hashlib.sha256(“unique-widget-identifier”.encode(‘utf-8’)).hexdigest()[:60]

最后得到下面的地址:

‘4ae1df0ad3ac05fdc7342c50d909d2331e296badb661416896f727131207db276a908e’

众所周知,2的10次方是1K,20次方是1M,30次方是1G,40次方是1T,对于一个名字空间,Sawtooth 为其保留64位,从存储空间需求上讲,即使有一些位被用来做子空间划分,应该也够用了。在查找时,完全可以根据 Transaction 的名字找到它的存储位置,所以检索速度也会非常快。

我们可以认为,Sawtooth 就像一个原始的区块链,每向后一层都可以分叉,以树的形式组织数据存储,而不再是以线性的方式来组织数据存储。也可以把原始的比特币区块链理解为只有一个Transaction Family 的 Sawtooth。在完整的分析过 Sawtooth 以后,最应该记住的就是 Sawtooth 的存储结构,它其后的所有设计都是基于这一结构。

  • Merkle Hash Tree

Merkle Hash Tree 的特点是所有节点的值都是哈希值,每个哈希值是根据其子节点的哈希值计算出来的,所以任何一个节点和哈希值出现变化,它的上层节点的哈希值都会跟着变。

技术图片

Sawtooth 采用 Radix Merkle Tree 结构做数据存储的好处就是给定 Block 名及类别,直接计算哈希值,就找到它的存储位置了。而且存储空间是隔离的,每个 transaction family 的存储空间和其它的都是分开的,互不影响。所以,从存储结构来看,基于 Sawtooth 的区块链天生是多条连的(Forked),很容易去解析它的分叉。

Sawtooth 的数据结构

Fabric 没有去严格定义数据结构,Sawtooth 的数据结构也没有什么值得特别提出的亮点。只要知道 Sawtooth 定义了 Transaction 包括Header 和 Payload 两部分即可,而 Sawtooth 要求不管是一个还是多个 Transaction 必须被封装在 Batch 中才可以提交给 Transactio n的 Processor ,或者说 Transaction Processor 只接受以 Batch 为最小单位的 Transactions 。同样地,Batch 也包括 Header 和 Payload 两部分,其关系如下图所示:

技术图片

Sawtooth 的网络结构

如下图所示,Sawtooth 的一个节点可能由如下几个部件组成:Validator、Transaction Proc essor、REST API、以及 Client。Validator 是 Sawtooth 的核心部件,主要功能包括接收 Transaction 请求,并将其转发给相应的 Transaction Processor 来处理,根据 Transaction Processor 的处理结果,决定如何生存新的区块,如何给 Client 回显。Validator 还要与其他的 Validator 协同,以保持 Sawtooth 网络的全局状态一致。Transaction Processor 顾名思义就是用来专门处理某一类型 Transaction Family 的 Transactions 的 Processor 。

Client 需要按照 Transaction 和 Batch 规定的数据结构生成请求,REST API 则是标准化的网络传输数据格式。之所以说可能由这几部分组成,是因为对 Sawtooth 来说,只有 Validator 属于其固定结构,比如图中有 Validator1 和 Validator2 ,而 Validator2 就没有连接其他部件,而是只与 Validator1 相连。从构成角度看,一个 Sawtooth 网络可以只由一个 Validator 构成。从网络方面看,其他的 Validator 可以动态加入网络。从部件方面看,Transaction Processor 可以动态注册到 Validator ,然后 Client 提交相应 Transaction 就有对应的 Processor 来进行处理。网络节点和部件可以分别使用不同的端口来区分。这样,Sawtooth 网络就变成完全动态的了,每个组成部分都可以动态插拔。

技术图片

接下来,我们先看看 Validator 的组成结构,Validator 的软件实现部分称为 Journal,如下图。从功能上看,Journal 包括 Completer、ChainController 和 BlockPublisher 三个主要部分。

技术图片

当 Batch 被提交给 Validator 后,先被交付到 Completer ,它先检查是否 Batch 的所有依赖项都得到了满足。完整且满足依赖的 Batch 会被提交给 ChainController 。Sawtooth 的这种设计可以支持串行和并行的 Batch,注意这已经不是进程级并行了,而是线程级并行。接下来再看看 ChainController 是干什么的:

技术图片

ChainController 需要完成4个工作:

  • 1)确定块的头在哪
  • 2)确定当前块在哪-先去 BlockCache 里找,再去 BlockStore 里找。
  • 3)验证块有没有损坏
  • 4)把新块写进区块链

写入新区块链后的发布工作则是由 BlockPublisher 完成。从图中可以看到,ChainController 和 BlockPublisher 本质上都是接口,具体的实现由更下层的共识(Consensus)机制完成,共识机制向上提供 BlockVerifier,ForkResolver 和 BlockPublisher 三个功能。

从整体上看,Validator 的结构比较简单。接下来再看看 Validator 之间是怎么连接起来的。Sawtooth 的 Validator 的网络连接方式如下图,可能会有点乱,同时解释地也不是很清楚,这里笔者的理解是:把它看做一个 Ad Hoc 网络,组网的过程完全就是模拟 Ad Hoc 网络路由节点发现的。开始的时候有初始(生成 Genesis block 的)节点,它可以发出广播包,问谁在它边上,可以按照设定的规则加入网络,如果有人应答就可以加入,然后这些节点继续广播,每个广播包只传播给距离自己1跳的 Validator 节点,这样网络很快就组成了。有新节点想加入也是这样,发广播包,看看自己周围有没有可以直连的节点,退出就无所谓了,反正少一个节点不影响网络。我们知道 Ad Hoc 网络的健壮性和灵活性都是非常高的,所以 Sawtooth 的 Validator 网络中任何节点都是可以动态加入或退出的,只要网络规模足够大,理论上,网络的健壮性是有保障的。

技术图片

这里有两个关键问题其实没有说清。

  • 1)哪些 Validator 可以加入该网络
  • 2)Validator 接受哪些 client 提交的 Batch

这两个问题就构成了访问控制和隐私保护功能的核心,而 Fabric 花大力气实现的体系结构也正是为了回答这两个问题,稍后会详细说明,核心网络介绍完毕以后,会想到 Client 提交了 Transaction,那Transaction 执行与否?所以,还差一个事件机制来实现消息传递和回显功能。这里的事件机制要确定这么几件事:

  • 1)谁应该被告知事件—(广播?还是根据注册情况组播单播)
  • 2)事件应该包括什么—(消息格式-收据(Transaction Receipt))
  • 3)事件在什么情况下,或什么时候才算有效—(放在 Transaction Receipt Store 中,通知发起 Transaction 的 client 来拿)

下图是 Sawtooth 的事件机制示意图,它把技术实现和组件名称混到一起,看起来也比较乱。大体的意思是左上部是事件子系统用 Zero message queue 的技术实现,其特点是在需要的时候可以随时创建,右上部是写好的类库,注册后,只要满足约束就可以调用它。下部说的是 Transaction Processor 调用具体的 Handler 处理 Transaction 后会告诉 ChainController 的 Scheduler 和 Executor 执行 Transaction 的结果情况,ChainController 除了把新的 block 写到它应该在的地方之外,还会把 Transaction 的 Receipt 放到一个叫 Transaction Receipt Store 的地方,这时候 ChainObserver (Client 注册后产生的一个部件)就会告诉 Client, Transaction 执行完了,来拿收据吧。

技术图片

下面是一些事件的例子,可以帮助我们理解事件的格式:

 1Example events generated by BlockEventExtractor:
 2Event {
 3  event_type = "sawtooth/block-commit",
 4  attributes = [
 5    Attribute { key = "block_id", value = "abc...123" },
 6    Attribute { key = "block_num", value = "523" },
 7    Attribute { key = "state_root_hash", value = "def...456" },
 8    Attribute { key = "previous_block_id", value = "acf...146" },
 9  ],
10}
11
12
13Example events generated by ReceiptEventExtractor:
14// Example transaction family specific event
15Event {
16  event_type = "xo/create",
17  attributes = [Attribute { key = "game_name", value = "game0" }],
18}
19
20// Example sawtooth/block-commit event
21Event {
22  event_type = "sawtooth/state-delta",
23  attributes = [Attribute { key = "address", value = "abc...def" }],
24  event_data = <bytes>
25}

Sawtooth的访问权限控制

Sawtooth 的权限(Permissions)机制应该参考过 Fabric。主要功能包括网络权限的设置(哪些 Validator 可以加入这个网络),和 Transaction 权限设置(哪些 client 提交的 Batch 可以被 Validator 执行)两种。和 Fabric 一样的是,Sawtooth 也需要配置文件,如果所有功能全部用配置文件完成则称为 Off-Chain transactor  Permission,通常来说小规模网络,极限情况下,只有一个节点的网络完全可以使用 Off-Chain 的方式实现。在 Off-Chain Permission 中,权限是静态设置的。在配置文件 validator.toml 中,直接配置:

[permissions]

ROLE = POLICY_NAME

Policy file:

PERMIT_KEY <key>

DENY_KEY <key>

这里的 ROLE,POLICY_NAME 暂不解释,key 一般是一个公钥,PERMIT_KEY 和 DENY_KEY 就将它理解为一个 bool 值,一个是1,一个是0,含义就是允许不允许。

和 Fabric 不一样的地方是,Sawtooth 还有一种配置方式叫 On-Chain transactor Permission 。就是在区块链上直接设置访问权限,还专门为此设置了一个叫 Identity 的 Transaction Family 。这样 transactor Permission 就有自己的存储空间,其当前值也好,变化也罢,所有节点都可以同步过去,不会存在各个节点配置文件不一样导致系统出错的可能性。

接下来具体看下 Identity。Identity Namespace 以 key-value 对的形式存储 roles,key 是 role name,value 是 policy。所有的 role 都以 transactor 为前缀。比如下面:

transactor.SUB_ROLE = POLICY_NAME

首先,第一个问题是开始谁可以设置访问权限。和 Fabric 例子中类似,机构 R4 通过网络配置文件设置访问权限一样。在 Sawtooth 中,理所当然的应该由创始区块的生成者来设置初始权限。它执行如下命令来设定允许给别人授权的人的公钥:

sawset proposal create sawtooth.identity.allowed_keys=00000

这里的00000是创始区块的生成者自己的公钥,那现在就它自己可以给别人授权。这个类似于 Fabric 里设定,公钥设定以后可以利用 identity-tp 进行授权,也可以继续用 sawset proposal create 命令让其他 Validator 有权做网络或者 Transaction 授权。proposal 这个子命令其实就能猜到 Sawtooth 设计访问权限的时候肯定是参考了 Fabric 的。

具体的 Transaction 授权命令的例子如下:

sawtooth identity policy create policy_1 “PERMIT_KEY *”,这个的意思是创建一个叫 policy_1 的策略,对所有人都是允许的,也就是谁都可以提交 Transaction ,注意这仅仅是个策略,还可以定义其他的策略,相当于 Fabric 里的 Deploy 而不是 Invoke 。可以调用 sawtooth identity policy list,查询当前有哪些策略,比如在执行了刚才的命令后,会得到如下回显:

$ sawtooth identity policy list

policy_1:

Entries:

PERMIT_KEY *

接下来执行如下命令:

$ sawtooth identity role create transactor policy_1

就会把 transactor 的策略设置为 policy_1。换句话说,这时,就真正让 policy_1 生效了,类似于 Fabric 里的 Invoke。然后可以调用sawtooth identity role list,查询当前角色的状态:

$ sawtooth identity role list

transactor: policy_1

上边我们都用 transactor 为例子,其实 role 可以有如下几种:

default、transactor、transactor.transaction_signer、transactor.transaction_signer.{tp_name}、transactor.batch_signer。

意思其实从字面上能看出来,这里 transactor 可以是 organization,一个 transactor.batch_signer 可以是一个 organization 下边的部门,transactor.transaction_signer 可以是该部门的一个用户,如果有好多 tp 的话,该用户可以只具有其中某些 tp 的执行权限。

比如,我们现在自己写了一个新的 tp 叫 supply_chain,新定义了两个用户,一个的公钥是12345,另一个的公钥是23456,我们希望这个 tp 只有这两个新用户可以运行,这时我们就可以执行命令:

sawtooth identity policy create policy_2 “PERMIT_KEY 12345” “PERMIT_KEY 23456”

sawtooth identity role create transactor.transaction_signer.supply_chain policy_2

网络权限设置和 tp 执行权限设置差不多,比如有个 Validator 对外的公钥是00001,然后执行如下命令,它就不能加入网络了:

$sawtooth identity policy create policy_3 “DENY_KEY 00001”

$ sawtooth identity role create network policy_3

$ sawtooth identity role list

network: policy_3

Fabric 和 Sawtooth 的比较

相信看完了 Fabric 和 Sawtooth 的介绍,大家对这两个项目都有了自己的认识。笔者再谈一下个人对这两个项目的理解。

首先,从背景上看,Fabric 是脱胎于 Ethereum 的,或者说能在 Fabric 上看到 Ethereum 的影子,而 Sawtooth 已经看不到 Ethereum 的任何痕迹了。反而,个人觉得 Sawtooth 更加纯粹一点,它就是一个有共同起点的 比特币区块链,只是比特币没有不同 Transaction 的概念,而 Sawtooth 把 Transaction 按照用途分类,且允许用户根据需要自己定义新的 Transaction (这个概念是 Ethereum 提出来的)。

从体系结构角度看,我认为 Sawtooth 明显优于 Fabric 。Fabric 像是针对特定问题的一个专用解决方案,而不像一个通用架构。Sawtooth 可以认为是一个通用架构,然后根据需求变为一个专用解决方案。从访问控制角度看,Fabric 像是根据实际情况建设了一套管网,让涉及隐私的数据只能在其中运行。Sawtooth 则更像是在一套管网上加装了阀门,通过阀门来控制数据的流向。这可能和 IBM 以及Intel 的业务特点和公司文化息息相关。我的印象中,IBM 是一家咨询公司,专门针对企业级用户设计解决方案。Intel 是处理器公司,不管你的业务是什么样的,它提供通用中央处理器,让你能根据自己的需要配置成自己的专用解决方案。

当然,二者也有一些具体的差异:Fabric 中,多个节点收到相同的输入后分别独立执行,以期得到一致的结果。Sawtooth 的 SGX 和基于 SGX 的 PoET 验证的是在一台机器上的执行结果,没有再让每个节点都去执行一遍,而是一个执行完了以后去和别的同步结果。二者的假设不同,效率上也有差别。Fabric 的权限控制依赖形成 channel 这种体系结构,Sawtooth 的权限控制通过 Transaction 本身进行设置。或者说,Fabric 只有特定的人能看,但能看到特定范围内的全部。Sawtooth 所有人都可以看,但 Transaction 的 Permissions 限制了能看什么。Fabric 的 orderer 完成 Transaction 排序,可以实现进程级并行。Sawtooth 的排序是在 batch 里指明依赖关系,通过Completer 排序实现线程级并行。

对 Fabric 来说,要设计它时,大家认可的网络结构就是 Ethereum 了,怎么能稍作修改,实现隐私保护和访问控制是它的设计目标。Sawtooth 没这种包袱,可以重新设计网络。所以,我感觉 Fabric 更像是一个过渡性的产品。从我的角度看,Sawtooth 的结构设计的比较精巧,可扩展性强,这是它比 Fabric 强的地方。但它还可以借鉴 Fabric,增加类似 CA 的机制确保用户可以被识别,也应该增加权限配置的灵活性,比如引入 ABAC,等等。不过,现在这样就已经非常不错了。

以上是关于Fabric 和 Sawtooth 技术分析(下)的主要内容,如果未能解决你的问题,请参考以下文章

竞品调研 - 腾讯bugly&fabric

特约专栏Hyperledger Fabric 源代码解读系列

HDU5047Sawtooth(java大数)

TOJ 4689: Sawtooth

[Fabric/源码分析] Proposal 消息处理流程(v1.0)

Hyperledger Sawtooth区块链 开发文档