超级账本 HyperLedger 初体验

作者:Yegor Maslov 等

阅读数:2591 2019 年 3 月 18 日

本文要点:

  • 不久前,OpenGift 团队探索了在生产环境中部署基于超级账本(HyperLedger)的区块链。本文呈现了我们集成它的尝试过程和所遇到的问题,以及帮助我们解决问题的技巧。
  • 我们认为,与私有以太坊(Ethereum)网络相比,超级账本 Fabric 可能是基于区块链的业务应用程序更好的选择。
  • 借助超级账本,我们可以构建一个系统,里面的客户不需要信任其他客户,合作者也不需要信任其他合作者(但是,客户必须信任合作者)。
  • 该网络易于扩展,无需父组织也可存在。
  • 超级账本并非没有技术缺陷,因此,要准备编写大量支持脚本以在生产环境中维护超级账本。

不久前,我们团队探索了在生产环境中部署基于超级账本的区块链。本文呈现了我们集成它的尝试过程、所遇到的问题以及有助于解决问题的技巧。超级账本框架中已经引入了一些重要更新,从而克服了一些挑战,但还有一些问题有待解决。

在本文的第一部分,我们将解释为什么决定使用区块链来解决业务问题,以及为什么选择超级账本框架而不是以太坊。本文的第二部分主要介绍基于超级账本的区块链架构,以及该框架的实现技术。

为什么用区块链?

我们最初认为,我们的业务不需要区块链。毕竟,大多数公司通过借助集中设施或仲裁中心来解决信任问题。因此,我们花了很长时间来确定我们具体是否需要区块链解决方案。

我们的平台是一种 Web 资源,公司在这个平台里可以直接和开源团队合作以减少开发时间和维护成本。我们发现,对于一些客户来说,可能难以和开源维护人员和关键合作者建立工作关系。由于项目时间和价格的增加,依靠内部开发人员或自由职业者的服务来微调开源代码的标准做法看起来不是最佳选择。

我们的平台旨在通过提供一个“切入点”和简单界面来解决这种低效率,以便客户请求和共同资助 OSS 中新功能的开发。为了让该系统具有可持续性,我们需要引入一个工具以鼓励开发人员满足客户的需要。经过深思熟虑后,我们提出了“数字所有权”的概念。

这个概念相当简单:在我们平台上注册项目的人会收到数字“股票”,他们可以把这些股票自行转让给其合作贡献者。顾名思义,我们的股票能使拥有者收到与所有权份额成比例的项目收入。在该约束的基础上,我们添加了一个规则,即任何“外部”开发人员都可以创建所请求的功能,并且,如果客户接受该解决方案,那么开发人员将收到该项目一定比例的股票。

我们希望开发人员把我们的项目股票视为有价值的长期资产,这本身就意味着开发人员认为这些股票不会消失。基本上,我们有两个选择:要么直到社区信任我们时,我们才引入该功能;要么我们建立一个无信任系统。后者需要构建一个这样的平台,即使父组织退出该业务,资产也不会受到影响。

我们还计划把平台和很多合作组织集成在一起,将开发任务外包给我们平台,并在任务完成时自动收取费用。在理想情况下,我们将只为组织提供一个接入点以通过某些简单注册流程(如 API 集成)进入我们的网络。我们的目标是让这个过程尽可能简单,以避开所有法律合规和文书。经过了一番疑惑后,我们认为区块链能够帮助我们实现这个愿景。

以太坊与超级账本之比较

以太坊是我们的首选,尽管我们对此平台没有丰富的经验。我们没有详细研究文档,直接就上手集成了。乍一看,这似乎是个简单的选择。我们选择一试是出于以下几个因素:

  • 它相当成熟
  • 它稳定
  • 它易于集成
  • 它易于开发
  • 它有很大的社区
  • 它一直在迅速发展
  • 它被大量项目采用
  • 它让我们有机会在我们的私有网络中进行私有化部署

而反过来,有一些因素最终让我们打消了之前的念头,以太坊未必是最合适我们的选择:

  • 共识算法的不确定性。
  • 工作证明的不可预测性。
  • 不存在角色
  • 访问网络的不可控性。
  • 交易费用和甚至在睡眠模式中的高 CPU 工作负载(次要)。

其中一些问题在以太坊世界的开发中有缓解的潜在可能性。例如,GHOST 协议修改也许有所帮助,但是,即使在这种情况下,当我们的大量交易正在前往目的地的同时,如果主池的所有者突然决定其支链要比我们的长…那么,如果交易是通过公共(或共享使用)以太坊网络进行的,取消支付交易可能会让我们大吃一惊。

在极端情况下,我们甚至可能有这么一位合作者,其节点容量允许他们来破坏整个网络,那么用区块链就没有意义了。

对我们来说,了解一个网络成员是客户还是合作者也很重要。我们必须确认这一点。以太坊网络不支持这个功能,因此,我们就需要在顶部构建这个功能。我们当然可以把我们的 VPN 集成到区块链。但是,如果我们给合作者提供访问权限,那么自然应该有方法来开通这样的访问。同时,我们希望控制谁能进入我们网络和他们可以从中获取到什么。

关键是要记住,在业务用例中,企业节点的容量也许比私有节点的明显有优势。这就是为什么我们选择私有区块链,使用超级账本框架。

超级账本还给我们提供比以太坊更大的方便,以让我们观察交易成本和 CPU 使用情况。

目前,超级账本 Fabric 是最先进和最成熟的框架之一。它还有一些功能让它变得与众不同。经过许可的体系结构确保在有人访问我们的区块链时,我们会知道他们是否拥有由证书颁发机构(Certificate Authority,简称 CA)颁发的证书。我们还喜欢它的确定性 PBFT 算法,它让我们能百分百地确信,一旦我们收到这样的通知,交易就已经完成。在 docker 容器上进行测试也很简单。

我们试图搞明白我们是否需要拜占庭容错。我们是否真的信任我们的合作者,他们是否真的信任我们?我们自己是否能承受得住拜占庭将军问题,知道在任何时刻任何节点都可以开始发送不正确的数据给网络?我们最终决定,我们应该有这样的保护措施,而用超级账本能使它变得相当简单。

但是我们仍不确定,所以我们在私有网络中进行了一些测试来比较超级账本 Fabric 和以太坊。我们编写了一个简单的合同,先生成了一个长数组,然后对其排序。结果如下所示。我们添加了 2 行(分别由 1 百万和 1 千万元素)到图中,只是为了显示超级账本也在这里。事实上,差异还是很大的,有些线条实际上都看不到。

Y 轴:毫秒

Y 轴:MB(兆字节)

现在,我们来看看达成共识所需的时间。我们采用了一个简单的空交易,把它放入由 8 台机器组成的集群中。这些机器必须达成一个协议并返回确认信息:我们等待以太坊私有网络中的 6 个确认信息,以及来自超级账本网络中每个节点的确认信息。在超级账本集群中,速度还是更快些。

Y 轴:秒

有一点应该注意到,我们是在超级账本 Fabric 框架 0.6 版本上进行的测试;如今,最新的版本是 1.2.0,其有一个单独节点负责维护交易顺序。当时,如果我们把节点数增加到 16,并把速度提高到每秒 500 个交易,那么网络就不能工作了。以这样的速度,网络在收到新的交易请求前是无法达成共识的。

超级账本架构

在我们继续介绍之前,我们来看看超级账本区块链的基本架构。

对等节点(Peer):主节点,其存储所有交易的信息(在 1.0 版本中,其被分为背书节点(Endorser)和提交节点(Committer),分别用于确认交易和记录交易到注册表中。)

应用程序(App):启动交易的客户端,可以在超级账本 SDK 上替换成其自己的应用程序

CA:给用户提供证书,允许他们进行交易并从注册表读取数据

排序节点(Orderer):管理区块中的交易并把区块传递给节点以记录在账本中

超级账本可以按角色区分节点。尤其是,有个存储注册表的对等节点。在 1.2 版本中,有几个对等节点的子类型,但是,通常来说,对等节点负责存储注册信息并验证传入的交易。它们存储所有的智能合约和链代码,批准传入的交易并把它们保存在注册表中。

我们构建的应用程序位于前端。它可以把交易信息发送到区块链,并且它可以用成员证书登录区块链。它还负责达成共识。

CA 颁发证书。默认情况下,超级账本可以通过组织属性来区分节点;每个组织有自身的根证书。凭借成员证书,我们可以分配在完成智能合约的权限、改变网络配置的权限和添加新对等节点的权限,基本上我们想要的权限都有。在最新的框架版本中,我们还可以给证书添加任何我们喜欢的属性,因此,我们在给系统参与者提供不同权限集时更具灵活性。

排序服务或“排序节点”是区块中一系列负责交易排序的节点。这些排序节点把交易信息收集到一个区块中,并把该区块发送到对等节点,以便它们将其提交到注册表。它不存储智能合约,但以二进制文件形式存储账本数据,该二进制文件用于引导一个新对等节点。丢失该文件意味着丢失所有区块链数据。排序节点也进行一些验证工作:检查哈希和签名。

例如,我们的系统由以下元素构成:

  • 一个 Web 应用程序,
  • 一个对等节点,
  • 一个 OpenGift 组织,
  • 该组织的根 CA,
  • 一个中间 CA,其设计理念是扩展系统;
  • 一组在 Apache Kafka 上的排序节点,供所有合作者的对等节点引用

目前,我们的区块链部署在四个真实的对等节点上,我们在 Kafka 上有 4 个排序节点。最终我们需要 5 个,因为如果在这个模式下使用排序服务,建议使用奇数个节点。我们大约有 100 个客户端应用程序、1 个根 CA 和 1 个中间 CA。在我们工作最开始的几个月里,我们进行了 1000 多个交易,但我们的系统允许我们在一秒钟内处理同样数量的交易。

合作者有他们自己的对等节点,因此,他们可以存储注册并验证交易,并且,客户可以引用任何他们喜欢的对等节点和区块链进行交互。

客户端应用程序通过提供证书登录到区块链,证书是由区块链信任的证书颁发机构中间服务器颁发的,比如,“组织 1”。CA 中间服务器由 CA 根服务器授权,CA 根服务器不受区块链网络的限制。然后,客户端应用程序可以在可用策略的框架内与对等节点进行交互,并遵守限制和许可。一旦任何对等节点确认由应用程序提交的交易,如果它使用任何共识算法,那么就把交易发送到排序节点。排序节点把这些交易提交给对等节点。接着,应用程序可以等待来自对等节点的任何数量的确认来确保交易记录到账本中。

在生产环境中实施超级账本 Fabric 是怎样的感觉?

也许我们首先注意到的是缺少管理面板。如果没有 Kubernetes 或 Swarm,那么,我们很难在生产模式下维护它,因此,我们必须编写大量支持脚本。希望Cello 项目能够让这种情况变得更好。

在尝试实现该架构时,我们面临着一些技术挑战。首先,排序节点服务可以在两种模式下运行,分别是单一模式(solo mode)和 Apache Kafka 模式。如果我们使用单一模式,就无法在没有重构整个网络的情况下切换到可扩展模式。

其次,如果我们在 Kafka 上使用排序节点服务,那么,我们就不可以把它扩展到其他组织。如果其他组织已经有自己的排序节点服务,那么我们就需要在谁将负责管理区块中的交易这个问题上达成协议。这意味着,只有一个组织可以负责区块中交易的顺序,这将导致一些漏洞。但是,总的来说,如果交易是有效的,那么它们在区块中的顺序就不是那么重要。如果有人改变了交易的顺序,并且它们变得无效的话,那么可以简单地在区块中把它们标记为无效,而我们的请求将返回“失败”。

CA(证书颁发机构)很容易扩展。每个组织有一个根 CA,并且它可以颁发任何数量的证书给中间 CA。这个非常好,因为 CA 负责添加新用户到网络。但是,该证书撤销模式还不够完备。首先,为了请求多个参与方签署撤销证书,我们需要编写额外的链代码。其次,甚至在我们添加撤销证书的信息到区块链时,该证书的前拥有者仍然可以连接到对等节点。我们必须手动生成证书,并将其添加到对等节点和排序文件夹中。在去中心化的结构中控制这类流程很有挑战性。

我们还需要记住,所有对注册表的查询将返回网络先前的状态(即注册表具有事务化,也即版本的语义),直到排序节点已经创建好新的区块。这意味着,如果我们有个业务流程,其中包含多个读取查询和紧接着它们的一个写入查询,并要考虑读取查询的结果,那么,我们最好让它们异步。因为在这种情况下,我们读取注册表的期望会和其实际状态不一致。通常,我们需要等待排序节点形成一个区块,并把它发送到账本;只有在此之后,假设状态已经改完,我们才可以发送读取查询。

由于这些区块不是根据 POW 协议创建的,因此我们可以为排序服务设置任何块创建频率。在单一模式中,我们每秒最多创建一个区块,但在 Apache Kafka 模式中,我们可以灵活地配置该参数。但请记住,如果我们减少创建新区块的等待时间,那么,我们的网络规模将飞快地变大。磁盘空间也将飞快地消耗,因此,我们总是需要在交易确认速度和容量之间取得平衡。

共识机制在交易级别实现,因此,我们可以指定交易需要遵循的要求才能在智能合约中有效。比如,当我们在链代码中引入一个新的智能合约时,我们可以设置它的确认程序,并设定需要多少个参与者签署交易以使其保持有效。

智能合约可以用几种语言来编写,Golang 和 Java 是主选。典型的智能合约有最简单的结构。智能合约中只需要使用两种简单的方法:其中之一是在设置新的链代码或升级(init)时调用,另一个是当调用它时(invoke)。配置不同的策略来初始化新的智能合约并调用它。一组用户可以负责更新智能合约,另一组可以负责其实施。这里,我们考虑最简单的函数调用,其用一个函数及其参数做为输入参数,并根据函数名称调用所需的方法。

复制代码
func (t *SimpleChaincode) add(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var cs clientState;
clienState.Name = args[0]
clientState.Balance = 0
strState, er := json.Marshal(clientState)
err = stub.PutState(pName, []byte(strState))
if err ~= nil {
return shim.Error("Failed to add Client state")
}
return shim.Success([]byte(“OK”))
}

在超级账本中存储数据可以视为键值映射,称为 KV 存储。用 KV 存储来工作是相当低级的。用 PutState() 方法,我们可以在 KV 存储中编程,并用 GetState() 从中读取。但最有趣的是,我们可以使用证书属性处理智能合约。在下面的例子中,我们可以看到授权用户的公钥哈希是如何被用作其钱包的标识的。在第 395 行,我们获得一个哈希,并把它用作 KV 存储的密钥。

复制代码
func (t *SimpleChaincode) add(stub shim.ChaincodeStubInterface, args []string) pb.Response {
pk, err := cid.GetX509CertificatePublicKey(stub)
var cs clientState;
clienState.Name = args[0]
clientState.Balance = 0
strState, er := json.Marshal(clientState)
err = stub.PutState(pName, []byte(strState))
if err ~= nil {
return shim.Error("Failed to add Client state")
}
return shim.Success([]byte(pk))
}
func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
pk, err := cid.GetX509CertificatePublicKey(stub)
strState, err :- stub.GetState(pk)
if strState == nil {
return shim.Error("Client not found")
}
var cs clientState
err = json.Unmarshal(Avalbytes, &cs)
return shim.Success([]byte(cs.Balance))
}

虽然,我们还在用该框架的 0.6 版本,但是更新的版本包含一些重大改进,我们必须提一下:

  • 在更旧的版本中,我们需要重建所有的区块链以在创世块中包含一个新组织。现在,这变得相当简单,并且,我们还可以改变每个组织使用区块链的策略。
  • 从 1.2 版本开始,该系统让自己的对等节点动态地计算所请求的信息,并用可消费的方式呈现给 SDK。
  • 外部应用程序可以接收和处理链上的事件信息。该功能在很多情况下也许有帮助,如,用于通知控制组织可疑活动。

超级账本体验概述

从技术角度来看,该系统还在发展过程中(很稳健)。存在一些技术问题,但是,希望社区会找出解决方案。尽管如此,我们认为超级账本对希望在实际业务中实施区块链的公司来说是最好的选择之一。

在业务方面,因为这个框架,我们才成功地实现了预期的数字所有权功能,这有助于我们激励开发团队开展开源项目工作。该网络易于扩展,无需父组织即可存在。如果我们不在了,那么社区同意设立一个新的排序服务、更新频道,就可以继续工作。

根据我们收到的反馈,该功能促进了平台的采用,因为我们的用户不需要信任我们并依赖我们的能力来做业务。我们正积极寻找合作伙伴以移交节点,并计划在 2019 年初进行我们的区块链的首次技术集成。

作者简介

Maslov 是 OpenGift Inc. 的 CEO,OpenGift 是个开源软件货币化平台。他也是 Hive 项目的负责人,该项目赋予组织内代码的重用性。Yegor 在 Web 和移动领域有超过 15 年的软件开发经验,并拥有广泛的技术创业背景。

Erokhin 是一位拥有超过 10 年专业经验的 DevOps 工程师。他曾就职于如下公司:Kaspersky、Sberband Technologies 和 Moscow Stock Exchange。

阅读英文原文:Exploring HyperLedger: Experience in Being a Framework Early Adopter

收藏

评论

微博

发表评论

注册/登录 InfoQ 发表评论

最新评论

_LeoHuang 2019 年 03 月 18 日 08:59 0 回复
solo是开发模式,是根本无法在生产环境下使用的,性能非常差。
没有更多了