区块链高级开发教程(全)

原文:zh.annas-archive.org/md5/64e2728fdd6fa177d97883a45d7dec42

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

区块链技术是一种分布式分类账,应用于金融、政府和媒体等行业。本学习路径是您构建使用以太坊、JavaScript 和 Solidity 构建区块链网络的指南。您将首先了解区块链技术的技术基础,包括分布式系统、密码学以及这个数字分类账如何保证数据安全。随着章节的深入,您将深入了解使用以太坊和 Hyperledger 开发应用程序的见解。随着对以太安全性、挖矿、智能合约和 Solidity 知识的积累,您将学会如何创建确切按程序运行、不受欺诈、审查或第三方干扰影响的健壮且安全的应用程序。在本书的结束章节,您将探讨区块链解决方案如何在 IoT 应用程序等应用中实施,以及它在货币中的应用。本书还将介绍如何增加区块链的可伸缩性,并讨论这项引人入胜且强大的技术的未来前景。通过本学习路径的学习,您将掌握解决区块链生命周期中遇到的问题所需的技能,并自信地设计和部署去中心化应用程序。

此学习路径包含以下 Packt 产品的内容:

适用对象

此学习路径专为想要使用 Hyperledger 从零开始构建去中心化应用程序和智能合约的区块链开发人员设计。对任何编程语言的基本熟悉将有助于开始本课程。

本书内容

第一章《区块链 101》介绍了基于分布式计算的基本概念,这是区块链技术的基础。它还涵盖了区块链的历史、定义、特征、类型和好处,以及构成区块链技术核心的各种共识机制。

第二章《去中心化》介绍了去中心化的概念及其与区块链技术的关系。还介绍了可以用于去中心化进程或系统的各种方法和平台。

第三章《了解以太坊的工作原理》解释了以太坊的工作原理。

第四章《智能合约》深入讨论了智能合约。本章介绍了智能合约的历史、定义、瑞卡迪安合约、Oracle 以及智能合约的理论方面。

第五章,对称密码学,介绍了对称密码学的理论基础,这是理解各种安全服务如保密性和完整性是如何提供的必要基础。

第六章,公钥密码学,介绍了公钥和私钥、数字签名和哈希函数等概念,并提供了实际示例。最后,还包括对金融市场的介绍,因为在金融领域有许多有趣的区块链技术用例。

第七章,开始使用 web3.js,介绍了 web3js 以及如何导入和连接到 geth。它还解释了如何在 Node.js 或客户端 JavaScript 中使用它。

第八章,介绍比特币,涵盖了比特币,第一个也是最大的区块链。它详细介绍了与比特币加密货币相关的技术概念。

第九章,构建钱包服务,解释了如何构建一个用户可以轻松创建和管理以太坊钱包的钱包服务,即使是脱机也可以。我们将专门使用 LightWallet 库来实现这一点。

第十章,替代货币,介绍了比特币发明后引入的替代加密货币。它还介绍了不同的替代货币、它们的属性以及它们是如何开发和实施的。

第十一章,开发工具与框架,详细介绍了 Solidity 编程语言以及用于以太坊开发的不同相关工具和框架。

第十二章,构建投丨注应用程序,解释了如何使用 Oraclize 从以太坊智能合约中进行 HTTP 请求,以访问来自万维网的数据。我们还将学习如何访问存储在 IPFS 中的文件,使用 strings 库处理字符串等。

第十三章,超级账本,介绍了 Linux Foundation 的 Hyperledger 项目,该项目包括其成员介绍的不同区块链项目的讨论。

第十四章,替代区块链,介绍了替代区块链解决方案和平台。它提供了替代区块链和相关平台的技术细节和特点。

第十五章,区块链 - 货币之外,提供了区块链技术在除加密货币之外的领域应用的实际和详细介绍,包括物联网、政府、媒体和金融。

第十六章,可扩展性及其他挑战,专门讨论了区块链技术面临的挑战以及如何解决这些挑战。

第十七章,构建共同体区块链,将讨论共同体区块链。

第十八章,现状及展望,旨在提供与区块链技术相关的当前景观、项目和研究工作的信息。此外,还根据当前的区块链技术状况进行了一些预测。

要充分利用这本书

您需要 Windows 7 SP1+、8、10 或 Mac OS X 10.8+,本书中的示例是在 Ubuntu 16.04.1 LTS(Xenial)上开发的。

和 macOS 版本 10.13.2。因此,建议使用 Ubuntu 或任何其他类 Unix 系统。但是,也可以使用任何适合的操作系统,包括 Windows 或 Linux,但是示例(尤其是与安装相关的示例)可能需要相应更改。

与加密相关的示例是使用 OpenSSL 1.0.2g 2016 年 3 月 1 日的命令行工具开发的。

以太坊 Solidity 示例是使用在线可用的 Remix IDE(https:/ / remix. ethereum. org)开发的。

用于开发与以太坊相关示例的是 Ethereum Byzantine 版本。在撰写本文时,这是最新版本,并可从 https:/ / www. ethereum. org/ 下载。

与物联网相关的示例是使用 Vilros 的 Raspberry Pi 套件开发的,但可以使用适用的最新型号或套件。具体来说,Raspberry Pi 3 Model B V 1.2 用于构建 IoT 的硬件示例。Node.js V8.9.3 和 npm V5.5.1 用于下载相关软件包并运行 IoT 示例的 Node js 服务器。

在一些智能合约部署的示例中使用了 Truffle 框架,可在 http://truffleframework.com/ 找到。通过 npm 可使用最新版本。

下载示例代码文件

您可以从您在www.packt.com的账户中下载本书的示例代码文件。如果您在其他地方购买了这本书,您可以访问www.packt.com/support并注册,以便文件可以直接通过电子邮件发送给您。

您可以按照以下步骤下载代码文件:

  1. 登录或注册www.packt.com

  2. 选择“支持”选项卡。

  3. 点击“代码下载与勘误”。

  4. 在搜索框中输入书名,并按照屏幕上的说明进行操作。

下载文件后,请确保您使用最新版本的解压软件解压或提取文件夹:

  • Windows 上的 WinRAR/7-Zip

  • Mac 上的 Zipeg/iZip/UnRarX

  • Linux 上的 7-Zip/PeaZip

该书的代码包也托管在 GitHub 上:github.com/TrainingByPackt/Advanced-Blockchain-Development。如果代码有更新,将在现有的 GitHub 存储库上更新。

我们还有其他代码包,来自我们丰富的图书和视频目录,可以在github.com/PacktPublishing/上找到。来看看吧!

下载本书的彩色图片

我们还为您提供了一个 PDF 文件,其中包含本书中使用的截图/图表的彩色图片。彩色图片将帮助您更好地理解输出的变化。您可以从www.packtpub.com/sites/default/files/downloads/9781838823191_ColorImages.pdf下载该文件。

使用的约定

整本书中使用了许多文本约定。

CodeInText:指示文本中的代码词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 用户名。以下是一个示例:"input()方法用于从用户获取输入。"

代码块设置如下:

pragma solidity ⁰.4.0;
contract TestStruct {
  struct Trade
  {
    uint tradeid;
    uint quantity;
    uint price;
    string trader;
  }
  //This struct can be initialized and used as below
  Trade tStruct = Trade({tradeid:123, quantity:1, price:1,
trader:"equinox"});
}

任何命令行输入或输出均按照以下方式编写:

$ sudo apt-get install solc

粗体: 指示一个新术语、一个重要单词,或者屏幕上显示的词。例如,菜单中的字或对话框中的单词会在文本中显示,如下所示:"如果您需要不同的内容,点击页眉中的 下载 链接以获取所有可能的下载:"

警告或重要提示如下。

贴士和技巧如下。

联系我们

我们随时欢迎读者的反馈意见。

一般反馈: 如果您对本书的任何方面有疑问,请在消息主题中提及书名,并发送邮件至customercare@packtpub.com

勘误: 尽管我们已经尽了最大的努力确保内容的准确性,但错误是不可避免的。如果您在本书中发现错误,我们将不胜感激您向我们报告。请访问www.packt.com/submit-errata,选择您的书籍,点击"勘误提交表格"链接,然后填写相关细节。

盗版: 如果您在互联网上发现我们的作品的任何非法副本,请向我们提供地址或网站名称。请使用copyright@packt.com联系我们,并附上材料的链接。

如果您有兴趣成为作者:如果您在某个专题上有专业知识,并且有兴趣撰写或投稿书籍,请访问authors.packtpub.com

评论

请留下评价。一旦您阅读并使用了本书,为什么不在您购买它的网站上留下一篇评论呢?潜在读者可以看到并使用您的公正意见来做购买决定,我们在 Packt 可以了解您对我们产品的看法,而我们的作者可以看到您对他们书籍的反馈。谢谢!

欲了解有关 Packt 的更多信息,请访问 packt.com

第一章:区块链 101

如果您正在阅读这本书,很可能您已经听说过区块链,并对其巨大潜力有一些基本的认识。如果没有,那么让我告诉您,这是一项承诺积极改变几乎所有行业现有范例的技术,包括但不限于 IT、金融、政府、媒体、医疗和法律。

这一章是对区块链技术的介绍,它的技术基础,背后的理论,以及各种技术的组合,构建了今天所知的区块链。

在本章中,我们首先描述了分布式系统的理论基础。接下来,我们通过比特币的先驱介绍了区块链技术。最后,我们向您介绍了区块链技术。这种方法是理解区块链技术的一种逻辑方式,因为区块链的根源在于分布式系统。我们将在这里迅速涵盖很多内容,但不用担心——随着您阅读本书,我们将会更详细地讲解这些材料。

区块链技术的发展

随着比特币在 2008 年的发明,世界引入了一个新概念,现在可能将彻底改变整个社会。这是一种承诺对每个行业,包括但不限于金融、政府、媒体、法律和艺术产生影响的东西。一些人将区块链描述为一场革命,而另一些人认为它将更加渐进,并且需要很多年才能实现任何实际的区块链利益。这种思维在某种程度上是正确的,但在我看来,这场革命已经开始了。

全世界许多著名的组织已经在使用区块链技术编写概念验证,因为它的破坏性潜力已经得到充分认可。然而,一些组织仍处于初步探索阶段,尽管随着技术的成熟,预计它们将更快地取得进展。区块链技术对当前技术也产生影响,并具有根本性的改变能力。

如果我们回顾过去几年,我们会注意到 2013 年开始出现了一些想法,表明区块链在加密货币以外的其他领域中的用途。那个时候,区块链的主要用途是加密货币,许多新币在那个时期出现了。下图显示了区块链技术的年度进展和适应趋势的广谱概述。 x 轴上显示的年份指示了特定区块链技术阶段所处的时间范围。每个阶段都有一个代表动作的名称,并且在 x 轴上显示,从IDEAS & THOUGHTS的阶段开始,最终到MATURITY & FURTHER STANDARDIZATIONy 轴显示了区块链技术的活动水平、参与度和采用情况。图表显示,大约在2025年左右,预计区块链技术将变得成熟,并拥有大量用户。

区块链技术的采用和成熟

前面的图表显示,2013 年出现了与区块链技术的其他用途有关的IDEAS & THOUGHTS。然后在 2014 年开始了一些RESEARCH & EXPERIMENTATION,这导致了PROOF OF CONCEPTSFURTHER RESEARCH以及 2015 年至 2017 年之间的全面TRIAL PROJECTS。到 2018 年,我们将看到REAL WORLD IMPLEMENTATIONS。目前已经有许多项目正在进行中,并准备用区块链技术替换现有系统,例如,澳大利亚证券交易所ASX)即将成为首个用区块链技术替换其传统清算和结算系统的组织。

更多关于这个主题的信息可以在www.asx.com.au/services/chess-replacement.htm找到。

预计在 2019 年,将会进行更多的研究,并对区块链技术的监管和标准化产生一些兴趣。之后,从 2020 年开始,将会有可供生产使用的项目和使用区块链技术的现成产品,并且预计到 2021 年,区块链技术的主流使用将开始。区块链技术的进展几乎感觉像是上世纪 90 年代末的互联网点 COM 热潮。预计将会继续进行更多的研究,以及对区块链技术的进一步适应和成熟,最终,在 2025 年,预计该技术将足够成熟,可以在日常基础上使用。请注意,图表中提供的时间表不是严格的,可能会有所变化,因为准确预测区块链技术何时会成熟是相当困难的。此图表基于近年来取得的进展以及当前对这项技术的研究、兴趣和热情的氛围,这表明到 2025 年,区块链技术预计将成熟。

过去几年对区块链技术的兴趣显著增加。曾一度只被认为是来自加密货币角度的极客钱,或者被认为不值得追求的东西,现在区块链正在受到全球最大公司和组织的研究。数百万美元被用来调整和尝试这项技术。最近欧盟宣布计划到 2020 年将区块链研究的资金增加至近 3.4 亿欧元。

有兴趣的读者可以在www.irishtimes.com/business/technology/boost-for-blockchain-research-as-eu-increases-funding-four-fold-1.3383340上阅读更多。

另一份报告表明,到 2021 年全球对区块链技术研究的支出可能达到 92 亿美元。

更多关于这方面的信息可在bitcoinmagazine.com/articles/report-suggests-global-spending-blockchain-tech-could-reach-92-billion-2021/上找到。

存在着各种财团,例如企业以太坊联盟EEA)、HyperledgerR3,这些财团旨在研究和发展区块链技术。此外,许多初创企业已经提供基于区块链的解决方案。在谷歌上进行的简单趋势搜索显示出过去几年对区块链技术的兴趣程度之高。特别是自 2017 年初以来,区块链的搜索量增加相当显著,如下图所示:

区块链的谷歌趋势图

想象中这项技术的各种好处,例如去中心化的信任、成本节约、透明度和效率。然而,也存在多个挑战,这些是目前区块链活跃研究领域,比如可扩展性和隐私。

在这本书中,我们将看到区块链技术如何帮助实现前述的好处。你将学习到什么是区块链技术,以及它如何通过带来诸如效率、节省成本、透明度和安全性等多种好处来重塑企业、多个行业,甚至日常生活。我们还将探索分布式账本技术、去中心化和智能合约,以及如何利用主流区块链平台如以太坊和 Hyperledger 开发和实施技术解决方案。我们还将调查在区块链可以成为主流技术之前需要解决的挑战。

第十六章,可扩展性与其他挑战,致力于讨论区块链技术的限制和挑战。

分布式系统

理解分布式系统对于理解区块链技术至关重要,因为区块链在其核心是一个分布式系统。它是一个可以集中或去中心化的分布式分类账。区块链最初是为去中心化平台而设计和通常被使用。它可以被看作是具有去中心化和分布式范式属性的系统。它是一个去中心化分布式系统。

分布式系统是一种计算范式,其中两个或更多节点以协调的方式共同实现一个共同的结果。它被建模为用户看到它是一个单一的逻辑平台。例如,谷歌的搜索引擎是基于一个大型分布式系统,但对于用户来说,它看起来像一个单一的、连贯的平台。

一个节点可以被定义为分布式系统中的个体玩家。所有节点都能够彼此发送和接收消息。节点可以是诚实的、有故障的或恶意的,并且它们具有内存和处理器。表现出非理性行为的节点也被称为拜占庭节点,源自于拜占庭将军问题。

拜占庭将军问题

在 1982 年,Lamport 等人在他们的研究论文拜占庭将军问题中提出了一个思想实验,可在www.microsoft.com/en-us/research/publication/byzantine-generals-problem/找到,其中一群率领拜占庭军队不同部分的将军计划攻击或撤退到一个城市。他们之间唯一的通信方式是通过信使。他们需要同意在同一时间发动攻击才能获胜。问题在于一个或多个将军可能是叛徒,可能发送误导性的消息。因此,需要一种可行的机制,允许将军之间达成一致,即使存在叛徒,也能够同时发动攻击。类比到分布式系统,将军可以被视为节点,叛徒为拜占庭(恶意)节点,信使可以被视为将军之间的通信渠道。

这个问题在 1999 年被卡斯特罗和利斯科夫解决,他们提出了实用拜占庭容错PBFT)算法,通过接收包含相同签名内容的一定数量的消息来达成共识。

拜占庭节点这种不一致行为可能是故意恶意的,这对网络的运行是有害的。网络上任何节点的意外行为,无论是否恶意,都可以归类为拜占庭。

下图展示了一个小规模的分布式系统示例。这个分布式系统有六个节点,其中一个(N4)是拜占庭节点,可能导致数据不一致。L2 是一个断开或者慢速的链接,这可能导致网络分区。

分布式系统的设计: N4 是一个拜占庭节点,L2 是断开或者慢速的网络链接

分布式系统设计的主要挑战是节点之间的协调和容错。即使一些节点发生故障或网络链接中断,分布式系统也应该能够容忍这一点,并继续工作以实现期望的结果。多年来,这个问题一直是分布式系统设计研究的一个活跃领域,已经提出了几种算法和机制来解决这些问题。

分布式系统设计是如此具有挑战性,以至于已经证明了一种被称为 CAP 定理 的假设,该定理指出,分布式系统不能同时具有所有三个非常期望的属性;即一致性、可用性和分区容忍性。我们将在本章的后面更详细地探讨 CAP 定理。

区块链和比特币的历史

区块链是在 2008 年比特币的发明中引入的。然后在 2009 年进行了实际的实现。对于本章而言,简要回顾比特币就足够了,因为它将在 第八章 引入比特币 中详细探讨。然而,引用比特币是必要的,因为没有它,区块链的历史就不完整。

电子现金

电子现金或数字货币的概念并不新鲜。自 20 世纪 80 年代以来,基于 David Chaum 提出的模型的 e-现金协议一直存在。

理解分布式系统的概念对于理解区块链技术是必要的,同样,理解电子现金的概念也是必要的,以便欣赏区块链的第一个和惊人成功的应用,比特币,或者更广泛地说,一般的加密货币。

需要解决两个基本的电子现金系统问题:问责制和匿名性。

问责制 是为了确保现金只能被消费一次(双重支付问题),并且只能由其合法所有者支出。双重支付问题是指相同的资金可以被花费两次。由于数字数据很容易复制,这在数字货币中成为一个很大的问题,因为你可以复制同样的数字现金。匿名性 是为了保护用户的隐私。与实物现金一样,几乎不可能追溯到实际支付货币的个人。

大卫·朝的工作在 1980 年代解决了这两个问题,他使用了两种密码操作,即盲签名秘密共享。这些术语和相关概念将在第五章《对称加密》和第六章《公钥加密》中进行详细讨论。目前,可以说盲签名允许在不实际看到文件的情况下对其进行签名,而秘密共享是一个概念,可以检测到双重支付,即使用相同的电子现金代币两次(双重支付)。

2009 年,第一个名为比特币的电子现金(e-cash)系统的实际实现出现了。后来出现了密码货币这个术语。这是有史以来第一次在不信任网络中解决了分布式共识问题。它使用公钥密码学工作证明PoW)机制,提供了一种安全、可控和去中心化的铸造数字货币的方法。关键创新是由 PoW 机制加密保护的由交易组成的区块的有序列表的概念。这个概念将在第八章《介绍比特币》中详细解释。

在比特币中使用的其他技术,但在其发明之前已存在的技术,包括默克尔树、哈希函数和哈希链。所有这些概念都在第六章《公钥加密》中得到适当深入的解释。

查看前面提到的所有技术及其相关历史,很容易看出是如何将电子现金方案和分布式系统的概念结合起来创建比特币以及现在所称的区块链的。这个概念也可以通过以下图表进行可视化:

支持比特币和区块链发明的各种想法

区块链

2008 年,一篇名为《比特币:一个点对点的电子现金系统》的开创性论文由匿名人士Satoshi Nakamoto撰写,讨论了点对点的电子现金主题。它引入了术语区块链。没有人知道 Satoshi Nakamoto 的真实身份。在 2009 年引入比特币后,他一直活跃于比特币开发社区,直到 2011 年。然后,他将比特币的开发交给了其核心开发人员,并简单地消失了。自那以后,他再也没有与外界交流,他的存在和身份笼罩在神秘之中。术语区块链随着年代的推移逐渐演变成了blockchain这个词。

正如前文所述,区块链技术涵盖了多种可以在各个经济领域实施的应用。特别是在金融领域,人们认为对金融交易和结算性能的显着改进将带来期望中的时间和成本降低。可以说,几乎所有经济领域的部分已经意识到了区块链的潜力和前景,并已经或即将着手利用区块链技术的好处。

区块链定义

外行人的定义:区块链是一个不断增长的、安全的、共享的记录保存系统,其中数据的每个用户都持有记录的副本,只有在参与交易的所有方同意更新时才能更新。

技术定义:区块链是一个点对点的、分布式的分类账,具有加密安全、只能追加、不可变(极难更改)、只能通过对等节点的共识或协议更新等特性。

现在让我们更详细地研究前面的定义。我们将逐一查看定义中的所有关键词。

点对点

技术定义中的第一个关键词是点对点。这意味着网络中没有中央控制器,所有参与者直接相互通信。这一特性使得现金交易可以直接在对等节点之间进行交换,而无需第三方(如银行)参与。

分布式分类账

进一步剖析技术定义会揭示区块链是一个分布式分类账,这简单地意味着分类账在网络中分布在所有对等节点之间,每个对等节点都持有完整分类账的副本。

加密安全

接下来,我们看到这个分类账是加密安全的,这意味着加密学已被用来提供安全服务,使得这个分类账安全免受篡改和滥用。这些服务包括不可否认性、数据完整性和数据来源认证。您将在稍后的第五章中看到这是如何实现的,该章介绍了令人着迷的加密世界。

只能追加

我们遇到的另一个属性是区块链是只能追加的,这意味着数据只能按时间顺序顺序添加到区块链中。这一属性意味着一旦数据被添加到区块链中,几乎不可能更改那些数据,可以被认为是实际上不可变的。尽管如此,在某些罕见的情况下,如果针对区块链网络的串通成功获得了超过 51% 的权力,那么数据可能会被更改。一旦数据被添加到区块链中,可能会有一些合法的理由来更改数据,比如被遗忘的权利被删除的权利(也在通用数据保护GDPR)裁决中定义,gdpr-info.eu/art-17-gdpr/)。

然而,这些都是需要单独处理并需要优雅的技术解决方案的个案。在实际操作中,区块链确实是不可变的,不能更改。

通过共识可更新

最后,区块链最关键的属性是只能通过共识来更新。这是赋予它去中心化权力的原因。在这种情况下,没有中央权威控制更新账本。相反,对区块链所做的任何更新都会根据区块链协议定义的严格标准进行验证,并且只有在网络上的所有参与节点达成共识后才会将其添加到区块链中。为了达成共识,有各种共识促进算法,它们确保所有参与方就区块链网络上数据的最终状态达成一致意见,并坚决认为其为真实的。共识算法将在本章后面以及书中的适当位置进行讨论。

可以将区块链视为在互联网上运行的分布式对等网络的一层,如下图所示。这类似于 SMTP、HTTP 或 FTP 在 TCP/IP 上运行。

图

区块链的网络视图

在上图的底层,有互联网,为任何网络提供基本的通信层。在这种情况下,一个对等网络运行在互联网之上,它承载了区块链的另一层。该层包含交易、块、共识机制、状态机和区块链智能合约。所有这些组件都显示为一个单一的逻辑实体,以一个方框表示,在对等网络之上表示区块链。最后,在顶部有用户或节点连接到区块链并执行各种操作,如共识、交易验证和处理。这些概念将在本书后面详细讨论。

从商业角度来看,区块链可以定义为一个平台,对等方可以在没有中心信任的仲裁者的情况下使用交易来交换价值/电子现金。例如,在现金转账中,银行充当信任的第三方。在金融交易中,中央结算所充当两个交易方之间的仲裁者。这个概念非常引人注目,一旦你掌握了它,你就会意识到区块链技术的巨大潜力。这种去中介化使得区块链成为一个分散的共识机制,没有任何单一的管理数据库的权威。立即,你会看到这里去中心化的显著好处,因为如果不需要银行或中央结算所,那么它立即带来成本节约、更快的交易速度和信任。

区块仅是一组交易的选择,逻辑上组织在一起。交易是事件的记录,例如,从发送者帐户向受益人帐户转账的事件。一个区块由交易组成,其大小取决于所使用的区块链的类型和设计。

区块还包括对前一个区块的引用,除非它是创世区块。创世区块(Genesis block)是区块链中的第一个区块,在区块链首次启动时被硬编码。区块的结构也取决于区块链的类型和设计。然而,一般来说,只有少数属性对区块的功能至关重要:块头,由指向前一个块的指针、时间戳、一次性数字、默克尔根和包含交易的块体组成。区块中还有其他属性,但一般来说,前述组件始终在一个区块中可用。

一次性数字(Nonce)是仅生成并使用一次的数字。一次性数字广泛用于许多密码操作,以提供重放保护、身份验证和加密。在区块链中,它被用于 PoW 共识算法和交易重放保护中。

默克尔根(Merkle root)是默克尔树的所有节点的哈希值。默克尔树被广泛用于安全有效地验证大型数据结构。在区块链世界中,默克尔树通常用于允许有效验证交易。在区块链中,默克尔根位于区块的块头部分,是区块中所有交易的哈希值。这意味着仅需要验证默克尔根就足以验证默克尔树中的所有交易,而不是逐个验证所有交易。我们将在第六章,公钥加密中进一步阐述这些概念。

区块的通用结构。

上述结构是描述区块的简单块图。与其区块链技术相关的特定区块结构将在本书后面以更深入的技术细节进行讨论。

区块链的通用元素

现在,让我们逐步了解区块链的通用元素。如果您需要关于区块链不同部分的提醒,您可以将其用作便利的参考部分。更精确的元素将在后面的章节中,例如以太坊区块链的上下文中讨论。通用区块链的结构可以通过以下图示进行可视化:

区块链的通用结构

这里逐一描述了通用区块链的元素。这些是您在与区块链相关时会遇到的元素:

  • 地址:地址是区块链交易中用于表示发送方和接收方的唯一标识符。一个地址通常是一个公钥或者由公钥派生而来。虽然同一个用户可以重复使用地址,但地址本身是唯一的。然而,在实践中,一个用户可能不会再次使用相同的地址,并为每笔交易生成一个新的地址。这个新创建的地址将是唯一的。实际上,比特币是一个伪匿名系统。最终用户通常无法直接识别,但一些去匿名化比特币用户的研究表明,他们可以成功地被识别。一个良好的实践是,用户为每个交易生成一个新地址,以避免将交易链接到共同的所有者,从而防止识别。

  • 交易:交易是区块链的基本单位。交易代表了从一个地址向另一个地址的价值转移。

  • 区块:一个区块由多个交易和其他元素组成,例如前一个区块哈希(哈希指针)、时间戳和随机数。

  • 点对点网络:顾名思义,点对点网络是一种网络拓扑结构,其中所有节点都可以相互通信并发送和接收消息。

  • 脚本或编程语言:脚本或程序在交易中执行各种操作,以便实现各种功能。例如,在比特币中,交易脚本是用一种称为脚本的语言预定义的,其中包含一组命令,允许节点将代币从一个地址转移到另一个地址。然而,脚本是一种有限的语言,它只允许执行交易所必需的基本操作,但不允许任意程序开发。可以将其视为仅支持标准预编程算术操作的计算器。因此,比特币脚本语言不能被称为Turing 完备。简单来说,Turing 完备语言意味着它可以执行任何计算。它是以发明了可以运行任何算法的图灵机的阿兰·图灵命名的。图灵完备语言需要循环和分支能力来执行复杂的计算。因此,比特币的脚本语言不是图灵完备的,而以太坊的 Solidity 语言是。

为了在区块链上方便开发任意程序,需要图灵完备的编程语言,这现在已经成为区块链非常理想的特性。可以把它想象成一台允许使用编程语言开发任何程序的计算机。然而,这些语言的安全性是一个关键问题,也是一个重要且持续的研究领域。我们将在本书的以后章节中(第八章,“介绍比特币”,第四章,“智能合约”,第十一章,“开发工具和框架”)更详细地讨论这个问题。

  • 虚拟机:这是对前面介绍的交易脚本的延伸。虚拟机允许在区块链上运行图灵完备的代码(作为智能合约);而交易脚本在操作上是有限制的。然而,并非所有区块链都支持虚拟机。各种区块链使用虚拟机来运行诸如以太坊虚拟机EVM)和链虚拟机CVM)等程序。EVM 用于以太坊区块链,而 CVM 是为一种名为Chain Core的企业级区块链开发并使用的虚拟机。

  • 状态机:区块链可以被视为状态转换机制,节点通过交易执行、验证和最终化过程使状态从初始形式修改为下一个形式,最终到达最终形式。

  • 节点:区块链网络中的节点根据其扮演的角色执行各种功能。节点可以提出和验证交易,并进行挖矿以促进共识和保护区块链的安全。这一目标是通过遵循共识协议(最常见的是 PoW)实现的。节点还可以执行其他功能,如简单支付验证(轻节点)、验证,以及根据使用的区块链类型和节点分配的角色而进行的许多其他功能。节点还执行交易签名功能。交易首先由节点创建,然后还由节点使用私钥进行数字签名,作为它们拥有希望在区块链网络上向他人转移的资产的合法持有者的证明。这种资产通常是代币或虚拟货币,如比特币,但也可以是通过使用代币在区块链上代表的任何现实世界资产。

  • 智能合约:这些程序在区块链之上运行,并封装了在满足某些条件时执行的业务逻辑。这些程序是可强制执行和自动可执行的。智能合约功能并非所有区块链平台都具备,但由于其提供给区块链应用的灵活性和强大性,目前已成为非常理想的功能。智能合约有许多用例,包括但不限于身份管理,资本市场,贸易金融,记录管理,保险和电子治理。智能合约将在第四章中进行更详细的讨论,智能合约

区块链的工作原理

我们现在已经定义和描述了区块链。现在让我们看看区块链是如何实际运作的。节点既可以是矿工,创建新区块并铸造加密货币(硬币),也可以是区块签名者,验证并用数字签名交易。每个区块链网络都必须做出的一个关键决定是确定哪个节点将在区块链上追加下一个区块。这个决定是通过共识机制来做出的。共识机制将在本章后面进行描述。

现在我们将看一下区块链是如何验证交易并创建和追加区块来增长区块链的。

区块链是如何累积区块的

现在我们将看一下一个创建区块的一般方案。这里呈现这个方案是为了让你对区块是如何生成的以及交易和区块之间的关系有一个大致的了解:

  1. 一个节点通过首先创建然后用私钥进行数字签名来启动交易。交易可以代表区块链中的各种行为。最常见的情况是,这是一个代表用户之间价值转移的数据结构。交易数据结构通常包括价值转移的某些逻辑,相关规则,来源和目的地地址以及其他验证信息。这将在本书后面关于比特币和以太坊的特定章节中进行更详细的介绍。

  2. 通过使用一种名为 Gossip 协议的洪泛协议来传播(洪泛)交易到根据预设标准验证交易的对等节点。通常,需要超过一个节点来验证交易。

  3. 一旦交易得到验证,它将被包含在一个区块中,然后传播到网络上。在这一点上,交易被视为已确认。

  4. 新创建的区块现在成为账本的一部分,并且下一个区块以加密方式连接到这个区块。这个连接是一个哈希指针。在这个阶段,交易得到了第二次确认,而区块得到了第一次确认。

  5. 每次创建新区块时,交易都会被重新确认。通常,比特币网络要求六次确认才能视为交易最终确认。

值得注意的是,步骤 4 和 5 被认为是非强制性的,因为交易本身在步骤 3 中已经最终确定;但是,如果需要,步骤 4 和步骤 5 会进行区块确认和进一步的交易重新确认。

这完成了区块链的基本介绍。在下一节中,您将了解到这项技术的好处和局限性。

区块链的好处和局限性

区块链技术的许多优点已经在许多行业中讨论,并由全球参与区块链领域的思想领袖提出。区块链技术的显着优点如下:

  • 去中心化:这是区块链的核心概念和优势。无需信任的第三方或中介来验证交易;相反,使用共识机制来就交易的有效性达成一致。

  • 透明度和信任:由于区块链是共享的,每个人都可以看到区块链上的内容,这使得系统具有透明性。因此,建立了信任。这在资金或福利发放等场景中更为相关,在这些场景中,与选择受益人相关的个人自由裁量权需要受到限制。

  • 不可变性:一旦数据被写入区块链,就极其难以将其改变回来。虽然数据并非真正不可变,但由于更改数据非常具有挑战性且几乎不可能,因此将其视为保持不可变交易分类账的好处。

  • 高可用性:由于系统基于对等网络中的数千个节点,并且数据在每个节点上被复制和更新,因此系统变得高度可用。即使一些节点离开网络或变得无法访问,整个网络仍然可以继续工作,从而使其高度可用。这种冗余导致了高可用性。

  • 高度安全:区块链上的所有交易都经过加密保护,因此提供了网络完整性。

  • 简化当前的范式:在许多行业中,如金融或健康领域,当前的区块链模型有些杂乱无章。在这种模型中,多个实体维护着自己的数据库,由于系统的不一致性,数据共享可能变得非常困难。然而,由于区块链可以作为许多利益相关方之间的单一共享分类账,这可能会通过减少每个实体维护的独立系统的复杂性来简化模型。

  • 交易更快:在金融行业,特别是在后期交易结算功能中,区块链可以通过使交易快速结算起到至关重要的作用。区块链不需要冗长的验证、调和和清算过程,因为共识机制已经在金融组织之间的共享分类账上提供了一致的数据版本。

  • 节省成本:在区块链模型中不需要信任的第三方或结算所,这可以大幅减少作为费用支付给这些方的开销。

与任何技术一样,为了使系统更加稳健、有用和易于访问,都需要解决一些挑战。区块链技术也不例外。事实上,学术界和工业界都在努力克服区块链技术带来的挑战。最敏感的区块链问题如下:

  • 可扩展性

  • 适应性

  • 规管

  • 技术相对不成熟

  • 隐私

所有这些问题和可能的解决方案将在第十六章中详细讨论,可扩展性和其他挑战

区块链技术的层次

在本节中,介绍了区块链技术的各个层面。人们认为,由于区块链技术的迅速发展和进步,许多应用程序将得到发展。一些这样的进步已经实现,而另一些则根据当前区块链技术发展速度的预期在不久的将来会实现。

这里讨论的三个层次最初是在Melanie Swan的书籍Blockchain: Blueprint for a New Economy中描述的,O'Reilly Media2015 年,作为每个类别中应用程序的区块链层次。这就是区块链的演变方式,这种版本化展示了区块链技术的不同演化和使用层次。事实上,所有区块链平台,除了少数例外,都支持这些功能和应用。这种版本化只是根据当前的使用方式、演变方式或预计的演变方式,对各种区块链类别进行的逻辑分割。

还要注意,这种版本化是为了完整性和历史原因而在这里呈现,因为这些定义现在已经有些模糊了,除了比特币(区块链 1.0)之外,所有支持智能合约开发的新一代区块链平台都可以编程提供所有区块链层次中提到的功能和应用程序:1.0、2.0、3.0 以及更高版本。

除了第一层,第二层和第三层,或者未来的第 X 层,以下代表了我对区块链技术最终可能会成为的愿景,随着这一技术的发展:

  • 区块链 1.0:这个层次是随着比特币的发明而引入的,主要用于加密货币。此外,由于比特币是加密货币的首次实施,因此将区块链技术的第一代分类为仅包括加密货币是合理的。所有替代加密货币以及比特币都属于这一类。它包括核心应用,如支付和应用程序。这一代始于 2009 年比特币发布,结束于 2010 年初。

  • 区块链 2.0:这第二代区块链被金融服务和智能合约所使用。该层次包括各种金融资产,如衍生品、期权、互换和债券。在这一层次上,涵盖了超越货币、金融和市场的各种应用。以太坊、超级账本和其他新一代区块链平台被视为区块链 2.0 的一部分。这一代的开始是在 2010 年开始出现有关将区块链用于其他目的的想法时。

  • 区块链 3.0:这第三代区块链用于实现超出金融服务行业的应用,并在政府、健康、媒体、艺术和司法领域中使用。与区块链 2.0 一样,以太坊、超级账本和具有编写智能合约能力的新一代区块链被视为此区块链技术层次的一部分。这一代区块链大约在 2012 年出现,当时研究了区块链技术在不同行业的多个应用。

  • 区块链 X.0:这一代代表了区块链奇点的愿景,有一天将会有一个公共区块链服务可用,任何人都可以像使用谷歌搜索引擎一样使用它。它将为社会的所有领域提供服务。它将是一个公共开放的分布式分类账,其上运行着通用目的的理性代理人(Machina economicus),代表人们做出决策,并与其他智能自治代理人进行交互,并由代码而不是法律或书面合同进行监管。这并不意味着法律和合同将消失,而是法律和合同将能够在代码中实施。

Machina Economicus 是来自人工智能AI)和计算经济学领域的概念。它可以被定义为一个做出逻辑和完美决策的机器。在实现这一梦想之前,有各种技术挑战需要解决。

对 Machina Economicus 的讨论超出了本书的范围,有兴趣的读者可以参考www.infosys.com/insights/purposeful-ai/Documents/machina-economicus.pdf获取更多信息。

在区块链和人工智能相结合的背景下,这个概念将在第十八章《当前情况及展望》中详细阐述。

区块链的特征

区块链执行各种功能,这些功能受到各种特性的支持。这些功能包括但不限于价值转移、资产管理和协议管理。前一节描述的所有区块链层都借助区块链提供的特性执行这些功能,但也存在一些例外情况。例如,像比特币这样的区块链平台不支持智能合约。另一个例子是,并非所有的区块链平台都会产生加密货币或代币,比如超级账本和多链。

区块链的特性在这里描述:

  • 分布式共识:分布式共识是区块链的主要支柱。该机制使得区块链能够呈现出一致的真实版本,而无需中央权威的要求,这被所有参与方所认可。

  • 交易验证:从区块链节点发布的任何交易都基于预定的一组规则进行验证。只有有效的交易才会被选中包含在一个块中。

  • 智能合约平台:区块链是一个可以运行程序的平台,以执行用户的业务逻辑。并非所有区块链都有执行智能合约的机制;然而,这是一个非常理想的特性,在像以太坊和多链这样的新型区块链平台上是可用的。

智能合约

区块链技术提供了运行智能合约的平台。这些是自动化的、自治的程序,驻留在区块链网络上,并封装了执行所需功能所需的业务逻辑和代码。例如,想象一下一个保险合约,在其中如果航班取消,则向旅客支付索赔。在现实世界中,这个过程通常需要很长时间来提出索赔、验证索赔,并向索赔人(旅客)支付保险金额。如果整个过程都是通过密码学强制信任、透明度和执行自动化的,那么一旦智能合约收到通知说所涉航班已取消,它就会自动触发向索赔人支付保险金的过程?如果航班准时,智能合约会自行支付。

这确实是区块链的一个革命性特性,因为它为现实场景提供了灵活性、速度、安全性和自动化,这可以导致一个完全值得信赖的系统,从而实现了显著的成本降低。智能合约可以被编程来执行区块链用户需要的任何操作,并根据他们的具体业务需求来执行。

  • 点对点价值转移:区块链通过代币实现了用户之间的价值转移。代币可以被视为价值的载体。

  • 加密货币的生成:这个功能是可选的,取决于所使用的区块链类型。区块链可以创建加密货币作为对验证交易并消耗资源以保障区块链安全的矿工的激励。我们将在第八章中详细讨论加密货币,引入比特币

  • 智能资产:现在可以以一种安全和精确的方式将数字或实物资产与区块链链接起来,使其不能被他人索取。您完全掌控您的资产,它既不能被双重花费也不能被双重拥有。以数字音乐文件为例,它可以被无限制地复制许多次而没有任何控制。尽管当前确实使用了许多数字版权管理DRM)方案以及版权法律,但它们中没有一个能像基于区块链的 DRM 那样可强制执行。区块链可以以一种完全可强制执行的方式提供 DRM 功能。有些曾经名声在外的 DRM 方案在理论上看起来很棒,但由于某种限制而被黑客攻破。一个例子是 Oculus 的黑客攻击(www.wired.co.uk/article/oculus-rift-drm-hacked)。

另一个例子是 PS3 的黑客攻击,还有受版权保护的数字音乐、电影和电子书籍通常在互联网上无限制地共享。多年来我们一直有版权保护,但数字盗版却否定了所有完全强制执行法律的尝试,然而,如果您拥有一个资产,除非您决定转让,否则没有人能够索取它。这个功能具有深远的影响,特别是在 DRM 和电子现金系统中,双重花费检测是一个关键要求。在比特币中,双重花费问题首次在没有可信第三方的要求下得到解决。

  • 提供安全性:区块链基于经过验证的加密技术,确保数据的完整性和可用性。通常,由于透明度的要求,不提供机密性。这一限制是金融机构和其他需要交易隐私和机密性的行业采用它的主要障碍。因此,区块链上的交易隐私和机密性正在受到非常积极的研究,已经取得了进展。可以说,在许多情况下,并不需要保密性,而是更喜欢透明性。例如,在比特币中,保密性并不是绝对必要的;然而,在某些情况下是可取的。一个更近期的例子是 Zcash,它提供了进行匿名交易的平台。这个方案将在第十章中详细讨论,“替代货币”。区块链还提供其他安全服务,如不可否认性和认证,因为所有操作都是使用私钥和数字签名进行保护的。

  • 不可变性:这是区块链的另一个关键特性:一旦记录添加到区块链中,它们就是不可变的。虽然有可能回滚更改,但这是要尽量避免的,因为这样做将消耗大量的计算资源。例如,在比特币中,如果恶意用户想要更改先前的区块,那么就需要再次计算已添加到区块链中的所有这些区块的 PoW。这个难度使得区块链上的记录基本上是不可变的。

  • 唯一性:这个区块链特性确保每个交易都是唯一的,并且没有已经花费过(双重支付问题)。这个特性在加密货币中尤其重要,其中检测和避免双重支付是一个至关重要的要求。

区块链的类型

基于区块链在过去几年的演变方式,它可以被分为多个类别,具有独特的,有时是部分重叠的属性。你应该注意,本章前面描述的层次结构是一个不同的概念,其中介绍了基于其演变和使用的逻辑分类的区块链。

在本节中,我们将从技术和业务使用的角度来检查不同类型的区块链。这些区块链类型可以出现在任何区块链层次上,因为这些层次与区块链的各种类型之间没有直接关系。

在本节中,我们将检查:

  • 分布式分类帐

  • 分布式分类帐技术(DLT)

  • 区块链

  • 分类帐

分布式分类帐

首先,我需要澄清一个模糊之处。应该注意,分布式账本是一个描述共享数据库的广义术语;因此,所有区块链在技术上都属于共享数据库或分布式账本的范畴。虽然所有区块链从根本上都是分布式账本,但并非所有分布式账本都一定是区块链。

分布式账本和区块链之间的一个关键区别在于,分布式账本不一定由交易块组成以保持账本增长。相反,区块链是一种特殊类型的共享数据库,由交易块组成。一个不使用交易块的分布式账本的例子是 R3 的 Corda。Corda 是一个分布式账本,开发用于记录和管理协议,特别专注于金融服务行业。另一方面,像比特币和以太坊这样更广为人知的区块链利用区块来更新共享数据库。

顾名思义,分布式账本分布在参与者之间,并分布在多个站点或组织之间。这种类型的账本可以是私有的或公开的。这里的基本思想是,与许多其他区块链不同,记录是连续存储的,而不是被分成区块。这个概念用在 Ripple 中,它是一个基于区块链和加密货币的全球支付网络。

分布式账本技术

应该注意,在过去几年里,术语分布式账本或分布式账本技术DLT)已经成为金融行业中普遍用来描述区块链的术语。有时,区块链和 DLT 是可以互换使用的。虽然这并不完全准确,但这是该术语近期如何发展的,特别是在金融领域。事实上,DLT 现在是金融领域一个非常活跃和繁荣的研究领域。从金融行业的角度来看,DLT 是被共享和用于已知参与者之间的权限区块链。DLT 通常充当共享数据库,所有参与者都是已知并经过验证的。它们没有加密货币,也不需要挖矿来保护账本。

公共区块链

顾名思义,公共区块链不归任何人所有。它们对公众开放,任何人都可以作为节点参与决策过程。用户可能会或可能不会因参与而受到奖励。所有这些 无许可未经许可 账本的用户都在本地节点上维护一个账本副本,并使用分布式共识机制来决定账本的最终状态。比特币和以太坊都被认为是公共区块链。

私有区块链

顾名思义,私人区块链就是私人的。也就是说,它只对一个共同体或一群决定相互分享账本的个人或组织开放。现在有各种此类类别的区块链,如 HydraChain 和 Quorum。如果需要,这两个区块链也可以在公共模式下运行,但它们的主要目的是提供私人区块链。

半私人区块链

半私人区块链中,部分区块链是私有的,部分是公开的。需要注意的是,这只是一个概念,今天还没有真正的世界 POCs 已经被开发。在半私人区块链中,私有部分由一群个人控制,而公共部分对任何人开放。

这种混合模型可以用于私人区块链的私有部分仍然保留在内部,并在已知参与者之间共享,而公共区块链的公共部分仍然可以被任何人使用,也可以选择允许挖矿以保护区块链的安全。通过这种方式,整个区块链可以使用 PoW 来保证安全,从而为私人和公共部分提供一致性和有效性。这种类型的区块链也可以称为半分散模型,其中它由一个单一实体控制,但仍允许多个用户通过遵循适当的程序加入网络。

侧链

更确切地说是挂钩侧链,这是一个概念,通过这个概念,硬币可以从一个区块链移动到另一个区块链,然后再移回。典型的用途包括创建新的山寨币(另类加密货币),其中硬币被烧毁作为充足股份的证明。在这种情况下,烧毁硬币的意思是硬币被发送到一个无法花费的地址,并且这个过程使烧毁的硬币无法恢复。这种机制用于启动一个新的货币或引入稀缺性,从而增加硬币的价值。

这种机制也被称为燃烧证明PoB),被用作 PoW 和股份证明PoS)的另一种分布式共识方法。前面提到燃烧硬币的例子适用于单向捆绑侧链。第二种类型被称为双向捆绑侧链,它允许硬币从主链移动到侧链,然后在需要时再次移回到主链。

这个过程使得可以为比特币网络构建智能合约。Rootstock 是一个侧链的主要例子,它使用这种范例为比特币实现智能合约开发。它通过允许比特币区块链进行双向捆绑,从而实现了更高的吞吐量。

许可账本

权限分类账 是一个区块链,其中网络参与者已知且值得信赖。权限分类账不需要使用分布式共识机制;而是使用协议达成一致,以维护关于区块链记录状态的共享版本的真实性。在这种情况下,对链上交易的验证,所有验证者已经由中央权威预先选择,通常不需要挖矿机制。

根据定义,权限区块链也没有私有的要求,因为它可以是公共区块链,但具有受监管的访问控制。例如,如果在比特币之上引入一个验证用户身份然后允许访问区块链的访问控制层,比特币可以成为权限分类账。

共享分类账

这是一个通用术语,用于描述任何由公众或联合体共享的应用程序或数据库。通常,所有区块链都属于共享分类账的范畴。

完全私有和专有区块链

这些类型的区块链没有主流应用,因为它们偏离了区块链技术中去中心化的核心概念。尽管如此,在组织内的特定私人环境中,可能需要共享数据并对数据的真实性提供一定程度的保证。

这种类型的区块链的一个例子可能是允许各个政府部门之间合作和共享数据。在这种情况下,除了简单的状态机复制和已知的中央验证者的协议外,不需要复杂的共识机制。即使在私有区块链中,实际上也不需要代币,但它们可以用作价值转移的手段或代表某些真实资产。

代币化区块链

这些区块链是通过挖矿或初始分配的共识过程生成加密货币的标准区块链。比特币和以太坊是这种类型区块链的主要例子。

无代币区块链

这些区块链设计成不具备价值转移的基本单位。然而,在不需要在节点之间转移价值,只需要在各种受信任方之间共享数据的情况下,它们仍然是有价值的。这与完全私有区块链类似,唯一的区别在于不需要使用代币。这也可以被看作是用于存储数据的共享分布式分类账。当涉及到不可变性、安全性和共识驱动的更新时,它确实具有其优点,但不用于价值转移或加密货币的常见区块链应用。

这结束了我们对各种类型的区块链的考察,我们现在将在下一节讨论普查的概念。

共识

共识是区块链的支柱,因此它通过一个名为挖矿的可选过程提供了控制的分散化。共识算法的选择也受到正在使用的区块链类型的控制;也就是说,并不是所有的共识机制都适用于所有类型的区块链。例如,在公共无许可区块链中,使用 PoW 而不是基于权威证明的简单协议机制可能是有意义的。因此,为特定的区块链项目选择合适的共识算法是至关重要的。

共识是在数据的最终状态上对不信任的节点之间达成一致的过程。为了达成共识,使用了不同的算法。在达成两个节点之间的协议(例如在客户端-服务器系统中)是容易的,但是当多个节点参与分布式系统并且它们需要就一个值达成一致时,达成共识就变得非常具有挑战性了。尽管某些节点失败,但在多个节点之间达成对单个值的共同状态或价值的过程被称为分布式共识

共识机制

共识机制是区块链中由大多数或所有节点采取的一组步骤,以便就提出的状态或值达成一致。这个概念已经被工业界和学术界的计算机科学家研究了三十多年。随着区块链和比特币的出现,共识机制最近受到了关注,并且得到了相当大的流行。

有各种各样的要求必须得到满足,以提供共识机制中所需的结果。以下描述了这些要求:

  • 协议:所有诚实节点决定相同的值

  • 终止:所有诚实节点终止共识过程的执行,并最终达成决定

  • 有效性:所有诚实节点达成的值必须与至少一个诚实节点提出的初始值相同

  • 容错:共识算法应能够在有故障或恶意节点(拜占庭节点)的情况下运行

  • 完整性:这是一个要求,在单个共识周期中,没有节点可以做出超过一次决定

共识机制的类型

所有的共识机制都是为了处理分布式系统中的故障,并允许分布式系统达成最终的一致状态。共识机制有两种一般类型。这些类型涉及所有类型的故障(故障停止类型或任意类型)。这些常见类型的共识机制如下:

  • 传统的拜占庭容错(BFT)基础:没有像比特币 PoW 中的部分哈希反转这样的计算密集型操作,这种方法依赖于一个简单的节点方案,即发布者签名的消息。最终,当接收到一定数量的消息时,就达成了一致。

  • 基于领导者选举的共识机制:这种安排要求节点竞争领导者选举彩票,获胜的节点提出最终值。例如,比特币中使用的 PoW 就属于这一类别。

许多实际的共识协议实现方案已被提出。Paxos 是其中最著名的协议。它由 Leslie Lamport 在 1989 年提出。使用 Paxos,节点被分配为提议者、接受者和学习者等各种角色。节点或进程被称为副本,并且在存在故障节点的情况下,通过大多数节点的协议达成一致。

Paxos 的一种替代方案是 RAFT,它通过将节点分配为三种状态之一来工作;即,追随者、候选者或领导者。在候选节点获得足够的选票后,会选举出一个领导者,然后所有更改都必须经过领导者。一旦在大多数追随者节点上完成复制,领导者就会批准所提议的更改。本章节的讨论不涵盖分布式系统角度上共识机制的理论细节。然而,本章后面将专门介绍共识协议的内容。具体算法将在本书后续专门讨论比特币和其他区块链的章节中进行讨论。

区块链中的共识

共识是一个分布式计算概念,在区块链中被用来通过区块链网络上的所有对等节点达成对真实版本的同意的一种手段。这个概念之前在本章的分布式系统部分进行了讨论。在本节中,我们将讨论区块链技术背景下的共识。这里介绍的一些概念仍然与分布式系统理论相关,但是它们是从区块链的角度进行解释的。

大致来说,以下描述了两种主要的共识机制类别:

  • 基于证明、基于领导者选举彩票的,或者纳卡莫托共识,其中通过随机选举领导者(使用算法)并提议最终值。这个类别也被称为完全去中心化无许可类型的共识机制。这种类型在比特币和以太坊区块链中以 PoW 机制的形式被广泛使用。

  • 基于 BFT 的是一种更传统的方法,基于投票轮次。这类共识也被称为联合体有许可类型的共识机制。

在有限数量的节点时,基于 BFT 的共识机制表现良好,但在扩展方面表现不佳。另一方面,基于领导者选举的抽签(PoW)类型共识机制扩展性极佳,但性能非常慢。由于在这个领域进行了大量研究,新类型的共识机制也在不断出现,比如在瑞波网络中使用的半去中心化类型。瑞波网络将在第十四章中,替代区块链中详细讨论。还有各种其他建议,试图找到扩展性和性能之间的正确平衡。一些值得注意的项目包括 PBFT、混合 BFT、BlockDAG、Tezos、Stellar 和 GHOST。

当今可用的共识算法,或者正在区块链背景下进行研究的算法,都列举在这里了。以下并非详尽列表,但包括了所有值得注意的算法。

  • 工作证明(PoW):这种共识机制依赖于证明在网络接受之前已经花费了足够的计算资源的证据。这种方案被用在比特币、莱特币和其他加密货币的区块链中。目前,这是唯一被证明在区块链网络上能惊人地成功对抗任何勾结攻击,比如西贝尔攻击的算法。西贝尔攻击将在第八章中讨论,介绍比特币

  • 股权证明(PoS):该算法基于一个思想,即一个节点或用户在系统中拥有足够的权益;也就是说,用户已经在系统中投入足够的资源,以至于该用户的任何恶意尝试都能抵消对网络进行此类攻击的好处。这个想法最初是由 Peercoin 提出的,并将会在以Serenity为名的以太坊区块链版本中使用。PoS 中另一个重要的概念是币龄,这是一个根据未被花费的时间和硬币数量得出的标准。在这个模型中,提出和签署下一个区块的机会随着币龄的增长而增加。

  • 委托权益证明(DPoS):这是对标准 PoS 的创新,其中每个在系统中有权益的节点可以通过投票将交易验证的权力委托给其他节点。这是在 BitShares 区块链中使用的。

  • 时间间隔证明(PoET):由英特尔在 2016 年推出,PoET 利用可信执行环境(TEE)通过一次有保证的等待时间来为领导者选举过程提供随机性和安全性。它需要英特尔软件保护扩展(SGX)处理器为其提供安全保证。这个概念在第十三章中,Hyperledger,在英特尔的Sawtooth Lake区块链项目的背景下有更详细的讨论。

  • 存款证明(PoD):在这种情况下,希望参与网络的节点必须在他们可以挖矿和提出区块之前先做出一笔安全保证金。这个机制被用于 Tendermint 区块链。

  • 重要性证明(PoI):这个想法与 PoS 不同而且重要。PoI 不仅依赖于用户在系统中所拥有的股份大小,还监控用户对令牌的使用和转移,以建立一定的信任和重要性水平。它被用于 NEM 币的区块链。有关该币的更多信息,请访问 NEM 的网站 nem.io

  • 联邦共识或联邦拜占庭共识:这种机制被用于恒星共识协议。在该协议中,节点保留一组公信力强的对等节点,并仅传播由大多数受信任节点验证的交易。

  • 基于声誉的机制:顾名思义,领导者是根据其在网络上建立的声誉而选出的。它基于其他成员的投票。

  • PBFT:该机制实现了状态机复制,提供了对拜占庭节点的容错。除了 PBFT、PAXOS、RAFT 和联邦拜占庭协议FBA)之外,还有许多其他协议正在被使用或已被提议用于分布式系统和区块链的许多不同实现中。

  • 活动证明PoA):这种方案是 PoS 和 PoW 的组合,确保股权持有者以伪随机但均匀的方式被选中。与 PoW 相比,这是一种更节能的机制。它利用了一个称为跟随 Satoshi的新概念。在这个方案中,PoW 和 PoS 被结合在一起以实现共识和较高水平的安全性。这种方案更加节能,因为 PoW 仅在机制的第一阶段中使用,第一阶段后它切换到 PoS,后者消耗能量极小。

  • 容量证明(PoC):该方案利用硬盘空间作为挖掘区块的资源。这与使用 CPU 资源的 PoW 不同。在 PoC 中,利用硬盘空间进行挖掘,因此也被称为硬盘挖矿。这个概念最早是在 Burstcoin 加密货币中引入的。

  • 存储证明(PoS):该方案允许外包存储容量。该方案基于一种假设,即特定数据可能由一个节点存储,该节点作为参与共识机制的手段。已经提出了该方案的几种变体,如复制证明、数据拥有权证明、空间证明和空间时间证明。

CAP 定理与区块链

CAP 定理,也称为布鲁尔定理,由 Eric Brewer 于 1998 年引入为猜想。 2002 年,Seth Gilbert 和 Nancy Lynch 证明了这个定理。 该理论指出任何分布式系统无法同时具有一致性、可用性和分区容忍性:

  • 一致性是一个属性,它确保分布式系统中的所有节点具有单一的、当前的和相同的数据副本。

  • 可用性意味着系统中的节点都在运行,可以使用,并且在需要的时候可以接受请求并响应数据,没有任何故障。 换句话说,数据在每个节点都可用,节点在响应请求。

  • 分区容忍性确保如果一组节点由于网络故障无法与其他节点通信,则分布式系统仍然能够正常运行。 这可能是由于网络和节点故障造成的。

已经证明,分布式系统无法同时具有一致性、可用性和分区容忍性。 这可以通过以下示例解释。 让我们想象一下,有一个具有两个节点的分布式系统。 现在让我们仅对这两个节点的最小可能的分布式系统应用这三个定理属性。

  • 如果两个节点具有相同的共享状态,即具有相同的最新数据副本,则实现一致性

  • 可用性是指如果两个节点都在运行并且响应最新的数据副本,可用性就得以实现。

  • 如果两个节点之间的通信不会中断(由于网络问题、拜占庭错误等),它们能够相互通信,则实现分区容忍性

现在想象一种情况,即发生分区并且节点无法再相互通信。 如果没有新的更新数据进来,那么它只能在一个节点上更新。 在这种情况下,如果节点接受更新,那么只有网络中的一个节点进行了更新,因此一致性就丢失了。 现在,如果节点拒绝了更新,那将导致可用性的丧失。 在这种情况下,由于分区容忍性,可用性和一致性都无法实现。

这很奇怪,因为区块链设法实现了所有这些属性,或者说是吗? 这将很快解释清楚。为了实现容错性,使用了复制。 这是一种实现容错性的标准和广泛使用的方法。 通过共识算法实现一致性,以确保所有节点具有相同的数据副本。 这也被称为状态机复制。 区块链是实现状态机复制的手段。 一般来说,节点可能经历两种类型的故障。 这两种类型都属于分布式系统可能发生的故障的更广泛类别:

  • 停止错误:这种类型的错误发生在节点仅仅崩溃时。停止错误是两种故障类型中较容易处理的一种。Paxos 协议,本章早期介绍的,通常用于处理这种类型的故障。这些故障很容易处理。

  • 拜占庭错误:第二种类型的错误是指出现恶意或任意不一致行为的故障节点。这种类型的错误很难处理,因为它可能会因误导性信息而导致混乱。这可能是由对手的攻击、软件错误或数据损坏引起的。状态机复制协议(如 PBFT)是为了解决这种第二类型的错误而开发的。

奇怪的是,似乎在区块链中违反了 CAP 定理,尤其是在其最成功的实现比特币中。然而,事实并非如此。在区块链中,一致性被牺牲以换取可用性和分区容忍性。在这种情况下,区块链上的一致性C)不会与分区容忍性P)和可用性A)同时实现,但它会随着时间的推移逐渐实现。这被称为最终一致性,其中一致性是通过多个节点随时间的验证而实现的。比特币中引入了挖矿的概念来实现这一目的。挖矿是通过使用 PoW 共识算法来促进共识达成的过程。在更高的层面上,挖矿可以被定义为一种用于向区块链添加更多区块的过程。稍后在第八章,介绍比特币中会详细讨论此问题。

摘要

在本章中,我们以高级水平介绍了区块链技术。首先,我们讨论了一些分布式系统的基本概念,然后回顾了区块链的历史。我们还讨论了诸如电子现金之类的概念。

此外,我们从不同的角度介绍了区块链的各种定义。我们还向您介绍了区块链技术的一些应用。接下来,我们探讨了不同类型的区块链。最后,我们研究了这项新技术的优缺点。像区块链可伸缩性和适应性等问题只是简要介绍,因为这些将在后续章节中深入讨论。

在下一章中,我们将向您介绍去中心化的概念,这是区块链及其广泛应用背后理念的核心。

第二章:分散化

分散化并不是一个新概念。在战略、管理和政府,它已经被使用了很长时间。分散化的基本理念是将控制权和权威分配到组织的边缘,而不是一个中央机构完全控制组织。这种配置可以为组织带来多项益处,比如提高效率、加速决策、更好的激励和减轻高层管理的负担。

在本章中,我们将讨论区块链背景下的分散化概念。区块链的根本基础是没有单一中央机构在控制,本章中,我们将介绍各种分散化方法和实现此目标的途径的例子。此外,我们将详细讨论区块链生态系统的分散化、分散化应用以及实现分散化的平台。此外,我们还将向您介绍许多出自分散化区块链技术的令人振奋的应用和想法。

使用区块链进行分散化

分散化是区块链技术提供的核心益处和服务。按设计,区块链是一个提供无需任何中介和可以通过共识机制选择许多不同领袖来运作的平台。这种模式允许任何人竞争成为决策机构。这种竞争受共识机制管理,最常用的方法被称为工作证明PoW)。

分散化在不同程度上应用各种模型,从半分散化模型到完全分散化模型,这取决于要求和情况。分散化可以从区块链的角度看作是一种重新设计现有应用和范式的机制,或者构建新的应用,以便完全控制用户。

信息与通信技术ICT)传统上基于中心化范式,其中数据库或应用服务器受中央管理机构的控制,比如系统管理员。随着比特币和区块链技术的出现,这种模型已经改变,现在存在这种技术,允许任何人开始一个分散化系统,并在没有单一故障点或单一受信任机构的条件下运作。它可以自主运行,也可以根据在区块链上运行的分散化应用的类型和模型所使用的治理类型而需要一些人为干预。

以下图表显示了当前存在的不同类型的系统:中心化、分散化和分布式。这个概念最早是由保罗·巴伦在分布式通信:分布式通信网络导论(兰德公司,1964 年)中发布的:

不同类型的网络/系统

中心化系统是传统的(客户-服务器)IT 系统,其中有一个单一的权威控制系统,并且完全负责系统上的所有操作。所有中心化系统的用户都依赖于单一的服务来源。包括谷歌、亚马逊、eBay、苹果应用商店等大多数在线服务提供商都使用这种传统模式来提供服务。

分布式系统中,数据和计算分布在网络中的多个节点上。有时,这个术语与并行计算混淆。虽然在定义上有一些重叠,但这些系统的主要区别在于,在并行计算系统中,所有节点同时执行计算以实现结果;例如,天气研究和预测、模拟和金融建模中使用并行计算平台。另一方面,在分布式系统中,计算可能不会并行进行,并且数据被复制到多个用户视为单一一致系统的节点上。这两种模型的变体都用于实现容错性和速度。在并行系统模型中,仍然存在一个对所有节点进行控制的中央权威,它管理着处理。这意味着系统仍然具有中央化的特性。

去中心化系统与分布式系统的关键区别在于,在分布式系统中仍然存在一个统治整个系统的中央权威;而在去中心化系统中,没有这样的权威存在。

去中心化系统是一种节点不依赖于单个主节点的网络类型;相反,控制权分布在许多节点之间。这类似于组织中的每个部门负责自己的数据库服务器的模型,从而剥夺了中央服务器的权力,并将其分配给管理自己数据库的子部门。

去中心化范式中的一个重要创新是去中心化共识。这种机制是随着比特币而出现的,它使用户可以通过共识算法就某事达成一致,而无需中央、可信赖的第三方、中介或服务提供商。

去中心化的方法

两种方法可用于实现去中心化:去中介化和竞争(基于竞赛驱动的去中心化)。这些方法将在接下来的章节中详细讨论。

去中介化

去中心化的概念可以通过一个例子来解释。想象一下,你想把钱汇给另一个国家的朋友。你去银行,他们会收取一定费用,将你的钱转到那个国家的银行。在这种情况下,银行维护着一个中央数据库,更新并确认你已经汇款。使用区块链技术,可以直接把这笔钱发送到你朋友的账户,而不需要银行。你只需要知道你朋友在区块链上的地址。这样,中间人——银行就不再需要,通过去中心化实现了分散化。然而,通过去中心化实现金融行业的实际分散化在很大程度上是有争议的,因为存在大量的监管和合规要求。尽管如此,这种模式不仅可以在金融领域使用,也可以在许多其他行业使用。

竞争驱动的分散化

在涉及竞争的方法中,不同的服务提供商互相竞争,以便被系统选中提供服务。这种模式并不能实现完全的分散化。然而,在一定程度上,它确保了中介或服务提供商不会垄断服务。在区块链技术的背景下,可以设想一个系统,智能合约可以根据声誉、历史得分、评论和服务质量从大量提供商中选择外部数据提供商。

这种方法不会导致完全的分散化,但它允许智能合约根据刚才提到的标准自由选择。这样,一个竞争的环境在服务提供商之间培育,他们互相竞争成为首选的数据提供商。

在下图中,显示了不同级别的分散化。左侧显示了传统的方法,其中一个中心系统处于控制之下;右侧实现了完全去中心化,中间人完全被移除。在中间,竞争中介或服务提供商被选择。在这个层面上,中介或服务提供商根据声誉或投票来选择,从而实现了部分分散化。

分散化规模

尽管分散化有许多好处,包括透明度、效率、节省成本、建立可信生态系统,以及在某些情况下的隐私和匿名性,但一些挑战,如安全要求、软件漏洞和人为错误需要深入研究。

例如,在像比特币或以太坊这样的去中心化系统中,安全通常由私钥提供,那么如何确保与这些私钥相关联的智能资产在私钥丢失或由于智能合约代码中的错误或去中心化应用程序变得容易受攻击时不会变得无用?在着手通过区块链和去中心化应用程序去实现一切去中心化之前,重要的是要理解并不是一切都可以或需要去中心化。

这种观点提出了一些基本问题。真的需要区块链吗?何时需要区块链?在什么情况下优先选择区块链而不是传统数据库?为了回答这些问题,请通过这里提出的简单问题集:

  1. 是否需要高数据吞吐量?如果对这个问题的答案是肯定的,则使用传统数据库。

  2. 更新是否由中央控制?如果是,则使用传统数据库。

  3. 用户是否彼此信任?如果是,则使用传统数据库。

  4. 用户是否匿名?如果是,则使用公共区块链;如果不是,则使用私有区块链。

  5. 如果需要在财团内部维持共识,则使用私有区块链,否则使用公共区块链。

回答所有这些问题可以帮助理解是否需要区块链。在这个模型提出的问题之外,还有许多其他问题需要考虑,比如延迟、共识机制的选择、是否需要共识、以及共识将在何处达成。如果共识由财团内部维持,那么应该使用私有区块链;否则,如果需要在多个实体之间公开达成共识,那么应该考虑公共区块链解决方案。在决定使用区块链还是传统数据库时,还应考虑其他方面,比如不可变性。如果需要严格的数据不可变性,则应使用公共区块链;否则,中央数据库可能是一个选择。

随着区块链技术的成熟,对于这种模型会有更多的问题。然而,就目前而言,这组问题已足以确定是否需要基于区块链的解决方案。

去中心化的途径

尽管之前已经存在了一些系统,包括 BitTorrent 和 Gnutella 文件共享系统,这些系统在一定程度上可以被归类为去中心化。然而,随着区块链技术的出现,许多倡议现在正在利用这种新技术来实现去中心化。比特币区块链通常是许多人的首选,因为在撰写本文时,它已被证明是最具韧性和安全的区块链,市值接近 1450 亿美元。另外,其他区块链,如以太坊,也是许多开发者构建去中心化应用程序的首选工具。与比特币相比,以太坊因其允许通过智能合约将任何业务逻辑编程到区块链中的灵活性而成为更为突出的选择。

如何去中心化

阿文德·纳拉亚南和其他人在他们的书中提出了一个框架,比特币与加密货币技术普林斯顿大学出版社,可用于在区块链技术的背景下评估各种问题的去中心化要求。该框架提出了四个问题,它们的答案提供了对系统如何实现去中心化的清晰理解:

  1. 正在去中心化什么?

  2. 需要什么程度的去中心化?

  3. 使用了什么样的区块链?

  4. 使用了什么安全机制?

第一个问题简单地要求您确定正在去中心化的系统是什么。这可以是任何系统,例如身份系统或交易系统。

第二个问题要求您通过审查前面讨论过的去中心化规模来指定所需的去中心化水平。它可以是完全的无中介或部分的无中介。

第三个问题要求开发者确定哪种区块链适用于特定应用。它可以是比特币区块链、以太坊区块链或任何其他被认为适合特定应用的区块链。

最后,需要解决的一个基本问题是如何保证去中心化系统的安全性。例如,安全机制可以基于原子性,其中事务要么完全执行,要么根本不执行。这种确定性方法确保了系统的完整性。其他机制可能基于声誉,允许对系统的信任程度有不同的看法。

去中心化框架示例

让我们以一个选定为去中心化的应用程序的例子——货币转账系统来评估。前面讨论过的四个问题用于评估该应用程序的去中心化要求。这些问题的答案如下:

  1. 转账系统

  2. 无中介

  3. 比特币

  4. 原子性

答案表明,通过在比特币区块链上实施去中心化的转账系统,可以通过去除中间商来去中心化,而且还将通过原子性提供安全保证。原子性将确保交易完全成功执行或根本不执行。我们选择比特币区块链,因为它是历史最悠久的区块链,经受住了时间的考验。

类似地,这个框架可以用于任何需要从去中心化角度进行评估的系统。对这四个简单问题的回答有助于澄清采取什么样的方法来去中心化系统。

区块链和完整生态系统的去中心化

要实现完全的去中心化,必须确保区块链周围的环境也是去中心化的。区块链是在传统系统之上运行的分布式账本。这些元素包括存储、通信和计算。还有其他因素,比如身份和财富,传统上基于中心化的范式,有必要也去中心化这些方面,以实现足够去中心化的生态系统。

存储

数据可以直接存储在区块链中,由此事实实现了去中心化。然而,这种方法的一个显著缺点是,从设计上来说,区块链不适合存储大量数据。它可以存储简单的交易和一些任意数据,但肯定不适合存储图像或大块数据,就像传统数据库系统的情况一样。

存储数据的更好选择是使用分布式哈希表DHTs)。DHTs 最初是在对等文件共享软件中使用的,比如 BitTorrent、Napster、Kazaa 和 Gnutella。DHT 研究由 CAN、Chord、Pastry 和 Tapestry 项目广泛推广。BitTorrent 是最可扩展和最快的网络,但 BitTorrent 和其他网络的问题在于,用户没有动力将文件永久保存。用户通常不会永久保留文件,如果拥有某些数据的节点离开网络,则无法检索到这些数据,除非需要这些节点重新加入网络,以便文件再次变得可用。

这里有两个主要要求,即高可用性和链路稳定性,这意味着在需要时数据应该可用,网络链路也应该始终可访问。胡安·贝内特(Juan Benet)的星际文件系统IPFS)具备这两个特性,其愿景是通过替换 HTTP 协议来提供一个去中心化的万维网。IPFS 使用 Kademlia DHT 和 Merkle 有向无环图DAG)来分别提供存储和搜索功能。DHTs 和 DAGs 的概念将在第六章 公钥加密 中详细介绍。

存储数据的激励机制是基于一个称为 Filecoin 的协议,该协议向使用 Bitswap 机制存储数据的节点支付激励。Bitswap 机制允许节点保持字节发送或接收的简单分类账关系。此外,IPFS 使用基于 Git 的版本控制机制,以提供对数据版本控制的结构化和控制。

还有其他的数据存储选择,如以太坊 Swarm、Storj 和 MaidSafe。以太坊拥有自己的分散式和分布式生态系统,使用 Swarm 进行存储和使用 Whisper 协议进行通信。MaidSafe 旨在提供一个分散式的万维网。所有这些项目在本书的后文中将会更详细地讨论。

BigchainDB 是另一个旨在提供可扩展、快速和线性可扩展的分散式数据库的存储层分散项目,与传统的文件系统相对立。BigchainDB 与以太坊和 IPFS 等分散处理平台和文件系统相辅相成。

通信

互联网(区块链中的通信层)被认为是分散式的。这种观念在某种程度上是正确的,因为互联网的最初愿景是开发一种分散式的通信系统。诸如电子邮件和在线存储等服务现在都是基于一种范式,其中服务提供商控制着,用户信任这些提供商授予他们所请求的服务访问权限。这种模式是建立在对中央权威(服务提供商)的无条件信任之上的,用户无法控制其数据。甚至用户密码也存储在可信的第三方系统上。

因此,有必要以某种方式为个人用户提供控制权,以保证他们的数据访问不依赖于单一的第三方。对互联网的访问(通信层)基于充当互联网用户的中心枢纽的互联网服务提供商ISP)。如果 ISP 因任何原因关闭,那么在这种模式下将无法进行任何通信。

另一种选择是使用网状网络。尽管与互联网相比,它们的功能受到限制,但它们仍然提供了一种分散式的选择,其中节点可以直接相互通信,而无需像 ISP 这样的中心枢纽。

Meshnet 的一个例子是 FireChat(www.opengarden.com/firechat.html),它允许 iPhone 用户以点对点的方式直接通信,无需互联网连接。

现在想象一种网络,允许用户控制他们的通信;没有人可以因任何原因关闭它。这可能是区块链生态系统中分散通信网络的下一步。必须指出的是,这种模式可能只在互联网受到政府审查和控制的司法管辖区中才至关重要。

正如前文所述,互联网的最初愿景是构建一个去中心化的网络;然而,多年来,随着谷歌、亚马逊和 eBay 等大型服务提供商的出现,控制权正转向这些大型参与者。例如,电子邮件本质上是一个去中心化系统;也就是说,任何人都可以轻松运行一个电子邮件服务器,并开始发送和接收电子邮件。还有更好的选择,例如 Gmail 和 Outlook.com,它们已经为最终用户提供了托管服务,因此人们自然倾向于从这些大型集中服务中进行选择,因为它们更方便和免费。这是一个例子,显示了互联网如何向中心化发展。

然而,免费服务是以暴露有价值的个人数据为代价的,许多用户并不知道这一事实。区块链再次向世界展示了去中心化的愿景,现在人们正在协同努力利用这项技术,并利用它所能提供的好处。

计算能力与去中心化

计算或处理能力的去中心化是通过像以太坊这样的区块链技术实现的,其中嵌入了业务逻辑的智能合约可以在区块链网络上运行。其他区块链技术也提供类似的处理层平台,其中业务逻辑可以以去中心化的方式在网络上运行。

下图显示了一个去中心化生态系统概览。在底层,互联网或 Meshnets 提供了一个去中心化的通信层。在上一层,存储层使用 IPFS 和 BigchainDB 等技术实现去中心化。最后,在上一层中,您可以看到区块链作为一个去中心化的处理(计算)层。区块链在有限的程度上也可以提供存储层,但这严重影响了系统的速度和容量。因此,其他解决方案,如 IPFS 和 BigchainDB,更适合以去中心化方式存储大量数据。身份、财富层显示在顶层。在互联网上,身份是一个庞大的话题,诸如 BitAuth 和 OpenID 等系统提供了具有不同程度的去中心化和安全假设的身份验证和识别服务。

去中心化生态系统

区块链能够提供各种与去中心化相关的问题的解决方案。一个与身份标识相关的概念被称为Zooko's Triangle要求网络协议中的命名系统是安全的、去中心化的,并且能够为用户提供有意义且易记的名字。猜想认为一个系统同时只能具备这三个属性中的两个。然而,随着 Namecoin 区块链的出现,这个问题得到了解决。现在可以通过 Namecoin 区块链实现安全、去中心化和有意义的名称。然而,这并非万能之策,而且伴随许多挑战,比如依赖用户安全存储和维护私钥。这也引发了其他关于去中心化对特定问题适用性的一般性问题。

去中心化可能并非适用于每种情境。在许多情况下,声誉良好的集中式系统往往效果更好。例如,来自谷歌或微软等知名公司的电子邮件平台相比于用户在互联网上托管的个人电子邮件服务器提供更好的服务。

正在进行许多项目,致力于开发更全面的分布式区块链系统解决方案。例如,Swarm 和 Whisper 被开发出来,用于为以太坊区块链提供去中心化存储和通讯。

随着去中心化范式的出现,媒体和学术文献中现在出现了不同的术语和流行语。随着区块链技术的出现,现在可以在分散组织DOs)和其他类似构造的软件版本中构建传统的物理组织,我们将很快详细研究。

在去中心化的背景下,以下概念值得讨论。

智能合约

智能合约是一个去中心化程序。智能合约并不一定需要区块链才能运行;然而,由于区块链技术提供的安全性优势,区块链已成为智能合约的标准去中心化执行平台。

一个智能合约通常包含一些业务逻辑和有限的数据。如果满足特定标准,业务逻辑将被执行。区块链中的参与者使用这些智能合约,或者它们代表网络参与者自主运行。

第四章将提供更多关于智能合约的信息,智能合约

分散组织

DO 是运行在区块链上的软件程序,基于实际组织与人员和协议的构想。一旦以智能合约或一组智能合约的形式添加到区块链中,它就变得去中心化,各方根据 DO 软件内定义的代码相互交互。

去中心化自治组织

就像 DOs 一样,去中心化自治组织(DAO)也是在区块链上运行的计算机程序,其中包含治理和商业逻辑规则。DAO 和 DO 本质上是相同的。然而,主要区别在于 DAO 是自治的,这意味着它们完全自动化并包含人工智能逻辑。而 DO 则缺乏这一特征,依赖于人员输入来执行业务逻辑。

以太坊区块链带头引入了 DAO。在 DAO 中,代码被视为统治实体,而不是人或书面合同。然而,人类策展人维护这个代码,并担任社区的提案评估者。如果来自代币持有人(参与者)的足够的意见,DAO 有能力雇佣外部承包商。

最著名的 DAO 项目是 The DAO,它在众筹阶段筹集了 1.68 亿美元。The DAO 项目旨在成为一个风险投资基金,旨在提供一个没有单一实体拥有者的去中心化商业模式。不幸的是,该项目由于 DAO 代码中的一个漏洞而被黑客入侵,价值数百万美元的以太币(ETH)被转移到了黑客创建的子 DAO 中。以太坊区块链需要进行硬分叉来逆转黑客行为的影响,并启动资金的恢复。这一事件引发了对智能合约代码安全性、质量和必要彻底测试的探讨,以确保其完整性和充分控制。尤其是在学术界,目前正在进行其他项目,旨在正规化智能合约的编码和测试。

目前,DAO 没有任何法律地位,尽管它们可能包含执行某些协议和条件的智能代码。然而,这些规则目前在现实世界的法律体系中毫无价值。也许有一天,一个无需人类干预的代码,由执法机构或监管机构委托的自治代理(AA)将包含规则和法规,这些规则和法规可能被嵌入 DAO,以确保其在法律和合规方面的完整性。DAO 是纯粹的去中心化实体,使它们能在任何司法管辖区内运行。因此,它们引发了一个很大的问题,即如何将现行的法律体系应用于如此多样化的司法管辖区和地理区域。

去中心化自治公司

分散自治公司 (DACs) 在概念上类似于 DAOs,尽管被认为是其中的一个较小的子集。DACs 和 DAOs 的定义有时可能重叠,但总体区别是 DAOs 通常被认为是非盈利性的;而 DACs 可以通过向参与者提供股份赚取利润,并向他们支付股息。DACs 可以根据其程序逻辑自动运营业务,无需人类干预。

分散自治社会

分散自治社会 (DASs) 是一个概念,整个社会可以借助多个复杂的智能合约以及 DAOs 和分散化应用 (DApps) 运行自主地在区块链上。这种模型并不一定转化为自由主义意识形态,也不是基于完全的自由主义思想;相反,许多政府通常提供的服务可以通过区块链提供,比如政府身份证系统、护照以及土地、婚姻和出生记录。另一种理论是,如果一个政府腐败,中心化系统无法提供社会所需的满意水平的信任,那么这个社会可以在区块链上启动自己的虚拟社区,由分散化共识和透明度驱动。这种概念可能看起来像一个自由主义者或密码朋克的梦想,但在区块链上完全可行。

分散应用 (DApps)

到目前为止提到的所有想法都属于更广泛的 DApps 范畴。DAOs、DACs 和 DOs 是在点对点网络的区块链上运行的 DApps。它们代表了分散化技术的最新进展。另一方面,DApps 是可以在各自的区块链上运行的软件程序,使用现有的建立了的区块链,或者仅使用现有区块链的协议。这些被称为类型 I、类型 II 和类型 III DApps。

分散应用的要求

要被视为分散化,一个应用必须符合以下标准。这个定义是由约翰斯顿等人在白皮书《分散化应用的普遍理论,Dapps》中提供的:

  • DApp 应该是完全开源和自主的,没有任何单一实体控制大部分代币。应用的所有更改都必须基于社区反馈达成共识。

  • 应用的数据和操作记录必须经过加密保护,并存储在一个公共的、分散化的区块链上,以避免任何中心化故障点。

  • 应用必须使用加密代币为那些为应用贡献价值的人提供访问和奖励,例如比特币矿工。

  • 代币必须由 DApp 根据标准的加密算法生成。这些代币的生成充当对贡献者(例如矿工)价值的证明。

DApp 的运作

通过诸如 PoW 和 PoS 等共识算法,DApp 可以实现共识的建立。到目前为止,只有 PoW 被发现非常抵抗 51%攻击,这一点从比特币上就可以看出来。此外,DApp 可以通过挖矿、筹款和开发来分发代币(硬币)。

DApp 示例

这里提供了一些去中心化应用的示例。

KYC-Chain

该应用提供了基于智能合约安全、便捷地管理了解您的客户KYC)数据的功能。

OpenBazaar

这是一个去中心化的点对点网络,使得商业活动可以直接在卖家和买家之间进行,而不是依赖于像 eBay 和亚马逊这样的中心方。需要注意的是,该系统并不是建立在区块链之上;相反,DHT 在点对点网络中被用来实现对等节点之间的直接通信和数据共享。它利用比特币和其他各种加密货币作为支付方式。

Lazooz

这是 Uber 的去中心化等价物。它允许点对点共享乘车和用户通过运动证明获得激励,他们可以获得 Zooz 硬币。

许多其他 DApp 已经构建在以太坊区块链上,并在dapps.ethercasts.com/展示。

去中心化平台

今天,有许多平台可用于去中心化。事实上,区块链网络的基本特征是提供去中心化。因此,任何区块链网络,如比特币、以太坊、Hyperledger Fabric 或 Quorum 都可以用来提供去中心化服务。全球许多组织都推出了承诺使分布式应用程序开发简单、易于访问和安全的平台。接下来描述了其中一些平台。

以太坊

以太坊名列榜首,是第一个引入图灵完备语言和虚拟机概念的区块链。这与比特币和许多其他加密货币的有限脚本语言形成了鲜明对比。随着其名为 Solidity 的图灵完备语言的可用性,无限的可能性为去中心化应用的开发打开了大门。这个区块链最早由 Vitalik Buterin 在 2013 年提出,它提供了一个公共区块链来开发智能合约和去中心化应用程序。以太坊上的货币代币被称为以太币

MaidSafe

MaidSafe提供了一个由未使用的计算资源,如存储、处理能力和用户的数据连接所构成的SAFE网络,以供每个人安全访问。网络上的文件被分割成小数据块,被加密并随机分布到整个网络中。这些数据只能被相应的所有者取回。MaidSafe 的一个关键创新是,网络上的重复文件会被自动拒绝,这有助于减少额外的计算资源需求来管理负载。它使用 Safecoin 作为奖励贡献者的代币。

Lisk

Lisk是一个区块链应用开发和加密货币平台。它允许开发者使用 JavaScript 来构建去中心化应用,并将它们托管在各自的侧链中。Lisk 使用股份授权证明DPOS)机制来实现共识,其中可以选举 101 个节点来保护网络并提出区块。它使用 Node.js 和 JavaScript 后端,而前端允许使用标准技术,如 CSS3、HTML5 和 JavaScript。

Lisk 使用LSK币作为区块链上的货币。Lisk 的另一个派生产品是 Rise,这是一个基于 Lisk 的去中心化应用和数字货币平台。其更注重系统的安全性。

对这些平台和其他平台更实用的介绍将在后面的章节中提供。

摘要

在本章中,我们介绍了去中心化的概念,这是区块链技术提供的核心服务。虽然去中心化的概念并不新鲜,但在区块链世界中它已经重新获得了重要意义。因此,最近已经推出了基于去中心化架构的各种应用程序。

我们从介绍去中心化的概念开始了这一章。接下来,我们从区块链的角度讨论了去中心化。此外,我们向您介绍了与区块链技术和去中心化相关的不同层次的概念,以及随着区块链技术和去中心化的出现而出现的一些新概念和术语,包括 DAO、DAC 和 DApp。最后,我们看了一些去中心化应用的示例。

在下一章,我们将了解以太坊是如何运作的,以及我们可以使用以太坊开发什么。我们还将介绍重要的以太坊客户端和节点实现。

第三章:理解以太坊的工作原理

在本章中,我们将深入了解以太坊的工作原理以及我们可以使用以太坊开发什么。我们还将看到重要的以太坊客户端和节点实现。

在本章中,我们将涵盖以下主题:

  • 以太坊用户账户

  • 什么是智能合约,它们是如何工作的?

  • 以太坊虚拟机

  • 在工作量证明共识协议中,挖矿是如何工作的?

  • 学习如何使用 geth 命令

  • 设置以太坊钱包和 Mist

  • Whisper 和 Swarm 概述

  • 以太坊的未来

以太坊概述

以太坊是一个去中心化的平台,允许我们在其上部署 DApps。智能合约使用 Solidity 编程语言编写。使用一个或多个智能合约创建 DApps。智能合约是按照编程方式精确运行的程序,没有任何停机、审查、欺诈或第三方接口的可能性。在以太坊中,智能合约可以用几种编程语言编写,包括 Solidity、LLL 和 Serpent。Solidity 是这些语言中最流行的。

以太坊有一种名为以太的内部货币。要部署智能合约或调用它们的方法,我们需要以太。一个智能合约可以有多个实例,就像任何其他 DApp 一样,每个实例都由其唯一地址标识。用户账户和智能合约都可以持有以太。

以太坊使用区块链数据结构和工作量证明共识协议。智能合约的方法可以通过交易或另一种方法调用。网络中有两种类型的节点:常规节点和矿工。常规节点只有区块链的副本,而矿工通过挖掘区块来构建区块链。

以太坊账户

要创建一个以太坊账户,我们只需要一个非对称密钥对。有各种算法,如 RSA、ECC 等,用于生成非对称加密密钥。以太坊使用椭圆曲线加密ECC)。ECC 有各种参数。这些参数用于调整速度和安全性。以太坊使用 secp256k1 参数。要深入了解 ECC 及其参数将需要数学知识,而且深入理解并不是构建使用以太坊的 DApps 所必需的。

以太坊使用 256 位加密。以太坊私钥/公钥是一个 256 位的数字。由于处理器无法表示如此大的数字,因此它被编码为长度为 64 的十六进制字符串。

每个账户都由一个地址表示。一旦我们有了生成地址所需的密钥,以下是从公钥生成地址的步骤:

  1. 首先,生成公钥的 keccak-256 哈希。它将给出一个 256 位的数字。

  2. 丢弃前 96 位,也就是 12 字节。现在你应该有 160 位的二进制数据,也就是 20 字节。

  3. 现在将地址编码为十六进制字符串。因此,最终您将得到一个包含 40 个字符的字节串,这就是您的账户地址。

现在任何人都可以向这个地址发送以太币。

交易

一个交易是一个签名的数据包,用于将以太币从一个账户转移到另一个账户或合约,调用合约的方法,或部署新合约。交易使用ECDSA椭圆曲线数字签名算法)进行签名,这是一种基于 ECC 的数字签名算法。交易包含了消息的接收者,一个标识发送者并证明其意图的签名,要转移的以太币数量,交易执行允许的最大计算步骤数(称为燃气限制),以及发送交易者愿意支付的每个计算步骤的成本(称为燃气价格)。如果交易的意图是调用合约的方法,则还包含输入数据;如果意图是部署合约,则可以包含初始化代码。燃气使用量和燃气价格的乘积被称为交易费用。要发送以太币或执行合约方法,您需要将交易广播到网络。发送者需要用其私钥对交易进行签名。

如果我们确信一个交易将永远出现在区块链中,那么该交易被认为是已确认的。建议在假设交易已确认之前等待 15 个确认。

共识

以太坊网络中的每个节点都保存着区块链的副本。我们需要确保节点无法篡改区块链,同时我们也需要一种机制来检查一个区块是否有效。而且,如果我们遇到两个不同的有效区块链,我们需要有一种方法来找出应该选择哪一个。

以太坊使用工作量证明共识协议来保持区块链的防篡改性。工作量证明系统涉及解决一个复杂的谜题来创建一个新的区块。解决这个谜题应该需要大量的计算能力,从而使创建区块变得困难。在工作量证明系统中创建区块的过程称为挖矿。矿工是网络中挖掘区块的节点。所有使用工作量证明的 DApp 都不会完全实现相同的一组算法。它们可能在矿工需要解决的谜题、谜题的难度、解决它需要多长时间等方面有所不同。我们将学习有关以太坊的工作量证明。

任何人都可以成为网络中的矿工。每个矿工都单独解决谜题;第一个解决谜题的矿工是赢家,并获得五个以太和该区块中所有交易的交易费用。如果您拥有比网络中其他任何节点更强大的处理器,并不意味着您总是会成功,因为各个矿工的谜题参数并不完全相同。但是,相反,如果您拥有比网络中其他任何节点更强大的处理器,这将增加您成功的机会。工作量证明的行为就像是一个抽奖系统,处理能力可以被看作是一个人持有的抽奖券数量。网络安全性不是由矿工的总数来衡量;而是由网络的总处理能力来衡量。

区块链可以拥有的区块数量没有限制,也没有总以太能够产生的限制。一旦一个矿工成功挖矿,他将向网络中的所有其他节点广播该区块。一个区块包含一个头部和一组交易。每个区块持有上一个区块的哈希,从而创建了一个连接的链。

让我们来看看矿工需要解决的谜题是什么,以及在高层次上是如何解决的。为了挖矿,首先,矿工收集新的未挖掘的交易广播到它,然后过滤掉无效的交易。要使交易有效,必须使用私钥正确签名,账户必须有足够的余额进行交易,等等。现在矿工创建一个区块,它包括头部和内容。内容是区块包含的交易列表。头部包含上一个区块的哈希、区块编号、随机数、目标、时间戳、难度、矿工的地址等等。时间戳代表区块初始时刻。然后,随机数是一个无意义的值,它被调整以找到谜题的解决方案。这个谜题基本上就是找到这样的随机数值,当区块被哈希时,哈希值小于或等于目标值。以太坊使用 ethash 哈希算法。找到随机数的唯一方法是枚举所有可能性。目标值是一个 256 位数,它基于各种因素计算得出。头部中的难度值是目标的不同表示,使之更容易处理。目标值越低,找到随机数所需的时间越长,目标值越高,则找到随机数所需的时间越短。这里是计算谜题难度的公式:

current_block_difficulty = previous_block_difficulty + previous_block_difficulty // 2048 * max(1 - (current_block_timestamp - previous_blocktimestamp) // 10, -99) + int(2 ** ((current_block_number // 100000) - 2)) 

现在,网络中的任何节点都可以通过首先检查区块链中的交易是否有效、时间戳验证、然后检查所有区块的目标和随机数是否有效、矿工是否分配了有效的奖励,等等来检查他们拥有的区块链是否有效。

如果网络中的节点接收到两个不同的有效区块链,那么所有区块的组合难度更高的区块链被视为有效区块链。

现在,举个例子,如果网络中的一个节点改变了一个区块中的一些交易,那么该节点需要计算所有后续区块的随机数。当它重新找到后续区块的随机数时,网络可能已经挖掘了更多的区块,因此拒绝此区块,因为其组合难度将更低。

时间戳

计算区块目标的公式需要当前时间戳,而且每个区块的头部都附有当前时间戳。没有什么能阻止矿工在挖掘新区块时使用其他时间戳而不是当前时间戳,但他们通常不会这样做,因为时间戳验证会失败,其他节点不会接受该区块,这将是矿工资源的浪费。当矿工广播一个新挖掘的区块时,它的时间戳将通过检查时间戳是否大于前一个区块的时间戳来进行验证。如果一个矿工使用的时间戳大于当前时间戳,难度将会很低,因为难度与当前时间戳成反比;因此,区块时间戳为当前时间戳的矿工将被网络接受,因为它将具有更高的难度。如果一个矿工使用的时间戳大于前一个区块的时间戳并且小于当前时间戳,难度将会更高,因此,挖掘该区块将需要更长的时间;当区块挖掘完成时,网络可能已经生成了更多的区块,因此,该区块将被拒绝,因为恶意矿工的区块链难度将低于网络的区块链难度。由于这些原因,矿工始终使用准确的时间戳,否则他们将得不到任何好处。

随机数

随机数是一个 64 位无符号整数。随机数是谜题的解答。矿工不断递增随机数,直到找到解答。现在你一定在想,如果有一个矿工的哈希功率比网络中的任何其他矿工都要高,那么该矿工总是会第一个找到随机数吗?嗯,并不会。

矿工正在挖掘的区块的哈希值对于每个矿工都是不同的,因为哈希值取决于诸如时间戳、矿工地址等因素,不太可能对所有矿工都相同。因此,这不是解决难题的竞赛;而是一个抽奖系统。当然,根据其哈希功率,矿工有可能幸运地找到下一个区块,但这并不意味着矿工总是能找到下一个区块。

区块时间

我们之前看到的区块难度公式使用了一个 10 秒的阈值,以确保父区块和子区块挖掘之间的时间差在 10-20 秒之间。但为什么是 10-20 秒而不是其他值?为什么有这样一个恒定的时间差限制,而不是恒定的难度?

假设我们有一个恒定的难度,矿工只需要找到一个随机数(nonce),使得区块的哈希值小于或等于该难度。假设难度很高;在这种情况下,用户将无法知道将以太币发送给另一个用户需要多长时间。如果网络的计算能力不足以快速找到满足难度的随机数,可能需要很长时间。有时,网络可能会幸运地快速找到随机数。但是这种系统很难吸引用户,因为用户始终想知道交易完成需要多长时间,就像我们从一个银行账户转账到另一个银行账户时,我们会被给予一个完成交易的时间段一样。如果恒定的难度值较低,将会损害区块链的安全性,因为大型矿工可以比小型矿工更快地挖掘区块,而网络中最大的矿工将有能力控制 DApp。不可能找到一个能使网络稳定的恒定难度值,因为网络的计算能力并不是恒定的。

现在我们知道为什么我们应该始终有一个平均时间来确定网络挖掘一个区块应该花费多长时间。现在的问题是,最适合的平均时间是什么,因为它可以是从 1 秒到无限秒的任何时间。通过降低难度可以实现较小的平均时间,通过增加难度可以实现较高的平均时间。但是较低和较高平均时间的优缺点是什么?在我们讨论这个问题之前,我们需要首先了解什么是陈旧区块。

如果两个矿工几乎同时挖掘下一个区块会发生什么?这两个区块肯定都是有效的,但是区块链无法容纳具有相同区块编号的两个区块,而且两个矿工也无法获得奖励。虽然这是一个常见的问题,但解决方法很简单。最终,拥有更高难度的区块将被网络接受。因此,最终被留下的有效区块被称为陈旧区块。

网络中产生的陈旧区块总数与生成新区块的平均时间成反比。较短的区块生成时间意味着新挖的区块在整个网络中传播的时间较短,而且多个矿工更有可能在同一时间找到解决方案,因此在区块传播完毕时,其他一些矿工可能也已经解决了难题并广播了出去,从而导致陈旧区块。但是,如果平均区块生成时间较长,则多个矿工解决难题的机会较小,即使他们解决了难题,也可能存在解决时间间隔,此时第一个解决的区块已经传播,其他矿工可以停止挖掘该区块并开始挖掘下一个区块。如果网络中频繁发生陈旧区块,将导致重大问题,但如果它们很少发生,则不会造成任何伤害。

那么,陈旧区块有什么问题呢?嗯,它们延迟了交易的确认。当两个矿工几乎同时挖出一个区块时,它们可能没有相同的交易集,因此如果我们的交易出现在其中一个区块中,我们不能说它已经确认,因为包含交易的区块可能是陈旧的。因此,我们应该等待更多的区块被挖掘。由于陈旧区块,平均确认时间不等于平均区块生成时间。

陈旧区块是否会影响区块链安全性?是的,它们会。我们知道,网络的安全性由网络中矿工的总计算能力来衡量。当计算能力增加时,会增加难度,以确保区块不会比平均区块时间更早生成。因此,更高的难度意味着更安全的区块链,因为要篡改节点,现在需要更多的哈希能力,这使得篡改区块链变得更加困难;因此,可以说区块链更安全了。当两个区块几乎同时挖出时,我们将看到网络分成两个部分,分别在两个不同的区块链上工作,但其中一个将成为最终的区块链。因此,网络中工作在陈旧区块上的部分会在陈旧区块之上挖掘下一个区块,这导致网络的哈希能力损失,因为哈希能力被用于不必要的事情。由于失去了哈希能力,网络的两部分挖掘下一个区块的时间可能会比平均区块时间长,因此,在挖掘下一个区块后,难度会下降,因为挖掘该区块所用的时间比平均区块时间长。难度的降低会影响整体区块链的安全性。如果陈旧率过高,将严重影响区块链的安全性。

以太坊利用所谓的幽灵协议解决了由过时区块引起的安全问题。以太坊使用了修改过的实际幽灵协议。幽灵协议通过简单地将过时区块添加到主区块链中来掩盖安全问题,从而增加了区块链的总难度,因为区块链的总难度也包括过时区块的难度之和。但是,如何在不发生交易冲突的情况下将过时区块插入主区块链呢?嗯,任何区块都可以指定 0 个或多个过时区块。为了激励矿工包括过时区块,矿工会受到奖励。而且,过时区块的矿工也会受到奖励。过时区块中的交易不用于计算确认,并且,过时区块的矿工不会收到包含在过时区块中的交易的交易费。请注意,以太坊将过时区块称为叔区块。

这里是计算过时区块矿工获得多少奖励的公式。其余的奖励归叔区块所有,即包含孤立区块的区块:

(uncle_block_number + 8 - block_number) * 5 / 8 

由于不奖励过时区块的矿工不会对任何安全性造成伤害,您一定想知道为什么要奖励过时区块的矿工?嗯,当网络中频繁出现过时区块时,会出现另一个问题,通过奖励过时区块的矿工来解决。矿工应该获得类似于其对网络贡献的哈希功率百分比的奖励。当两个不同的矿工几乎同时挖出一个区块时,由于矿工挖掘下一个区块的效率更高,因此更有可能将由哈希功率更高的矿工挖出的区块添加到最终区块链中;因此,小矿工将失去奖励。如果过时率较低,这不是一个大问题,因为大矿工将获得少量奖励的增加;但是如果过时率较高,就会引起一个大问题,即网络中的大矿工最终会获得比其应该获得的奖励要多得多。幽灵协议通过奖励过时区块的矿工来平衡这一点。由于大矿工不会获得所有奖励,而是获得了比应获得的更多的奖励,因此我们不像对待叔区块那样奖励过时区块的矿工;相反,我们奖励一个较少的金额来平衡。前述的公式可以很好地平衡这一点。

幽灵限制了叔区块可以引用的总过时区块数量,以防止矿工简单地挖掘过时区块并使区块链停滞不前。

因此,无论网络中出现多少过时区块,它都在某种程度上影响着网络。过时区块的频率越高,网络受到的影响就越大。

分叉

当节点之间存在关于区块链有效性的冲突时,就会发生分叉,也就是说,在网络中可能存在多个区块链,每个区块链都由一些矿工验证。有三种类型的分叉:常规分叉、软分叉和硬分叉。

常规分叉是由于两个或更多的矿工几乎同时找到一个区块而导致的临时冲突。当其中一个区块的难度大于另一个区块时,冲突会得到解决。

对源代码的更改可能会导致冲突。根据冲突类型的不同,可能需要超过 50%的哈希算力的矿工进行升级,或者所有矿工都进行升级以解决冲突。当需要超过 50%的哈希算力的矿工进行升级以解决冲突时,称为软分叉,而当需要所有矿工都进行升级以解决冲突时,称为硬分叉。软分叉的一个例子是,如果源代码的更新使得一些旧的区块/交易无效,那么当超过 50%的哈希算力的矿工进行了升级,新的区块链将具有更高的难度,最终被整个网络接受。硬分叉的一个例子是,如果源代码的更新是更改矿工的奖励,那么所有矿工都需要升级以解决冲突。

以太坊自发布以来已经经历了各种硬分叉和软分叉。

创世区块

创世区块是区块链的第一个区块。它被分配给区块号 0。它是区块链中唯一一个不引用前一个区块的区块,因为没有前一个区块。它不包含任何交易,因为还没有产生任何以太。

网络中的两个节点只有在它们都有相同的创世区块时才会连接,也就是说,只有当两个对等体都有相同的创世区块时,区块同步才会发生,否则它们都将互相拒绝。高难度的不同创世区块不能替换低难度的创世区块。每个节点都会生成自己的创世区块。对于各种网络,创世区块都是硬编码到客户端中的。

以太币面值

与任何其他货币一样,以太币有各种面值。以下是各种面值:

  • 1 以太 = 1000000000000000000 韦

  • 1 以太 = 1000000000000000 兆韦

  • 1 以太 = 1000000000000 兆韦

  • 1 以太 = 1000000000 吉韦

  • 1 以太 = 1000000 萨博

  • 1 以太 = 1000 芬尼

  • 1 以太 = 0.001 兆以太

  • 1 以太 = 0.000001 兆以太

  • 1 以太 = 0.000000001 吉以太

  • 1 以太 = 0.000000000001 泰以太

以太坊虚拟机

EVM(或以太坊虚拟机)是以太坊智能合约字节码执行环境。网络中的每个节点都运行 EVM。所有节点都使用 EVM 执行指向智能合约的所有交易,因此每个节点都执行相同的计算并存储相同的值。只转移以太的交易也需要一些计算,即查找地址是否有余额并相应地扣除余额。

每个节点执行交易并存储最终状态有各种原因。例如,如果有一个智能合约存储了参加派对的每个人的姓名和详细信息,每当添加新成员时,就会向网络广播一个新的交易。对于网络中的任何节点来说,只需读取合约的最终状态就可以显示所有参加派对的人的详细信息。

每个交易在网络中都需要一些计算和存储。因此,需要有交易成本,否则整个网络将被垃圾交易淹没,而且没有交易成本,矿工就没有理由将交易包含在区块中,他们将开始挖掘空块。每个交易都需要不同数量的计算和存储;因此,每个交易都有不同的交易成本。

EVM 有两种实现方式,即字节码 VM 和 JIT-VM。在撰写本书时,JIT-VM 已经可以使用,但其开发尚未完成。无论哪种情况,Solidity 代码都会被编译为字节码。在 JIT-VM 的情况下,字节码还会被进一步编译。与其对应的字节码 VM 相比,JIT-VM 更高效。

Gas

Gas 是计算步骤的衡量单位。每个交易都需要包含一个 Gas 限制和一个愿意支付的每 Gas 费用(即每次计算支付的费用);矿工可以选择包含交易并收取费用。如果交易使用的 Gas 小于或等于 Gas 限制,则交易处理。如果总 Gas 超过了 Gas 限制,则所有更改都将被撤销,但交易仍然有效,并且矿工仍然可以收取费用(即可以使用的最大 Gas 和 Gas 价格的乘积)。

矿工决定 Gas 价格(即每次计算的价格)。如果交易的 Gas 价格低于矿工决定的 Gas 价格,则矿工将拒绝挖掘该交易。Gas 价格是以 wei 单位的金额。因此,如果 Gas 价格低于矿工所需的 Gas 价格,矿工可以拒绝将交易包含在区块中。

EVM 中的每个操作都被分配了消耗多少 Gas 的数量。

交易成本会影响账户可以转账给另一个账户的最大以太量。例如,如果一个账户的以太余额为五,它不能全部转移给另一个账户,因为如果所有以太都转移了,账户中就没有余额可以扣除交易费用。

如果交易调用了一个合约方法,并且该方法发送了一些以太币或调用了其他合约方法,则交易费用从调用合约方法的账户中扣除。

对等发现

要使节点成为网络的一部分,它需要连接到网络中的一些其他节点,以便广播交易/区块并监听新交易/区块。一个节点不需要连接到网络中的每个节点;相反,一个节点连接到一些其他节点。而这些节点连接到一些其他节点。通过这种方式,整个网络相互连接。

但是,由于没有中央服务器让所有人都能连接到以便交换信息,一个节点如何找到网络中的其他节点呢?以太坊有自己的节点发现协议来解决这个问题,该协议基于 Kadelima 协议。在节点发现协议中,我们有一种特殊类型的节点称为引导节点。引导节点在一段时间内维护着与它们连接的所有节点的列表。它们不保存区块链本身。当节点连接到以太坊网络时,它们首先连接到引导节点,后者分享了连接到它们的节点列表,在预定义的时间段内连接到它们。然后连接的对等方连接并与对等方同步。

可以有各种各样的以太坊实例,也就是各种网络,每个网络都有自己的网络 ID。两个主要的以太坊网络是主网和测试网。主网是在交易所交易其以太币的网络,而测试网是开发者用于测试的。到目前为止,我们已经学习了有关主网区块链的一切。

Bootnode 是以太坊引导节点的最流行实现。如果你想要托管自己的引导节点,可以使用 bootnode。

Whisper 和 Swarm

Whisper 和 Swarm 分别是由以太坊开发者开发的分布式通信协议和分布式存储平台。Whisper 是一种分布式通信协议,而 Swarm 是一个分布式文件系统。

Whisper 允许网络中的节点相互通信。它支持广播、用户间加密消息等功能。它并非设计用于传输大量数据。你可以在 github.com/ethereum/wiki/wiki/Whisper 了解更多关于 Whisper 的信息,并在 github.com/ethereum/wiki/wiki/Whisper-Overview 查看代码示例概述。

Swarm 类似于 Filecoin,主要在技术和激励方面有所不同。Filecoin 不惩罚存储,而 Swarm 则会惩罚存储;因此,这会进一步增加文件的可用性。你可能想知道激励在 Swarm 中是如何运作的。它是否有内部货币?实际上,Swarm 没有内部货币,而是使用以太坊作为激励。以太坊中有一个智能合约,用于跟踪激励。显然,智能合约无法与 Swarm 通信;取而代之的是,Swarm 与智能合约通信。因此,你通过智能合约向存储支付费用,并且在到期日期后,支付会释放给存储。你还可以向智能合约报告文件丢失的情况,这样智能合约可以惩罚相应的存储。你可以在 github.com/ethersphere/go-ethereum/wiki/IPFS-&-SWARM 了解更多关于 Swarm 和 IPFS/Filecoin 的区别,并在 github.com/ethersphere/go-ethereum/blob/bzz-config/bzz/bzzcontract/swarm.sol 查看智能合约代码。

在撰写本书时,Whisper 和 Swarm 仍在开发中;因此,还有许多事情不明朗。

Geth

Geth(也称为 go-ethereum)是以太坊、Whisper 和 Swarm 节点的实现。Geth 可用于成为它们中的所有部分,也可以只选择其中的某些部分。将它们合并的原因是使它们看起来像一个单一的 DApp,还可以通过一个节点,客户端就可以访问这三个 DApp。

Geth 是一个 CLI 应用程序。它是用 go 编程语言编写的。它适用于所有主要操作系统。当前版本的 geth 尚不支持 Swarm,仅支持 Whisper 的一些功能。在撰写本书时,最新版本的 geth 是 1.3.5。

安装 Geth

Geth 适用于 OS X、Linux 和 Windows。它支持两种安装类型:二进制安装和脚本安装。在撰写本书时,geth 的最新稳定版本是 1.4.13. 让我们看看如何在各种操作系统中使用二进制安装方法安装它。当需要修改 geth 源代码并安装它时,使用脚本安装。由于我们不想对源代码做任何更改,因此我们将选择二进制安装。

OS X

在 OS X 中安装 geth 的推荐方法是使用 brew。在终端中运行以下两个命令来安装 geth:

brew tap ethereum/ethereum 
brew install ethereum  

Ubuntu

在 Ubuntu 中安装 geth 的推荐方法是使用 apt-get。在 Ubuntu 终端中运行以下命令来安装 geth:

sudo apt-get install software-properties-common 
sudo add-apt-repository -y ppa:ethereum/ethereum 
sudo apt-get update 
sudo apt-get install ethereum

Windows

Geth 作为 Windows 的可执行文件提供。从github.com/ethereum/go-ethereum/wiki/Installation-instructions-for-Windows下载 zip 文件,并解压缩。在其中,您将找到geth.exe文件。

要了解有关在各种操作系统上安装 geth 的更多信息,请访问github.com/ethereum/go-ethereum/wiki/Building-Ethereum

JSON-RPC 和 JavaScript 控制台

Geth 为其他应用程序提供了使用 JSON-RPC 与其通信的 JSON-RPC API。Geth 使用 HTTP、WebSocket 和其他协议提供 JSON-RPC API。JSON-RPC 提供的 API 分为以下类别:admin、debug、eth、miner、net、personal、shh、txpool 和 web3。您可以在这里找到更多关于它的信息 github.com/ethereum/go-ethereum/wiki/JavaScript-Console

Geth 还提供了一个交互式 JavaScript 控制台,使用 JavaScript API 以编程方式与其交互。此交互式控制台使用 IPC 上的 JSON-RPC 与 geth 进行通信。我们将在后续章节中更多地了解有关 JSON-RPC 和 JavaScript API 的内容。

子命令和选项

让我们使用示例学习 geth 命令的一些重要子命令和选项。您可以使用帮助子命令找到所有子命令和选项的列表。我们将在接下来的章节中了解更多关于 geth 及其命令的内容。

连接到主网网络

以太坊网络中的节点默认使用30303端口进行通信。但是节点也可以自由监听其他端口号。

要连接到主网网络,只需运行geth命令。以下是如何明确指定网络 ID 并指定 geth 将存储下载的区块链的自定义目录的示例:

    geth --datadir "/users/packt/ethereum" --networkid 1

--datadir选项用于指定存储区块链的位置。如果未提供, 默认路径为$HOME/.ethereum

--networkid用于指定网络 ID。1 是主网网络的 ID。如果未提供,默认值为 1。测试网的网络 ID 为 2。

创建私有网络

要创建私有网络,只需提供一个随机网络 ID。私有网络通常是为开发目的创建的。Geth 还提供了与日志记录和调试相关的各种标志,在开发过程中非常有用。因此,我们可以使用--dev标志,而不是提供一个随机网络 ID 和放置各种日志记录和调试标志,它会启动一个私有网络并启用各种调试和日志记录标志。

创建账户

Geth 还可以让我们创建账户,即生成与其关联的密钥和地址。要创建账户,请使用以下命令:

    geth account new

当您运行此命令时,将要求您输入密码以加密您的账户。如果您忘记密码,将无法访问您的账户。

要获取本地钱包中所有账户的列表,请使用以下命令:

    geth account list

前面的命令将打印出所有账户地址的列表。默认情况下,密钥存储在 --datadir 路径中,但是您可以使用 --keystore 选项指定其他目录。

挖矿

默认情况下,geth 不会开始挖矿。要指示 geth 开始挖矿,只需提供 --mine 选项。与挖矿相关的还有一些其他选项:

    geth --mine --minerthreads 16 --minergpus '0,1,2' --etherbase '489b4e22aab35053ecd393b9f9c35f4f1de7b194' --unlock '489b4e22aab35053ecd393b9f9c35f4f1de7b194'

这里,除了 --mine 选项外,我们还提供了各种其他选项。 --minerthreads 选项指定了在哈希过程中要使用的线程总数。默认情况下,使用八个线程。 Etherbase 是挖矿所得奖励存入的地址。默认情况下,账户是加密的。因此,要访问账户中的以太币,我们需要解锁它,即解密账户。解密用于解密与账户关联的私钥。要开始挖矿,我们不需要解锁它,因为只需要地址来存入挖矿奖励。可以使用 -unlock 选项解锁一个或多个账户。通过使用逗号分隔地址,可以提供多个地址。

--minergpus 用于指定用于挖矿的 GPU。要获取 GPU 列表,请使用 geth gpuinfo 命令。对于每个 GPU,您需要拥有 1-2 GB 的 RAM。默认情况下,不使用 GPU,而只使用 CPU。

快速同步

撰写本书时,区块链大小约为 30 GB。如果您的互联网连接速度较慢,下载可能需要几个小时或几天。以太坊实现了一种快速同步算法,可以更快地下载区块链。

快速同步不会下载整个区块;相反,它只下载区块头、交易收据和最近的状态数据库。因此,我们不必下载和重播所有交易。为了检查区块链的完整性,该算法在每个定义的区块数之后下载一个完整的区块。要了解更多关于快速同步算法的信息,请访问github.com/ethereum/go-ethereum/pull/1889

在下载区块链时使用快速同步,需要在运行 geth 时使用 --fast 标志。

出于安全原因,快速同步仅在初始同步期间运行(即当节点自己的区块链为空时)。当一个节点成功地与网络同步后,快速同步将永远被禁用。作为额外的安全特性,如果快速同步在接近或在随机枢轴点之后失败,它将被禁用作为安全预防措施,并且节点将恢复到完全基于区块处理的同步。

以太坊钱包

以太坊钱包是一个以太坊 UI 客户端,它让你创建账户、发送以太币、部署合约、调用合约方法等。

以太坊钱包已捆绑了 geth。当你运行以太坊时,它会尝试找到本地的 geth 实例并连接到它,如果找不到正在运行的 geth,则启动自己的 geth 节点。以太坊钱包使用 IPC 与 geth 通信。Geth 支持基于文件的 IPC。

如果在运行 geth 时更改数据目录,则也会更改 IPC 文件路径。因此,为了让以太坊钱包找到并连接到你的 geth 实例,你需要使用 --ipcpath 选项来指定 IPC 文件的位置到其默认位置,这样以太坊钱包才能找到它;否则以太坊钱包将无法找到它并将启动自己的 geth 实例。要找到默认的 IPC 文件路径,请运行 geth 帮助命令,它将在 --ipcpath 选项旁边显示默认路径。

访问github.com/ethereum/mist/releases下载以太坊钱包。它适用于 Linux、OS X 和 Windows。就像 geth 一样,它有两种安装模式:二进制和脚本安装。

这里有一张显示以太坊钱包外观的图片:

Mist

Mist 是以太坊、Whisper 和 Swarm 的客户端。它让我们发送交易、发送 Whisper 消息、检查区块链等。

Mist 和 geth 之间的关系类似于以太坊钱包和 geth 之间的关系。

Mist 最受欢迎的特点是它带有一个浏览器。目前,运行在浏览器中的前端 JavaScript 可以使用 web3.js 库(一种为其他应用程序与 geth 通信提供以太坊控制台 JavaScript API 的库)访问 geth 节点的 web3 API。

Mist 的基本思想是构建第三代互联网(Web 3.0),它将通过使用以太坊、Whisper 和 Swarm 作为替代中心化服务器来消除对服务器的需求。

这里有一张显示 Mist 外观的图片:

弱点

每个系统都有一些弱点。同样,以太坊也有一些弱点。显然,就像任何其他应用程序一样,以太坊源代码可能会有漏洞。而且就像任何其他基于网络的应用程序一样,以太坊也容易受到 DoS 攻击。但让我们来看看以太坊的独特和最重要的弱点。

Sybil 攻击

攻击者可以尝试用自己控制的常规节点填满网络;然后你很可能只会连接到攻击者节点。一旦你连接到攻击者节点,攻击者可以拒绝中继来自所有人的区块和交易,从而将你与网络断开。攻击者只能中继他自己创建的区块,从而将你置于一个单独的网络中,依此类推。

51% 攻击

如果攻击者控制了网络哈希率的一半以上,攻击者可以比网络其余部分更快地生成区块。攻击者可以简单地保留他的私有分支,直到它比诚实网络构建的分支更长,然后广播它。

拥有超过 50% 的哈希算力,矿工可以撤销交易,阻止所有/部分交易被挖掘,并阻止其他矿工的挖掘块被插入到区块链中。

Serenity

Serenity 是以太坊的下一个重大更新的名称。在编写本书时,Serenity 仍在开发中。此更新将需要硬分叉。Serenity 将把共识协议改为 casper,并将集成状态通道和分片。这些将如何工作的完整细节目前尚不清楚。让我们先看一下这些是什么的高层概述。

支付通道和状态通道

在深入了解状态通道之前,我们需要了解支付通道是什么。支付通道是一种功能,允许我们将发送以太币到另一个账户的两个以上的交易合并为两个交易。它是如何工作的呢?假设 X 是一个视频流网站的所有者,而 Y 是一个用户。X 每分钟收取一以太币。现在 X 希望 Y 每分钟观看视频后付费。当然,Y 可以每分钟广播一次交易,但这里有一些问题,比如 X 必须等待确认,所以视频将暂停一段时间等。这是支付通道解决的问题。使用支付通道,Y 可以通过广播一个锁定交易将一些以太币(也许 100 以太币)锁定一段时间(也许 24 小时)给 X。现在,在观看了 1 分钟的视频后,Y 将发送一个签名记录,指示可以解锁锁定,其中一个以太币将转到 X 的账户,剩余的将转到 Y 的账户。再过一分钟,Y 将发送一个签名记录,指示可以解锁锁定,其中两个以太币将转到 X 的账户,剩余的将转到 Y 的账户。随着 Y 在 X 的网站上观看视频,这个过程将持续下去。现在一旦 Y 观看了 100 小时的视频或者 24 小时的时间即将到达,X 将向网络广播最终的签名记录,以将资金提取到他的账户。如果 X 在 24 小时内未能提取资金,则完全退款给 Y。所以在区块链上,我们只会看到两个交易:锁定和解锁。

支付通道用于与发送以太币相关的交易。同样,状态通道允许我们将与智能合约相关的交易合并。

权益证明和 casper

在我们深入了解 casper 共识协议之前,我们需要了解权益证明共识协议是如何工作的。

股权证明是工作量证明的最常见替代方案。工作量证明浪费了太多的计算资源。 POW 和 POS 的区别在于,在 POS 中,矿工不需要解决难题;相反,矿工需要证明对股份的所有权来挖掘区块。在 POS 系统中,账户中的以太被视为股份,矿工挖掘区块的概率与其持有的股份成正比。因此,如果矿工持有网络中 10% 的股份,那么它将挖掘 10% 的区块。

但问题是,我们如何知道谁将挖掘下一个区块?我们不能简单地让持有最高股份的矿工总是挖掘下一个区块,因为这会导致集中化。有各种算法用于选择下一个区块,例如随机区块选择和基于币龄的选择。

Casper 是 POS 的一种修改版本,用于解决 POS 的各种问题。

分片

目前,每个节点都需要下载所有交易,这是巨大的。随着区块链大小增长的速度,未来几年,将很难下载整个区块链并保持同步。

如果你熟悉分布式数据库架构,你一定很熟悉分片。如果不熟悉,那么分片是一种将数据分布到多台计算机上的方法。以太坊将实现分片以将区块链分割并分发到节点上。

您可以在github.com/ethereum/wiki/wiki/Sharding-FAQ了解更多关于分片区块链的信息。

总结

在本章中,我们详细了解了以太坊的工作原理。我们了解了区块时间如何影响安全性以及以太坊的弱点。我们还了解了 Mist 和以太坊钱包是什么以及如何安装它们。我们还看到了 geth 的一些重要命令。最后,我们了解了以太坊的 Serenity 更新中将会有什么新内容。

第四章:智能合约

本章介绍了智能合约的概念。这个概念并不新鲜,但是随着区块链的出现,对这个想法的兴趣重新被唤起,现在这是区块链领域的一个活跃研究领域。由于智能合约可以为金融服务行业带来节省成本的好处,降低交易成本并简化复杂合同,各种商业和学术机构正在进行严格的研究,以便尽快形式化和使智能合约的实施变得简单和实用。

历史

智能合约最初由 Nick Szabo 在 1990 年代末在一篇名为《在公共网络上规范和保护关系》的文章中提出,但直到比特币的发明和区块链技术的后续发展,人们才真正意识到它们的潜力和好处。Szabo 将智能合约描述为以下方式:

"智能合约是执行合同条款的电子交易协议。一般目标是满足常见的合同条件(如付款条件、留置权、保密性,甚至强制执行),尽量减少恶意和意外异常,并最小化对可信中介的需求。相关的经济目标包括降低欺诈损失、仲裁和执行成本,以及其他交易成本。"

Szabo 撰写的原始文章可在firstmonday.org/ojs/index.php/fm/article/view/548上找到。

智能合约的这个想法在 2009 年以有限的方式在比特币中实现,比特币交易使用有限的脚本语言可以用于在用户之间传输价值,这是一个对等网络,用户之间不一定信任彼此,也没有必要信任中介。

定义

对于智能合约的标准定义没有共识。定义智能合约是必不可少的,以下是我对智能合约的一般化定义的尝试:

智能合约是一个安全的、无法阻止的计算机程序,代表着一个自动可执行和可执行的协议。

进一步剖析这个定义会发现,智能合约实际上是一个计算机程序,它是用计算机或目标机器可以理解的语言编写的。此外,它包含了各方之间的业务逻辑形式的协议。另一个基本的想法是,智能合约在满足某些条件时会自动执行。它们是可强制执行的,这意味着所有合同条款都会按照定义和期望的方式执行,即使在存在对手方的情况下也是如此。

执法是一个更广泛的术语,它包括传统的法律执法,以及实施特定措施和控制的实施,使得能够执行合同条款而无需任何调解。值得注意的是,真正的智能合约不应依赖于传统的执法方法。相反,它们应该依据代码即法的原则工作,这意味着没有必要由仲裁员或第三方来控制或影响智能合约的执行。智能合约是自我执行的,而不是法律可执行的。这个想法可能被视为自由主义者的梦想,但它完全是可能的,并符合智能合约的真正精神。

此外,它们是安全的和不可阻挡的,这意味着这些计算机程序必须设计成容错性强且在合理的时间内可执行。即使外部因素不利,这些程序也应该能够执行和维护健康的内部状态。例如,想象一个典型的计算机程序,它被编码了一些逻辑并根据其中编码的指令执行。然而,如果它运行的环境或它所依赖的外部因素偏离了正常或预期的状态,该程序可能会任意地反应或简单地中止。智能合约免疫于这种问题是至关重要的。

安全和不可阻挡可能被认为是要求或期望的特性,但从长远来看,如果安全和不可阻挡的特性从一开始就包含在智能合约的定义中,将会带来更显著的好处。这将使研究人员能够从一开始就专注于这些方面,并有助于构建坚实的基础,进而进行进一步的研究。一些研究人员还提出,智能合约不需要自动执行;相反,在某些情况下,它们可以是所谓的可自动化的,因为某些场景需要人工输入。例如,可能需要由合格的医疗专业人员进行医疗记录的手动验证。在这种情况下,完全自动化的方法可能效果不佳。虽然在某些情况下人类的输入和控制是可取的,但并非必要;并且,为了使合约真正智能,在作者看来,它必须是完全自动化的。一些需要人为提供的输入也可以通过使用 Oracles 来自动化。后文将更详细地讨论 Oracles。

智能合约通常通过使用状态机模型来管理其内部状态。这使得能够开发一个有效的智能合约编程框架,其中合约的状态根据一些预定义的标准和条件进一步推进。

就代码是否可以作为法院合同的基础而进行的讨论也在持续进行。智能合同在形式上与传统的法律文书有所不同,尽管它们代表并执行所有合同条款,但法院并不理解代码。这一困境提出了有关智能合同如何具有法律约束力的几个问题:它能否以一种容易被法院接受和理解的方式开发?如何在代码内实施争端解决,这是可能的吗?此外,在智能合同能够像传统法律文件一样有效使用之前需要解决的另一个主题是监管和合规要求。

即使智能合同被称为智能,它们实际上只做它们被编程做的事情,这是可以接受的,因为智能合同的这一属性确保智能合同每次执行时都产生相同的输出。由于一致的共识要求,这种确定性的性质在区块链平台上非常理想。这意味着智能合同并不是真正的智能,它们只是做它们被编程做的事情。

现在,这引发了一个问题,即现实世界和区块链世界之间出现了很大的差距。在这种情况下,自然语言对智能合同来说是不可理解的,类似地,代码对自然世界来说也是无法理解的。因此,一些问题出现了,现实生活中的合同如何部署在区块链上?如何构建真实世界和智能合同世界之间的桥梁?

上述问题打开了各种可能性,例如使智能合同代码不仅可以被机器理解,还可以被人理解。如果人类和机器都能理解智能合同中编写的代码,它在法律情况下可能更容易被接受,而不只是一个除程序员外没有人能够理解的代码片段。这种可取的属性是一个值得研究的领域,大量的研究工作在这一领域已经进行,以回答关于合同的语义、含义和解释的问题。

已经有一些工作通过将智能合同代码和自然语言合同组合在一起,通过链接合同术语与机器可理解的元素,形式上描述自然语言合同。这是通过使用一种标记语言来实现的。这种标记语言的示例称为法律知识交换格式LKIF),它是用于表示理论和证明的 XML 模式。它是在 2008 年的 ESTRELLA 项目下开发的。

关于更多信息,请参阅研究论文:doi.org/10.1007/978-3-642-15402-7_30

智能合约固有地需要是确定的。这个属性将允许任何网络上的任何节点运行智能合约并获得相同的结果。如果结果在节点之间即使稍有不同,那么就无法达成共识,而区块链上的分布式共识整个范式可能会失败。此外,还希望合约语言本身也是确定的,从而确保智能合约的完整性和稳定性。所谓确定性是指语言中没有使用非确定性函数,这些函数可能在各个节点上产生不同结果。

举个例子,各种编程语言中由各种函数计算的各种浮点操作在不同的运行环境中可能会产生不同的结果。另一个例子是 JavaScript 中的一些数学函数,在不同浏览器上可能会为相同的输入产生不同结果,这反过来可能导致各种错误。在智能合约中这是非常不可取的,因为如果节点之间的结果不一致,那么将永远无法达成共识。

确定性特征确保智能合约始终为特定输入产生相同输出。换句话说,程序在执行时生成可靠准确的业务逻辑,完全符合高级代码中编程的要求。

总之,智能合约具有以下四个属性:

  • 自动可执行

  • 可执行的

  • 语义上合理

  • 安全不可阻止

前两个属性至少是必需的,而后两个在某些情况下可能不是必需的或不可实施,并且可以放宽。例如,金融衍生产品合同也许不需要语义上合理和不可阻止,但至少在基本层面上应该是自动可执行和可强制执行的。另一方面,不动产所有权证书需要语义上合理和完整,因此要将其实现为智能合约,语言必须被计算机和人理解。Ian Grigg 解决了这个解释问题,他发明了理查德合同,我们将在下一节更详细地看一下。

理查德合同

理查德合同最初是在 1990 年代末由Ian Grigg在论文*《金融密码学七层》中提出的。这些合同最初被用于一种名为里卡多的债券交易和支付系统中。其基本思想是编写一份可被法律法院和计算机软件理解和接受的文件。理查德合同解决了通过互联网发行价值的挑战。它确定了发行方并在文件中捕获合同的所有条款和条款,使其可接受为具有法律约束力的合同。

理查德合同是一个具有以下几个特性的文件:

  • 由发行方向持有人提供的合同

  • 由持有者持有和发行者管理的有价权利

  • 人们易读(像纸质合同一样)

  • 可被程序阅读(可解析,如数据库)

  • 数字签名

  • 携带密钥和服务器信息

  • 与独特且安全的标识符相关联

上述信息基于 Ian Grigg 在 iang.org/papers/ricardian_contract.html 的原始定义。

在实践中,合同通过生成一份包含法律文言合同条款和所需机器可读标签的单一文档来实施。该文件由发行方使用其私钥进行数字签名。然后使用消息摘要函数对该文档进行哈希处理,以生成可以识别文档的哈希值。在合同履行过程中,各方进一步使用并签署该哈希,以将每笔交易与标识符哈希链接起来,从而使标识符哈希作为意图证据。这通常在下一个图表中描述,通常称为蝴蝶模型。

该图表显示了多个元素:

  • 法律世界 在左侧,文档起源地。这份文件是一份使用法律文言书写的书面合同,并带有一些机器可读的标签。

  • 然后对该文档进行哈希处理。

  • 所得的消息摘要作为标识符在会计世界中使用,如图表右侧所示。

会计世界 元素代表着在业务中用于执行各种业务操作的任何会计、交易和信息系统。该流程背后的想法是通过对文档进行哈希生成消息摘要,首先将其用于所谓的起始交易,或者第一笔交易,然后在合同的运营执行过程中作为标识符在每笔交易中使用。

这样,原始书面合同与会计世界中的每笔交易之间就建立了安全链接:

Ricardian 合同,蝴蝶结图

Ricardian 合同与智能合同不同,智能合同不包括任何合同文件,纯粹关注合同的执行。另一方面,Ricardian 合同更关注合同法律文言的语义丰富性和文件的制作。合同的语义可以分为两种类型:操作语义和指称语义。

第一种类型定义了合同的实际执行、正确性和安全性,后者则涉及完整合同的真实含义。 一些研究人员已经区分了智能合同代码和智能法律合同,其中智能合同仅涉及合同的执行。 第二种类型包括法律协议的指示和操作语义。 基于语义的差异将智能合同划分为类型也许有意义,但最好将智能合同视为能够在其中编码法律散文和代码(业务逻辑)的独立实体。

在比特币中,可以观察到基本智能合同(条件逻辑)的直接实现,它完全面向合同的执行和性能,而里卡迪安合同更倾向于生成一个对人类易懂的文件,其中有些部分是计算机程序可以理解的。 这可以看作是法律语义与操作性能(语义与性能)的对比,如下图所示。 本图显示里卡迪安合同更加语义丰富,而智能合同更加性能丰富。 这个概念最初是由Ian Grigg在他的论文《On the intersection of Ricardian and smart contracts》中提出的。

图解释了性能与语义是 Ian Grigg 描述的正交问题;稍微修改以展示两个轴上不同类型合同的示例

一个智能合同包括了这两个元素(性能和语义)的嵌入,从而完成了一个完美的智能合同模型。

里卡迪安合同可以表示为三个对象的元组,即散文参数代码。 散文代表自然语言中的法律合同;代码代表了计算机可理解的法律散文的表示;参数将法律合同的适当部分与等效代码连接起来。

里卡迪安合同已经在许多系统中实施,例如 CommonAccord、OpenBazaar、OpenAssets 和 Askemos。

智能合同模板

智能合同可以在需要的任何行业实现,但大多数当前的用例与金融行业相关。 这是因为区块链最初在金融业发现了许多用例,并在其他行业很久之前就引起了金融业的巨大研究兴趣。 特定于金融行业的智能合同领域的最新工作提出了智能合同模板的理念。 这个理念是建立提供支持金融工具法律协议的标准模板框架。

这个想法是由 Clack et al. 在他们 2016 年发表的名为 智能合同模板:基础、设计风景和研究方向 的论文中提出的。该论文还提出应该构建支持智能合同模板设计和实现的领域特定语言。一个名为 CLACK 的语言,即增强合同知识的通用语言已经被提出,并已开始研究开发这种语言。这种语言旨在非常丰富,并提供多种功能,从支持法律条文到在多个平台上执行和加密功能。

Clack 等人进行了开发支持法律可执行智能合同的智能合同模板的最新工作。该提案在他们的研究论文 智能合同模板:基本要求和设计选项 中进行了讨论。该论文的主要目的是调查如何使用标记语言将法律条文与代码联系起来。它还涵盖了如何创建、格式化、执行和序列化智能法律协议以供存储和传输。这是一项正在进行的工作,也是一个进一步研究和开发的开放领域。

金融行业的合同并不是一个新概念,各种领域特定语言 DSL 在金融行业已经被广泛使用,为特定领域提供了专门的语言。例如,有支持保险产品开发、代表能源衍生品或用于构建交易策略的 DSL 可用。

可以在 www.dslfin.org/resources.html 找到一个全面的金融领域特定语言列表。

了解领域特定语言的概念也很重要,因为这种类型的语言可以开发用于编程智能合同。这些语言是为特定应用或兴趣领域开发的,具有有限的表现力。领域特定语言DSLs)与通用编程语言GPLs)不同。DSLs 具有一小组功能,这些功能足以并且针对它们打算在的领域进行了优化,并且通常不像 GPLs 那样用于构建通用大型应用程序。

基于 DSL 的设计理念,可以设想这样的语言将被专门开发用于编写智能合同。已经做了一些工作,Solidity 是一种已经引入以太坊区块链用于编写智能合同的语言。Vyper 是另一种最近为以太坊智能合约开发引入的语言。

用于智能合约编程的领域特定语言的概念可以进一步扩展到图形领域特定语言,这是一个智能合约建模平台,领域专家(比如前台交易员而非程序员)可以使用图形用户界面和画布定义和绘制金融合同的语义和性能。一旦流程被绘制并完成,可以首先进行仿真测试,然后从同一系统部署到目标平台,可以是区块链。这也不是一个新概念,在 Tibco StreamBase 产品中也使用了类似的方法,该产品是一个基于 Java 的系统,用于构建事件驱动的高频交易系统。

建议在开发可用于使用用户友好的图形用户界面编程智能合约的高级 DSL 领域也应进行研究,从而使非程序员领域专家(例如律师)能够设计智能合约。

神谕

神谕是智能合约生态系统的重要组成部分。智能合约的限制在于它们无法访问外部数据,而这些数据可能是控制业务逻辑执行所需的;例如,合约需要发布股息支付所需的证券产品的股价。神谕可以用来为智能合约提供外部数据。神谕是一个从外部来源向智能合约传递数据的接口。

根据行业和要求,神谕可以提供不同类型的数据,包括天气报告、现实世界新闻和公司行动以及来自物联网(IoT)设备的数据。神谕是受信任的实体,使用安全通道将数据传输到智能合约。

神谕还能够数字签名数据,证明数据来源真实可靠。智能合约可以订阅神谕,然后智能合约可以拉取数据,或者神谕可以将数据推送给智能合约。还需要确保神谕无法操纵他们提供的数据,并且必须能够提供真实可靠的数据。虽然神谕是可信的,但在某些情况下,由于操纵原因,数据可能仍然是不正确的。因此,需要确保神谕无法更改数据。后面章节将讨论使用各种公证方案提供此验证。

在这种方法中,可能已经出现了一个问题,这在某些情况下可能是不可取的,那就是信任的问题。你如何相信第三方提供的数据的质量和真实性?这在金融世界尤为重要,市场数据必须准确可靠。智能合约设计者可能会接受由大型、值得信赖的第三方提供的甲骨文数据,但中心化的问题仍然存在。这些类型的甲骨文可以称为标准或简单的甲文。例如,数据来源可以是知名天气预报机构或机场信息系统的航班延误。

为了确保第三方来源的数据的可信度,还可以利用另一个概念,即数据来自多个来源;甚至可以来自访问和了解某些数据的公众或公众会员提供所需的数据。然后可以对这些数据进行聚合,如果同一信息从多个来源输入,则数据是正确的并值得信赖的可能性很大。

另一种甲骨文是分散式甲骨文,它基本上是由于分散化的要求而出现的。这些类型的甲骨文可以基于某种分布机制构建。也可以设想甲骨文可以从另一个由分布式共识驱动的区块链获取数据源,从而确保数据的真实性。例如,某个机构运行其私有区块链,可以通过一个甲骨文发布其数据源,然后其他区块链可以使用该数据。

研究人员还介绍了另一种硬件甲骨文的概念,这种概念需要来自物理设备的真实世界数据。例如,这可以用于遥测和物联网。然而,这种方法需要硬件设备是防篡改的。这可以通过提供物联网设备数据的加密证据(不可否认性和完整性)和设备防篡改机制来实现,从而使设备在防篡改尝试的情况下无法使用。

以下图表展示了一个甲骨文和智能合约生态系统的通用模型:

一个甲骨文和智能合约生态系统的通用模型

现在有平台可以使用甲骨文使智能合约获取外部数据。根据所使用的区块链类型,甲骨文使用不同的方法将数据写入区块链。例如,在比特币区块链中,甲骨文可以将数据写入特定交易,而智能合约可以监视区块链中的该交易并读取数据。

提供 Oracle 服务的各种在线服务,如 www.oraclize.it/www.realitykeys.com/。还提供了另一项服务 smartcontract.com/,它提供了外部数据和使用智能合约进行支付的能力。

所有这些服务旨在使智能合约能够获取执行和做出决策所需的数据。为了证明来自外部来源的 Oracles 检索到的数据的真实性,可以使用像 TLSnotary 这样的机制,它会产生数据源和 Oracle 之间通信的证明。这确保了反馈给智能合约的数据是从源头检索到的。

关于 TLSnotary 的更多详细信息可以在这里找到: tlsnotary.org/

智能 Oracles

瑞波实验室(codius)也提出了智能 Oracle 的概念。其原始白皮书可在 github.com/codius/codius/wiki/Smart-Oracles:-A-Simple,-Powerful-Approach-to-Smart-Contracts找到。Codius 提出的智能 Oracle 与 Oracle 一样是实体,但具有合约代码执行的附加能力。Codius 提出的智能 Oracle 使用 Google Native Client 运行,这是一个用于运行不受信任的 x86 本机代码的沙盒环境。

在区块链上部署智能合约

智能合约可能会或可能不会部署在区块链上,但由于区块链提供的分布式和去中心化共识机制,将其部署在区块链上是有意义的。以太坊是一个原生支持智能合约开发和部署的区块链平台的例子。以太坊区块链上的智能合约通常是分散自治组织(DAOs)等更广泛应用的一部分。

作为对比,在比特币区块链中,诸如nLocktime字段和比特币交易中的 CHECKLOCKTIMEVERIFY(CLTV)、CHECKSEQUENCEVERIFY 脚本操作符等交易时锁定机制可以被视为简单版本智能合约的启用器。这些交易时锁定机制使得交易可以被锁定直到特定时间或者直到一定数量的区块,从而强制执行一个基本合约,即只有在满足特定条件(经过的时间或者区块数量)时才能解锁某笔交易。例如,你可以实现诸如“在 3 个月后支付 X 方 N 比特币”的条件。然而,这非常有限,应该仅被视为基本智能合约的示例。除了上面提到的例子,比特币脚本语言,虽然有限,也可以用来构建基本智能合约。其中一个例子是资助一个可以由任何证明“哈希碰撞攻击”的人花费的比特币地址。这是在 Bitcointalk 论坛上宣布的一个比赛,比特币被设置为奖励给任何成功找到哈希碰撞的人(我们在第六章,公钥密码学中讨论了这个概念)的攻击。只有在成功攻击的演示上才能解锁比特币的这种条件性解锁是基本类型的智能合约。

这个想法是在 Bitcointalk 论坛上提出的,更多信息可以在bitcointalk.org/index.php?topic=293382.0找到。这也可以被看作是一种基本形式的智能合约。

其他各种区块链平台支持智能合约,如 Monax、Lisk、Counterparty、Stellar、Hyperledger fabric、corda 和 Axoni core。智能合约可以用各种语言开发。然而,关键要求是确定性,这非常重要,因为无论智能合约代码在何处执行,它每次都应该产生相同的结果。智能合约的这种确定性要求也意味着智能合约代码绝对没有错误。智能合约的验证和验证是一个活跃的研究领域,对这个主题的详细讨论将在第十六章,可扩展性和其他挑战中展示。已经开发了各种语言来构建智能合约,例如 Solidity,它运行在以太坊虚拟机EVM)上。值得注意的是,已经有平台支持主流语言用于智能合约开发,比如 Lisk 支持 JavaScript。然而,另一个显著的例子是 Hyperledger fabric,它支持 Golang、Java 和 JavaScript 用于智能合约开发。

DAO

DAO 是最高众筹项目之一,始于 2016 年 4 月。这是一组旨在提供投资平台的智能合约。由于代码中的一个错误,在 2016 年 6 月被黑,并有相当于 5000 万美元被转移到另一个账户。

尽管上文使用了术语“被黑”,但实际上并没有被黑,智能合约只是按照要求执行了。这只是 DAO 程序员没有预料到的一个无意的行为。这一事件导致了以太坊的硬分叉以从攻击中恢复过来。值得注意的是,“代码即法律”或不可阻止的智能合约的概念应该带有一些怀疑,因为这些概念的实施还不成熟到足以获得完全和不可质疑的信任。从最近的事件可以看出,以太坊基金会能够通过引入硬分叉来停止和更改“The DAO”的执行。尽管这个硬分叉是出于真正的原因引入的,但它违背了去中心化的真正精神和“代码即法律”的概念。另一方面,对这个硬分叉的抵抗以及一些矿工决定继续在原始链上挖矿导致了以太坊经典的产生。这条链是原始的、非分叉的以太坊区块链,其中“代码仍然是法律”。

这次攻击突显了不正式和彻底测试智能合约的危险性。它还突显了开发和验证智能合约的形式语言绝对的必要性。此次攻击还突显了彻底测试的重要性,以避免 DAO 经历的问题。最近在以太坊智能合约开发语言周围发现了各种漏洞。因此,开发一个标准框架来解决所有这些问题至关重要。一些工作已经开始,例如,一个在线服务securify.ch,它提供工具来正式验证智能合约。然而,这个领域正值更多研究的时候,以解决智能合约语言的限制。

总结

本章首先介绍了智能合约的历史,然后详细讨论了智能合约的定义。由于对智能合约的标准定义没有达成一致意见,我们试图引入一个包含智能合约核心的定义。

还提供了对瑞克底亚合约的介绍,并解释了瑞克底亚合约与智能合约之间的区别,突出了瑞克底亚合约关注合同定义而智能合约则专注于合同实际执行的事实。

讨论了智能合约模板的概念,针对该主题,学术界和行业正在进行高质量的积极研究。 还讨论了创建高级领域特定语言来创建智能合约或智能合约模板的可能性。 在本章的后续部分中,介绍了 Oracle 的概念,随后简要讨论了 DAO 以及 DAO 和智能合约中的安全问题。

讨论智能合约的形式验证和安全性将在本书的第十六章 可扩展性及其他挑战 中介绍。

在下一章中,你将介绍对称加密的概念、理论和实际方面。

第五章:对称加密

在本章中,您将介绍对称加密的概念、理论和实践方面。我们将更多关注与区块链技术相关的元素。我们将为您提供理解后续章节涵盖内容所需的概念。

你还将学习加密算法的应用,以便获得加密功能实际实施的实践经验。为此,我们将使用 OpenSSL 命令行工具。在开始理论基础之前,我们将在下一节中介绍 OpenSSL 的安装,以便您在阅读概念材料时进行一些实际工作。

使用 OpenSSL 命令行

在 Ubuntu Linux 发行版上,OpenSSL 通常已经可用。但是,可以使用以下命令进行安装:

$ sudo apt-get install openssl  

本章中的示例是使用 OpenSSL 版本 1.0.2g 开发的。

它可以在packages.ubuntu.com/xenial/openssl找到。

鼓励您使用此特定版本,因为本章中的所有示例都是使用它开发和测试的。可以使用以下命令检查 OpenSSL 版本:

$ openssl version  

您将看到以下输出:

OpenSSL 1.0.2g  1 Mar 2016  

现在,您已经准备好运行本章提供的示例了。如果您使用的版本不是 1.0.2g,则示例可能仍然有效,但不能保证,因为旧版本缺少示例中使用的功能,而新版本可能与版本 1.0.2g 不兼容。

接下来的章节首先讨论密码学的理论基础,然后提供一系列相关的实验。

简介

密码学是在敌方存在的情况下使信息安全的科学。它在假设敌方拥有无限资源的情况下进行。密码是用于加密或解密数据的算法,因此,如果被敌方截获,数据对他们来说没有意义,除非进行解密,这需要一个秘密密钥。

密码学主要用于提供保密服务。单独而言,它不能被视为完整的解决方案,而是作为更广泛的安全系统中的重要组成部分,用于解决安全问题。例如,保护区块链生态系统需要许多不同的加密原语,如哈希函数、对称密钥加密、数字签名和公钥加密。

除了保密服务外,密码学还提供其他安全服务,例如完整性、身份验证(实体身份验证和数据源身份验证)和不可否认性。此外,还提供了责任追究,这是许多安全系统的要求。

在进一步讨论密码学之前,需要解释一些数学术语和概念,以便为后面本章所提供的材料建立基础。

下一节作为这些概念的基本介绍。解释所有这些术语并提供相关背景需要一些复杂的数学知识,这超出了本书的范围。有关这些主题的更多详细信息可以在任何标准数论、代数或密码学专业书籍中找到。例如,Neal Koblitz《数论与密码学课程》提供了所有相关数学概念的优秀介绍。

数学

由于密码学的主题是基于数学的,本节将介绍一些基本概念,这些概念将帮助您理解后面章节中提到的概念。

集合

一个集合是一组不同的对象,例如,X = {1, 2, 3, 4, 5}

群组

一个群组是一个具有结合性的集合,其中包含一个结合两个集合元素的操作。群操作是封闭的,并与一个定义好的单位元素相关联。此外,集合中的每个元素都有一个逆元素。封闭性(封闭)意味着,例如,如果元素AB在集合中,则在元素上执行操作后的结果元素也在集合中。结合性意味着,元素的分组不影响操作的结果。

一个是一个包含加法和乘法群的集合。更确切地说,集合中的所有元素形成加法和乘法群。它满足加法和乘法的特定公理。对于所有群操作,也适用分配律。该法则规定,即使对任何项或因子重新排序,也将产生相同的和或乘积。

一个有限域

一个有限域是具有有限元素集的域。也被称为伽罗瓦域,这些结构在密码学中尤为重要,因为它们可以用来产生精确和无误的算术运算结果。例如,素有限域在椭圆曲线密码学ECC)中被用来构造离散对数问题。

是域中元素的数量。也被称为域的基数

一个阿贝尔群

一个阿贝尔群是当一个集合中元素的操作是可交换的时形成的。可交换律意味着更改元素的顺序不会影响操作的结果,例如,A X B = B X A

素域

一个素域是一个具有素数个元素的有限域。它具有特定的加法和乘法规则,并且域中每个非零元素都有一个逆元素。加法和乘法操作是模p执行的,即,素数。

如果阿贝尔群上可以定义多个操作,则该群成为。还需要满足特定的性质。环必须具有闭包、结合和分配性质。

循环群

循环群是一种可以由称为群生成元的单个元素生成的群类型。

模算术

在模算术中,数在达到固定数字时会循环。这个固定数字是一个称为模数的正数,所有操作都是关于这个固定数字进行的。类似于时钟,有从 1 到 12 的数字。当它达到 12 时,数字 1 会重新开始。换句话说,这种算术处理除法运算后的余数。例如,50 mod 11 为 6,因为 50 / 11 留下余数 6。

这完成了对密码学中涉及的一些数学概念的基本介绍。在下一节中,您将介绍密码学概念。

密码学

通用密码学模型显示如下图所示:

通用加密和解密模型

在前面的图表中,PECD分别表示明文,加密,密文和解密。同样基于这一模型,实体、发送方、接收方、对手、密钥和通道概念的解释如下:

  • 实体:发送、接收或对数据执行操作的人或系统

  • 发送方:传输数据的实体

  • 接收者:接收数据的实体

  • 对手:试图规避安全服务的实体

  • 密钥:用于加密或解密其他数据的数据

  • 通道:通道为实体之间提供通信媒介

接下来,我们将更详细地描述本章前面提到的密码学服务。

机密性

机密性是信息仅对授权实体可用的保证。

完整性

完整性是信息仅可由授权实体修改的保证。

认证

认证提供有关实体身份或消息有效性的保证。

有两种认证机制,即实体认证和数据源认证,将在下一节讨论。

实体认证

实体认证是确保实体当前正在通信会话中参与和活动的保证。传统上,用户被发放一个用户名和密码,用于访问他们正在使用的各种平台。这种做法被称为单因素认证,因为只涉及一个因素,即你所知道的东西,即密码和用户名。由于各种原因,例如密码泄露,这种类型的身份验证不是非常安全;因此,现在常用其他附加因素提供更好的安全性。使用附加技术进行用户识别称为多因素认证(如果只使用两种方法,则为双因素认证)。

这里描述了各种身份验证因素:

  • 第一个因素是你拥有的东西,比如硬件令牌或智能卡。在这种情况下,用户可以使用硬件令牌以及登录凭据来访问系统。这种机制通过要求两个身份验证因素来保护用户。拥有硬件令牌并知道登录凭据的用户将能够访问系统。要获得系统访问权限,这两个因素都应该可用,从而使这种方法成为双因素认证机制。如果硬件令牌丢失,单独使用它将毫无用处,除非与硬件令牌一起使用你所知道的东西,即登录密码。

  • 第二个因素是你是的东西,它使用生物特征来识别用户。使用这种方法,可以使用用户的指纹、视网膜、虹膜或手部几何来提供身份验证的额外因素。这样,可以确保用户确实在身份验证过程中出现,因为生物特征对每个人都是独特的。然而,需要谨慎实施以确保高水平的安全性,因为一些研究表明,在特定条件下,生物特征系统可以被规避。

数据来源认证

也称为消息认证数据来源认证是确保信息来源确实经过验证的保证。数据来源认证保证了数据完整性,因为如果来源得到证实,那么数据必定没有被篡改。最常用的各种方法,如消息认证码MACs)和数字签名将在本章后面详细解释。

不可否认性

非否认是一种保证,指的是实体无法通过提供无可辩驳的证据来否认先前的承诺或行动。它是一项安全服务,提供确凿证据表明特定活动已发生。在存在争议的情况下,这一属性至关重要,因为实体已否认执行的行动,例如在电子商务系统中下订单。该服务在电子交易中产生密码学证据,以便在争议情况下,可用作行动的确认。

非否认已经是一个活跃的研究领域多年。电子交易中的争议是一个常见问题,有必要解决这些问题,以提高消费者对此类服务的信心。

非否认协议通常在通信网络中运行,用于提供证据表明网络上的实体(发起者或接收者)已经采取了行动。在这种情况下,有两种通信模型可用于将消息从发起者A传输到接收者B

  • 一条消息直接从发起者A发送到接收者B

  • 一条消息从发起者A发送到交付代理,然后由交付代理将消息传递给接收者B

非否认协议的主要要求是公平性、有效性和及时性。在许多情况下,一个交易涉及多个参与方,而不仅仅是两个当事方。例如,在电子交易系统中,可能存在许多实体,如清算代理、经纪人和交易员,它们可能参与一个交易。在这种情况下,双方非否认协议不适用。为了解决这个问题,已经开发了多方非否认MPNR)协议。

可追究性

可追究性是一种保证,指的是影响安全性的行动可以追溯到责任方。这通常由系统中的日志记录和审计机制提供,在业务性质要求详细审计的系统中尤其重要,例如在电子交易系统中。详细的日志记录对于追踪实体的行动至关重要,例如在交易被记录在带有日期和时间戳的审计记录中,实体的身份被生成并保存在日志文件中。此日志文件可以选择加密,并且可以是数据库的一部分,也可以是系统上的独立 ASCII 文本日志文件。

为了提供前面讨论的所有服务,使用了不同的密码学原语,这些原语将在下一节中介绍。

密码学原语

加密原语 是安全协议或系统的基本构建模块。在接下来的章节中,您将了解到构建安全协议和系统所必需的加密算法。安全协议 是通过利用适当的安全机制来实现所需的安全目标的一系列步骤。目前使用各种类型的安全协议,如认证协议、不可否认协议和密钥管理协议。

加密原语的分类可以通过以下图示来进行可视化:

密码原语

如加密原语分类图所示,密码学主要分为两类:对称密码学非对称密码学

这些原语在下一节中进一步讨论。

对称密码学

对称密码学 指的是一种使用加密数据的密钥进行解密的类型的密码学,它也被称为 共享密钥密码学。密钥必须在通信各方之间进行数据交换之前建立或达成一致。这也是它被称为 秘密密钥密码学 的原因。

对称密码有两种类型:流密码块密码数据加密标准 (DES) 和 高级加密标准 (AES) 是块密码的典型示例,而 RC4 和 A5 通常用作流密码。

流密码

流密码 是加密算法,它将密钥流逐位应用于明文以使用密钥流进行加密(对每个位进行一次)。流密码有两种类型: 同步流密码异步流密码

  • 同步流密码 是那些密钥流仅依赖于密钥的密码

  • 异步流密码 具有密钥流还依赖于加密数据

在流密码中,加密和解密是相同的功能,因为它们是简单的模 2 加法或异或操作。流密码的基本要求是密钥流的安全性和随机性。从伪随机数生成器到硬件实现的真随机数生成器等各种技术已经开发出来生成随机数,并且至关重要的是所有密钥生成器都是具有密码安全性的:

流密码的操作

块密码

块密码 是将要加密的文本(明文)分割成固定长度的数据块,然后逐块应用加密。块密码通常是使用一种被称为费斯特尔密码的设计策略构建的。最近的块密码,如 AES (Rijndael) 是使用被称为 替代-置换网络 (SPN) 的替代和置换的组合来构建的。

费斯特尔密码基于由霍斯特·费斯特尔开发的费斯特尔网络。这种结构基于将多轮重复操作组合起来以实现称为混淆扩散的理想密码学属性的思想。费斯特尔网络通过将数据分成两个块(左侧和右侧),并通过迭代使用带键的轮函数来处理这些块,以提供足够的伪随机排列。

混淆使得加密文本与明文之间的关系复杂化。这是通过替换实现的。在实践中,明文中的A被替换为加密文本中的X。在现代密码算法中,使用称为S 盒的查找表进行替换。扩散属性将明文统计地传播到加密数据中。这确保即使在输入文本中更改了单个位,也会导致至少改变(平均而言)密文中一半以上的位。混淆是为了使找到加密密钥变得非常困难,即使使用相同的密钥创建了许多加密和解密数据对也是如此。在实践中,这是通过换位或置换来实现的。

使用费斯特尔密码的一个主要优点是加密和解密操作几乎是相同的,只需要对加密过程进行反转即可实现解密。DES 是费斯特尔密码的一个主要示例:

块密码的简化操作

用于块密码的各种操作模式包括电码本ECB)、密码块链接CBC)、输出反馈OFB)模式和计数器CTR)模式。这些模式用于指定加密函数应用于明文的方式。这里介绍了一些块密码加密模式。

块加密模式

块加密模式中,明文根据使用的密码类型被分成固定长度的块,然后对每个块应用加密函数。

最常见的块加密模式在以下小节中简要讨论。

电码本

电码本ECB)是一种基本的操作模式,其中加密数据是通过将加密算法逐个应用于每个明文块而产生的。这是最简单直接的模式,但不应在实践中使用,因为它是不安全的,并且可能会泄露信息:

用于块密码的电码本模式

前面的图表显示,我们将明文P提供为输入到块密码加密函数,连同密钥KEY,并且生成了密文C作为输出。

密码块链接

密码块链CBC)模式中,每个明文块都与先前加密的块进行异或运算。CBC 模式使用初始化向量IV)来加密第一个块。建议随机选择 IV:

密码块链模式

计数器模式

计数器CTR)模式有效地将块密码用作流密码。在这种情况下,提供一个唯一的随机数用于与计数器值连接以生成一个密钥流

计数器模式

还有其他模式,如密码反馈CFB)模式,Galois 计数器GCM)模式和输出反馈OFB)模式,它们在各种场景中也被使用。

密钥流生成模式

密钥流生成模式中,加密函数生成一个密钥流,然后与明文流进行异或运算以实现加密。

消息认证模式

消息认证模式中,通过加密函数生成一个消息认证码MAC)。MAC 是一个提供完整性服务的密码校验和。使用块密码生成 MAC 的最常见方法是 CBC-MAC,其中链的最后一个块的一部分用作 MAC。例如,MAC 可用于确保消息是否被未经授权的实体修改。这可以通过使用 MAC 函数使用密钥加密消息来实现。一旦接收者接收到消息和消息的 MAC,就可以通过使用密钥再次加密接收到的消息并将结果与发送方接收到的 MAC 进行比较来检查消息和 MAC。如果它们匹配,则意味着消息没有被未经授权的用户修改,因此提供了完整性服务。如果它们不匹配,则意味着消息在传输过程中被未经授权的实体修改。

密码哈希模式

散列函数主要用于将消息压缩为固定长度的摘要。在密码哈希模式中,块密码被用作压缩函数以产生明文的哈希值。

有了这些,我们现在已经完成了对块密码的介绍。在接下来的部分中,你将会了解到一个目前市场主导的块密码的设计和机制,即 AES。

在讨论 AES 之前,我们先介绍一些关于数据加密标准DES)的历史,这导致了新的 AES 标准的发展。

数据加密标准

数据加密标准 (DES) 是由美国 国家标准与技术研究所 (NIST) 作为加密标准算法引入的,并且在 1980 年代和 1990 年代广泛使用。 但是,由于技术和密码学研究的进步,它并没有表现出对暴力破解攻击的很强抵抗力。 例如,在 1998 年 7 月,电子前沿基金会 (EFF) 使用一种称为 EFF DES 破丨解丨器(或 Deep Crack)的专用机器破解了 DES。

DES 仅使用 56 位密钥,引起了一些担忧。 这个问题在引入了 Triple DES (3DES) 后得到了解决,它提议使用三个 56 位密钥和 DES 算法相同次数的执行来使用 168 位密钥,从而几乎使暴力破解攻击变得不可能。 然而,其他限制,如性能缓慢和 64 位块大小,是不可取的。

高级加密标准

在 2001 年,在一次公开竞赛之后,由密码学家 Joan Daemen 和 Vincent Rijmen 发明的加密算法 Rijndael 被 NIST 标准化为 Advanced Encryption Standard (AES) 并进行了轻微修改。 到目前为止,尚未发现任何比暴力方法更有效的 AES 攻击。 Rijndael 的原始版本允许 128 位、192 位和 256 位的不同密钥和块大小。 然而,在 AES 标准中,仅允许 128 位块大小。 但是,允许 128 位、192 位和 256 位的密钥大小。

AES 的工作原理

在 AES 算法处理期间,使用多个轮次修改称为 state 的 4 x 4 字节数组。 全部加密需要 10 到 14 轮,具体取决于密钥的大小。 以下表显示了密钥大小和所需轮次:

密钥大小 所需轮次
128 位 10 轮次
192 位 12 轮次
256 位 14 轮次

一旦状态用密码输入初始化,将在四个阶段执行四个操作来加密输入。 这些阶段是:AddRoundKeySubBytesShiftRowsMixColumns

  1. AddRoundKey 步骤中,状态数组与从主密钥派生的子密钥进行 XOR 运算

  2. SubBytes 是替换步骤,其中使用查找表(S-盒)来替换状态数组的所有字节

  3. ShiftRows 步骤用于将状态数组中的每一行向左移动,除了第一行外,以循环和递增的方式向左移动

  4. 最后,在 MixColumns 步骤中,所有字节都以线性方式、按列混合。

前述步骤描述了 AES 的一个轮次。

在最后一轮(取决于密钥大小的 10、12 或 14),将第 4 阶段替换为 AddRoundKey 以确保前三步不能简单地反转:

AES 块图,显示 AES 加密的第一轮。 在最后一轮中,不执行混合步骤

各种加密货币钱包使用 AES 加密来加密本地存储的数据。特别是在比特币钱包中,使用 AES-256 的 CBC 模式。

这是使用 AES 加密和解密的 OpenSSL 示例:

$ openssl enc -aes-256-cbc -in message.txt -out message.bin 
enter aes-256-cbc encryption password:
Verifying - enter aes-256-cbc encryption password:
$ ls -ltr

-rw-rw-r-- 1 drequinox drequinox 14 Sep 21 05:54 message.txt
-rw-rw-r-- 1 drequinox drequinox 32 Sep 21 05:57 message.bin
$ cat message.bin  

下面是message.bin文件的内容:

请注意,message.bin是一个二进制文件。有时,将此二进制文件编码为文本格式以实现兼容性/互操作性是可取的。以下命令可用于执行此操作:

$ openssl enc -base64 -in message.bin -out message.b64
$ ls -ltr
-rw-rw-r-- 1 drequinox drequinox 14 Sep 21 05:54 message.txt
-rw-rw-r-- 1 drequinox drequinox 32 Sep 21 05:57 message.bin
-rw-rw-r-- 1 drequinox drequinox 45 Sep 21 06:00 message.b64
$ cat message.b64
U2FsdGVkX193uByIcwZf0Z7J1at+4L+Fj8/uzeDAtJE=  

为了解密一个 AES 加密的文件,可以使用以下命令。使用前面示例中的message.bin作为示例:

$ openssl enc -d -aes-256-cbc -in message.bin -out message.dec 
enter aes-256-cbc decryption password:
$ ls -ltr
-rw-rw-r-- 1 drequinox drequinox 14 Sep 21 05:54 message.txt
-rw-rw-r-- 1 drequinox drequinox 32 Sep 21 05:57 message.bin
-rw-rw-r-- 1 drequinox drequinox 45 Sep 21 06:00 message.b64
-rw-rw-r-- 1 drequinox drequinox 14 Sep 21 06:06 message.dec
$ cat message.dec
Datatoencrypt  

机智的读者可能已经注意到,虽然在除了 ECB 以外的所有块加密操作模式中都需要提供 IV,但是没有提供 IV。原因是 OpenSSL 会自动从给定的密码中派生 IV。用户可以使用以下开关指定 IV:

-K/-iv      , (Initialization Vector) should be provided in Hex.  

为了从 base64 解码,使用以下命令。跟随前面示例中的message.b64文件:

$ openssl enc -d -base64 -in message.b64 -out message.ptx
$ ls -ltr
-rw-rw-r-- 1 drequinox drequinox 14 Sep 21 05:54 message.txt
-rw-rw-r-- 1 drequinox drequinox 32 Sep 21 05:57 message.bin
-rw-rw-r-- 1 drequinox drequinox 45 Sep 21 06:00 message.b64
-rw-rw-r-- 1 drequinox drequinox 14 Sep 21 06:06 message.dec
-rw-rw-r-- 1 drequinox drequinox 32 Sep 21 06:16 message.ptx 
$ cat message.ptx 

下面是message.ptx文件的内容:

OpenSSL 支持许多类型的密码。您可以根据前面的示例来探索这些选项。支持的密码类型列表显示在以下屏幕截图中:

展示了 OpenSSL 中可用的丰富库选项的屏幕截图

OpenSSL 工具可用于对屏幕截图中显示的所有密码进行实验。

总结

在本章中,我们向您介绍了对称密钥加密。我们从基本的数学定义和密码原语开始。之后,我们向您介绍了流密码和块密码的概念,以及块密码的工作模式。此外,我们向您介绍了使用 OpenSSL 进行实际练习,以补充理论概念。

在下一章中,我们将介绍公钥密码学,这在区块链技术中被广泛使用,并具有非常有趣的属性。

第六章:公钥密码

在本章中,您将了解公钥密码的概念和实际应用,也称为非对称加密或非对称密钥密码。我们将继续使用 OpenSSL,就像在前一章中所做的那样,来实验一些密码算法的应用,以便您能够获得实践经验。我们将从公钥密码的理论基础开始,逐渐建立相关的实践练习。此外,我们还将研究哈希函数,这是区块链中广泛使用的另一个密码原语。之后,我们将介绍一些新的、先进的密码构造。

非对称加密

非对称加密指的是一种密码学类型,其中用于加密数据的密钥与用于解密数据的密钥不同。这也被称为公钥密码。它分别使用公钥和私钥进行数据的加密和解密。目前使用各种非对称加密方案,包括 RSA、DSA 和 ElGammal。

以下图表显示了公钥密码的概述:

使用公/私密钥进行加密/解密

前图说明了发送方如何使用接收者的公钥和加密函数E将数据P进行加密,产生一个输出为加密数据C,然后通过网络传输给接收者。一旦到达接收者,可以使用接收者的私钥将加密数据C输入函数D中进行解密,将输出纯文本P。这样,私钥保留在接收方手中,无需共享密钥即可进行加密和解密,这是对称加密的情况。

以下图表显示了接收者如何使用公钥密码来验证接收到的消息的完整性。在这个模型中,发送方使用他们的私钥对数据进行签名,并将消息传输给接收方。一旦消息被接收,发送方的公钥就会验证其完整性。

值得注意的是,在这个模型中没有进行加密操作。这里只是为了帮助你充分理解本章后面涵盖的消息认证和验证部分:

公钥密码签名方案模型

前图显示了发送方如何使用签名函数S用他的私钥对明文P进行数字签名,并产生数据C,发送给接收者,接收者使用发送方的公钥和函数V来验证C,以确保消息确实来自发送方。

公钥密码系统提供的安全机制包括密钥建立,数字签名,身份验证,加密和解密。

密钥建立机制关注的是设计允许在不安全通道上设置密钥的协议。 在许多场景中,不可否认的服务是一种非常理想的属性,可以使用数字签名提供。 有时,不仅要对用户进行身份验证,还要识别涉及交易的实体也很重要。 这也可以通过数字签名和挑战-响应协议的组合来实现。 最后,提供机密性的加密机制也可以使用公钥密码系统获得,例如 RSA、ECC 和 ElGammal。

公钥算法在计算方面比对称密钥算法慢。 因此,它们不常用于加密大文件或需要加密的实际数据。 通常用于交换对称算法的密钥。 一旦安全地建立了密钥,就可以使用对称密钥算法对数据进行加密。

公钥密码算法基于各种基础数学函数。 这里描述了三种主要的非对称算法类别。

整数因子分解

整数因子分解方案基于大整数很难因子分解的事实。 RSA 是这种类型算法的典型示例。

离散对数

离散对数方案基于模算术中的一个问题。 计算模函数的结果很容易,但是找到生成器的指数是计算上不可行的。 换句话说,从结果中找到输入是极其困难的。 这是一个单向函数。

例如,考虑以下方程:

3² mod 10 = 9

现在,给定9,是前面方程中发现的结果,其指数为前面问题中的生成器3,这是极难确定的。 这个困难的问题通常在 Diffie-Hellman 密钥交换和数字签名算法中使用。

椭圆曲线

椭圆曲线算法基于前面讨论的离散对数问题,但是在椭圆曲线的上下文中。 椭圆曲线是一个代数立方曲线,可以由以下方程定义。 曲线是非奇异的,这意味着它没有尖点或自交点。 它有两个变量ab,以及一个无穷远点。

在这里,ab是整数,其值是定义椭圆曲线的域上的元素。 椭圆曲线可以在实数、有理数、复数或有限域上定义。 为了加密目的,使用素数有限域上的椭圆曲线,而不是实数。 此外,素数应大于 3。 通过改变a和/或b的值可以生成不同的曲线。

基于椭圆曲线的最显著使用的加密系统是椭圆曲线数字签名算法(ECDSA)和椭圆曲线迪菲-赫尔曼(ECDH)密钥交换。

要理解公钥密码学,需要探讨的关键概念是公钥和私钥。

公钥和私钥

私钥,顾名思义,是用户随机生成并保密的数字。私钥需要受到保护,不得未经授权访问;否则,公钥密码的整个方案都会受到威胁,因为这是用于解密消息的密钥。私钥可以根据使用的算法的类型和类别的不同长度而不同。例如,在 RSA 中,通常使用 1024 位或 2048 位的密钥。1024 位密钥大小不再被认为是安全的,建议至少使用 2048 位密钥大小。

公钥是由私钥所有者免费提供并发布的。此后任何希望向公钥发布者发送加密消息的人都可以使用公开的公钥对消息进行加密并将其发送给私钥持有人。其他人无法解密消息,因为相应的私钥被拟定的接收方安全地持有。收件人收到具有公钥加密的消息后,可以使用私钥解密消息。然而,公钥存在一些问题,包括公钥发布者的真实性和身份识别。

在下一节中,我们将介绍两个非对称密钥密码学的例子:RSA 和 ECC。RSA 是公钥密码学的第一个实现,而 ECC 广泛用于区块链技术。

RSA

RSA是由 Ron Rivest,Adi Shamir 和 Leonard Adelman 在 1977 年发明的,因此被称为Rivest–Shamir–Adleman (RSA)。这种公钥密码学基于整数分解问题,其中两个大素数的乘法很容易,但将其(乘法结果,积)分解回两个原始数字很困难。

与 RSA 算法相关的工作要点是在密钥生成过程中。RSA 密钥对通过执行以下步骤生成:

  1. 模数生成:
    • 选择pq,它们是非常大的质数

    • pq相乘,n=p.q生成模数n

  1. 生成互质:
    • 假设一个称为e的数字。

    • e应满足某种条件;即,它应大于1且小于(p-1) (q-1)。换句话说,e必须是这样一个数字,除了1之外没有任何其他数字可以整除e(p-1) (q-1)。这被称为互素,也就是e(p-1) (q-1)的互素。

  1. 生成公钥:

步骤 1 生成的模数和步骤 2 生成的互质 e 构成了一对共同的公钥。这部分是可以与任何人共享的公共部分;然而,pq 需要保密。

  1. 生成私钥

这里称为 d 的私钥是从 pqe 计算得出的。私钥基本上是 e 模 (p-1) (q-1) 的倒数。用方程表示如下:

ed = 1 mod (p-1) (q-1)

通常,扩展欧几里得算法用于计算 d。该算法接受 pqe,并计算 d。这种方案的关键思想是,任何知道 pq 的人都可以通过应用扩展欧几里得算法轻松计算出私钥 d。然而,不知道 pq 值的人无法生成 d。这也意味着 pq 应该足够大,使得模数 n 因子分解变得极其困难(计算上不可行)。

使用 RSA 进行加密和解密

RSA 使用以下方程产生密文:

C = P**^e mod n

这意味着明文 P 被提升到 e 次方,然后对模 n 进行了缩减。RSA 中的解密由以下方程提供:

P = C^(d) mod n

这意味着拥有公钥对(ne)的接收方可以通过将 C 提升到私钥 d 的值并减少到模 n 来解密数据。

椭圆曲线密码学

椭圆曲线密码学ECC)基于有限域上的椭圆曲线离散对数问题(伽罗华域)。ECC 相对于其他类型的公钥算法的主要优点是,它需要更小的密钥大小,同时提供与 RSA 等算法相同级别的安全性。源自 ECC 的两个值得注意的方案是用于密钥交换的 ECDH 和用于数字签名的 ECDSA。

ECC 也可以用于加密,但在实践中通常不用于此目的。相反,它通常用于密钥交换和数字签名。由于 ECC 需要更少的空间来运行,因此在嵌入式平台和存储资源有限的系统中变得非常流行。相比之下,与 RSA 中的 3072 位操作数相比,仅使用 256 位操作数即可实现相同级别的安全性。

ECC 背后的数学

要理解 ECC,有必要对底层数学进行基本介绍。椭圆曲线基本上是一种称为魏尔斯特拉斯方程的多项式方程,它在有限域上生成曲线。最常用的域是所有算术运算都在模 a 素数 p 上执行的域。椭圆曲线群由有限域上的曲线上的点组成。

椭圆曲线在以下方程中定义:

在这里,AB 属于有限域 ZpFp(素有限域),还有一个称为 无穷点 的特殊值。无穷点(∞)用于为曲线上的点提供标识操作。

此外,还需要满足一个条件,确保前面提到的方程没有重复根。这意味着曲线是非奇异的。

在以下方程中描述了条件,这是需要满足的标准要求。更确切地说,这确保了曲线是非奇异的:

为了基于椭圆曲线构造离散对数问题,需要一个足够大的循环群。首先,群元素被确定为满足上述方程的一组点。然后,需要在这些点上定义群操作。

椭圆曲线上的群操作是点加法和点倍增。点加法是指添加两个不同的点,而 点倍增 意味着将同一点加到自身。

点加法

点加法在下图中展示。这是椭圆曲线上点加法的几何表示。在这种方法中,通过曲线画一条对角线,该对角线与曲线在两点 PQ 处相交,如图所示,这产生了曲线和线之间的第三点。这个点被镜像为 P+Q,表示加法的结果为 R

这在下图中显示为 P+Q

在实数域上的点加法

用于加法的 + 符号表示的群操作产生以下方程:

P + Q = R

在这种情况下,两点相加以计算曲线上第三点的坐标:

P + Q = R

更确切地说,这意味着坐标相加,如下方程所示:

(x[1], y[1]) + (x[2], y[2]) = (x[3], y[3])

点加法的方程如下:

X[3] = s²**- x[1] - x[2] mod p

y[3] = s (x[1] - x[3]) - y[1] mod p

在这里,我们看到前述方程的结果:

前述方程中的 S 描述了穿过 PQ 的线。

在下图中显示了点加法的一个示例。它是使用 Certicom 的在线计算器生成的。此示例显示了在有限域 F[23] 上的方程的加法和解。这与之前显示的实数示例相反,后者仅显示曲线但不提供方程的解:

点加法示例

在前面的例子中,左侧的图表显示满足此方程的点:

有 27 个解用于F[23]上先前显示的方程。选择PQ用于添加以产生点R。计算显示在右侧,计算第三个点R。请注意,在这里,l用于描绘通过PQ的线。

作为示例,展示了如何通过图中的点满足方程的选择,其中选择了一个点(x, y),其中x = 3y = 6

使用这些值显示了方程确实被满足:

下一小节介绍了可在椭圆曲线上执行的另一项运算,即点加倍的概念。

点加倍

椭圆曲线上的另一种运算被称为点加倍。 这是一个过程,其中P被加到自身。在这种方法中,穿过曲线的切线被绘制,如下图所示。得到第二个点,即通过切线和曲线的交点。

然后,将此点镜像以得出结果,即2P = P + P

代表在实数上进行点加倍的图

对于点加倍,方程变为:

在这里,S是穿过P的切线(切线)的斜率。它是前面示图上方的线。在前面的示例中,曲线以实数绘制为一个简单的例子,并未显示方程的解。

以下示例显示了在有限域F[23]上的椭圆曲线的解和点加倍。左侧的图表显示满足方程的点:

点加倍的例子

如前图右侧所示,计算在P加入自身后找到R的标记(点加倍)。没有在这里显示的Q,并且相同的点P用于加倍。请注意,在计算中,l用于描绘穿过P的切线。

在下一节中,将介绍离散对数问题的概念。

ECC 中的离散对数问题

ECC 中的离散对数问题基于这样的思想,即在某些条件下,椭圆曲线上的所有点形成一个循环群。

在椭圆曲线上,公钥是生成点的随机倍数,而私钥是用于生成该倍数的随机选择的整数。换句话说,私钥是随机选择的整数,而公钥是曲线上的一个点。离散对数问题用于找到私钥(一个整数),其中该整数落在椭圆曲线上的所有点之内。以下方程更准确地展示了这个概念。

考虑一个椭圆曲线E,其中有两个元素PT。离散对数问题是找到整数d,其中1 <= d <= #E,使得:

在这里,T 是公钥(曲线上的一个点),d 是私钥。换句话说,公钥是生成器的随机倍数,而私钥是用于生成该倍数的整数。#E表示椭圆曲线的阶,这意味着椭圆曲线的循环群中存在的点的数量。循环群由椭圆曲线上的点和无穷点的组合形成。

密钥对与椭圆曲线的特定域参数相关联。域参数包括字段大小、字段表示、来自字段ab的两个元素、两个字段元素XgYg、点G的顺序n计算为G = (Xg, Yg),以及余因子h = #E(Fq)/n。后面的章节中将描述使用 OpenSSL 的实际示例。

推荐和标准化了各种参数以作为 ECC 的曲线使用。这里展示了secp256k1规范的一个例子。这是比特币中使用的规范:

来自 http://www.secg.org/sec2-v2.pdfsecp256k1规范

六元组中所有这些值的解释如下:

  • P 是指定有限域大小的素数p

  • ab 是椭圆曲线方程的系数。

  • G 是生成所需子群的基点,也称为生成器。基点可以以压缩或未压缩形式表示。在实际实现中,没有必要存储曲线上的所有点。压缩的生成器有效是因为可以仅使用x坐标和y坐标的最低有效位来识别曲线上的点。

  • n 是子群的阶。

  • h 是子群的余因子。

在下一节中,展示了使用 OpenSSL 的两个示例,帮助您了解 RSA 和 ECC 加密的实际方面。

使用 OpenSSL 进行 RSA

下面的示例说明了如何使用 OpenSSL 命令行生成 RSA 公钥和私钥对。

RSA 公钥和私钥对

首先,下面的小节展示了如何使用 OpenSSL 生成 RSA 私钥。

私钥

执行以下命令生成私钥:

$ openssl genpkey -algorithm RSA -out privatekey.pem -pkeyopt \
 rsa_keygen_bits:1024
...............................++++++
....................++++++  

命令中使用的反斜杠(\)是用于续行的。

执行该命令后,将生成一个名为privatekey.pem的文件,其中包含生成的私钥,如下所示:

$ cat privatekey.pem
-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKJOFBzPy2vOd6em Bk/UGrzDy7TvgDYnYxBfiEJId/r+EyMt/F14k2fDTOVwxXaXTxiQgD+BKuiey/69 9itnrqW/xy/pocDMvobj8QCngEntOdNoVSaN+t0f9nRM3iVM94mz3/C/v4vXvoac PyPkr/0jhIV0woCurXGTghgqIbHRAgMBAAECgYEAlB3s/N4lJh0l1TkOSYunWtzT 6isnNkR7g1WrY9H+rG9xx4kP5b1DyE3SvxBLJA6xgBle8JVQMzm3sKJrJPFZzzT5 NNNnugCxairxcF1mPzJAP3aqpcSjxKpTv4qgqYevwgW1A0R3xKQZzBKU+bTO2hXV D1oHxu75mDY3xCwqSAECQQDUYV04wNSEjEy9tYJ0zaryDAcvd/VG2/U/6qiQGajB eSpSqoEESigbusKku+wVtRYgWWEomL/X58t+K01eMMZZAkEAw6PUR9YLebsm/Sji iOShV4AKuFdi7t7DYWE5Ulb1uqP/i28zN/ytt4BXKIs/KcFykQGeAC6LDHZyycyc ntDIOQJAVqrE1/wYvV5jkqcXbYLgV5YA+KYDOb9Y/ZRM5UETVKCVXNanf5CjfW1h MMhfNxyGwvy2YVK0Nu8oY3xYPi+5QQJAUGcmORe4w6Cs12JUJ5p+zG0s+rG/URhw B7djTXm7p6b6wR1EWYAZDM9MArenj8uXAA1AGCcIsmiDqHfU7lgz0QJAe9mOdNGW 7qRppgmOE5nuEbxkDSQI7OqHYbOLuwfCjHzJBrSgqyi6pj9/9CbXJrZPgNDwdLEb 
GgpDKtZs9gLv3A==
-----END PRIVATE KEY-----  

公钥

由于私钥在数学上与公钥相关联,因此也可以从私钥生成或派生公钥。使用前述私钥的示例,可以生成公钥,如下所示:

$ openssl rsa -pubout -in privatekey.pem -out publickey.pem 

writing RSA key  

可以使用文件阅读器或任何文本查看器查看公钥:

$ cat publickey.pem
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCiThQcz8trznenpgZP1Bq8w8u0 74A2J2MQX4hCSHf6/hMjLfxdeJNnw0zlcMV2l08YkIA/gSronsv+vfYrZ66lv8cv 6aHAzL6G4/EAp4BJ7TnTaFUmjfrdH/Z0TN4lTPeJs9/wv7+L176GnD8j5K/9I4SF 
dMKArq1xk4IYKiGx0QIDAQAB
-----END PUBLIC KEY-----  

为了查看各种组件的更多细节,例如在加密过程中使用的模数、素数,或者生成的私钥的指数和系数,可以使用以下命令(这里仅显示部分输出,因为实际输出非常长):

$ openssl rsa -text -in privatekey.pem 
Private-Key: (1024 bit)
modulus: 
   00:a2:4e:14:1c:cf:cb:6b:ce:77:a7:a6:06:4f:d4: 
   1a:bc:c3:cb:b4:ef:80:36:27:63:10:5f:88:42:48: 
   77:fa:fe:13:23:2d:fc:5d:78:93:67:c3:4c:e5:70: 
   c5:76:97:4f:18:90:80:3f:81:2a:e8:9e:cb:fe:bd: 
   f6:2b:67:ae:a5:bf:c7:2f:e9:a1:c0:cc:be:86:e3: 
   f1:00:a7:80:49:ed:39:d3:68:55:26:8d:fa:dd:1f: 
   f6:74:4c:de:25:4c:f7:89:b3:df:f0:bf:bf:8b:d7: 
   be:86:9c:3f:23:e4:af:fd:23:84:85:74:c2:80:ae:  
   ad:71:93:82:18:2a:21:b1:d1 
publicExponent: 65537 (0x10001)
privateExponent: 
   00:94:1d:ec:fc:de:25:26:1d:25:d5:39:0e:49:8b: 
   a7:5a:dc:d3:ea:2b:27:36:44:7b:83:55:ab:63:d1: 
   fe:ac:6f:71:c7:89:0f:e5:bd:43:c8:4d:d2:bf:10: 
   4b:24:0e:b1:80:19:5e:f0:95:50:33:39:b7:b0:a2: 
   6b:24:f1:59:cf:34:f9:34:d3:67:ba:00:b1:6a:2a: 
   f1:70:5d:66:3f:32:40:3f:76:aa:a5:c4:a3:c4:aa: 
   53:bf:8a:a0:a9:87:af:c2:05:b5:03:44:77:c4:a4: 
   19:cc:12:94:f9:b4:ce:da:15:d5:0f:5a:07:c6:ee:  
   f9:98:36:37:c4:2c:2a:48:01 
prime1: 
   00:d4:61:5d:38:c0:d4:84:8c:4c:bd:b5:82:74:cd: 
   aa:f2:0c:07:2f:77:f5:46:db:f5:3f:ea:a8:90:19: 
   a8:c1:79:2a:52:aa:81:04:4a:28:1b:ba:c2:a4:bb: 
   ec:15:b5:16:20:59:61:28:98:bf:d7:e7:cb:7e:2b:   
   4d:5e:30:c6:59 
prime2: 
   00:c3:a3:d4:47:d6:0b:79:bb:26:fd:28:e2:88:e4: 
   a1:57:80:0a:b8:57:62:ee:de:c3:61:61:39:52:56: 
   f5:ba:a3:ff:8b:6f:33:37:fc:ad:b7:80:57:28:8b: 
   3f:29:c1:72:91:01:9e:00:2e:8b:0c:76:72:c9:cc: 
   9c:9e:d0:c8:39 

探索公钥

同样,可以使用以下命令探索公钥。公钥和私钥都是 base64 编码的:

$ openssl pkey -in publickey.pem -pubin -text
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCiThQcz8trznenpgZP1Bq8w8u0 74A2J2MQX4hCSHf6/hMjLfxdeJNnw0zlcMV2l08YkIA/gSronsv+vfYrZ66lv8cv 6aHAzL6G4/EAp4BJ7TnTaFUmjfrdH/Z0TN4lTPeJs9/wv7+L176GnD8j5K/9I4SF 
dMKArq1xk4IYKiGx0QIDAQAB
-----END PUBLIC KEY-----
Public-Key: (1024 bit)
Modulus:
   00:a2:4e:14:1c:cf:cb:6b:ce:77:a7:a6:06:4f:d4:
   1a:bc:c3:cb:b4:ef:80:36:27:63:10:5f:88:42:48:
   77:fa:fe:13:23:2d:fc:5d:78:93:67:c3:4c:e5:70:
   c5:76:97:4f:18:90:80:3f:81:2a:e8:9e:cb:fe:bd:
   f6:2b:67:ae:a5:bf:c7:2f:e9:a1:c0:cc:be:86:e3:
   f1:00:a7:80:49:ed:39:d3:68:55:26:8d:fa:dd:1f:
   f6:74:4c:de:25:4c:f7:89:b3:df:f0:bf:bf:8b:d7:
   be:86:9c:3f:23:e4:af:fd:23:84:85:74:c2:80:ae: 
   ad:71:93:82:18:2a:21:b1:d1
Exponent: 65537 (0x10001)  

现在公钥可以公开共享,任何想要向您发送消息的人都可以使用公钥加密消息并将其发送给您。然后,您可以使用相应的私钥解密文件。

加密和解密

在本节中,将介绍一个示例,演示如何使用 OpenSSL 中的 RSA 执行加密和解密操作。

加密

使用前面示例中生成的私钥,可以构造如下所示的加密文本文件message.txt的命令:

$ echo datatoencrypt > message.txt

$ openssl rsautl -encrypt -inkey publickey.pem -pubin -in message.txt \
  -out message.rsa  

这将生成一个名为message.rsa的文件,它是以二进制格式保存的。如果你在 nano 编辑器或你选择的任何其他文本编辑器中打开message.rsa,它将显示一些垃圾数据,如下图所示:

图片

显示垃圾数据(加密)的message.rsa

解密

为了解密 RSA 加密的文件,可以使用以下命令:

$ openssl rsautl -decrypt -inkey privatekey.pem -in message.rsa \
  -out message.dec  

现在,如果使用cat读取文件,可以看到解密后的明文,如下所示:

$ cat message.dec 
datatoencrypt  

使用 OpenSSL 进行 ECC

OpenSSL 提供了一个非常丰富的函数库,用于执行 ECC。以下小节显示了如何在 OpenSSL 中实际使用 ECC 函数。

ECC 私钥和公钥对

在这个小节中,首先介绍了一个示例,演示了使用 OpenSSL 库中可用的 ECC 函数创建私钥的过程。

私钥

ECC 是基于各种标准定义的域参数。您可以使用以下命令查看 OpenSSL 中定义的所有可用标准以及推荐的曲线列表。(再次强调,这里仅显示部分输出,并且在中间被截断。)

$ openssl ecparam -list_curves
secp112r1 : SECG/WTLS curve over a 112 bit prime field 
secp112r2 : SECG curve over a 112 bit prime field 
secp128r1 : SECG curve over a 128 bit prime field 
secp128r2 : SECG curve over a 128 bit prime field
secp160k1 : SECG curve over a 160 bit prime field 
secp160r1 : SECG curve over a 160 bit prime field 
secp160r2 : SECG/WTLS curve over a 160 bit prime field
secp192k1 : SECG curve over a 192 bit prime field
secp224k1 : SECG curve over a 224 bit prime field
secp224r1 : NIST/SECG curve over a 224 bit prime field
secp256k1 : SECG curve over a 256 bit prime field
secp384r1 : NIST/SECG curve over a 384 bit prime field
secp521r1 : NIST/SECG curve over a 521 bit prime field
prime192v1: NIST/X9.62/SECG curve over a 192 bit prime field
 .
 .
 .
 .
brainpoolP384r1: RFC 5639 curve over a 384 bit prime field 
brainpoolP384t1: RFC 5639 curve over a 384 bit prime field 
brainpoolP512r1: RFC 5639 curve over a 512 bit prime field 
brainpoolP512t1: RFC 5639 curve over a 512 bit prime field  

在下面的示例中,使用secp256k1来演示 ECC 的使用。

生成私钥

要生成私钥,请执行以下命令:

$ openssl ecparam -name secp256k1 -genkey -noout -out ec-privatekey.pem
$ cat ec-privatekey.pem
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIJHUIm9NZAgfpUrSxUk/iINq1ghM/ewn/RLNreuR52h/oAcGBSuBBAAK oUQDQgAE0G33mCZ4PKbg5EtwQjk6ucv9Qc9DTr8JdcGXYGxHdzr0Jt1NInaYE0GG 
ChFMT5pK+wfvSLkYl5ul0oczwWKjng==
-----END EC PRIVATE KEY-----  

现在名为ec-privatekey.pem的文件包含基于secp256k1曲线生成的椭圆曲线EC)私钥。要从私钥生成公钥,发出以下命令:

$ openssl ec -in ec-privatekey.pem -pubout -out ec-pubkey.pem 
read EC key
writing EC key  

读取文件会产生以下输出,显示生成的公钥:

$ cat ec-pubkey.pem
-----BEGIN PUBLIC KEY----- 
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAE0G33mCZ4PKbg5EtwQjk6ucv9Qc9DTr8J
dcGXYGxHdzr0Jt1NInaYE0GGChFMT5pK+wfvSLkYl5ul0oczwWKjng==
-----END PUBLIC KEY-----  

现在ec-pubkey.pem文件包含从ec-privatekey.pem导出的公钥。可以使用以下命令进一步探究私钥:

$ openssl ec -in ec-privatekey.pem -text -noout 
read EC key
Private-Key: (256 bit) 
priv:
   00:91:d4:22:6f:4d:64:08:1f:a5:4a:d2:c5:49:3f:
   88:83:6a:d6:08:4c:fd:ec:27:fd:12:cd:ad:eb:91: 
   e7:68:7f
pub:
   04:d0:6d:f7:98:26:78:3c:a6:e0:e4:4b:70:42:39:
   3a:b9:cb:fd:41:cf:43:4e:bf:09:75:c1:97:60:6c:
   47:77:3a:f4:26:dd:4d:22:76:98:13:41:86:0a:11:
   4c:4f:9a:4a:fb:07:ef:48:b9:18:97:9b:a5:d2:87:
   33:c1:62:a3:9e 
ASN1 OID: secp256k1  

同样,可以使用以下命令进一步探究公钥:

$ openssl ec -in ec-pubkey.pem -pubin -text -noout
read EC key
Private-Key: (256 bit) 
pub:
   04:d0:6d:f7:98:26:78:3c:a6:e0:e4:4b:70:42:39:
   3a:b9:cb:fd:41:cf:43:4e:bf:09:75:c1:97:60:6c:
   47:77:3a:f4:26:dd:4d:22:76:98:13:41:86:0a:11:
   4c:4f:9a:4a:fb:07:ef:48:b9:18:97:9b:a5:d2:87:
   33:c1:62:a3:9e 
ASN1 OID: secp256k1  

也可以生成包含所需参数的文件,例如secp256k1,然后进一步探究它以理解底层参数:

$ openssl ecparam -name secp256k1 -out secp256k1.pem 
$ cat secp256k1.pem
-----BEGIN EC PARAMETERS-----
BgUrgQQACg==
-----END EC PARAMETERS-----  

该文件现在包含所有secp256k1参数,可以使用以下命令进行分析:

$ openssl ecparam -in secp256k1.pem -text -param_enc explicit -noout    

此命令将产生类似于这里显示的输出:

Field Type: prime-field 
Prime:
   00:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:
   ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:fe:ff: 
   ff:fc:2f
A:  0
B:  7 (0x7)
Generator (uncompressed): 
   04:79:be:66:7e:f9:dc:bb:ac:55:a0:62:95:ce:87:
   0b:07:02:9b:fc:db:2d:ce:28:d9:59:f2:81:5b:16:
   f8:17:98:48:3a:da:77:26:a3:c4:65:5d:a4:fb:fc:
   0e:11:08:a8:fd:17:b4:48:a6:85:54:19:9c:47:d0:
   8f:fb:10:d4:b8
Order:
   00:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:
   ff:fe:ba:ae:dc:e6:af:48:a0:3b:bf:d2:5e:8c:d0:
   36:41:41
Cofactor:  1 (0x1)  

前面的例子显示了所使用的素数,以及AB的值,还有secp256k1曲线域参数的生成器、阶和余因子。

通过前述示例,我们通过加密和解密的角度完成了对公钥密码学的介绍。其他相关构造,如数字签名,将在本章后面讨论。

在下一节中,我们将讨论另一类加密原语,即哈希函数。哈希函数不用于加密数据,而是产生提供给哈希函数作为输入的数据的固定长度摘要。

哈希函数

哈希函数用于创建任意长输入字符串的固定长度摘要。哈希函数是无密钥的,它们提供数据完整性服务。通常使用迭代和专用哈希函数构建技术来构建它们。

各种哈希函数可供选择,例如 MD、SHA-1、SHA-2、SHA-3、RIPEMD 和 Whirlpool。哈希函数通常用于数字签名和消息认证码MACs),如 HMACs。它们具有三种安全性质,即原像抗性、第二原像抗性和碰撞抗性。这些性质将在本节后面进行解释。

哈希函数通常也用于提供数据完整性服务。它们可以被用作单向函数,也可以被用来构建其他加密原语,如 MACs 和数字签名。一些应用程序将哈希函数用作生成伪随机数生成器PRNGs)的手段。根据所需完整性级别,哈希函数必须满足两个实用性和三个安全性质。这些性质将在以下子节中讨论。

将任意消息压缩为固定长度的摘要。

此属性与哈希函数必须能够接受任意长度的输入文本并输出固定长度的压缩消息有关。哈希函数通常以不同的位大小产生压缩输出,通常在 128 位到 512 位之间。

易于计算

哈希函数是高效且快速的单向函数。哈希函数需要非常快速地计算,而不管消息大小如何。如果消息太大,效率可能会降低,但函数仍应足够快以供实际使用。

在下一节中,将讨论哈希函数的安全性质。

原像抗性

可以使用以下简单方程来解释此属性:

h(x) = y

在这里,h是哈希函数,x是输入,y是哈希。第一个安全属性要求y不能被逆向计算到xx被视为y的原像,因此被称为原像抗性。这也被称为单向属性。

第二原像抗性

第二原像抗性属性要求给定xh(x),几乎不可能找到任何其他消息m,其中m != x消息 m 的哈希 = 消息 x 的哈希h(m) = h(x)。此属性也称为弱碰撞抗性

碰撞抗性

碰撞抗性属性要求两个不同的输入消息不应散列到相同的输出。换句话说,h(x) != h(z)。此属性也称为强碰撞抗性

所有这些属性都显示在以下图表中:

哈希函数的三个安全性质

由于其本质,哈希函数总会存在一些碰撞。这是两个不同的消息散列到相同的输出的情况。但是,找到它们应该是计算上不可行的。所有哈希函数中都希望存在一种称为雪崩效应的概念。雪崩效应规定,即使是输入文本中的一个小变化,甚至是单个字符的变化,也将导致完全不同的散列输出。

哈希函数通常是通过遵循迭代哈希函数方法设计的。使用此方法,输入消息按块进行多轮压缩,以产生压缩输出。一种流行的迭代哈希函数类型是Merkle-Damgard 结构。该结构基于将输入数据划分为相等的块大小,然后通过迭代方式将它们馈送到压缩函数中的想法。压缩函数的碰撞抗性确保了哈希输出也是抗碰撞的。可以使用分组密码构建压缩函数。除了 Merkle-Damgard 之外,研究人员还提出了各种其他压缩函数的构造,例如 Miyaguchi-Preneel 和 Davies-Meyer。

在以下各小节中介绍了多种哈希函数类别。

消息摘要

消息摘要MD)函数在 1990 年代初很流行。MD4 和 MD5 属于此类。这两个 MD 函数都被发现是不安全的,不再建议使用。MD5 是一个常用于文件完整性检查的 128 位哈希函数。

安全哈希算法

以下列出了最常见的安全哈希算法SHAs):

  • SHA-0:这是 NIST 在 1993 年引入的一个 160 位的函数。

  • SHA-1:SHA-1 是由 NIST 于 1995 年引入的,作为 SHA-0 的替代。这也是一个 160 位的哈希函数。SHA-1 在 SSL 和 TLS 实现中被普遍使用。值得注意的是,SHA-1 现在被认为是不安全的,并且正在被证书颁发机构弃用。在任何新的实现中都不推荐使用它。

  • SHA-2:这个类别包括了根据哈希位数定义的四个函数:SHA-224、SHA-256、SHA-384 和 SHA-512。

  • SHA-3:这是最新的 SHA 函数系列。SHA-3-224、SHA-3-256、SHA-3-384 和 SHA-3-512 是该系列的成员。SHA-3 是 Keccak 的 NIST 标准化版本。Keccak 使用了一种称为海绵构造的新方法,而不是常用的 Merkle-Damgard 转换。

  • RIPEMD:RIPEMD 是RACE 完整性原语评估消息摘要的缩写。它基于构建 MD4 的设计思想。RIPEMD 有多个版本,包括 128 位、160 位、256 位和 320 位。

  • Whirlpool:这基于修改版的 Rijndael 密码,称为 W。它使用 Miyaguchi-Preneel 压缩函数,这是一种用于将两个固定长度输入压缩为单个固定长度输出的单向函数类型。它是一个单个块长度的压缩函数。

哈希函数具有许多实际应用,从简单的文件完整性检查和密码存储到在加密协议和算法中使用。它们被用于哈希表、分布式哈希表、布隆过滤器、病毒指纹、点对点文件共享等许多应用中。

哈希函数在区块链中发挥着重要作用。特别是,PoW 函数特别是两次使用 SHA-256 来验证矿工所花费的计算工作。RIPEMD 160 用于生成比特币地址。这将在后面的章节中进一步讨论。

在下一节中,将介绍 SHA 算法的设计。

安全哈希算法的设计

在接下来的部分中,您将了解到 SHA-256 和 SHA-3 的设计。这两者分别在比特币和以太坊中使用。以太坊不使用 NIST 标准 SHA-3,而是使用原始算法 Keccak。经过一些修改(如增加轮数和更简单的消息填充),NIST 将 Keccak 标准化为 SHA-3。

SHA-256 的设计

SHA-256 具有输入消息大小 < 2⁶⁴-bits。块大小为 512-bits,字长为 32-bits。输出为 256-bit 摘要。

压缩函数处理 512-bit 消息块和 256-bit 中间散列值。此函数的主要组成部分有两个:压缩函数和消息调度。

算法运行如下,经过八个步骤:

  1. 预处理

    1. 使用消息填充来调整块的长度为 512-bits,如果小于所需的块大小。

    2. 将消息解析为消息块,从而确保消息及其填充被分成等长的 512 位块。

    3. 设置初始散列值,由取首八个素数的平方根的小数部分的前 32 位得到的八个 32 位字组成。这些初始值是随机选择的来初始化过程,它们提供了一定的信心,即算法中不存在后门。

  2. 散列计算

    1. 然后按顺序处理每个消息块,并需要 64 轮来计算完整的散列输出。每轮使用略有不同的常量来确保没有两轮相同。

    2. 准备消息调度。

    3. 初始化八个工作变量。

    4. 计算中间散列值。

    5. 最后,处理消息,并生成输出散列:

SHA-256 压缩函数一轮

在上图中,abcdefgh 是寄存器。MajCh 以位方式应用。∑[0]∑[1] 执行位旋转。循环常量为 W[j]K[j],它们相加后取余 2³²

设计 SHA-3(Keccak)

SHA-3 的结构与 SHA-1 和 SHA-2 很不相同。SHA-3 背后的关键思想是基于无键排列,而不是其他典型的散列函数构造使用的有键排列。Keccak 也不使用常用于处理散列函数中的任意长度输入消息的 Merkle-Damgard 转换。在 Keccak 中使用了一种称为 海绵和挤压构造 的新方法。这是一个随机排列模型。SHA-3 有不同的变种进行了标准化,如 SHA-3-224、SHA-3-256、SHA-3-384、SHA-3-512、SHAKE-128 和 SHAKE-256。SHAKE-128 和 SHAKE-256 是可扩展输出函数XOFs),也被 NIST 标准化。XOFs 允许输出扩展到任意所需长度。

下图显示了海绵和挤压模型,这是 SHA-3 或 Keccak 的基础。类似于海绵,数据首先被吸收到海绵中,然后应用填充。然后,它通过异或变换为置换状态的子集,并且输出被从代表转换后的状态的海绵函数中挤出。速率是海绵函数的输入块大小,而容量确定了一般安全级别:

SHA-3 吸收和挤压函数

OpenSSL 哈希函数示例

以下命令将使用 SHA-256 算法对Hello消息生成 256 位的哈希值:

$ echo -n 'Hello' | openssl dgst -sha256
(stdin)= 185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969  

注意,即使是文本中的微小更改,例如更改字母 H 的大小写,也会导致输出哈希的巨大变化。这被称为雪崩效应,正如之前所讨论的那样:

$ echo -n 'hello' | openssl dgst -sha256
(stdin)= 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824  

请注意,两个输出完全不同:

Hello: 
18:5f:8d:b3:22:71:fe:25:f5:61:a6:fc:93:8b:2e:26:43:06:ec:30:4e:da:51:80:07: 
d1:76:48:26:38:19:69

hello: 
2c:f2:4d:ba:5f:b0:a3:0e:26:e8:3b:2a:c5:b9:e2:9e:1b:16:1e:5c:1f:a7:42:5e:73:
04:33:62:93:8b:98:24  

通常,哈希函数不使用密钥。然而,如果它们与密钥一起使用,则可以用于创建另一种称为 MACs 的加密构造。

消息认证码

MACs 有时被称为密钥散列函数,可用于提供消息完整性和身份验证。更具体地说,它们用于提供数据的源身份验证。这些是对称加密原语,使用发送方和接收方之间的共享密钥。MACs 可以使用块密码或散列函数构造。

使用块密码的 MACs

使用此方法,块密码以 密码块链CBC)模式用于生成 MAC。任何块密码,例如 AES 在 CBC 模式下,都可以使用。消息的 MAC 实际上是 CBC 操作的最后一轮的输出。MAC 输出的长度与用于生成 MAC 的块密码的块长度相同。

MACs 的验证很简单,只需计算消息的 MAC 并将其与接收到的 MAC 进行比较。如果它们相同,则确认了消息完整性;否则,消息被视为已被更改。还应注意,MACs 的工作方式类似于数字签名,但由于其对称性质,它们无法提供不可否认的服务。

基于哈希的 MACs

与哈希函数类似,基于哈希的 MACsHMACs)产生固定长度的输出,并将任意长的消息作为输入。在此方案中,发送方使用 MAC 对消息进行签名,接收方使用共享密钥进行验证。密钥使用两种方法之一与消息一起使用,分别称为密钥前缀密钥后缀。使用密钥前缀方法时,密钥与消息连接在一起;也就是说,密钥在前,消息在后,而使用密钥后缀方法时,密钥在消息之后,如下面的方程所示:

密钥前缀:M = MACk(x) = h(k||x)

密钥后缀:M=MACk(x) = h(x||k)

这两种方法都有优缺点。对这两种方案的一些攻击已经发生。密码研究人员提出了使用各种技术的 HMAC 构造方案,例如ipadopad(内部填充和外部填充)。这些方案在一些假设下被认为是安全的:

MAC 函数的操作

在点对点网络和区块链技术中使用哈希函数的各种强大应用。一些显著的例子,如默克尔树、帕特里夏树和分布式哈希表DHT),将在以下子章节中讨论。

默克尔树

默克尔树的概念由 Ralph Merkle 引入。这里显示了默克尔树的图表。默克尔树可以安全有效地验证大型数据集。

默克尔树

默克尔树是一种二叉树,其中首先将输入放置在叶节点(没有子节点的节点)上,然后将子节点的值对的值哈希在一起,以产生父节点(内部节点)的值,直到达到一个称为默克尔根的单一哈希值。

帕特里夏树

要理解帕特里夏树,您首先会介绍trie的概念。Trie,或数字树,是一种用于存储数据集的有序树数据结构。

用于检索字母数字编码信息的实用算法Patricia),也称为基数树,是 trie 的紧凑表示,其中作为父节点的唯一子节点与其父节点合并。

基于帕特里夏和默克尔的定义,Merkle-Patricia 树是一个具有根节点的树,该根节点包含整个数据结构的哈希值。

分布式哈希表

哈希表是一种用于将键映射到值的数据结构。在内部,使用哈希函数来计算一个索引,以便从存储桶数组中找到所需的值。桶中使用哈希键存储记录,并按特定顺序组织。

考虑到之前提供的定义,可以将 DHT 视为数据分布在各个节点上,而节点等价于点对点网络中的存储桶的数据结构。

下图显示了分布式哈希表(DHT)的工作原理。数据通过哈希函数传递,然后生成一个紧凑的密钥。然后将此密钥与点对点网络上的数据(值)相关联。当网络上的用户请求数据(通过文件名)时,可以再次对文件名进行哈希以生成相同的密钥,然后可以请求网络上的任何节点以查找相应的数据。DHT 提供了分散性、容错性和可扩展性:

分布式哈希表

哈希函数的另一个应用是数字签名,它们可以与非对称加密结合使用。这个概念在下面的小节提供的示例中有详细讨论。

数字签名

数字签名提供了将消息与消息来源实体关联起来的一种方式。数字签名用于提供数据的原始认证和不可否认性。

数字签名在区块链中使用,发送方在向网络广播交易之前使用他们的私钥对交易进行数字签名。这种数字签名证明他们是资产的合法所有者,例如比特币。这些交易再次被网络上的其他节点验证,以确保资金确实属于声称是所有者的节点(用户)。我们将在本书专门介绍比特币和以太坊的章节中更详细地讨论这些概念。

数字签名分为两步进行计算。例如,RSA 数字签名方案的高级步骤如下。

RSA 数字签名算法

下面是 RSA 数字签名算法:

  1. 计算数据包的哈希值:这将提供数据的完整性保证,因为接收方可以再次计算哈希并与原始哈希匹配,以检查数据在传输过程中是否被修改。从技术上讲,消息签名可以在不先对数据进行哈希处理的情况下工作,但被认为不安全。

  2. 用签名者的私钥对哈希值进行签名:因为只有签名者有私钥,所以可以确保签名和签名数据的真实性。

数字签名有一些重要的属性,如真实性、不可伪造性和不可重用性。真实性意味着数字签名可以被接收方验证。不可伪造性属性确保只有消息发送者可以使用私钥进行签名功能。换句话说,其他人不能生成合法发送者产生的签名消息。不可重用性意味着数字签名不能与消息分离并再次用于另一个消息。

通用数字签名功能的操作如下图所示:

数字签名(左)和验证过程(右)(RSA 数字签名示例)

如果发送方想给接收方发送一个经过身份验证的消息,可以使用两种方法:先签名再加密和先加密再签名。以下是这两种方法使用数字签名加密的方式。

先签名再加密

采用这种方法,发送方使用私钥对数据进行数字签名,将签名附加到数据上,然后使用接收方的公钥对数据和数字签名进行加密。与接下来描述的 先加密再签名 方案相比,这被认为是一种更安全的方案。

先加密再签名

使用这种方法,发送方使用接收方的公钥加密数据,然后对加密数据进行数字签名。

在实践中,包含数字签名的数字证书由一个将公钥与身份关联起来的 证书颁发机构CA)颁发。

在实践中使用了各种方案,如 RSA、数字签名算法DSA)和基于 ECDSA 的数字签名方案。RSA 是最常用的;然而,随着 ECC 的发展,基于 ECDSA 的方案也变得相当流行。在区块链中,这是有利的,因为 ECC 提供了与 RSA 相同的安全级别,但使用的空间更少。此外,在 ECC 中,密钥的生成速度比 RSA 快得多,因此有助于系统的整体性能。下表显示了 ECC 能够以更小的密钥尺寸提供与基于 RSA 的系统相同级别的加密强度:

RSA 密钥尺寸(位) 椭圆曲线密钥尺寸(位)
1024 160
2048 224
3072 256
7680 384
15360 521

RSA 和椭圆曲线密钥尺寸提供相同级别安全性的比较

ECDSA 方案在以下子部分中进行了详细描述。

椭圆曲线数字签名算法

为了使用 ECDSA 方案进行签名和验证,首先需要生成密钥对:

  1. 首先,定义一个椭圆曲线 E
    • 与模数 P

    • 系数 ab

    • 形成素数阶循环群的生成点 A

  1. 选择一个随机整数 d,使得 0 < d < q.

  2. 计算公钥 B 使得 B = d A.

公钥的形式如下所示的六元组:

Kpb = (p,a,b,q,A,B)

私钥 d 在步骤 2 中随机选择:

Kpr = d

现在可以使用私钥和公钥生成签名。

  1. 首先,选择一个临时密钥 K[e],其中 0 < K[e] < q。应确保 K[e] 是真正随机的,并且没有两个签名具有相同的密钥;否则,私钥可以被计算出来。

  2. 使用 R = K[e] A 计算另一个值 R;即,通过将 A(生成点)和随机的临时密钥相乘。

  3. 使用点 Rx 坐标值初始化变量 r,使得 r = xR

  4. 签名可以按以下方式计算:

这里,m 是正在计算签名的消息,h(m) 是消息 m 的哈希值。

签名验证是按照以下流程进行的:

  1. 辅助值 w 计算为 w = s-1 mod q

  2. 辅助值 u1 = w. h(m) mod q

  3. 辅助值 u2 = w. r mod q

  4. 计算点 P, P = u1A + u2B.

  5. 验证如下进行:

r, s 在第 4 步计算的点Px坐标与签名参数r mod q的值相同时被接受为有效签名;即:

Xp = r mod q 意味着有效签名

Xp != r mod q 意味着无效签名

以下子章节展示了各种实际示例,演示了如何使用 OpenSSL 生成、使用和验证 RSA 数字签名。

如何使用 OpenSSL 生成数字签名

第一步是生成消息文件的哈希:

$ openssl dgst -sha256 message.txt 
SHA256(message.txt)=
eb96d1f89812bf4967d9fb4ead128c3b787272b7be21dd2529278db1128d559c  

散列生成和签名可以在一步中完成,如下所示。请注意,privatekey.pem是在先前提供的步骤中生成的:

$ openssl dgst -sha256 -sign privatekey.pem -out signature.bin message.txt  

现在,让我们显示显示相关文件的目录:

$ ls -ltr 
total 36
-rw-rw-r-- 1 drequinox drequinox 14 Sep 21 05:54 message.txt
-rw-rw-r-- 1 drequinox drequinox 32 Sep 21 05:57 message.bin
-rw-rw-r-- 1 drequinox drequinox 45 Sep 21 06:00 message.b64
-rw-rw-r-- 1 drequinox drequinox 32 Sep 21 06:16 message.ptx
-rw-rw-r-- 1 drequinox drequinox 916 Sep 21 06:28 privatekey.pem
-rw-rw-r-- 1 drequinox drequinox 272 Sep 21 06:30 publickey.pem
-rw-rw-r-- 1 drequinox drequinox 128 Sep 21 06:43 message.rsa
-rw-rw-r-- 1 drequinox drequinox 14 Sep 21 06:49 message.dec
-rw-rw-r-- 1 drequinox drequinox  128 Sep 21 07:05 signature.bin

通过执行以下命令查看signature.bin的内容:

$ cat signature.bin

执行此命令将返回以下输出:

为验证签名,可以执行以下操作:

$ openssl dgst -sha256 -verify publickey.pem -signature \
  signature.bin message.txt
Verified OK  

类似地,如果使用了不合法的其他签名文件,验证将失败,如下所示:

$ openssl dgst -sha256 -verify publickey.pem -signature someothersignature.bin message.txt
Verification Failure  

接下来,展示了一个示例,显示了如何使用 OpenSSL 执行与 ECDSA 相关的操作。

使用 OpenSSL 的 ECDSA

首先,使用以下命令生成私钥:

$ openssl ecparam -genkey -name secp256k1 -noout -out eccprivatekey.pem
$ cat eccprivatekey.pem
-----BEGIN EC PRIVATE KEY-----
MHQCAQEEIMVmyrnEDOs7SYxS/AbXoIwqZqJ+gND9Z2/nQyzcpaPBoAcGBSuBBAAK oUQDQgAEEKKS4E4+TATIeBX8o2J6PxKkjcoWrXPwNRo/k4Y/CZA4pXvlyTgH5LYm QbU0qUtPM7dAEzOsaoXmetqB+6cM+Q==
-----END EC PRIVATE KEY-----  

接下来,从私钥生成公钥:

$ openssl ec -in eccprivatekey.pem -pubout -out eccpublickey.pem 
read EC key
writing EC key
$ cat eccpublickey.pem
-----BEGIN PUBLIC KEY----- 
MFYwEAYHKoZIzj0CAQYFK4EEAAoDQgAEEKKS4E4+TATIeBX8o2J6PxKkjcoWrXPw
NRo/k4Y/CZA4pXvlyTgH5LYmQbU0qUtPM7dAEzOsaoXmetqB+6cM+Q==
-----END PUBLIC KEY-----  

现在,假设需要对名为testsign.txt的文件进行签名和验证。可以按照以下步骤实现:

  1. 创建一个测试文件:
      $ echo testing > testsign.txt
      $ cat testsign.txt 
      testing 
  1. 运行以下命令,为testsign.txt文件使用私钥生成签名:
      $ openssl dgst -ecdsa-with-SHA1 -sign eccprivatekey.pem \ 
        testsign.txt > ecsign.bin  
  1. 最后,验证命令可按照这里显示的方式运行:
      $ openssl dgst -ecdsa-with-SHA1 -verify eccpublickey.pem \
        -signature ecsign.bin testsign.txt 
      Verified OK

证书也可以通过使用先前生成的私钥生成,方法如下:

$ openssl req -new -key eccprivatekey.pem -x509 -nodes -days 365 \
  -out ecccertificate.pem     

这个命令将生成与这里显示的类似输出。输入适当的参数以生成证书:

You are about to be asked to enter information that will be incorporated into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank
For some fields there will be a default value, 
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:GB
State or Province Name (full name) [Some-State]:Cambridge 
Locality Name (eg, city) []:Cambridge
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Dr.Equinox! Organizational Unit Name (eg, section) []:NA
Common Name (e.g. server FQDN or YOUR name) []:drequinox 
Email Address []:drequinox@drequinox.com  

可以使用以下命令查看证书:

$ openssl x509 -in ecccertificate.pem -text -noout  

以下输出显示了证书:

使用 SHA-256 算法和 ECDSA 算法的 X509 证书

以下密码学主题的介绍是因为它们与区块链的相关性或在未来区块链生态系统中的潜在用途。

同态加密

通常,例如 RSA 等公钥密码系统是乘法同态或加法同态的,如 Paillier 密码系统,称为部分同态加密PHE)系统。加法同态加密适用于电子投票和银行业务应用。

直到最近,没有一个系统支持这两种操作,但是在 2009 年,克雷格·根特里发现了一个全同态加密 (FHE) 系统。由于这些方案使得加密数据的处理不需要解密,它们在许多不同的潜在应用中有着很多不同的潜在应用,特别是在需要保持隐私的情况下,但数据也被要求由潜在不受信任的方进行处理的场景,例如,云计算和在线搜索引擎。同态加密的最新发展非常有前景,研究人员正在积极努力使其更有效和更实用。这在区块链技术中尤其有趣,正如本书后文所述,因为它可以解决区块链中的保密性和隐私问题。

签名加密

签名加密 是一种提供数字签名和加密所有功能的公钥密码原语。郑育亮发明了签名加密,现在它是 ISO 标准 ISO/IEC 29150:2011。传统上,使用签名然后加密或加密然后签名方案来提供不可伪造性、身份验证和不可否认性,但是使用签名加密,所有数字签名和加密的服务都以比签名然后加密方案更低的成本提供。

签名加密使得成本(签名和加密) << 成本(签名) + 成本(加密) 在一个单独的逻辑步骤中实现。

零知识证明

零知识证明 (ZKPs) 是由 Goldwasser、Micali 和 Rackoff 于 1985 年引入的。这些证明用于证明某个断言的有效性,而不泄露任何与断言有关的信息。ZKPs 所需的三个属性是:完备性、声音性和零知识性质。

完备性 确保如果某个断言为真,则验证者将被证明者说服。声音性 属性确保如果一个断言是假的,那么没有不诚实的证明者能说服验证者相反。零知识性质,正如其名称所暗示的,是 ZKP 的关键属性,确保除了该断言是真还是假之外,绝对不会透露任何关于断言的信息。

ZKP 在区块链领域引起了研究人员的特别兴趣,因为它们的隐私属性在金融和许多其他领域中非常受欢迎,包括法律和医学。成功实现 ZKP 机制的最新例子是 Zcash 加密货币。在 Zcash 中,实现了一种特定类型的 ZKP,称为零知识简洁非交互式知识论证 (ZK-SNARK)。这将在 第十章 替代货币 中详细讨论。

盲签名

盲签名是由 David Chaum 于 1982 年引入的。它们基于公钥数字签名方案,如 RSA。盲签名背后的关键思想是让签名者在实际上不透露消息的情况下对消息进行签名。这通过在签名之前伪装或盲化消息来实现,因此称为盲签名。这种盲签名然后可以像普通数字签名一样对原始消息进行验证。盲签名被引入作为允许数字货币方案发展的机制。

编码方案

除了密码学基元外,二进制到文本的编码方案也在各种场景中使用。最常见的用途是将二进制数据转换为文本,以便可以通过不支持处理二进制数据的协议进行处理、保存或传输。例如,有时,图像以 base64 编码的形式存储在数据库中,这使得文本字段能够存储图片。一个常用的编码方案是 base64。另一个名为 base58 的编码方案因在比特币中的使用而广受欢迎。

密码学是一个庞大的领域,本节仅介绍了对于理解密码学以及从区块链和加密货币角度来看的基本概念。在下一节中,将介绍基本的金融市场概念。

本节描述了与交易、交易所和交易生命周期相关的一般术语。更详细的信息将在后面的章节中提供,其中将讨论特定的用例。

金融市场和交易

金融市场使金融证券如债券、股票、衍生品和货币得以交易。广义上有三种类型的市场:货币市场、信贷市场和资本市场:

  • 货币市场:这是短期市场,资金借出给公司或银行进行同业拆借。外汇或 FX 是货币市场的另一个类别,其中进行货币交易。

  • 信贷市场:这些主要由零售银行组成,他们从中央银行借款,以抵押贷款或贷款的形式向公司或家庭提供贷款。

  • 资本市场:这些促进金融工具的买卖,主要是股票和债券。资本市场可以分为两种类型:一级市场和二级市场。股票直接由公司在一级市场发行给投资者,而在二级市场,投资者通过证券交易所将其证券转售给其他投资者。今天,交易所使用各种电子交易系统来促进金融工具的交易。

交易

市场是各方进行交易的地方。它可以是一个实际的地点,也可以是一个电子的或虚拟的地点。在这些市场上交易各种金融工具,包括股票、外汇、商品和各种类型的衍生品。最近,许多金融机构推出了软件平台,以交易不同资产类别的各种类型的工具。

交易可以定义为交易员买卖各种金融工具以获取利润和对冲风险的活动。投资者、借款人、对冲者、资产交换者和赌徒是交易员的几种类型。当交易员欠某物时,即如果他们卖出了一份合约,则他们持有空头仓位;当他们买入一份合约时,则持有多头仓位。有各种各样的交易方式,例如通过经纪人或直接在交易所或场外交易OTC)进行交易,买方和卖方直接彼此交易,而不是使用交易所。经纪人是为客户安排交易的代理商。经纪人代表客户以给定价格或最佳价格交易。

交易所

交易所通常被认为是一个非常安全、受监管和可靠的交易场所。在过去的十年中,电子交易比传统的基于交易大厅的交易更受欢迎。现在,交易员将订单发送到一个中央电子订单簿,订单、价格和相关属性通过通信网络发布到所有关联系统,从而实质上创建了一个虚拟市场。只有交易所成员才能进行交易。为了避免这些限制,交易对手可以直接参与场外交易。

订单和订单属性

订单是交易的指令,它们是交易系统的主要构建块。它们具有以下一般属性:

  • 工具名称

  • 交易数量

  • 方向(买入或卖出)

  • 表示各种条件的订单类型,例如,限价订单和止损订单是一旦价格达到订单中指定的价格就进行买入或卖出的订单,例如,以 200 英镑购买谷歌股票。限价订单允许以特定价格或更好价格出售或购买股票。例如,如果价格是 100 美元或更高,就出售微软股票。

订单通过买价和卖价交易。交易员通过给他们的订单附加买价和卖价来表明他们的买卖意向。交易员愿意购买的价格称为买价。交易员愿意出售的价格称为卖价

订单管理和路由系统

订单路由系统根据业务逻辑将订单路由并交付到不同的目的地。客户使用它们将订单发送给他们的经纪人,然后经纪人将这些订单发送给经销商、结算所和交易所。

有不同类型的订单。其中两种最常见的是市场订单和限价订单。

市场订单是以市场当前最佳价格进行交易的指令。这些订单会立即以现货价格填补。另一方面,限价订单是以可用的最佳价格进行交易的指令,但前提是它不低于交易员设定的限价。根据订单的方向,限价也可以更高。所有这些订单都由交易所维护的订单簿管理,它记录了交易员的买卖意向。

头寸是对以特定价格出售或购买一定数量的金融工具(包括证券、货币或大宗商品)的承诺。交易员买卖的合同、证券、商品和货币通常被称为交易工具,它们属于资产类别的广泛范畴。最常见的类别包括实物资产、金融资产、衍生合约和保险合约。

交易的组成部分

交易单据是与一项交易相关的所有细节的组合。但是,这些元素的具体内容取决于工具的类型和资产类别。这些元素在以下小节中描述。

底层工具

底层工具是交易的基础。它可以是货币、债券、利率、商品或股票。

金融工具的属性将在以下小节中讨论。

一般特性

这包括与每笔交易相关的一般识别信息和基本特征。典型属性包括唯一 ID、工具名称、类型、状态、交易日期和时间。

经济特性

经济特性与交易价值相关,例如购买或出售价值、股票代码、交易所、价格和数量。

销售

销售指与销售相关的特征细节,例如销售人员的名称。这只是一个信息字段,通常不会对交易生命周期产生任何影响。

对手方

对手方是交易的重要组成部分,因为它显示了交易中涉及的另一方(交易中的另一方),并且需要成功结算交易。常见的属性包括对手方名称、地址、支付类型、任何参考 ID、结算日期和交付类型。

交易生命周期

一个一般的交易生命周期包括从下单到执行和结算的各个阶段。这个生命周期逐步描述如下:

  • 预执行:在这个阶段下单。

  • 成交和预订:当订单被匹配和执行时,它会转化为一笔交易。在这个阶段,交易对手之间的合约就成熟了。

  • 确认:在这里,交易双方就交易的各种具体事项达成一致。

  • 后预订:这个阶段涉及到各种仔细审查和验证过程,以确认交易的正确性。

  • 结算:这是交易生命周期中最关键的部分。在这个阶段,交易就已经最终确定了。

  • 隔夜(日终处理):日终处理包括报告生成、损益计算和各种风险计算。

该生命周期也显示在以下截图中:

交易生命周期

在所有上述流程中,涉及到许多人和业务职能。最常见的是将这些职能划分为前台、中台和后台等职能。

在接下来的部分,将介绍一些对于理解严格而必要的金融行业规章制度至关重要的概念。一些这里描述的概念在后面的章节中再次描述,当讨论具体的应用案例时。这些想法将帮助您理解所描述的场景。

订单预测者

订单预测者试图在其他交易员进行交易之前获利。这是基于一个交易员预期他人的交易活动将如何影响价格。先行者、情绪导向的技术交易者和挤压者都是订单预测者的一些实例。

市场操纵

市场操纵在许多国家严格禁止。欺诈交易者可以在市场中传播虚假信息,这可能导致价格波动,从而实现非法获利。通常,操纵市场行为是基于交易的,包括普遍性和特定时间的操纵。可以创建股票人为短缺、虚假活动的印象和价格操纵以获取犯罪利益的行为都包括在此类别中。

这两个名词都和金融犯罪有关。然而,由于区块链系统的透明度和安全性,有可能开发基于区块链的系统来阻截市场滥用。

总结

我们从介绍非对称密钥加密开始了本章。我们讨论了诸如 RSA 和 ECC 之类的各种构造。我们还使用 OpenSSL 进行了一些实验,以验证理论概念如何实际实现。之后,我们详细讨论了哈希函数及其特性和用法。接下来,我们涵盖了 Merle 树等概念,这些概念在区块链中被广泛使用,实际上是其核心。我们还介绍了其他概念,如 Patricia 树和哈希表。

第七章:开始使用 web3.js

在本章中,我们将学习 web3.js 以及如何在 Node.js 或客户端 JavaScript 中导入、连接到 geth 并使用它。我们还将学习如何使用 web3.js 构建 web 客户端。

在本章中,我们将涵盖以下主题:

  • 在 Node.js 和客户端 JavaScript 中导入 web3.js

  • 连接到 geth

  • 探索使用 web3.js 可以完成的各种事务

  • 探索 web3.js 的各种最常用的 API

  • 为所有权合同构建一个 Node.js 应用程序

web3.js 介绍

web3.js 为我们提供了 JavaScript API,用于与 geth 通信。它在内部使用 JSON-RPC 与 geth 通信。web3.js 还可以与支持 JSON-RPC 的任何其他类型的以太坊节点通信。它将所有 JSON-RPC API 公开为 JavaScript API;也就是说,它不仅支持所有与以太坊相关的 API;还支持与 Whisper 和 Swarm 相关的 API。

随着我们构建各种项目,您将越来越了解 web3.js,但现在让我们先了解一下 web3.js 的一些最常用的 API,然后我们将使用 web3.js 为我们的所有权智能合同构建前端。

在撰写本文时,web3.js 的最新版本是 0.16.0。我们将针对该版本学习所有内容。

web3.js 托管在 github.com/ethereum/web3.js,完整的文档托管在 github.com/ethereum/wiki/wiki/JavaScript-API

导入 web3.js

要在 Node.js 中使用 web3.js,只需在项目目录中运行 npm install web3,然后在源代码中,可以使用 require("web3"); 进行导入。

要在客户端 JavaScript 中使用 web3.js,可以将 web3.js 文件加入队列,该文件可以在项目源代码的 dist 目录中找到。现在你将全局可用的 Web3 对象。

连接节点

web3.js 可以使用 HTTP 或 IPC 与节点通信。我们将使用 HTTP 建立与节点的通信。web3.js 允许我们与多个节点建立连接。web3 的一个实例表示与一个节点的连接。该实例公开了 API。

当应用程序在 Mist 中运行时,它会自动使一个名为 web3 的实例可用,该实例连接到 mist 节点。实例的变量名是 web3

这是连接到节点的基本代码:

if (typeof web3 !== 'undefined') { 
  web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); 
} 

首先,在此处我们通过检查 web3 是否 undefined 来检查代码是否在 mist 中运行。如果 web3 已定义,则使用已有的实例;否则,通过连接到我们的自定义节点创建一个实例。如果要连接到自定义节点,而不管应用程序是否在 mist 中运行,请从上述代码中删除 if 条件。在这里,我们假设我们的自定义节点在本地运行,端口号为 8545

Web3.providers 对象暴露了构造函数(在这个上下文中称为提供程序),用于使用各种协议建立连接和传输消息。Web3.providers.HttpProvider 让我们建立 HTTP 连接,而 Web3.providers.IpcProvider 让我们建立 IPC 连接。

web3.currentProvider 属性会自动分配给当前提供程序实例。创建 web3 实例后,你可以使用 web3.setProvider() 方法更改其提供程序。它接受一个参数,即新提供程序的实例。

请记住,geth 默认禁用 HTTP-RPC。因此,在运行 geth 时通过传递 --rpc 选项来启用它。默认情况下,HTTP-RPC 在端口 8545 上运行。

web3 暴露了一个 isConnected() 方法,用于检查是否连接到节点。根据连接状态,它返回 truefalse

API 结构

web3 包含一个专门用于以太坊区块链交互的 eth 对象 (web3.eth) 和一个用于 whisper 交互的 shh 对象 (web3.shh)。web3.js 的大多数 API 都在这两个对象内部。

所有的 API 默认都是同步的。如果你想发出异步请求,你可以将可选的回调作为大多数函数的最后一个参数传递。所有回调都使用错误优先的回调风格。

一些 API 对异步请求有别名。例如,web3.eth.coinbase() 是同步的,而 web3.eth.getCoinbase() 是异步的。

这是一个示例:


//sync request 
try 
{ 
  console.log(web3.eth.getBlock(48)); 
} 
catch(e) 
{ 
  console.log(e); 
} 

//async request 
web3.eth.getBlock(48, function(error, result){ 
    if(!error) 
        console.log(result) 
    else 
        console.error(error); 
}) 

getBlock 用于通过其编号或哈希获取区块的信息。或者,它可以接受字符串,如 "earliest"(创世区块),"latest"(区块链的顶部区块)或 "pending"(正在挖掘的区块)。如果不传递参数,则默认为 web3.eth.defaultBlock,默认为 "latest"

所有需要区块标识作为输入的 API 如果没有传递值,则默认使用 web3.eth.defaultBlock

BigNumber.js

JavaScript 在正确处理大数字方面天生能力较弱。因此,需要处理大数字并进行精确计算的应用程序使用 BigNumber.js 库来处理大数字。

web3.js 也依赖于 BigNumber.js。它会自动添加它。web3.js 总是返回 BigNumber 对象作为数字值。它可以接受 JavaScript 数字、数字字符串和 BigNumber 实例作为输入。

这里是一个示例来说明这一点:

web3.eth.getBalance("0x27E829fB34d14f3384646F938165dfcD30cFfB7c").toString(); 

在这里,我们使用 web3.eth.getBalance() 方法来获取地址的余额。该方法返回一个 BigNumber 对象。我们需要在 BigNumber 对象上调用 toString() 来将其转换为数字字符串。

BigNumber.js 无法正确处理具有超过 20 个浮点数字的数字;因此,建议您将余额存储在 wei 单位中,而在显示时将其转换为其他单位。web3.js 本身始终以 wei 单位返回和接受余额。例如,getBalance() 方法以 wei 单位返回地址的余额。

单位转换

web3.js 提供了将 wei 余额转换为任何其他单位以及将任何其他单位余额转换为 wei 的 API。

web3.fromWei() 方法用于将 wei 数字转换为任何其他单位,而 web3.toWei() 方法用于将任何其他单位中的数字转换为 wei。以下是演示此功能的示例:

web3.fromWei("1000000000000000000", "ether"); 
web3.toWei("0.000000000000000001", "ether"); 

在第一行中,我们将 wei 转换为 ether,在第二行中,我们将 ether 转换为 wei。两种方法中的第二个参数可以是以下字符串之一:

  • kwei/ada

  • mwei/babbage

  • gwei/shannon

  • szabo

  • finney

  • ether

  • kether/grand/einstein

  • mether

  • gether

  • tether

检索 gas 价格、余额和交易详情

让我们看一下获取 gas 价格、地址余额和已挖掘交易信息的 API:

//It's sync. For async use getGasPrice 
console.log(web3.eth.gasPrice.toString()); 

console.log(web3.eth.getBalance("0x407d73d8a49eeb85d32cf465507dd71d507100c1", 45).toString()); 

console.log(web3.eth.getTransactionReceipt("0x9fc76417374aa880d4449a1f7f31ec597f00b1f6f3dd2d66f4c9c6c445836d8b")); 

输出将采用以下形式:

20000000000 
30000000000 
{ 
  "transactionHash": "0x9fc76417374aa880d4449a1f7f31ec597f00b1f6f3dd2d66f4c9c6c445836d8b ", 
  "transactionIndex": 0, 
  "blockHash": "0xef95f2f1ed3ca60b048b4bf67cde2195961e0bba6f70bcbea9a2c4e133e34b46", 
  "blockNumber": 3, 
  "contractAddress": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b", 
  "cumulativeGasUsed": 314159, 
  "gasUsed": 30234 
} 

以下是前述方法的工作原理:

  • web3.eth.gasPrice(): 通过最近 x 个区块的中位 gas 价格确定 gas 价格。

  • web3.eth.getBalance(): 返回给定地址的余额。所有哈希应该以十六进制字符串的形式提供给 web3.js API,而不是十六进制文字。对于 solidity address 类型的输入,也应该是十六进制字符串。

  • web3.eth.getTransactionReceipt(): 这用于使用其哈希获取有关交易的详细信息。如果在区块链中找到了交易,则返回交易收据对象;否则返回 null。交易收据对象包含以下属性:

    • blockHash: 此交易所在的区块的哈希

    • blockNumber: 此交易所在的区块号

    • transactionHash: 交易的哈希

    • transactionIndex: 该交易在区块中的事务索引位置的整数

    • from: 发件人的地址

    • to: 收件人的地址;当它是合约创建交易时为 null

    • cumulativeGasUsed: 该交易在区块中执行时使用的总 gas 量

    • gasUsed: 仅此特定交易使用的 gas 量

    • contractAddress: 如果交易是合约创建,则为创建的合约地址;否则为 null

    • logs: 此交易生成的日志对象数组

发送以太币

让我们看看如何向任何地址发送以太币。要发送以太币,你需要使用 web3.eth.sendTransaction() 方法。这个方法可以用来发送任何类型的交易,但大多数情况下用于发送以太币,因为使用该方法部署合约或调用合约方法很麻烦,因为它需要你生成交易数据而不是自动生成。它接受一个具有以下属性的交易对象:

  • from:发送账户的地址。如果未指定,则使用 web3.eth.defaultAccount 属性。

  • to:这是可选的。这是消息的目标地址,在创建合约交易时保持未定义。

  • value:这是可选的。这是以 wei 为单位的交易中转的价值,以及如果是合约创建交易的话就是捐赠。

  • gas:这是可选的。这是用于交易的气体数量(未使用的气体将被退还)。如果未提供,则会自动确定。

  • gasPrice:这是可选的。这是以 wei 为单位的交易的燃气价格,默认为网络平均燃气价格。

  • data:这是可选的。它是一个包含消息关联数据的字节字符串,或者在创建合约交易的情况下是初始化代码。

  • nonce:这是可选的。这是一个整数。每个交易都与一个 nonce 相关联。一个 nonce 是一个计数器,表示发送交易的发送者发送的交易数量。如果未提供,则会自动确定。它有助于防止重放攻击。这个 nonce 不是与一个区块相关联的 nonce。如果我们使用的 nonce 大于交易应该具有的 nonce,那么交易将被放入队列,直到其他交易到达。例如,如果下一个交易的 nonce 应该是 4,而我们设置了 nonce 为 10,那么 geth 将等待中间的六个交易到达,然后再广播此交易。具有 nonce 10 的交易称为排队交易,它不是挂起交易。

让我们看一个向地址发送以太币的示例:

var txnHash = web3.eth.sendTransaction({ 
  from: web3.eth.accounts[0], 
  to: web3.eth.accounts[1], 
  value: web3.toWei("1", "ether") 
}); 

在这里,我们从账户编号为 0 的账户向账户编号为 1 的账户发送一个以太币。确保在运行 geth 时两个账户都已解锁,使用 unlock 选项。在 geth 交互式控制台中,它会提示输入密码,但在交互式控制台之外使用 web3.js API 时,如果账户被锁定,会抛出错误。该方法返回交易的交易哈希。然后你可以使用 getTransactionReceipt() 方法来检查交易是否被挖掘。

你也可以在运行时使用 web3.personal.listAccounts()web3.personal.unlockAccount(addr, pwd)web3.personal.newAccount(pwd) API 来管理账户。

与合约交互

让我们学习如何部署一个新的合约,使用它的地址获取已部署合约的引用,向合约发送以太币,发送交易来调用合约方法,并估算方法调用的 gas。

要部署一个新合约或获取对已部署合约的引用,你首先需要使用web3.eth.contract()方法创建一个合约对象。它将合约 ABI 作为参数,并返回合约对象。

这是创建合约对象的代码:

var proofContract = web3.eth.contract([{"constant":false,"inputs":[{"name":"fileHash","type":"string"}],"name":"get","outputs":[{"name":"timestamp","type":"uint256"},{"name":"owner","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"owner","type":"string"},{"name":"fileHash","type":"string"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"status","type":"bool"},{"indexed":false,"name":"timestamp","type":"uint256"},{"indexed":false,"name":"owner","type":"string"},{"indexed":false,"name":"fileHash","type":"string"}],"name":"logFileAddedStatus","type":"event"}]); 

一旦你有了合约,你可以使用合约对象的new方法部署它,或者使用at方法获取与 ABI 匹配的已部署合约的引用。

让我们看一个部署新合约的例子:

var proof = proofContract.new({ 
     from: web3.eth.accounts[0],  
     data: "0x606060405261068...",  
     gas: "4700000" 
    },  
    function (e, contract){ 
    if(e) 
    { 
    console.log("Error " + e);     
}     
else if(contract.address != undefined) 
  {     
    console.log("Contract Address: " + contract.address);     
   }     
else      
  {     
    console.log("Txn Hash: " + contract.transactionHash)     
  } 
}) 

这里,new方法是异步调用的,所以如果交易被成功创建和广播,回调函数会被触发两次。第一次,在交易被广播后调用,第二次,在交易被挖掘后调用。如果你不提供回调函数,那么proof变量的address属性将被设置为undefined。一旦合约被挖掘,address属性将被设置。

proof合约中,没有构造函数,但如果有构造函数,则构造函数的参数应放在new方法的开头。我们传递的对象包含来自地址、合约的字节码和要使用的最大 gas。这三个属性必须存在;否则,交易将不会被创建。这个对象可以具有传递给sendTransaction()方法的对象中存在的属性,但这里,data是合约的字节码,to属性被忽略。

你可以使用at方法来获取一个已经部署的合约的引用。这里是演示这一点的代码:

var proof = proofContract.at("0xd45e541ca2622386cd820d1d3be74a86531c14a1"); 

现在让我们看看如何发送交易来调用合约的方法。这里有一个示例来演示这一点:

proof.set.sendTransaction("Owner Name", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", { 

from: web3.eth.accounts[0], 
}, function(error, transactionHash){ 

if (!err) 

console.log(transactionHash); 
}) 

这里,我们调用方法同名的对象的sendTransaction方法。传递给此sendTransaction方法的对象具有与web3.eth.sendTransaction()相同的属性,除了datato属性被忽略。

如果你想要在节点本身上调用一个方法而不是创建一个交易并广播它,那么你可以使用call而不是sendTransaction。这里有一个示例来演示这一点:

var returnValue = proof.get.call("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); 

有时,有必要找出调用方法所需的 gas,以便决定是否调用它。web3.eth.estimateGas可以用于此目的。然而,直接使用web3.eth.estimateGas()需要你生成交易的数据;因此,我们可以使用同名方法对象的estimateGas()方法。这里有一个示例来演示这一点:

var estimatedGas = proof.get.estimateGas("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); 

如果你只想向合约发送一些以太币而不调用任何方法,那么你可以简单地使用web3.eth.sendTransaction方法。

检索和监听合约事件

现在让我们看一下如何监听合约中的事件。监听事件非常重要,因为通过事务调用的方法返回结果通常是通过触发事件来获取的。

在我们深入讨论如何检索和监听事件之前,我们需要学习事件的索引参数。一个事件最多可以有三个参数具有indexed属性。此属性用于向节点发出索引信号,以便应用客户端可以搜索具有匹配返回值的事件。如果不使用索引属性,那么将不得不从节点检索所有事件并过滤所需的事件。例如,你可以这样编写logFileAddedStatus事件:

event logFileAddedStatus(bool indexed status, uint indexed timestamp, string owner, string indexed fileHash); 

以下是一个示例,演示如何监听合约事件:

var event = proof.logFileAddedStatus(null, { 
fromBlock: 0, 
toBlock: "latest" 
}); 
event.get(function(error, result){ 
if(!error) 
{ 
  console.log(result); 
} 
else 
{ 
  console.log(error); 
} 
}) 
event.watch(function(error, result){ 
if(!error) 
{ 
  console.log(result.args.status); 
} 
else 
{ 
  console.log(error); 
} 
}) 
setTimeout(function(){ 
event.stopWatching(); 
}, 60000) 
 var events = proof.allEvents({ 
fromBlock: 0, 
 toBlock: "latest" 
}); 
events.get(function(error, result){ 
if(!error) 
{ 
  console.log(result); 
} 
else 
{ 
  console.log(error); 
} 
}) 
events.watch(function(error, result){ 
if(!error) 
{ 
  console.log(result.args.status); 
} 
else 
{ 
  console.log(error); 
} 
}) 
setTimeout(function(){ 
events.stopWatching(); 
}, 60000)

这就是上述代码的工作方式:

  1. 首先,通过在合约实例上调用同名事件的方法来获取事件对象。此方法使用两个对象作为参数,用于过滤事件:

    • 第一个对象用于通过索引返回值过滤事件:例如,{'valueA': 1, 'valueB': [myFirstAddress, mySecondAddress]}。默认情况下,所有过滤值都设置为null。这意味着它们将匹配来自该合约的给定类型的任何事件。

    • 下一个对象可以包含三个属性:fromBlock(最早的块;默认为"latest")、toBlock(最新的块;默认为"latest")和address(只从中获取日志的地址列表;默认为合约地址)。

  2. event对象公开了三种方法:getwatchstopWatchingget用于获取块范围内的所有事件。watch类似于get,但在获取事件后会监视更改。stopWatching可用于停止监视更改。

  3. 然后,我们有合约实例的allEvents方法。它用于检索合约的所有事件。

  4. 每个事件都由一个包含以下属性的对象表示:

    • args:一个带有事件参数的对象

    • event:表示事件名称的字符串

    • logIndex:表示块中日志索引位置的整数

    • transactionIndex:表示日志创建的交易索引位置的整数

    • transactionHash:表示创建此日志的交易哈希的字符串

    • address:表示此日志来源地址的字符串

    • blockHash:表示此日志所在块的哈希的字符串;其状态为挂起时为null

    • blockNumber:表示此日志所在块的块号;其状态为挂起时为null

web3.js 提供了一个web3.eth.filter API 来检索和监听事件。你可以使用这个 API,但是较早方法处理事件的方式更容易。你可以在github.com/ethereum/wiki/wiki/JavaScript-API#web3ethfilter了解更多相关信息。

构建所有权合约的客户端

现在,是时候为我们的智能合约构建一个客户端,以便用户可以轻松使用它了。

我们将构建一个客户端,用户选择一个文件并输入所有者详细信息,然后点击提交来广播一个交易以调用合约的set方法,其中包含文件哈希和所有者的详细信息。一旦交易成功广播,我们将显示交易哈希。用户还将能够选择一个文件,并从智能合约获取所有者的详细信息。客户端还将实时显示最近的set交易。

我们将在前端使用 sha1.js 获取文件的哈希值,jQuery 用于 DOM 操作,Bootstrap 4 创建响应式布局。我们将在后端使用 express.js 和 web3.js。我们将使用 socket.io,以便后端在前端每隔一段时间后自动推送最近挖掘的交易,而无需前端请求数据。

web3.js 可以在前端使用。但对于这个应用程序来说,这将是一个安全风险;也就是说,我们正在使用存储在 geth 中的账户,并将 geth 节点 URL 暴露给前端,这将使这些账户中存储的以太币面临风险。

项目结构

在本章的练习文件中,你会找到两个目录:FinalInitialFinal包含项目的最终源代码,而Initial包含了空的源代码文件和库,可以快速开始构建应用程序。

要测试Final目录,你需要在其中运行npm install并将app.js中的硬编码的合约地址替换为部署合约后得到的合约地址。然后,在Final目录中使用node app.js命令运行应用程序。

Initial目录中,你会找到一个public目录和两个名为app.jspackage.json的文件。package.json包含了我们应用程序的后端依赖项,app.js是你将放置后端源代码的地方。

public目录包含与前端相关的文件。在public/css中,你会找到bootstrap.min.css,这是 Bootstrap 库;在public/html中,你会找到index.html,其中包含我们应用程序的 HTML 代码;在public/js目录中,你会找到 jQuery、sha1 和 socket.io 的 JS 文件。在public/js中,你还会找到一个main.js文件,其中包含我们应用程序的前端 JS 代码。

构建后端

让我们首先构建应用程序的后端。首先,在Initial目录中运行npm install以安装我们后端所需的依赖项。在我们开始编写后端代码之前,请确保 geth 正在运行并启用了 rpc。如果你正在私有网络上运行 geth,则确保也启用了挖矿。最后,请确保账户 0 存在并已解锁。你可以在启用了 rpc 和挖矿并解锁账户 0 的私有网络上运行 geth:

geth --dev --mine --rpc --unlock=0

在开始编码之前,您需要做的最后一件事是使用我们在第四章中看到的代码部署所有权合同,并复制合同地址。

现在让我们创建一个单一服务器,该服务器将向浏览器提供 HTML,并接受 socket.io 连接:

var express = require("express");   
var app = express();   
var server = require("http").createServer(app); 
var io = require("socket.io")(server); 
server.listen(8080); 

在这里,我们将 expresssocket.io 服务器集成到一个运行在 8080 端口的服务器中。

现在让我们创建路由来提供静态文件以及应用程序的主页。以下是执行此操作的代码:

app.use(express.static("public")); 
app.get("/", function(req, res){  
  res.sendFile(__dirname + "/public/html/index.html"); 
}) 

在这里,我们使用 express.static 中间件来提供静态文件。我们要求它在 public 目录中查找静态文件。

现在让我们连接到 geth 节点,并获取已部署合同的引用,以便我们可以发送交易并监视事件。以下是执行此操作的代码:

var Web3 = require("web3"); 

web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); 

var proofContract = web3.eth.contract([{"constant":false,"inputs":[{"name":"fileHash","type":"string"}],"name":"get","outputs":[{"name":"timestamp","type":"uint256"},{"name":"owner","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"owner","type":"string"},{"name":"fileHash","type":"string"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"status","type":"bool"},{"indexed":false,"name":"timestamp","type":"uint256"},{"indexed":false,"name":"owner","type":"string"},{"indexed":false,"name":"fileHash","type":"string"}],"name":"logFileAddedStatus","type":"event"}]); 

var proof = proofContract.at("0xf7f02f65d5cd874d180c3575cb8813a9e7736066"); 

代码很简单明了。只需用您获取的合同地址替换原合同地址即可。

现在让我们创建路由来广播交易并获取有关文件的信息。以下是执行此操作的代码:

app.get("/submit", function(req, res){ 
var fileHash = req.query.hash; 
var owner = req.query.owner; 
proof.set.sendTransaction(owner, fileHash, { 
from: web3.eth.accounts[0], 
}, function(error, transactionHash){ 
if (!error) 
{
  res.send(transactionHash); 
} 
else 
{ 
  res.send("Error"); 
} 
}) 
}) 
app.get("/getInfo", function(req, res){ 
var fileHash = req.query.hash; 
var details = proof.get.call(fileHash); 
res.send(details); 
}) 

在这里,/submit 路由用于创建和广播交易。一旦我们得到交易哈希,我们就将其发送到客户端。我们没有做任何等待交易挖掘的操作。/getInfo 路由调用节点上合同的 get 方法,而不是创建交易。它只是发送回收到的任何响应。

现在让我们监听来自合同的事件并将其广播给所有客户端。以下是执行此操作的代码:

proof.logFileAddedStatus().watch(function(error, result){ 
if(!error) 
{ 
  if(result.args.status == true) 
  { 
    io.send(result); 
  } 
} 
}) 

在这里,我们检查状态是否为 true,如果为 true,则只广播事件给所有连接的 socket.io 客户端。

构建前端

让我们从应用程序的 HTML 开始。将此代码放入 index.html 文件中:

<!DOCTYPE html> 
<html lang="en"> 
    <head> 
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> 
        <link rel="stylesheet" href="/css/bootstrap.min.css"> 
    </head> 
    <body> 
        <div class="container"> 
            <div class="row"> 
                <div class="col-md-6 offset-md-3 text-xs-center"> 
                    <br> 
                    <h3>Upload any file</h3> 
                    <br> 
                    <div> 
                        <div class="form-group"> 
                            <label class="custom-file text-xs-left"> 
                                <input type="file" id="file" class="custom-file-input"> 
                                <span class="custom-file-control"></span> 
                            </label> 
                        </div> 
                        <div class="form-group"> 
                            <label for="owner">Enter owner name</label> 
                            <input type="text" class="form-control" id="owner"> 
                        </div> 
                        <button onclick="submit()" class="btn btn-primary">Submit</button> 
                        <button onclick="getInfo()" class="btn btn-primary">Get Info</button>  
                        <br><br> 
                        <div class="alert alert-info" role="alert" id="message"> 
                            You can either submit file's details or get information about it. 
                        </div> 
                    </div> 
                </div> 
            </div> 
            <div class="row"> 
                <div class="col-md-6 offset-md-3 text-xs-center"> 
                    <br> 
                    <h3>Live Transactions Mined</h3> 
                    <br> 
                    <ol id="events_list">No Transaction Found</ol> 
                </div> 
            </div> 
        </div> 
        <script type="text/javascript" src="img/sha1.min.js"></script> 
        <script type="text/javascript" src="img/jquery.min.js"></script> 
        <script type="text/javascript" src="img/socket.io.min.js"></script> 
        <script type="text/javascript" src="img/main.js"></script> 
    </body> 
</html> 

以下是代码的工作原理:

  1. 首先,我们显示 Bootstrap 的文件输入字段,以便用户可以选择文件。

  2. 然后,我们显示一个文本字段,用户可以在其中输入所有者的详细信息。

  3. 然后,我们有两个按钮。第一个按钮用于将文件哈希和所有者的详细信息存储在合同中,第二个按钮用于从合同获取文件信息。单击提交按钮会触发 submit() 方法,而单击获取信息按钮会触发 getInfo() 方法。

  4. 然后,我们有一个警报框用于显示消息。

  5. 最后,我们显示一个有序列表,以显示用户在页面上的时间内获得的合同交易。

现在让我们为 getInfo()submit() 方法编写实现,与服务器建立 socket.io 连接,并监听来自服务器的 socket.io 消息。以下是执行此操作的代码。将此代码放在 main.js 文件中:

  function submit() 
  { 
    var file = document.getElementById("file").files[0]; 
    if(file) 
  { 
   var owner = document.getElementById("owner").value; 
   if(owner == "") 
  { 
   alert("Please enter owner name"); 
  } 
 else 
 { 
  var reader = new FileReader(); 
  reader.onload = function (event) { 
  var hash = sha1(event.target.result); 
  $.get("/submit?hash=" + hash + "&owner=" + owner, function(data){ 
  if(data == "Error") 
  {  
    $("#message").text("An error occured."); 
  } 
  else 
  { 
    $("#message").html("Transaction hash: " + data); 
  } 
  }); 
  }; 
  reader.readAsArrayBuffer(file); 
   } 
} 
  else 
  { 
    alert("Please select a file"); 
  } 
} 
function getInfo() 
{ 
  var file = document.getElementById("file").files[0]; 
  if(file) 
  { 
    var reader = new FileReader(); 
    reader.onload = function (event) { 
    var hash = sha1(event.target.result); 
    $.get("/getInfo?hash=" + hash, function(data){ 
    if(data[0] == 0 && data[1] == "") 
    { 
      $("#message").html("File not found"); 
    } 
    else 
    { 
      $("#message").html("Timestamp: " + data[0] + " Owner: " + data[1]); 
    }   
  }); 
}; 
reader.readAsArrayBuffer(file); 
} 
else 
  { 
    alert("Please select a file"); 
  } 
} 
var socket = io("http://localhost:8080"); 
socket.on("connect", function () { 
socket.on("message", function (msg) { 
if($("#events_list").text() == "No Transaction Found") 
{ 
    $("#events_list").html("<li>Txn Hash: " + msg.transactionHash + "nOwner: " + msg.args.owner + "nFile Hash: " + msg.args.fileHash + "</li>"); 
} 
else  
{ 
  $("#events_list").prepend("<li>Txn Hash: " + msg.transactionHash + "nOwner: " + msg.args.owner + "nFile Hash: " + msg.args.fileHash + "</li>"); 
} 
  }); 
}); 

这就是上述代码的工作原理:

  1. 首先,我们定义了submit()方法。在submit方法中,我们确保选择了一个文件并且文本字段不为空。然后,我们将文件内容读取为数组缓冲区,并将数组缓冲区传递给由 sha1.js 暴露的sha1()方法,以获取数组缓冲区内的内容的哈希。一旦我们有了哈希,我们就使用 jQuery 发送 AJAX 请求到/submit路由,然后在警告框中显示交易哈希。

  2. 我们接下来定义getInfo()方法。首先确保选择了文件。然后,生成像之前生成的那样的哈希,并向/getInfo端点发出请求以获取有关该文件的信息。

  3. 最后,我们使用由socket.io库暴露的io()方法建立了socket.io连接。然后,我们等待触发连接事件,该事件指示已建立连接。连接建立后,我们监听来自服务器的消息,并向用户显示有关交易的详细信息。

我们不将文件存储在以太坊区块链中,因为存储文件非常昂贵,需要大量的 gas。对于我们的情况,实际上不需要存储文件,因为网络中的节点将能够看到文件;因此,如果用户希望保持文件内容的机密性,那么他们将无法做到。我们应用的目的只是证明对文件的所有权,而不是像云服务一样存储和提供文件。

测试客户端

现在运行app.js节点以运行应用程序服务器。打开您喜欢的浏览器并访问http://localhost:8080/。您将在浏览器中看到此输出:

现在选择一个文件并输入所有者的名称,然后点击提交。屏幕将变成这样:

在这里,您可以看到交易哈希被显示出来。现在等待交易被挖掘。一旦交易被挖掘,您将能够在实时交易列表中看到交易。屏幕会是这样的:

现在再次选择相同的文件,然后单击获取信息按钮。您将看到此输出:

在这里,您可以看到时间戳和所有者的详细信息。现在我们已经完成了第一个 DApp 的客户端构建。

概要

在本章中,我们首先通过示例了解了 web3.js 的基础知识。我们学习了如何连接到节点,基本的 API,发送各种类型的交易和监视事件。最后,我们为我们的所有权合同构建了一个适当的生产使用客户端。现在您将可以轻松编写智能合约并为其构建 UI 客户端,以便简化其使用。

在第九章中,我们将构建一个钱包服务,用户可以轻松地创建和管理以太坊钱包,而且还是离线的。我们将专门使用 LightWallet 库来实现这一点。

第八章:引入比特币

比特币是区块链技术的第一个应用。在本章中,你将详细介绍比特币技术。

比特币通过引入第一个完全去中心化的数字货币,并且从网络和协议的角度证明了极其安全和稳定,引发了一场革命。作为一种货币,比特币非常不稳定和高度波动,尽管它很有价值。我们将在本章后面解释这一点。这也激发了学术和工业研究的浓厚兴趣,并引入了许多新的研究领域。

自 2008 年由中本聪引入以来,比特币已经获得了巨大的 popularity,并且目前是世界上最成功的数字货币,有数十亿美元投资于其中。在撰写本文时,该货币的当前市值为$149, 984, 293, 122。它的流行也从用户和投资者的数量、比特币价格的增长、每天与比特币相关的新闻以及提供基于比特币的在线交易的初创公司和公司的数量等方面表现出来,现在还在 芝加哥商品交易所 (CME) 上作为 比特币期货 进行交易。

有兴趣的读者可以在 www.cmegroup.com/trading/bitcoin-futures.html 阅读更多关于 比特币期货 的信息。

比特币发明者 中本聪 的名字被认为是一个化名,因为比特币发明者的真实身份是未知的。它建立在几十年来在密码学、数字货币和分布式计算领域的研究基础之上。下面将介绍一个简要的历史,以便了解比特币发明背后的基础。

数字货币一直是许多年来的一个活跃研究领域。早期提议创建数字现金可以追溯到上世纪 80 年代初。1982 年,计算机科学家和密码学家大卫·乔姆提出了一种使用盲签名构建不可追踪数字货币的方案。这项研究发表在一篇名为 不可追踪支付的盲签名 的研究论文中。

有兴趣的读者可以阅读大卫·乔姆(David Chaum)在原始研究论文中描述他的盲签名密码学原语发明的原始论文,网址为 www.hit.bme.hu/~buttyan/courses/BMEVIHIM219/2009/Chaum.BlindSigForPayment.1982.PDF

在这个方案中,银行通过签署用户提出的一个盲目和随机序列号来发行数字货币。然后,用户可以使用银行签发的数字令牌作为货币。这个方案的局限性在于银行必须跟踪所有已使用的序列号。这是一个中心化的系统,必须得到用户的信任。

后来,于 1988 年,大卫·朱姆(David Chaum)等人提出了一种更精致的版本,名为电子现金,该版本不仅使用了盲签名,还使用了一些私有身份数据来制作消息,然后将其发送给银行。

此项原始研究论文可在citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.26.5759找到。

这个方案可以检测到双重支付,但无法阻止。如果同一令牌在两个不同的位置使用,则双重支付者的身份将被揭示。电子现金只能表示固定金额的货币。

密码学家、现任 Blockstream CEO 亚当·贝克(Adam Back)于 1997 年提出了hashcash。最初提出来阻止电子邮件垃圾邮件。 hashcash 的背后思想是解决一个易于验证但相对难以计算的计算难题。其理念是,对于单个用户和单个电子邮件,额外的计算工作是微不足道的,但是发送大量垃圾邮件的人将受到阻止,因为运行垃圾邮件活动所需的时间和资源会大大增加。

1998 年,微软前员工、计算机工程师魏 Dai 提出了 B-money,该方案引入了使用工作证明PoW)创建货币的想法。术语工作证明后来随着比特币而兴起并变得流行,但在魏 Dai 的 B-money 中,通过提供对以前未解决的计算问题的解决方案来引入了一种创建货币的方案。该论文中将其称为先前未解决的计算问题的解决方案。这个概念类似于 PoW,其中通过广播以前未解决的计算问题的解决方案来创建货币。

原始论文可在www.weidai.com/bmoney.txt找到。

系统中的一个主要弱点是,具有更高计算能力的对手可以生成未经请求的货币,而不允许网络调整到适当的难度级别。该系统缺乏节点之间的共识机制的细节,也没有解决一些安全问题,如 Sybil 攻击。与此同时,来自国际计算机科学研究所ICSI)伯克利的托马斯·桑德尔(Tomas Sander)和阿姆农·塔什马(Amnon Ta-Shma)在 1999 年的一篇名为《可审计的、匿名的电子现金》的研究论文中介绍了一种电子现金方案。该方案首次使用 Merkle 树表示硬币,并使用零知识证明ZKPs)证明了硬币的拥有权。

最初的研究论文名为可审计、匿名电子现金,可在此处获取:www.cs.tau.ac.il/~amnon/Papers/ST.crypto99.pdf

在这个方案中,需要一个中央银行来记录所有已使用的序列号。该方案允许用户完全匿名。这是一个理论设计,由于证明机制的低效而不适合实施。

可重用工作证明RPoW)于 2004 年由计算机科学家、开发者和第一个接收比特币的人 Hal Finney 引入。它使用了 Adam Back 的哈希现金方案作为创建货币所花费的计算资源的证明。这也是一个保持中央数据库以跟踪所有已使用的 PoW 令牌的中央系统。这是一个在线系统,利用了由可信计算平台(TPM 硬件)实现的远程认证。

所有先前提到的方案都设计得很聪明,但在某个方面都存在弱点。具体来说,所有这些方案都依赖于一个中央服务器,用户需要信任该服务器。

比特币

2008 年,比特币通过一篇名为比特币:一个点对点电子现金系统的论文被介绍。

本文可在bitcoin.org/bitcoin.pdf获取。

这篇文章由被认为是一个化名的 Satoshi Nakamoto 撰写,因为比特币发明者的真实身份是未知的,引起了许多猜测。论文中引入的第一个关键思想是一种纯粹的点对点电子现金,不需要中介银行来在对等方之间转移付款。

比特币建立在数十年的密码学研究基础上,如 Merkle 树、哈希函数、公钥密码学和数字签名的研究。此外,像 BitGold、B-money、哈希现金和密码时间戳等思想为比特币的发明提供了基础。所有这些技术都巧妙地结合在一起,创造了世界上第一个去中心化货币。比特币解决的关键问题是拜占庭将军问题的优雅解决方案以及双重支付问题的实际解决方案。回想一下,这两个概念都在第一章,区块链 101中解释过。

自 2011 年以来,比特币的价值显著增长,然后自 2017 年 3 月以来如下图所示:

自 2017 年 3 月以来的比特币价格

对比特币的监管是一个有争议的话题,正如它是自由主义者的梦想一样,执法机构、政府和银行正在提出各种规定来控制它,例如纽约州金融服务部门颁发的 BitLicense。这是一个发放给从事虚拟货币相关活动的企业的许可证。由于 BitLicense 的高成本和非常严格的监管要求,许多公司已经退出了在纽约的服务。

对于具有自由主义思想的人来说,比特币是一个可用于业务的代替银行的平台,但他们认为由于监管,比特币可能会成为另一个不受信任的机构。比特币的原始理念是开发一个无需信任第三方且用户可以匿名的电子现金系统。如果监管要求了解您的客户KYC)检查和详细的业务交易信息以促进监管流程,那么可能需要共享的信息过多,因此比特币对一些人来说可能不再具吸引力。

目前已经采取了许多措施来监管比特币、加密货币和相关活动,如 ICO。证券交易委员会SEC)最近宣布数字代币、货币和相关活动(如首次代币发行ICOs))属于证券范畴。这意味着任何数字货币交易平台都需要在 SEC 进行注册,并适用于所有相关证券法律和法规。这直接影响了比特币价格,在这一公告发布当天下跌了近 10%。

感兴趣的读者可以在www.coindesk.com/category/regulation/了解更多关于比特币监管和其他相关活动的信息。

比特币增长也是由所谓的网络效应引起的。也称为需求端规模经济,这个概念基本上意味着使用网络的用户越多,它就越有价值。随着时间的推移,比特币网络增长呈指数增长。用户数量的增加主要是出于经济上的驱动。此外,比特币的稀缺性和内置的通货膨胀控制机制赋予了它价值,因为只能挖掘出 2100 万个比特币,而且矿工奖励每四年减半。尽管比特币价格波动很大,但在过去几年里它增长显著。当前(撰写本文时),比特币价格为 9250 美元(USD)。

比特币定义

比特币可以以各种方式定义;它是一种协议、一种数字货币和一个平台。它是一种点对点网络、协议、软件的组合,促进了被称为比特币的数字货币的创建和使用。这个点对点网络中的节点使用比特币协议相互交流。

请注意,用大写字母 B 的比特币用来指代比特币协议,而小写字母 b 的 bitcoin 用来指代比特币,即货币。

使用比特币发明了货币的分散化,同时以一种巧妙和巧妙的方式解决了双重支付的问题。双重支付问题是指当用户同时向两个不同的用户发送硬币并且这些硬币分别经过独立验证为有效交易时所出现的问题。双重支付问题在比特币中通过使用分布式总账簿(区块链)解决,其中每笔交易都被永久记录,并且通过实施交易验证和确认机制来解决。这个过程将在本章的后面解释,我们将介绍挖掘的概念。

比特币- 俯瞰

在这一部分中,我们将看到比特币网络从用户的角度是什么样子。如何进行交易,交易如何从用户传播到网络,如何验证交易,并最终积累在区块中。我们将看看比特币网络的各种角色和组件。最后,我们还会提供一些关于所有角色和组件如何相互作用形成比特币网络的讨论。

首先,让我们看一下比特币网络的主要组成部分。比特币由以下列出的元素构成。随着我们在本章的进展,我们将进一步展开这些元素。

  • 数字钥匙

  • 地址

  • 交易

  • 区块链

  • 矿工

  • 比特币网络

  • 钱包(客户端软件)

现在,我们将看到用户如何使用比特币网络。以下例子将帮助您了解从最终用户角度看比特币网络的情况。我们将看到哪些角色和组件参与了比特币交易。最常见的交易之一是向其他人发送资金,因此在以下例子中,我们将看到如何在比特币网络上从一个用户向另一个用户发送支付。

向某人发送付款

这个例子将演示如何使用比特币网络从一个用户发送资金给另一个用户。这个过程涉及到一些步骤。例如,我们使用区块链钱包来进行移动设备的演示。

步骤如下:

  1. 首先,用户可以通过向发送者发送他的比特币地址通过电子邮件或其他手段,例如短信、聊天应用程序等,甚至任何合适的通信机制来请求付款。发送者也可以发起转账,将资金发送给另一个用户。在这两种情况下,都需要受益者的地址。例如,显示了区块链钱包创建支付请求的情况:

比特币支付请求(使用区块链钱包)

  1. 发件人可以输入收件人的地址,或者扫描具有比特币地址、金额和可选描述编码的 QR 码。钱包应用程序识别此 QR 码并将其解码为类似于 请发送 <金额> BTC 到比特币地址 <接收者的比特币地址> 的内容。

  2. 这将如下所示,其中包括数值:请将 0.00033324 BTC 发送至比特币地址 1JzouJCVmMQBmTcd8K4Y5BP36gEFNn1ZJ3

  3. 这也显示在这里呈现的截图中:

比特币支付二维码

在前述截图中显示的 QR 码被解码为 bitcoin://1JzouJCVmMQBmTcd8K4Y5BP36gEFNn1ZJ3?amount=0.00033324,可以作为 URL 在比特币钱包中打开。

  1. 在发送方的钱包应用程序中,此交易是按照一些规则构建并广播到比特币网络中的。在广播之前,此交易使用发送方的私钥进行数字签名。交易是如何创建、数字签名、广播、验证和添加到区块中的将在后续章节中清晰地描述。从用户的角度来看,一旦 QR 码被解码,交易将类似于以下截图所示:

使用区块链钱包发送 BTC

请注意,在前述截图中有许多字段,如发件人、收件人、BTC 和费用。虽然其他字段是不言自明的,但值得注意的是,费用是根据交易的大小计算的,费率是一个取决于网络中交易量的值。这表示为 Satoshis/byte。比特币网络中的费用确保你的交易将被矿工包含在区块中。

近期比特币的手续费非常高,以至于即使对于较小的交易也会收取高额的费用。这是因为矿工可以自由选择他们要验证和添加到区块中的交易,他们选择具有较高手续费的交易。大量用户创建成千上万的交易也导致了这种高手续费的情况,因为交易在竞争中争先被挑选出来,而矿工选择了手续费最高的交易。这笔费用通常也是在发送交易之前由比特币钱包软件自动估算和计算的。交易手续费越高,你的交易被优先挑选并包含在区块中的机会就越大。这个任务由矿工执行。挖矿和矿工是我们在本章稍后会在比特币挖矿的背景下详细了解的概念。

一旦交易发送,它将显示在区块链钱包软件中,如下所示:

交易已发送

  1. 在此阶段,交易已构建、签名并发送到比特币网络。此交易将被矿工选中进行验证并包含在区块中。另请注意,在前面的截图中,此交易正在等待确认。一旦交易被验证、包含在区块中并被挖掘,确认就会开始出现。此外,将从要转移的原始值中扣除适当的费用,并支付给将其包含在挖矿区块中的矿工。

此流程显示在以下图表中,其中从发送方地址发起支付 0.001267 BTC(约 11 美元)并支付给接收方地址(以 1Jz 开头)。手续费为 0.00010622(约 95 美分),也从交易中扣除作为挖矿费用。

图片

交易流程可视化(Blockchain.info)

前面的截图直观地展示了交易是如何从原始(发送方)流向右侧接收方的网络中的。

显示了交易各种属性的摘要视图:

图片

来自 Blockchain.info 的交易快照

查看前面的截图,有许多包含各种值的字段。以下列出了重要字段及其目的和说明:

  • 大小:这是交易的字节大小。

  • 权重:这是自比特币隔离见证SegWit)版本引入以来用于区块和交易大小的新度量单位。

  • 接收时间:这是收到交易的时间。

  • 包含在区块中:这显示了区块链上包含该交易的区块编号。

  • 确认数:这是矿工对此交易的确认次数。

  • 总输入:这是交易中的总输入数量。

  • 总输出:这是交易中的总输出数量。

  • 费用:这是收取的总费用。

  • 每字节费用:此字段表示总费用除以交易中的字节数。例如,每字节 10 Satoshis。

  • 每权重单位费用:对于传统交易,它是通过总字节数 * 4计算的。对于隔离见证交易,它是通过将隔离见证标记、标志和见证字段组合为一个权重单位,以及将其他字段的每个字节视为四个权重单位来计算的。

此交易在比特币网络上的交易 ID 为d28ca5a59b2239864eac1c96d3fd1c23b747f0ded8f5af0161bae8a616b56a1d,可以通过blockchain.info/tx/d28ca5a59b2239864eac1c96d3fd1c23b747f0ded8f5af0161bae8a616b56a1d链接进一步探索,该链接通过blockchain.info/提供的服务提供。 此交易 ID 在交易发送到网络后在钱包软件中可用。 从那里可以通过众多在线可用的比特币区块链浏览器之一进一步探索。 我们以blockchain.info/作为示例。

比特币交易被序列化以在网络上传输,并以十六进制格式编码。 例如,前述交易也在这里显示。 我们将在交易部分中看到,如何解码此十六进制编码的交易以及交易由哪些字段组成。

01000000017d3876b14a7ac16d8d550abc78345b6571134ff173918a096ef90ff0430e12408b0000006b483045022100de6fd8120d9f142a82d5da9389e271caa3a757b01757c8e4fa7afbf92e74257c02202a78d4fbd52ae9f3a0083760d76f84643cf8ab80f5ef971e3f98ccba2c71758d012102c16942555f5e633645895c9affcb994ea7910097b7734a6c2d25468622f25e12ffffffff022c820000000000001976a914c568ffeb46c6a9362e44a5a49deaa6eab05a619a88acc06c0100000000001976a9149386c8c880488e80a6ce8f186f788f3585f74aee88ac00000000  

总之,在比特币网络中的支付交易可以分为以下步骤:

  1. 交易始于发件人用其私钥签署交易

  2. 交易被序列化以便在网络上传输

  3. 交易被广播到网络上

  4. 监听交易的矿工拾取了该交易

  5. 矿工验证交易的有效性

  6. 交易被添加到候选/建议的挖掘块中

  7. 挖掘完成后,结果将广播到比特币网络上的所有节点

在本章的后续部分中,将更清楚地了解挖掘、交易和其他相关概念。 现在,在下一节中,将介绍比特币的各种面额。

作为数字货币,比特币具有各种面额,下表列出了这些面额。 发件人或收件人可以请求任何金额。 最小的比特币面额是 Satoshi。 比特币货币单位描述如下:

比特币面额

现在,您将逐一介绍比特币的构建块。 首先,我们将看看用于表示比特币网络上的所有权和价值转移的密钥和地址。

数字密钥和地址

在比特币网络上,比特币的拥有权和通过交易转移的价值取决于私钥、公钥和地址。 在第六章中,公钥加密,我们已经涵盖了这些概念,这里我们将看到私钥和公钥如何在比特币网络中使用。

椭圆曲线加密ECC)用于在比特币网络中生成公钥和私钥对。

比特币中的私钥

私钥需要保管安全,通常只存储在所有者一侧。私钥用于数字签名交易,证明比特币的所有权。

私钥基本上是在secp256k1 ECDSA 曲线建议的范围内随机选择的 256 位数字。任何从0x10xFFFF FFFF FFFF FFFF FFFF FFFF FFFF FFFE BAAE DCE6 AF48 A03B BFD2 5E8C D036 4140中随机选择的 256 位数字都是有效的私钥。

私钥通常使用钱包导入格式WIF)进行编码,以便更易于复制和使用。这是一种以不同格式表示完整大小私钥的方式。WIF 可以转换为私钥,反之亦然。步骤如下描述。

以下是私钥的示例:

A3ED7EC8A03667180D01FB4251A546C2B9F2FE33507C68B7D9D4E1FA5714195201

当转换为 WIF 格式时,它看起来像这样:

L2iN7umV7kbr6LuCmgM27rBnptGbDVc8g4ZBm6EbgTPQXnj1RCZP

感兴趣的读者可以使用以下网站提供的工具进行一些实验:

gobittest.appspot.com/PrivateKey

此外,有时会使用迷你私钥格式创建最多 30 个字符的私钥,以允许在空间有限的情况下存储,例如,刻在实体硬币上或者编码在耐损伤的 QR 码中。QR 码变得更加耐损伤,因为可以用更多的点来进行错误校正,而用更少的点来进行私钥的编码。使用迷你私钥格式编码的私钥有时也称为迷你密钥。迷你私钥的第一个字符始终是大写字母S。可以将迷你私钥转换为常规大小私钥,但现有的常规大小私钥无法转换为迷你私钥。这种格式曾用于 Casascius 实体比特币。

感兴趣的读者可以在这里找到更多信息en.bitcoin.it/wiki/Casascius_physical_bitcoins

Casascius 实体比特币的安全全息纸带有迷你密钥和 QR 码

比特币核心客户端还允许对包含私钥的钱包进行加密。

比特币中的公钥

公钥存在于区块链上,所有网络参与者都可以看到。公钥是从私钥派生的,因为它们与私钥有着特殊的数学关系。一旦使用私钥签名的交易被广播到比特币网络上,节点就会使用公钥来验证该交易确实已经使用相应的私钥签名。这个验证过程证明了比特币的所有权。

比特币使用基于secp256k1标准的 ECC。更具体地说,它利用 ECDSA 确保资金保持安全,并且只能由合法所有者花费。如果您需要刷新相关的密码学概念,可以参考第六章,公钥密码学,其中解释了 ECC。公钥长度为 256 位。公钥可以以未压缩或压缩格式表示。公钥基本上是椭圆曲线上的xy坐标。在未压缩格式中,公钥以 16 进制格式的前缀0x4表示。xy坐标都是 32 位长。压缩公钥总共为 33 字节,而未压缩格式为 65 字节。压缩版本的公钥仅包含x部分,因为y部分可以由它派生出来。

压缩公钥版本有效的原因在于,如果将 ECC 图形可视化,会发现y坐标可以在x轴下方或x轴上方,由于曲线是对称的,因此只需要存储在素数域中的位置。如果y是偶数,则在x轴上方,如果y是奇数,则在x轴下方。这意味着可以仅存储x而不是存储xy作为公钥,只需存储y是偶数还是奇数的信息。

最初,比特币客户端使用未压缩密钥,但从比特币核心客户端 0.6 开始,压缩密钥被用作标准。这导致在区块链中用于存储公钥的空间几乎减少了 50%。

键由不同的前缀标识,描述如下:

  • 未压缩公钥使用0x04作为前缀

  • 压缩公钥以0x03开头,如果公钥的y 32 位部分是奇数

  • 压缩公钥以0x02开头,如果公钥的y 32 位部分是偶数

比特币地址

比特币地址是通过取私钥的相应公钥并对其进行两次哈希运算创建的,首先使用 SHA-256 算法,然后使用 RIPEMD-160。160 位哈希结果然后加上版本号前缀,最后使用 Base58Check 编码方案进行编码。比特币地址长度为 26-35 个字符,以数字13开头。

典型的比特币地址看起来像是这样的字符串:

1ANAguGG8bikEv2fYsTBnRUmx7QUcK58wt  

这也常常被编码为 QR 码以便于分发。上述比特币地址的 QR 码显示在以下屏幕截图中:

比特币地址 1ANAguGG8bikEv2fYsTBnRUmx7QUcK58wt 的 QR 码

目前有两种类型的地址,常用的 P2PKH 和另一种 P2SH 类型,分别以数字13开头。在早期,比特币使用直接的支付到公钥,现在已经被 P2PKH 取代。这些类型将在本章后面解释。然而,比特币仍然在 coinbase 地址中使用直接的支付到公钥。地址不应该被多次使用;否则,可能会出现隐私和安全问题。避免地址重用可以在一定程度上规避匿名性问题,比特币还有一些其他的安全问题,如交易篡改、Sybil 攻击、竞争攻击和自私挖矿,需要采用不同的方法来解决。

交易篡改已经通过比特币协议的所谓隔离见证软分叉升级得到解决。这个概念将在本章后面解释。

从 bitaddress.org,纸钱包中的私钥和比特币地址

Base58Check 编码

比特币地址使用 Base58Check 编码进行编码。这种编码用于限制各种字符之间的混淆,例如 0OIl 因为它们在不同字体中可能看起来相同。该编码基本上将二进制字节数组转换为人类可读的字符串。这个字符串是通过使用一组 58 个字母数字符号来组成的。更多的解释和逻辑可以在比特币源代码中的base58.h源文件(github.com/bitcoin/bitcoin/blob/master/src/base58.h)中找到:

/**
* Why base-58 instead of standard base-64 encoding?
* - Don't want 0OIl characters that look the same in some fonts and
* could be used to create visually identical looking data.
* - A string with non-alphanumeric characters is not as easily accepted as input.
* - E-mail usually won't line-break if there's no punctuation to break at.
* - Double-clicking selects the whole string as one word if it's all alphanumeric.
*/

虚荣地址

由于比特币地址是基于 base-58 编码的,所以可以生成包含人类可读消息的地址。一个示例如下所示:

用 QR 编码的虚荣公共地址

虚荣地址是使用纯粹的蛮力方法生成的。以下截图显示了一个带有虚荣地址的纸钱包示例:

https://bitcoinvanitygen.com/ 生成的虚荣地址

在上面的截屏中,右下角显示了带有二维码的公开虚荣地址。纸钱包可以作为私钥的电子存储的替代而被物理地存储。

多重签名地址

如其名,这些地址需要多个私钥。在实践中,这意味着为了释放比特币,需要一定数量的签名。这也被称为M-of-N 多重签名。在这里,M 表示阈值或从 N 个密钥中需要的最小签名数来释放比特币。

交易

交易是比特币生态系统的核心。交易可以简单到只是将一些比特币发送到一个比特币地址,也可以根据需求而相当复杂。每个交易至少由一个输入和输出组成。输入可以被视为在以前的交易中创建并花费的硬币,输出可以被视为创建的硬币。如果一笔交易正在铸造新币,那么就没有输入,因此也不需要签名。如果一笔交易是要将硬币发送给其他用户(比特币地址),那么发送者需要使用他们的私钥对其进行签名,并且还需要对以前的交易进行引用以显示硬币的来源。事实上,硬币是以 Satoshis 表示的未花费交易输出。

交易不加密,可以在区块链上公开查看。区块由交易组成,这些交易可以使用任何在线区块链浏览器查看。

交易生命周期

以下步骤描述了交易的生命周期:

  1. 用户/发送方使用钱包软件或其他界面发送交易。

  2. 钱包软件使用发送者的私钥对交易进行签名。

  3. 交易使用泛洪算法广播到比特币网络中。

  4. 监听交易的挖矿节点(矿工)验证并将此交易包含在下一个要挖掘的区块中。就在交易被放置在区块中之前,它们会被放置在一个名为交易池的特殊内存缓冲区中。交易池的目的将在下一节中解释。

  5. 开采开始,这是一种确保区块链安全并作为对花费适当计算资源的矿工的奖励生成新币的过程。这个概念稍后在本章中将会详细解释。

  6. 一旦矿工解决了 PoW 问题,它就会将新挖掘的区块广播到网络中。PoW 将在本章后面详细解释。

  7. 节点验证区块并进一步传播区块,并开始生成确认。

  8. 最后,确认开始出现在接收方的钱包中,大约在三次确认后,交易被视为已完成和确认。然而,三到六次只是一个推荐的数字;即使在第一次确认后,交易也可以被视为最终确认。等待六次确认的关键思想是,在三次确认后,双重支付的概率几乎被消除。

交易费

矿工收取交易费。收取的费用取决于交易的大小和权重。交易费用通过减去输入和输出的总和来计算。

可以使用一个简单的公式:

费用 = 总数(输入) - 总数(输出)

手续费被用作激励,以鼓励矿工将用户交易包括在他们正在创建的区块中。所有交易最终都会进入内存池,矿工会根据它们的优先级在内存池中选择交易并包括在建议的区块中。关于优先级的计算将在本章后面介绍;然而,从交易手续费的角度来看,交易的手续费越高,矿工越快地会选择该交易。

根据不同的规则,针对各种类型的操作计算手续费,例如发送交易、包括在区块中以及节点中继。手续费由比特币协议不固定,并不是强制性的;即使没有手续费的交易也将按时处理,但可能需要很长的时间。然而,由于比特币网络中的交易数量大和投资者之间的竞争,这已经不再实际,因此建议始终提供手续费。交易确认时间通常在 10 分钟到 12 小时以上的范围内。交易时间取决于交易费和网络活动。如果网络非常繁忙,那么交易自然需要更长的处理时间,如果支付更高的费用,那么您的交易更有可能被矿工首先选中,因为更高的手续费会有额外的激励。

交易池

这些池也被称为内存池,它们基本上是由节点在本地内存(计算机 RAM)中创建的,以维护一个尚未在区块中确认的交易的临时列表。交易经过验证后,并根据它们的优先级被包括在一个区块中。

交易数据结构

在高层次上,一个交易包含元数据、输入和输出。交易被组合在一起以创建一个区块。

交易数据结构如下表所示:

字段 大小 描述
版本号 4 字节 用于为矿工和节点指定要使用的交易处理规则。
输入计数器 1-9 字节 交易中包含的输入数量(正整数)。
输入列表 变量 每个输入由几个字段组成,包括上一个 Tx 哈希上一个 Tx 输出索引Txin 脚本长度Txin 脚本,以及可选的序列号。块中的第一笔交易也被称为 coinbase 交易。它指定一个或多个交易输入。
输出计数器 1-9 字节 表示输出数量的正整数。
输出列表 变量 包含在交易中的输出。
锁定时间 4 字节 该字段定义交易生效的最早时间。它可以是 Unix 时间戳,也可以是区块高度。

下面是一个示例交易。这是本章开头提供的支付交易示例的解码交易。

{ 
   "lock_time":0, 
   "size":226, 
   "inputs":[ 
      { 
         "prev_out":{ 
            "index":139, 
        "hash":"40120e43f00ff96e098a9173f14f1371655b3478bc0a558d6dc17a4ab176387d" 
         }, 
"script":"483045022100de6fd8120d9f142a82d5da9389e271caa3a757b01757c8e4fa7afbf92e74257c02202a78d4fbd52ae9f3a0083760d76f84643cf8ab80f5ef971e3f98ccba2c71758d012102c16942555f5e633645895c9affcb994ea7910097b7734a6c2d25468622f25e12" 
      } 
   ], 
   "version":1, 
   "vin_sz":1, 
   "hash":"d28ca5a59b2239864eac1c96d3fd1c23b747f0ded8f5af0161bae8a616b56a1d", 
   "vout_sz":2, 
   "out":[ 
      { 
         "script_string":"OP_DUP OP_HASH160 c568ffeb46c6a9362e44a5a49deaa6eab05a619a OP_EQUALVERIFY OP_CHECKSIG", 
         "address":"1JzouJCVmMQBmTcd8K4Y5BP36gEFNn1ZJ3", 
         "value":33324, 
         "script":"76a914c568ffeb46c6a9362e44a5a49deaa6eab05a619a88ac" 
      }, 
      { 
         "script_string":"OP_DUP OP_HASH160 9386c8c880488e80a6ce8f186f788f3585f74aee OP_EQUALVERIFY OP_CHECKSIG", 
         "address":"1ET3oBGf8JpunjytE7owyVtmBjmvcDycQe", 
         "value":93376, 
         "script":"76a9149386c8c880488e80a6ce8f186f788f3585f74aee88ac" 
      } 
   ] 
} 

如前面的代码所示,交易由多个结构组成。所有这些元素都在下面的小节中描述。

元数据

交易的这一部分包含一些值,例如交易的大小、输入和输出的数量、交易的哈希以及一个lock_time字段。每个交易都有一个指定版本号的前缀。这些字段在前面的示例中显示为:lock_timesizeversion

输入

通常,每个输入都花费了前一个输出。每个输出被视为未花费交易输出UTXO),直到输入将其消耗掉。UTXO 是可以作为新交易的输入花费的未花费交易输出。

交易输入数据结构如下表所示:

字段 大小 描述
交易哈希 32 字节 这是具有 UTXO 的先前交易的哈希。
输出索引 4 字节 这是先前交易的输出索引,即要花费的 UTXO。
脚本长度 1-9 字节 这是解锁脚本的大小。
解锁脚本 可变 满足锁定脚本要求的输入脚本(ScriptSig)。
序列号 4 字节 通常禁用或包含锁定时间。禁用用'0xFFFFFFFF'表示。

在上面的示例中,“inputs”部分中定义了输入。

输出

输出有三个字段,它们包含发送比特币的指令。第一个字段包含 Satoshis 的数量,而第二个字段包含锁定脚本的大小。最后,第三个字段包含一个锁定脚本,其中包含需要满足的条件,以便花费输出。更多关于使用锁定和解锁脚本以及产生输出进行交易花费的信息在本节稍后讨论。

交易输出数据结构如下所示:

字段 大小 描述
8 字节 要转移的正整数 Satoshis 的总数
脚本大小 1-9 字节 锁定脚本的大小
锁定脚本 可变 输出脚本(ScriptPubKey

在上面的示例中,“OUT”部分显示了两个输出。

验证

使用比特币的脚本语言进行验证,下一节会详细描述。

脚本语言

比特币使用一种称为脚本的简单基于堆栈的语言来描述比特币如何花费和转移。它不是图灵完备的,没有循环,以避免长时间运行/挂起脚本对比特币网络造成任何不良影响。这种脚本语言基于类似于 Forth 编程语言的语法,并使用逆波兰表示法,其中每个操作数后面跟着它的操作符。它使用后进先出LIFO)堆栈从左到右进行评估。

脚本使用各种操作码或指令来定义其操作。 操作码也被称为单词、命令或函数。 比特币节点的早期版本有一些操作码,由于发现了设计中的错误而不再使用。

脚本操作码的各种类别包括常量、流程控制、堆栈、位逻辑、切片、算术、加密和锁定时间。

交易脚本通过组合ScriptSigScriptPubKey进行评估。 ScriptSig是解锁脚本,而ScriptPubKey是锁定脚本。 这是如何评估要花费的交易的方式:

  1. 首先,它被解锁,然后才能花费。

  2. ScriptSig由希望解锁交易的用户提供。

  3. ScriptPubkey 是交易输出的一部分,指定了需要满足的条件才能花费输出。

  4. 换句话说,输出由包含条件的ScriptPubKey锁定,当条件满足时,输出将被解锁,硬币可以被兑换。

常用的操作码。

所有操作码都在比特币参考客户端源代码的script.h文件中声明。

这可以从以下链接访问:https😕/github.com/bitcoin/bitcoin/blob/master/src/script/script.h 下面的评论中获取:

/** 脚本操作码 */

最常用的操作码的描述在此列出。此表格摘自比特币开发者指南:

操作码 描述
OP_CHECKSIG 这获取公钥和签名,并验证交易哈希的签名。如果匹配,则将TRUE推送到堆栈;否则,推送FALSE
OP_EQUAL 如果输入完全相同,则返回1;否则,返回0
OP_DUP 这复制堆栈中的顶部项目。
OP_HASH160 输入先使用 SHA-256 进行两次哈希,然后再使用 RIPEMD-160 进行哈希。
OP_VERIFY 如果堆栈顶部值不为 true,则将事务标记为无效。
OP_EQUALVERIFY 这与OP_EQUAL相同,但之后运行OP_VERIFY
OP_CHECKMULTISIG 这获取第一个签名并将其与每个公钥进行比较,直到找到匹配项,然后重复此过程直到检查所有签名。如果所有签名都有效,则返回1;否则,返回0

交易类型

比特币中有各种脚本可用于处理从源到目的地的价值转移。这些脚本根据交易的要求,从非常简单到非常复杂的范围都有。标准交易类型在此处讨论。标准交易通过IsStandard()IsStandardTx()测试进行评估,并且通常只有通过测试的标准交易才允许在比特币网络上进行挖掘或广播。但是,非标准交易是有效的,并且允许在网络上进行。

以下是标准交易类型:

  • 支付至公钥哈希P2PKH):P2PKH 是最常用的交易类型,用于向比特币地址发送交易。交易格式如下所示:
      ScriptPubKey: OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
      ScriptSig: <sig> <pubKey>

ScriptPubKeyScriptSig参数被串联在一起并执行。在本节中将会有一个示例,更详细地解释这一点。

  • 支付至脚本哈希P2SH):P2SH 用于将交易发送到脚本哈希(即以3开头的地址),并在 BIP16 中进行了标准化。除了传递脚本之外,还必须评估赎回脚本并确保其有效。模板如下所示:
      ScriptPubKey: OP_HASH160 <redeemScriptHash> OP_EQUAL
      ScriptSig: [<sig>...<sign>] <redeemScript>
  • 多重签名支付至多重签名):M-of-N 多重签名交易脚本是一种复杂类型的脚本,可以构建需要多个签名才能有效赎回交易的脚本。使用此脚本可以构建各种复杂的交易,如担保和存款。模板如下所示:
      ScriptPubKey: <m> <pubKey> [<pubKey> . . . ] <n> OP_CHECKMULTISIG
      ScriptSig: 0 [<sig > . . . <sign>]

原始多重签名已过时,并且多重签名通常是 P2SH 赎回脚本的一部分,如前面的项目中所述。

  • 付款给公钥:此脚本是一种非常简单的脚本,通常用于 coinbase 交易。它现在已经过时,并且是比特币的旧版本中使用的。在此情况下,公钥存储在脚本中,解锁脚本需要使用私钥对交易进行签名。

模板如下所示:

      <PubKey> OP_CHECKSIG
  • Null 数据/OP_RETURN:此脚本用于以费用在区块链上存储任意数据。消息的限制为 40 字节。此脚本的输出无法兑现,因为 OP_RETURN 无论如何都会失败验证。在此情况下不需要 ScriptSig

模板非常简单,如下所示:

      OP_RETURN <data>

P2PKH 脚本执行如下图所示:

P2PKH 脚本执行

所有交易最终都会在传输到比特币网络之前以十六进制格式编码。下面以十六进制格式显示了使用 bitcoin-cli 在主网上运行的比特币节点检索的示例交易:

$ bitcoin-cli getrawtransaction "d28ca5a59b2239864eac1c96d3fd1c23b747f0ded8f5af0161bae8a616b56a1d" 
{ 
  "result": "01000000017d3876b14a7ac16d8d550abc78345b6571134ff173918a096ef90ff0430e12408b0000006b483045022100de6fd8120d9f142a82d5da9389e271caa3a757b01757c8e4fa7afbf92e74257c02202a78d4fbd52ae9f3a0083760d76f84643cf8ab80f5ef971e3f98ccba2c71758d012102c16942555f5e633645895c9affcb994ea7910097b7734a6c2d25468622f25e12ffffffff022c820000000000001976a914c568ffeb46c6a9362e44a5a49deaa6eab05a619a88acc06c0100000000001976a9149386c8c880488e80a6ce8f186f788f3585f74aee88ac00000000", 
  "error": null, 
  "id": null 
} 

请注意,这是本章开头示例中提到的相同交易。

Coinbase 交易

Coinbase 交易或生成交易始终由矿工创建,是区块中的第一笔交易。它用于创建新的比特币。它包括一个特殊字段,也称为 coinbase,它充当 coinbase 交易的输入。此交易还允许最多 100 字节的任意数据,可用于存储任意数据。在创世区块中,此交易包含了最著名的评论,取自 The Times 报纸:

"The Times 03/Jan/2009 Chancellor on brink of second bailout for banks."

此消息证明了创世区块不早于 2009 年 1 月 3 日挖掘。这是因为比特币的第一个区块(创世区块)是在 2009 年 1 月 3 日创建的,而此新闻摘录取自当天的报纸。

Coinbase 交易输入的字段数量与通常的交易输入相同,但结构包含 coinbase 数据大小和 coinbase 数据字段,而不是解锁脚本大小和解锁脚本字段。此外,它没有指向上一个交易的引用指针。该结构如下表所示:

字段 大小 描述
交易哈希 32 字节 设置为全零,因为不使用哈希引用
输出索引 4 字节 设置为 0xFFFFFFFF
Coinbase 数据长度 1-9 字节 2 字节至 100 字节
数据 可变 任何数据
序列号 4 字节 设置为 0xFFFFFFFF

合约

如比特币核心开发者指南中所定义的,合同基本上是使用比特币系统执行财务协议的交易。这是一个简单的定义,但具有深远的影响,因为它允许用户设计可以在许多现实场景中使用的复杂合同。合同允许开发一个完全去中心化、独立和降低风险的平台。

可以使用比特币脚本语言构建各种合同,例如托管、仲裁和微支付通道。脚本的当前实现非常有限,但仍然可以开发各种类型的合同。例如,只有在多方签署交易后才释放资金,或者只有在一定时间过去后才释放资金。这两种情况都可以使用多重签名和交易锁定时间选项来实现。

交易验证

这个验证过程是由比特币节点执行的。比特币开发者指南中描述了以下内容:

  1. 检查语法,并确保交易的语法和数据结构符合协议提供的规则。

  2. 验证没有交易输入和输出为空。

  3. 检查字节大小是否小于最大区块大小。

  4. 输出值必须在允许的货币范围内(0 到 2100 万比特币)。

  5. 所有输入必须具有指定的先前输出,除了 coinbase 交易,不应该被中继。

  6. 验证nLockTime不能超过 31 位。(nLockTime指定交易不会在区块中包含之前的时间。)

  7. 为了使交易有效,其长度不应小于 100 字节。

  8. 标准交易中的签名操作数量应小于或不超过两个。

  9. 拒绝非标准交易;例如,ScriptSig仅允许在堆栈上推送数字。ScriptPubkey未通过isStandard()检查。isStandard()检查规定只允许标准交易。

  10. 如果池中或主分支中的某个区块中已经存在匹配的交易,则交易将被拒绝。

  11. 如果每个输入的引用输出存在于池中的任何其他交易中,则将拒绝交易。

  12. 对于每个输入,必须存在一个被引用的未花费交易输出。

  13. 对于每个输入,如果引用的输出交易是 coinbase,它必须至少有 100 个确认;否则,交易将被拒绝。

  14. 对于每个输入,如果引用的输出不存在或已经花费,则交易将被拒绝。

  15. 使用引用的输出交易来获取输入值,验证每个输入值以及总和是否在 0-2100 万比特币的允许范围内。如果输入值的总和小于输出值的总和,则拒绝交易。

  16. 如果交易费用太低而无法进入空块,则拒绝交易。

  17. 每个输入解锁脚本必须具有相应的有效输出脚本。

交易可塑性

比特币中的交易可塑性是由比特币实现中的一个错误引入的。由于这个错误,对手有可能改变交易的交易 ID,从而导致某个交易似乎没有被执行的情况。这可以导致双重存款或提款等情况发生。换句话说,这个错误允许在比特币交易确认之前更改其唯一 ID。如果在确认之前更改了 ID,则似乎根本没有发生交易,这样就可以发生这些攻击。

区块链

区块链是比特币网络上所有交易的时间戳、有序和不可变列表的公共分类帐。每个块在链中由哈希标识,并通过引用前一个块的哈希链接到其前一个块。

在下表中提供了一个块的结构,后跟一个详细的图表,提供了区块链结构的详细视图。

块的结构

下表显示了一个块的结构:

字段 大小 描述
块大小 4 字节 这是块的大小。
块头 80 字节 这包括下一节中描述的块头中的字段。
交易计数器 可变 此字段包含块中所有交易的总数,包括 coinbase 交易。大小范围为 1-9 字节
交易 可变 块中的所有交易。

块头的结构

以下表格描述了块头的结构:

字段 大小 描述
版本 4 字节 指定要遵循的块验证规则的块版本号。
上一个块的头哈希 32 字节 这是上一个块头的双 SHA-256 哈希。
Merkle 根哈希 32 字节 这是包含在块中的所有交易的 Merkle 树的双 SHA-256 哈希。
时间戳 4 字节 此字段包含块的大致创建时间,以 Unix 时代时间格式表示。更确切地说,这是矿工开始对头进行散列的时间。(从矿工的角度看的时间。)
难度目标 4 字节 这是网络/块的当前难度目标。
随机数 4 字节 这是矿工反复更改以产生低于难度目标的哈希的任意数字。

如下图所示,区块链是一个块链,其中每个块通过引用前一个块头的哈希链接到其前一个块。这种链接确保除非记录它的块和所有跟随它的块也被修改,否则不会修改任何交易。第一个块未链接到任何先前的块,并且称为创世块。

区块链、区块、区块头、交易和脚本的可视化

前面的图表显示了比特币区块链的高级概述。左侧显示从上到下的区块。每个区块包含交易和区块头,在右侧进一步放大。顶部,第一个区块头被展开以显示区块头内的各个元素。然后在右侧显示了区块头的 Merkle 根元素的被放大视图,显示了 Merkle 根是如何计算的。我们之前已经详细讨论了 Merkle 树,如果需要复习这个概念,可以参考第五章,对称加密。进一步向下,交易也被放大以展示交易的结构和包含的元素。此外,请注意,交易以显示锁定和解锁脚本的形式进一步阐述。该图表显示了许多组件,我们将在本章中讨论所有这些内容。

创世区块

这是比特币区块链中的创世区块。创世区块在比特币核心软件中被硬编码。它在chainparams.cpp文件中(github.com/bitcoin/bitcoin/blob/master/src/chainparams.cpp):

static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward) 
{ 
   const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks"; 
   const CScript genesisOutputScript = CScript() <<  
ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG; 
   return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTime, nNonce, 
   nBits, nVersion, genesisReward); 
} 

比特币通过强制执行交易验证和通过挖矿来提供防止双重花费的保护。只有在交易验证部分之前解释的严格规则检查和成功的 PoW 解决方案后,交易和区块才会被添加到区块链中。区块高度是在区块链中某一特定区块之前的区块数量。当前区块链(截至 2018 年 3 月 6 日)的高度为 512,328 个区块。PoW 用于保护区块链。每个区块包含一个或多个交易,其中第一笔交易是 coinbase 交易。对于 coinbase 交易有一个特殊条件,防止它们在至少 100 个区块前被花费,以避免后来该区块可能被声明为陈旧的情况。

当一个区块被解决并且其他每一个仍在努力寻找哈希谜题解的矿工都在该区块上工作时,就会产生陈旧区块。后续将详细讨论挖矿和哈希谜题。由于不再需要对该区块进行工作,因此被视为陈旧区块。

孤立区块也称为分开的区块,在某个时间点被网络接受为有效区块,但当创建了一个不包括最初接受的区块的经过验证更长链时,这些区块会被拒绝。它们不是主链的一部分,有时会发生在两个矿工同时生产区块的情况下。

最新的区块版本是版本 4,提出了 BIP65,并自比特币核心客户端 0.11.2 实施 BIP9 位以来一直被使用,nVersion字段正在用于指示软分叉更改。

由于比特币的分布式本质,网络分叉可能会自然发生。在两个节点同时宣布一个有效区块的情况下,可能会导致两个具有不同交易的区块链的情况。这是一个不希望发生的情况,但只能通过比特币网络接受最长的链来解决。在这种情况下,较小的链将被视为孤块。如果对手设法控制网络哈希率(计算能力)的 51%,那么他们可以强加自己的交易历史版本。

区块链中的分叉也可以随着比特币协议的更改引入而发生。在软分叉的情况下,选择不升级到支持更新协议的最新版本的客户端仍然能正常工作和运行。在这种情况下,先前和新的区块都是可接受的,因此软分叉是向后兼容的。

在软分叉的情况下,只有矿工需要升级到新的客户端软件,以利用新的协议规则。计划的升级不一定会创建分叉,因为所有用户应该已经更新了。另一方面,硬分叉使以前有效的区块无效,并要求所有用户升级。新的交易类型有时被添加为软分叉,任何更改,例如区块结构更改或主要协议更改都会导致硬分叉。截至 2017 年 10 月 29 日,比特币区块链的当前大小约为 139 GB。

以下图示显示了区块链大小随时间变化的情况:

截至 2017 年 10 月 29 日,区块链的当前大小为多少?

新的区块大约每 10 分钟添加到区块链上,并且网络难度每 2016 个区块动态调整,以保持对网络的新区块的稳定添加。

网络难度是使用以下方程计算的:

目标 = 先前的目标 * 时间/2016 * 10 分钟

难度和目标是可以互换的,表示相同的意思。先前的目标表示旧的目标值,时间表示生成前 2016 个区块所花费的时间。网络难度基本上表示矿工发现新区块的难度,即现在哈希难题的难度如何。

在接下来的一节中,将讨论挖矿,这将解释如何解决哈希难题。

挖矿

挖矿是将新区块添加到区块链的过程。区块包含通过比特币网络上的挖矿节点验证的交易。一旦挖矿和验证完成,区块就会被添加到保持不断增长的区块链中。这个过程由于 PoW 的要求而需要大量资源,其中矿工竞争找到一个小于网络难度目标的数字。找到正确值的难度(有时也称为数学难题)旨在确保矿工在新的建议区块被接受之前已经花费了必要的资源。矿工通过解决 PoW 问题,也称为部分哈希反演问题,铸造新的硬币。这个过程消耗大量资源,包括计算能力和电力。这个过程还通过向比特币生态系统增加更多虚拟货币来保护系统免受欺诈和双重花费攻击的侵害。

大约每 10 分钟创建(挖掘)一个新区块,以控制比特币生成的频率。这个频率需要由比特币网络维护,并且编码在比特币核心客户端中,以控制货币供应。如果矿工通过解决 PoW 问题发现新的区块,则会获得新的比特币作为奖励。矿工通过包含交易来获得交易费用作为回报。新的区块以大约每 10 分钟的固定速率创建。每 210,000 个区块,大约每 4 年,新比特币的创造速率减少 50%。比特币最初推出时,区块奖励为 50 个比特币;然后在 2012 年,将其减少为 25 个比特币。2016 年 7 月,进一步减少为 12.5 个硬币(12 个比特币),下一次减少预计在 2020 年 7 月 4 日。这将进一步将硬币奖励减少到大约六个比特币。

每天产生大约 144 个区块,即 1,728 个比特币。实际的比特币数量每天可能有所不同,但每天的区块数保持在 144 个。比特币的供应也是有限的,在 2140 年,将最终创造近 2100 万比特币,并且此后将不会再创造新的比特币。然而,比特币矿工仍将通过收取交易费用从生态系统中获利。

矿工的任务

一旦节点连接到比特币网络,比特币矿工会执行以下几项任务:

  1. 与网络同步: 一旦新节点加入比特币网络,它通过从其他节点请求历史区块来下载区块链。这里提到了比特币矿工的上下文中,但这并不一定只是矿工的任务。

  2. 交易验证: 网络上广播的交易由完整节点通过验证和验证签名和输出进行验证。

  3. 区块验证:矿工和完整节点可以从根据一定规则对接收到的区块进行验证开始验证这些区块。这包括验证区块中每个交易以及验证随机数值。

  4. 创建一个新的区块:矿工通过验证后,将网络上广播的交易组合到一起来提议一个新的区块。

  5. 执行工作证明:这个任务是挖矿过程的核心,挖矿者通过解决一个计算难题找到一个有效的区块。区块头包含一个 32 位的随机数字段,矿工需要反复改变随机数,直到结果哈希小于预定目标值。

  6. 获取奖励:一旦一个节点解决了哈希难题(PoW),它立即广播结果,其他节点验证并接受区块。由于在大约同一时间发现另一个区块,新铸造的区块可能不会被网络上其他矿工接受,但一旦被接受,矿工将获得 12.5 比特币和任何相关的交易费用。

挖矿奖励

当比特币在 2009 年开始时,挖矿奖励是 50 比特币。每 210,000 个区块后,区块奖励减半。2012 年 11 月,它减半到 25 比特币。目前,自 2016 年 7 月以来,每个区块奖励为 12.5 比特币。下一次减半将在 2020 年 6 月 12 日星期五,之后区块奖励将减少到每个区块 6.25 比特币。比特币中硬编码了这个机制来调节、控制通货膨胀,并限制比特币的供应。

工作证明(PoW)

这是计算资源足够以构建有效区块的证明。PoW 是基于随机节点每次被选中创建新区块的想法。在这个模型中,节点按其计算能力的比例竞争被选中。以下方程概括了比特币 PoW 要求:

H(N || P_hash || Tx || Tx || . . . Tx) < Target

其中N是一个随机数,P_hash是前一个区块的哈希,Tx代表区块中的交易,Target是目标网络难度值。这意味着前面提到的连接字段的哈希应该小于目标哈希值。

找到这个随机数的唯一方法就是穷举法。一旦一个矿工满足了一定数量的零的某种模式,区块就会立即被广播并被其他矿工接受。

挖矿算法

挖矿算法包括以下步骤。

  1. 从比特币网络中检索先前区块的头部。

  2. 将网络上广播的一组交易组合成一个要提议的区块。

  3. 计算前一个区块头部与一个随机数和新提议的区块的双重哈希,使用 SHA-256 算法。

  4. 检查结果哈希是否低于当前难度级别(目标),然后 PoW 就被解决了。成功完成 PoW 后,发现的区块将被广播到网络,矿工将获得奖励。

  5. 如果结果哈希不小于当前难度级别(目标),则在增加随机数后重复该过程。

随着比特币网络的哈希率增加,32 位随机数的总量耗尽得太快。为了解决这个问题,实施了额外的随机数解决方案,其中 Coinbase 交易被用作额外随机数的来源,以提供更大范围的随机数供矿工搜索。

这个过程可以通过使用以下流程图来可视化:

挖矿过程

随着时间的推移,挖矿难度不断增加,而现在单个 CPU 笔记本电脑可以挖掘的比特币现在需要专用的挖矿中心来解决哈希难题。可以使用比特币命令行界面使用以下命令来查询当前的难度级别:

$ bitcoin-cli getdifficulty 
1452839779145

此数字代表比特币网络的难度级别。从前面的部分可以得知,矿工竞争寻找问题的解决方案。实际上,这个数字显示了要找到比网络难度目标更低的哈希值有多困难。所有成功挖掘的区块必须包含一个哈希值,该哈希值低于此目标数字。此数字每隔 2 周或 2016 个区块更新一次,以确保平均每 10 分钟生成一个区块。

比特币网络难度呈指数增长,以下图表显示了在一年内的这种难度水平:

过去一年的挖矿难度

上述图表显示了过去一年比特币网络的难度,难度已经显着增加。挖矿难度增加的原因是因为在比特币中,区块生成时间必须始终约为 10 分钟。这意味着如果快速硬件快速挖掘区块,则会增加难度,以便区块生成时间保持大约每 10 分钟一个区块。如果区块不是每 10 分钟挖掘一次,则难度会减小。难度,每 2016 个区块(两周)计算一次,并相应地进行调整。如果上一组 2016 个区块在两周内挖掘完毕,则难度将增加。同样,如果 2016 个区块在两周以上找到(如果每 10 分钟挖掘一个区块,则 2016 个区块需要 2 周时间挖掘),则难度将减小。

哈希率

哈希率基本上表示每秒计算哈希的速率。换句话说,这是比特币网络中矿工计算哈希以找到一个区块的速度。在比特币早期,由于使用 CPU,哈希率曾经相当小。然而,随着现在专用的挖矿池和 ASIC,过去几年里这个速度呈指数级增长。这导致了比特币网络难度的增加。下图显示了随时间增加的哈希率,并且目前以 Exa 哈希进行测量。这意味着比特币网络矿工每秒计算超过 24,000,000,000,000,000,000 个哈希。

哈希率(以 Exa-hashes 表示)截至 2018 年 3 月,在 1 年的时间内显示

2018 年 3 月的哈希率(以 Exa-hashes 表示),在 1 年的时间内显示

挖矿系统

随着时间的推移,比特币矿工使用了各种方法来挖掘比特币。由于挖掘背后的核心原理是基于双重 SHA-256 算法,专家们随着时间的推移开发出了复杂的系统来越来越快地计算哈希。以下是比特币中使用的不同挖矿方法的回顾,以及它们随时间的演变。

CPU

CPU 挖矿是原始比特币客户端中可用的第一种挖矿类型。用户甚至可以使用笔记本电脑或台式电脑来挖比特币。CPU 挖矿已不再盈利,现在更先进的挖矿方法,如基于 ASIC 的挖矿被使用。CPU 挖矿仅在比特币推出后的一年多一点的时间内持续存在,很快矿工们就开始尝试并探索其他方法。

GPU

由于比特币网络难度的增加以及寻找更快挖矿方法的普遍趋势,矿工开始使用 PC 中提供的 GPU 或图形处理器来进行挖矿。GPU 支持更快速和并行计算,通常使用 OpenCL 语言编程。与 CPU 相比,这被证明是一种更快的选择。用户还使用超频等技术来充分利用 GPU 的性能。此外,使用多个显卡的可能性增加了使用显卡进行比特币挖矿的流行度。然而,GPU 挖矿也有一些局限性,如过热以及需要专门的主板和额外的硬件来容纳多个显卡。从另一个角度来看,由于需求增加,显卡变得相当昂贵,这影响了玩家和图形软件用户。

FPGA

即使 GPU 挖矿也没有持续太久,很快矿工们找到了另一种使用 FPGA 进行挖矿的方法。现场可编程门阵列FPGA)基本上是可以编程执行特定操作的集成电路。FPGA 通常使用硬件描述语言HDLs)编程,如 Verilog 和 VHDL。双 SHA-256 很快成为 FPGA 程序员的一个有吸引力的编程任务,并且有几个开源项目也开始了。与 GPU 相比,FPGA 提供了更好的性能;然而,诸如可访问性、编程难度以及需要专业知识来编程和配置 FPGA 等问题导致了比特币挖矿 FPGA 时代的短暂寿命。

ASIC 的出现迅速淘汰了基于 FPGA 的挖矿系统。在 FPGA 挖矿盈利的时期,诸如 X6500 矿工、Ztex 和 Icarus 等挖矿硬件被开发出来。各种 FPGA 制造商,如赛灵思和 Altera,生产可以用于编程挖矿算法的 FPGA 硬件和开发板。值得注意的是,GPU 挖矿对于某些其他加密货币在某种程度上仍然是盈利的,比如 Zcoin(zcoin.io/guide-on-how-to-mine-zcoin-xzc/),但对于比特币来说不是,因为比特币的网络难度非常高,只有运行在并行模式下的 ASIC(专用硬件)才能产生一些合理的利润。

ASIC

特定应用集成电路ASIC)是为执行 SHA-256 操作而设计的。这些特殊芯片由各种制造商销售,并提供非常高的哈希速率。这在一段时间内有效,但由于挖矿难度水平迅速增加,单个 ASIC 已不再具有盈利性。

目前,挖矿对个人来说已经不再可及,因为需要花费大量的能源和资金才能建立一个盈利的挖矿平台。现在,使用成千上万的 ASIC 单位并行的专业挖矿中心向用户提供挖矿合同,代表他们进行挖矿。技术上没有限制,单个用户可以并行运行成千上万个 ASIC,但这将需要专用数据中心和硬件,因此,对于单个个人来说成本可能会成为一个障碍。以下是四种类型的挖矿硬件:

CPU

GPU

FPGA

ASIC

挖矿池

当一组矿工共同挖掘一个区块时,就形成了一个矿池。如果区块成功挖掘,矿池管理员将接收 coinbase 交易,然后负责将奖励分发给投资资源进行挖掘的一组矿工。这比独立挖矿更有利可图,因为在矿池中,奖励将支付给矿池的每个成员,而不管他们(更具体地说,他们的个人节点)是否解决了难题。

矿池管理员可以使用各种模式来支付给矿工,例如按份支付PPS)模式和比例模式。在 PPS 模式中,矿池管理员向所有参与挖矿的矿工支付固定费用,而在比例模式中,份额是根据用于解决哈希难题的计算资源量来计算的。

现在有许多商业矿池存在,并通过云和易于使用的网络界面提供挖矿服务合约。其中最常用的是 AntPool (www.antpool.com)、BTC (btc.com) 和 BTC TOP (www.btc.top)。所有主要矿池的哈希功率比较如下图所示:

2017 年 10 月 28 日的矿池及其哈希功率(哈希率)

来源:blockchain.info/pools

如果一个矿池控制了比特币网络超过 51%的哈希率,就可能发生挖矿集中化。

如前述的介绍部分所讨论的,51%攻击可能导致成功的双重支付攻击,它可能影响共识,事实上在比特币网络上施加另一版本的交易历史。

这种事件在比特币历史上曾经发生过一次,当时一家名为 GHash.IO 的大型矿池成功获得了超过 51%的网络容量。理论上的解决方案,如两阶段 PoW (hackingdistributed.com/2014/06/18/how-to-disincentivize-large-bitcoin-mining-pools/),已经在学术界提出,以防止大型矿池。该方案引入了第二个加密难题,导致矿池要么透露他们的私钥,要么提供他们矿池的相当一部分哈希率,从而降低矿池的总体哈希率。

目前,有各种类型的硬件可供商业用于挖矿。目前,最赚钱的是 ASIC 挖矿,来自一些供应商如蚂蚁矿机(Antminer)、AvalonMiner 和 Whatsminer。目前,独立挖矿除非投入大量资金和能源建立自己的挖矿设备甚至数据中心,否则收益不高。根据当前的难度系数(2018 年 3 月),如果用户设法产生 12 TH/s 的哈希率,他们可能每天希望获得 0.0009170 BTC(约 6 美元),与购买可以产生 12 TH/s 的设备所需的投资相比,这很低。考虑到电费等运行成本,这并不是很有利可图。

例如,Antminer S9 是一种有效的 ASIC 矿工,可以产生 13.5 TH/s 的哈希功率,看起来它每天可以产生一些利润是正确的,但单个 Antminer S9 的成本约为 1700 英镑,加上电费后,投资回报几乎需要一年的时间,当它产生大约 0.3 BTC 时。也许看起来还可以投资,但也要考虑到比特币网络难度会随着时间的推移不断上升,在一年内挖矿会变得更加困难,并且挖矿硬件在几个月内就会失去用途。

总结

我们通过介绍了比特币以及从用户角度讲述了交易如何工作的方式来开始本章。然后,我们从技术角度介绍了交易的概念。随后,我们讨论了在比特币中使用的公钥和私钥。

在接下来的章节中,我们介绍了地址及其不同类型,并讨论了交易及其类型和用途。接下来,我们详细解释了区块链的运作方式以及比特币区块链中包含的各种组件。

在本章的最后几节中,我们介绍了挖矿过程和相关概念。

第九章:构建钱包服务

钱包服务用于发送和接收资金。构建钱包服务的主要挑战是安全性和信任。用户必须确信他们的资金是安全的,钱包服务的管理员不会窃取他们的资金。本章中我们将构建的钱包服务将解决这两个问题。

在本章中,我们将涵盖以下主题:

  • 在线钱包和离线钱包的区别

  • 使用 hooked-web3-provider 和 ethereumjs-tx 来更容易地创建和签名使用由以太坊节点管理的账户的交易

  • 了解什么是 HD 钱包以及它的用途

  • 使用 lightwallet.js 创建 HD 钱包和交易签名者

  • 构建钱包服务

在线钱包和离线钱包的区别

一个钱包是一组账户,而账户是地址和其关联私钥的组合。

当钱包连接到互联网时,称为在线钱包。例如,存储在 geth、任何网站/数据库等中的钱包称为在线钱包。在线钱包也称为热钱包、网络钱包、托管钱包等。至少在存储大量以太币或长时间存储以太币时,不建议使用在线钱包,因为它们很危险。此外,取决于钱包存储的位置,可能需要信任第三方。

例如,大多数流行的钱包服务都将钱包的私钥存储在自己身上,并允许您通过电子邮件和密码访问钱包,所以基本上,您没有实际访问钱包的权限,如果他们想,他们可以窃取钱包中的资金。

当钱包未连接到互联网时,称为离线钱包。例如,存储在 U 盘、纸张、文本文件等中的钱包。离线钱包也称为冷钱包。离线钱包比在线钱包更安全,因为要窃取资金,需要有人对存储设备进行物理访问。离线存储的挑战在于需要找到一个不会意外删除或遗忘的位置,或者没有其他人可以访问。许多人将钱包存储在纸上,并将纸放在保险柜中,以便安全地保存一些资金很长一段时间。如果您想经常从您的账户中发送资金,那么您可以将其存储在受密码保护的 U 盘中,也可以存储在保险柜中。将钱包仅存储在数字设备中风险略高,因为数字设备随时可能损坏,您可能会无法访问您的钱包;因此,除了存储在 U 盘中,您还应该将其放在保险柜中。您也可以根据自己的需求找到更好的解决方案,但请确保它是安全的,并且您不会意外丢失对它的访问权限。

hooked-web3-provider 和 ethereumjs-tx 库

到目前为止,我们看到的 Web3.js 库的sendTransaction()方法的所有示例都在使用以太坊节点中存在的from地址;因此,在广播之前以太坊节点能够对交易进行签名。但是,如果您将钱包的私钥存储在其他地方,则 geth 无法找到它。因此,在这种情况下,您需要使用web3.eth.sendRawTransaction()方法来广播交易。

web3.eth.sendRawTransaction()用于广播原始交易,也就是说,您将不得不编写代码来创建和签署原始交易。以太坊节点将直接广播它,而不对交易进行其他任何处理。但是,编写使用web3.eth.sendRawTransaction()广播交易的代码很困难,因为它需要生成数据部分、创建原始交易,以及签署交易。

Hooked-Web3-Provider 库为我们提供了一个自定义提供程序,它使用 HTTP 与 geth 进行通信;但是该提供程序的独特之处在于,它允许我们使用我们的密钥对合约实例的sendTransaction()调用进行签名。因此,我们不再需要创建交易的数据部分。自定义提供程序实际上覆盖了web3.eth.sendTransaction()方法的实现。因此,基本上它允许我们对合约实例的sendTransaction()调用以及web3.eth.sendTransaction()调用进行签名。合约实例的sendTransaction()方法在内部生成交易数据并调用web3.eth.sendTransaction()来广播交易。

EthereumJS 是与以太坊相关的那些库的集合。ethereumjs-tx 是其中之一,它提供了与交易相关的各种 API。例如,它允许我们创建原始交易、签署原始交易、检查是否使用正确的密钥签署了交易等。

这两个库都适用于 Node.js 和客户端 JavaScript。从www.npmjs.com/package/hooked-web3-provider下载 Hooked-Web3-Provider,并从www.npmjs.com/package/ethereumjs-tx下载 ethereumjs-tx。

在撰写本书时,Hooked-Web3-Provider 的最新版本是 1.0.0,ethereumjs-tx 的最新版本是 1.1.4。

让我们看看如何将这些库一起使用,以从未由 geth 管理的帐户发送交易。

var provider = new HookedWeb3Provider({ 
 host: "http://localhost:8545", 
 transaction_signer: { 
  hasAddress: function(address, callback){ 
   callback(null, true); 
  }, 
  signTransaction: function(tx_params, callback){ 
   var rawTx = { 
          gasPrice: web3.toHex(tx_params.gasPrice), 
          gasLimit: web3.toHex(tx_params.gas), 
          value: web3.toHex(tx_params.value) 
          from: tx_params.from, 
          to: tx_params.to, 
          nonce: web3.toHex(tx_params.nonce) 
      }; 

   var privateKey = EthJS.Util.toBuffer('0x1a56e47492bf3df9c9563fa7f66e4e032c661de9d68c3f36f358e6bc9a9f69f2', 'hex'); 
   var tx = new EthJS.Tx(rawTx); 
   tx.sign(privateKey); 

   callback(null, tx.serialize().toString('hex')); 
  } 
 } 
}); 

var web3 = new Web3(provider); 

web3.eth.sendTransaction({ 
 from: "0xba6406ddf8817620393ab1310ab4d0c2deda714d", 
 to: "0x2bdbec0ccd70307a00c66de02789e394c2c7d549", 
 value: web3.toWei("0.1", "ether"), 
 gasPrice: "20000000000", 
 gas: "21000" 
}, function(error, result){ 
 console.log(error, result) 
})

代码的工作原理如下:

  1. 首先,我们创建了一个HookedWeb3Provider实例。这是由 Hooked-Web3-Provider 库提供的。该构造函数接受一个具有两个属性的对象,这两个属性必须提供。host是节点的 HTTP URL,transaction_signer是与自定义提供程序通信以获取交易签名的对象。

  2. transaction_signer对象有两个属性:hasAddresssignTransaction。调用hasAddress来检查是否可以对交易进行签名,即检查交易签名者是否具有from地址账户的私钥。此方法接收地址和一个回调函数。如果找不到地址的私钥,则应调用回调,并将第一个参数作为错误消息,第二个参数为false。如果找到私钥,则第一个参数应为null,第二个参数应为true

  3. 如果找到地址的私钥,则自定义提供程序调用signTransaction方法来获取交易的签名。此方法有两个参数,即交易参数和一个回调函数。在方法内部,首先我们将交易参数转换为原始交易参数,即原始交易参数值被编码为十六进制字符串。然后我们创建一个缓冲区来保存私钥。缓冲区是使用EthJS.Util.toBuffer()方法创建的,该方法是ethereumjs-util库的一部分。ethereumjs-util库被ethereumjs-tx库导入。然后我们创建一个原始交易并对其进行签名,之后我们对其进行序列化并转换为十六进制字符串。最后,我们需要使用回调将签名的原始交易的十六进制字符串提供给自定义提供程序。如果方法内部存在错误,则回调的第一个参数应为错误消息。

  4. 现在自定义提供程序获取原始交易并使用web3.eth.sendRawTransaction()进行广播。

  5. 最后,我们调用web3.eth.sendTransaction函数向另一个账户发送一些以太币。在这里,我们需要提供除了nonce以外的所有交易参数,因为自定义提供程序可以计算 nonce。以前,这些参数中的许多是可选的,因为我们让以太坊节点来计算它们,但是现在,因为我们自己签名,所以需要提供所有这些参数。当交易没有与之关联的任何数据时,gas永远是 21,000。

公钥呢?

在上述代码中,我们从未提及签名地址的公钥。你一定会想知道矿工如何在没有公钥的情况下验证交易的真实性。矿工使用 ECDSA 的一个独特属性,它允许你从消息和签名计算出公钥。在交易中,消息指示交易的意图,签名用于确定消息是否使用正确的私钥进行了签名。这就是使 ECDSA 如此特殊的地方。ethereumjs-tx 提供了一个 API 来验证交易。

什么是分层确定性钱包?

分层确定性钱包是从称为种子的单个起始点派生地址和密钥的系统。确定性表明对于相同的种子,将生成相同的地址和密钥,并且分层表明地址和密钥将以相同的顺序生成。这使得备份和存储多个账户变得更容易,因为你只需要存储种子,而不是单独的密钥和地址。

用户为什么需要多个账户?

你一定会想知道用户为什么需要多个账户。原因是为了隐藏他们的财富。账户的余额在区块链上是公开可见的。所以,如果用户 A 与用户 B 分享一个地址以接收一些以太币,那么用户 B 可以检查该地址中有多少以太币。因此,用户通常会将他们的财富分布在各种账户中。

有各种类型的 HD 钱包,它们在种子格式和生成地址和密钥的算法方面有所不同,例如,BIP32、Armory、Coinkite、Coinb.in 等等。

什么是 BIP32、BIP44 和 BIP39?

比特币改进提案BIP)是向比特币社区提供信息的设计文档,或者描述比特币或其过程或环境的新功能。BIP 应提供该功能的简明技术规范和该功能的理由。在撰写本书时,有 152 个 BIPS(比特币改进提案)。BIP32 和 BIP39 分别提供了有关实现 HD 钱包和助记符种子规范的算法的信息。你可以在 github.com/bitcoin/bips 了解更多信息。

密钥派生函数简介

非对称加密算法定义了它们的密钥的性质以及如何生成密钥,因为密钥需要相关联。例如,RSA 密钥生成算法是确定性的。

对称加密算法只定义了密钥大小。生成密钥的责任在于我们自己。有各种算法可以生成这些密钥。其中一种算法是 KDF。

密钥派生函数KDF)是一个确定性算法,从某个秘密值(如主密钥、密码或口令)派生对称密钥。有各种类型的 KDF,如 bcrypt、crypt、PBKDF2、scrypt、HKDF 等。你可以在 en.wikipedia.org/wiki/Key_derivation_function 了解更多关于 KDF 的信息。

要从单个秘密值生成多个密钥,可以连接一个数字并递增它。

基于密码的密钥派生函数接受一个密码并生成一个对称密钥。由于用户通常使用弱密码,基于密码的密钥派生函数被设计得更慢,需要大量内存,以使启动暴力破解攻击和其他类型的攻击变得困难。基于密码的密钥派生函数被广泛使用,因为很难记住秘密密钥,并且将其存储在某处是有风险的,因为它可能会被盗取。PBKDF2 是基于密码的密钥派生函数的一个例子。

主密钥或密码短语很难被暴力破解;因此,如果您想从主密钥或密码短语生成对称密钥,可以使用非基于密码的密钥派生函数,例如 HKDF。与 PBKDF2 相比,HKDF 要快得多。

为什么不直接使用哈希函数而不是 KDFs?

哈希函数的输出可以用作对称密钥。所以你可能会想,KDFs 是为什么需要呢?嗯,如果您使用主密钥、密码短语或强密码,您可以简单地使用哈希函数。例如,HKDF 简单地使用哈希函数生成密钥。但是如果不能保证用户会使用强密码,最好使用基于密码的哈希函数。

LightWallet 简介

LightWallet 是一个实现了 BIP32、BIP39 和 BIP44 的 HD 钱包。LightWallet 提供了使用其生成的地址和密钥创建和签署交易,或者加密和解密数据的 API。

LightWallet API 被分为四个命名空间,即 keystoresigningencryptiontxutilssigningencryptiontxutils 分别提供了用于签名交易、非对称加密和创建交易的 API,而 keystore 命名空间用于创建 keystore、生成种子等。keystore 是一个保存了种子和加密密钥的对象。如果我们使用 Hooked-Web3-Provider,keystore 命名空间会实现交易签名方法,用于签署 web3.eth.sendTransaction() 的调用。因此,keystore 命名空间可以自动为其内找到的地址创建和签署交易。实际上,LightWallet 主要用作 Hooked-Web3-Provider 的签名提供者。

keystore 实例可以配置为创建和签署交易,也可以用于加密和解密数据。对于签署交易,它使用 secp256k1 参数,对于加密和解密,它使用 curve25519 参数。

LightWallet 的种子是一个包含 12 个单词的助记词,易于记忆但难以破解。它不能是任意的 12 个单词;相反,它应该是由 LightWallet 生成的种子。LightWallet 生成的种子在单词选择和其他方面具有特定的属性。

HD 派生路径

HD 推导路径是一个字符串,易于处理多种加密货币(假设它们都使用相同的签名算法)、多个区块链、多个账户等等。

HD 推导路径可以有任意多个参数,并且使用不同值的参数,可以产生不同组的地址及其关联密钥。

默认情况下,LightWallet 使用m/0'/0'/0'推导路径。在这里,/n'是一个参数,n是参数值。

每个 HD 推导路径都有一个curvepurposepurpose可以是signasymEncryptsign表示该路径用于签署交易,asymEncrypt表示该路径用于加密和解密。curve表示 ECC 的参数。对于签名,参数必须是secp256k1,对于非对称加密,曲线必须是curve25591,因为 LightWallet 强制我们使用这些参数,由于它们在这些目的上的好处。

构建一个钱包服务

现在我们已经学习了足够多关于 LightWallet 的理论知识,是时候使用 LightWallet 和 hooked-web3-provider 构建钱包服务了。我们的钱包服务将让用户生成一个唯一的种子,显示地址及其关联余额,最后,该服务将让用户向其他账户发送以太币。所有操作都将在客户端进行,以便用户能够轻松信任我们。用户要么必须记住种子,要么将其存储在某个地方。

先决条件

在构建钱包服务之前,请确保您正在运行挖矿的 geth 开发实例,启用了 HTTP-RPC 服务器,允许来自任何域的客户端请求,并最后锁定了帐户 0。您可以通过运行以下内容来实现所有这些要求:

    geth --dev --rpc --rpccorsdomain "*" --rpcaddr "0.0.0.0" --rpcport "8545" --mine --unlock=0

在这里,--rpccorsdomain用于允许特定域与 geth 进行通信。我们需要提供一个以空格分隔的域列表,例如 "http://localhost:8080 https://mySite.com *"。它还支持*通配符字符。--rpcaddr指示 geth 服务器的可访问 IP 地址。这个默认值是127.0.0.1,所以如果它是托管服务器,您将无法使用服务器的公共 IP 地址来访问它。因此,我们将其值更改为0.0.0.0,这表明服务器可以使用任何 IP 地址进行访问。

项目结构

在本章的练习文件中,您将找到两个目录,即FinalInitialFinal包含项目的最终源代码,而Initial包含空白的源代码文件和库,可快速开始构建应用程序。

要测试Final目录,您需要在其中运行npm install,然后使用Final目录内的node app.js命令运行该应用程序。

Initial 目录内,你会找到一个 public 目录和两个名为 app.jspackage.json 的文件。 package.json 包含后端依赖项。 我们的应用程序 app.js 是你会放置后端源代码的地方。

public 目录包含与前端相关的文件。在 public/css 内,你会找到 bootstrap.min.css,这是 bootstrap 库。 在 public/html 内,你会找到 index.html,其中你会放置我们应用程序的 HTML 代码,最后,在 public/js 目录内,你会找到 Hooked-Web3-Provider、web3js 和 LightWallet 的 .js 文件。 在 public/js 内,你还会找到一个 main.js 文件,其中你会放置我们应用程序的前端 JS 代码。

构建后端

让我们首先构建应用程序的后端。首先,在初始目录内运行 npm install 来安装后端所需的依赖。

以下是运行 express 服务并提供 index.html 文件和静态文件的完整后端代码:

var express = require("express");   
var app = express();   

app.use(express.static("public")); 

app.get("/", function(req, res){ 
 res.sendFile(__dirname + "/public/html/index.html"); 
}) 

app.listen(8080);

上述代码不言自明。

构建前端

现在让我们构建应用程序的前端。前端将包括主要功能,即生成种子、显示种子的地址和发送以太币。

现在让我们编写应用程序的 HTML 代码。将此代码放在 index.html 文件中:

<!DOCTYPE html> 
 <html lang="en"> 
     <head> 
         <meta charset="utf-8"> 
         <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> 
         <meta http-equiv="x-ua-compatible" content="ie=edge"> 
         <link rel="stylesheet" href="/css/bootstrap.min.css"> 
     </head> 
     <body> 
         <div class="container"> 
             <div class="row"> 
                 <div class="col-md-6 offset-md-3"> 
                     <br> 
                     <div class="alert alert-info" id="info" role="alert"> 
                           Create or use your existing wallet. 
                     </div> 
                     <form> 
                         <div class="form-group"> 
                             <label for="seed">Enter 12-word seed</label> 
                             <input type="text" class="form-control" id="seed"> 
                         </div> 
                         <button type="button" class="btn btn-primary" onclick="generate_addresses()">Generate Details</button> 
                         <button type="button" class="btn btn-primary" onclick="generate_seed()">Generate New Seed</button> 
                     </form> 
                     <hr> 
                     <h2 class="text-xs-center">Address, Keys and Balances of the seed</h2> 
                     <ol id="list"> 
                     </ol> 
                     <hr> 
                     <h2 class="text-xs-center">Send ether</h2> 
                     <form> 
                         <div class="form-group"> 
                             <label for="address1">From address</label> 
                             <input type="text" class="form-control" id="address1"> 
                         </div> 
                         <div class="form-group"> 
                             <label for="address2">To address</label> 
                             <input type="text" class="form-control" id="address2"> 
                         </div> 
                         <div class="form-group"> 
                             <label for="ether">Ether</label> 
                             <input type="text" class="form-control" id="ether"> 
                         </div> 
                         <button type="button" class="btn btn-primary" onclick="send_ether()">Send Ether</button> 
                     </form> 
                 </div> 
             </div> 
         </div> 

            <script src="img/web3.min.js"></script> 
            <script src="img/hooked-web3-provider.min.js"></script> 
         <script src="img/lightwallet.min.js"></script> 
         <script src="img/main.js"></script> 
     </body> 
 </html>

以下是代码的工作原理:

  1. 首先,我们引入了 Bootstrap 4 样式表。

  2. 然后我们显示一个信息框,我们将向用户显示各种消息。

  3. 然后,我们有一个带有输入框和两个按钮的表单。输入框用于输入种子,或者在生成新种子时,在那里显示种子。

  4. 生成详细信息按钮用于显示地址,生成新种子用于生成新的唯一种子。当点击生成详细信息时,我们调用 generate_addresses() 方法;当点击生成新种子按钮时,我们调用 generate_seed() 方法。

  5. 稍后,我们会有一个空的有序列表。在这里,当用户点击生成详细信息按钮时,我们将动态显示种子的地址、余额和关联的私钥。

  6. 最后,我们有另一个表单,带有一个来自地址和一个到地址以及要转移的以太币数量。来自地址必须是当前在无序列表中显示的地址之一。

现在让我们编写 HTML 代码调用的每个函数的实现。首先,让我们编写生成新种子的代码。将此代码放在 main.js 文件中:

function generate_seed() 
{ 
 var new_seed = lightwallet.keystore.generateRandomSeed(); 

 document.getElementById("seed").value = new_seed; 

 generate_addresses(new_seed); 
}

keystore 命名空间的 generateRandomSeed() 方法用于生成一个随机种子。它接受一个可选参数,即指示额外熵的字符串。

熵是应用程序收集用于算法或其他需要随机数据的随机性。通常,熵来自硬件源,可以是预先存在的源,如鼠标移动或专门提供的随机性生成器。

为了产生一个唯一的种子,我们需要非常高的熵。LightWallet 已经使用方法来生成唯一的种子。LightWallet 用于产生熵的算法取决于环境。但是,如果您觉得您可以生成更好的熵,您可以将生成的熵传递给generateRandomSeed()方法,它将与内部使用generateRandomSeed()生成的熵连接在一起。

在生成一个随机种子之后,我们调用generate_addresses方法。这个方法需要一个种子,并在其中显示地址。在生成地址之前,它会提示用户询问他们想要生成多少个地址。

这里是generate_addresses()方法的实现。将这段代码放在main.js文件中:

var totalAddresses = 0; 

function generate_addresses(seed) 
{ 
 if(seed == undefined) 
 { 
  seed = document.getElementById("seed").value; 
 } 

 if(!lightwallet.keystore.isSeedValid(seed)) 
 { 
  document.getElementById("info").innerHTML = "Please enter a valid seed"; 
  return; 
 } 

 totalAddresses = prompt("How many addresses do you want to generate"); 

 if(!Number.isInteger(parseInt(totalAddresses))) 
 { 
  document.getElementById("info").innerHTML = "Please enter valid number of addresses"; 
  return; 
 } 

 var password = Math.random().toString(); 

 lightwallet.keystore.createVault({ 
  password: password, 
    seedPhrase: seed 
 }, function (err, ks) { 
    ks.keyFromPassword(password, function (err, pwDerivedKey) { 
      if(err) 
      { 
       document.getElementById("info").innerHTML = err; 
      } 
      else 
      { 
       ks.generateNewAddress(pwDerivedKey, totalAddresses); 
       var addresses = ks.getAddresses();  

       var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); 

       var html = ""; 

       for(var count = 0; count < addresses.length; count++) 
       { 
     var address = addresses[count]; 
     var private_key = ks.exportPrivateKey(address, pwDerivedKey); 
     var balance = web3.eth.getBalance("0x" + address); 

     html = html + "<li>"; 
     html = html + "<p><b>Address: </b>0x" + address + "</p>"; 
     html = html + "<p><b>Private Key: </b>0x" + private_key + "</p>"; 
     html = html + "<p><b>Balance: </b>" + web3.fromWei(balance, "ether") + " ether</p>"; 
        html = html + "</li>"; 
       } 

       document.getElementById("list").innerHTML = html; 
      } 
    }); 
 }); 
}

代码的工作原理如下:

  1. 首先,有一个名为totalAddresses的变量,它保存一个数字,表示用户想要生成的地址总数。

  2. 然后我们检查seed参数是否已定义。如果未定义,则我们从输入字段中获取种子。我们这样做是为了能够使用generate_addresses()方法显示种子的信息,同时也可以在生成新种子时使用,以及用户点击 Generate Details 按钮时。

  3. 然后我们使用keystore命名空间的isSeedValid()方法验证种子。

  4. 首先,我们要求用户输入他们想要生成和显示多少个地址。然后我们验证输入。

  5. keystore命名空间中的私钥总是加密存储的。在生成密钥时,我们需要将它们加密,并在签名交易时,我们需要解密密钥。用于派生对称加密密钥的密码可以从用户输入或通过提供随机字符串作为密码来获取。为了更好的用户体验,我们生成一个随机字符串并将其用作密码。对称密钥不存储在keystore命名空间内;因此,我们需要根据密码生成密钥,每当我们进行与私钥相关的操作时,例如生成密钥,访问密钥等。

  6. 然后我们使用createVault方法创建一个keystore实例。createVault接受一个对象和一个回调函数。对象可以有四个属性:passwordseedPharsesalthdPathStringpassword是必须的,其他都是可选的。如果我们不提供seedPharse,它会生成并使用一个随机种子。salt被连接到密码以增加对称密钥的安全性,因为攻击者还必须找到盐以及密码。如果未提供盐,则会随机生成。keystore命名空间保存未加密的盐。hdPathString用于为keystore命名空间提供默认派生路径,即在生成地址、签署交易等过程中使用的派生路径。如果我们不提供派生路径,则使用此派生路径。如果不提供hdPathString,则默认值为m/0'/0'/0'。此派生路径的默认目的是sign。您可以使用keystore实例的addHdDerivationPath()方法创建新的派生路径或覆盖已有派生路径的目的。您还可以使用keystore实例的setDefaultHdDerivationPath()方法更改默认派生路径。最后,一旦创建了keystore命名空间,通过回调返回实例。因此,在这里,我们仅使用密码和种子创建了一个keystore

  7. 现在,我们需要生成用户需要的地址数量及其关联的密钥。由于我们可以从种子生成数百万个地址,keystore不会生成任何地址,直到我们要求它这样做,因为它不知道我们要生成多少个地址。创建了keystore之后,我们使用keyFromPassword方法从密码生成对称密钥。然后我们调用generateNewAddress()方法生成地址及其关联的密钥。

  8. generateNewAddress()接受三个参数:从密码派生的密钥、要生成的地址数量和派生路径。由于我们没有提供派生路径,它使用keystore的默认派生路径。如果多次调用generateNewAddress()方法,则会从上次调用中创建的地址继续。例如,如果两次调用此方法,每次生成两个地址,则会有前四个地址。

  9. 然后我们使用getAddresses()获取存储在keystore中的所有地址。

  10. 我们使用exportPrivateKey方法解密和检索地址的私钥。

  11. 我们使用web3.eth.getBalance()获取地址的余额。

  12. 最后,我们在无序列表中显示所有信息。

现在我们知道如何从种子生成地址及其私钥。现在让我们编写send_ether()方法的实现,该方法用于从种子生成的地址之一发送以太币。

这是此操作的代码。将此代码放在main.js文件中:

function send_ether() 
{ 
 var seed = document.getElementById("seed").value; 

 if(!lightwallet.keystore.isSeedValid(seed)) 
 { 
  document.getElementById("info").innerHTML = "Please enter a valid seed"; 
  return; 
 } 

 var password = Math.random().toString(); 

 lightwallet.keystore.createVault({ 
  password: password, 
    seedPhrase: seed 
 }, function (err, ks) { 
    ks.keyFromPassword(password, function (err, pwDerivedKey) { 
      if(err) 
      { 
       document.getElementById("info").innerHTML = err; 
      } 
      else 
      { 
       ks.generateNewAddress(pwDerivedKey, totalAddresses); 

       ks.passwordProvider = function (callback) { 
          callback(null, password); 
       }; 

       var provider = new HookedWeb3Provider({ 
       host: "http://localhost:8545", 
       transaction_signer: ks 
    }); 

       var web3 = new Web3(provider); 

       var from = document.getElementById("address1").value; 
    var to = document.getElementById("address2").value; 
       var value = web3.toWei(document.getElementById("ether").value, "ether"); 

       web3.eth.sendTransaction({ 
        from: from, 
        to: to, 
        value: value, 
        gas: 21000 
       }, function(error, result){ 
        if(error) 
        {  
         document.getElementById("info").innerHTML = error; 
        } 
        else 
        { 
         document.getElementById("info").innerHTML = "Txn hash: " + result; 
        } 
       }) 
      } 
    }); 
 }); 
}

在这里,直到从种子生成地址的代码是自说明的。之后,我们将回调分配给了kspasswordProvider属性。此回调在事务签名期间调用以获取解密私钥的密码。如果我们不提供此信息,LightWallet 将提示用户输入密码。然后,我们通过将keystore作为事务签名者传递来创建一个HookedWeb3Provider实例。现在,当自定义提供程序需要对事务进行签名时,它调用kshasAddresssignTransactions方法。如果要签名的地址不在生成的地址之间,ks将向自定义提供程序返回错误。最后,我们使用web3.eth.sendTransaction方法发送一些以太币。

测试

现在我们已经完成了构建我们的钱包服务,让我们测试一下,确保它按预期工作。首先,在初始目录中运行node app.js,然后在您喜欢的浏览器中访问http://localhost:8080。您将看到这个屏幕:

现在点击生成新种子按钮以生成新的种子。您将被提示输入一个数字,指示要生成的地址数量。您可以提供任何数字,但出于测试目的,提供一个大于 1 的数字。现在屏幕会显示如下内容:

现在,要测试发送以太币,您需要将一些以太币发送到从 coinbase 账户生成的地址之一。一旦您向生成的地址之一发送了一些以太币,请点击生成详细信息按钮以刷新 UI,尽管不必要使用钱包服务测试发送以太币。确保再次生成相同的地址。现在屏幕会显示如下内容:

现在在“来自地址”字段中输入列表中具有“来自”地址字段中余额的帐户地址。然后在“到地址”字段中输入另一个地址。出于测试目的,您可以输入显示的其他地址之一。然后输入小于或等于来自地址帐户的以太币余额的一些以太币数量。现在您的屏幕将显示如下内容:

现在点击发送以太币按钮,您将在信息框中看到交易哈希。等待一段时间让它被挖掘。与此同时,您可以通过在非常短的时间内点击生成详细信息按钮来检查交易是否被挖掘。一旦交易被挖掘,您的屏幕将显示如下内容:

如果一切都按照说明进行,您的钱包服务已经准备就绪。您实际上可以将此服务部署到自定义域,并使其可公开使用。它完全安全,用户将信任它。

概要

在本章中,您了解了三个重要的以太坊库:Hooked-Web3-Provider、ethereumjs-tx 和 LightWallet。这些库可用于在以太坊节点之外管理帐户和签署交易。在为大多数类型的 DApp 开发客户端时,您会发现这些库非常有用。

最后,我们创建了一个钱包服务,允许用户管理他们的帐户,与服务的后端共享私钥或与其钱包相关的任何其他信息。

第十章:另类货币

自比特币的初期成功以来,许多另类货币项目已经推出。比特币于 2009 年发布,第一个替代币项目(名为 Namecoin)于 2011 年推出。在 2013 年和 2014 年,另类货币(又称另类币)市场呈爆炸性增长,开启了许多不同类型的另类货币项目。

其中一些取得了成功,而许多因缺乏兴趣而不受欢迎,并因此未获成功。有一些是炒作和抛售骗局,短暂出现但很快就消失了。比特币的替代方法可以大致分为两大类,根据其开发的主要目的。如果主要目标是构建一个去中心化的区块链平台,它们被称为另类链;如果替代项目的唯一目的是推出新的虚拟货币,它就被称为另类货币。

另类区块链将在第十四章“另类区块链”中详细讨论。

本章主要专注于旨在推出新的虚拟货币(币)的另类货币,尽管也会介绍一些建立在比特币之上提供各种服务的另类协议的内容。其中包括 Namecoin 等概念,其主要目的是提供去中心化的命名和身份服务而不是货币。

目前,截止 2018 年底,市场上有数百种另类货币,它们具有一定的货币价值,如 Namecoin、Zcash、Primecoin 等。我们将在本章的后面部分对其中一些进行详细考察。Zcash 是一种成功的另类货币,于 2016 年推出。另一方面,Primecoin 并没有获得太多的关注,但仍在使用。许多另类项目是比特币源代码的直接分叉,尽管有些是从头开始编写的。一些另类货币旨在解决比特币的限制,如隐私问题。其他一些提供不同类型的挖矿、改变区块时间和分配方案。

根据定义,硬分叉的情况下会产生一种替代币。如果比特币发生硬分叉,则其他旧链有效地被认为是另一种货币。然而,尚无确立的规则规定哪条链成为替代币。这在以太坊中已经发生过,其中一次硬分叉导致了一种新的货币以太坊经典ETC)的产生,除了以太坊ETH)货币之外。以太坊经典是旧链,而以太是硬分叉后的新链。这样具有争议的硬分叉出于某些原因是不可取的。首先,它违背了去中心化的真正精神,因为以太坊基金会,一个中央实体,决定继续进行硬分叉,即使并非每个人都同意该提议;第二,它还由于对硬分叉的分歧而分裂了用户社区。尽管硬分叉在理论上会生成一种替代币,但它在提供的内容上受到限制,因为即使更改导致硬分叉,通常在货币的基本参数周围也没有重大变化。它们通常保持不变。出于这个原因,最好要么从头开始编写一个新币,要么分叉比特币(或其他币种的源代码)来创建一个具有所需参数和功能的新货币。

替代币必须能够吸引新用户、交易和矿工,否则该货币将毫无价值。货币获得其价值,特别是在虚拟货币领域,是由于网络效应和社区的可接受性。如果一种货币未能吸引足够多的用户,那么很快它将被遗忘。通过提供初始数量的货币可以吸引用户,并且可以通过使用各种方法实现。然而,存在一种风险,即如果新币表现不佳,则他们的初始投资可能会丢失。提供初始数量的替代币的方法如下所述:

  • 创建一个新的区块链:替代币可以创建一个新的区块链,并向初始矿工分配货币,但由于许多欺诈计划或炒作和倾销计划,这种方法现在不受欢迎,其中初始矿工在推出新货币时获利,然后消失了。

  • 燃烧证明(PoB):另一种为新的替代币分配初始资金的方法是 PoB,也称为单向锚定或价格上限。在这种方法中,用户永久性地销毁一定数量的比特币,与要认领的替代币的数量成比例。例如,如果销毁了十个比特币,则替代币的价值不得高于一些被销毁的比特币。这意味着比特币通过销毁转换为替代币。

  • 所有权证明:与永久销毁比特币不同,一种替代方法是证明用户拥有一定数量的比特币。这种所有权证明可以用来通过将替代币区块与比特币区块绑定来声明替代币。例如,这可以通过合并挖矿来实现,在合并挖矿中,比特币矿工可以在挖掘比特币的同时挖掘替代币区块,而无需额外工作。合并挖矿将在本章后面解释。

  • 固定侧链:侧链,顾名思义,是与比特币网络分开的区块链,但比特币可以转移到它们。替代币也可以转回比特币网络。这个概念被称为双向锚定

投资和交易这些替代币也是一个大生意,尽管不及比特币大,但足以吸引新的投资者和交易者,并为市场提供流动性。综合替代币市值如下所示:

此图表由coinmarketcap.com/生成。

此图表显示,写作时的综合替代币市值超过 2000 亿美元。

当前前十大币的市值(截至 2018 年 3 月)如下所示:

名称 市值 价格美元
Bitcoin $151,388,873,045 | $8,951.83
Ethereum $68,472,253,587 | $697.94
Ripple $31,340,920,806 | $0.801723
Bitcoin Cash $17,182,167,856 | $1,010.08
Litecoin $9,952,905,688 | $179.11
NEO $5,638,100,000 | $86.74
Cardano $5,450,310,987 | $0.210217
Stellar $5,438,720,268 | $0.294010
EOS $4,347,501,290 | $6.04
Monero $4,211,690,257 | $266.40

数据来自coinmarketcap.com/

伴随替代币出现了各种因素和新概念。许多概念甚至是在比特币之前就发明了,但随着比特币的出现,不仅引入了新概念,如拜占庭将军问题的解决方案,还巧妙地使用了以前的想法,如 hashcash 和工作证明PoW),并受到了关注。

从那时起,随着替代币项目的推出,各种新技术和概念得到了发展和介绍。要欣赏当前替代加密货币的景观,首先理解一些理论概念是必不可少的。

理论基础

在本节中,介绍了各种理论概念,这些概念是在过去几年引入不同替代币的同时发展起来的。

工作证明的替代方案

在加密货币的背景下,PoW 方案首次在比特币中使用,并作为一种机制来确保矿工已经完成了找到一个区块所需的工作量。作为回报,此过程为区块链提供了去中心化、安全性和稳定性。这是比特币提供去中心化分布式共识的主要手段。PoW 方案需要具有一种非常理想的属性,称为进展自由性,这意味着消耗计算资源的奖励应该是随机的,并且与矿工的贡献成正比。在这种情况下,即使是那些具有相对较少计算能力的矿工也有一定机会赢得区块奖励。

进展自由这个术语是由 Arvind Narayanan 等人在书籍《比特币和加密货币技术》中首次提出的。挖矿计算难题的其他要求包括可调节难度和快速验证。可调节难度确保区块链挖矿的难度目标根据增加的哈希功率和用户数量进行调节。

快速验证是一个属性,意味着挖矿计算难题的验证应该简单而快速。PoW 方案的另一个方面,特别是比特币中使用的方案(双 SHA-256),是自从 ASIC 引入以来,权力正在向能够承担大规模 ASIC 农场运营成本的矿工或矿池转移。这种权力转移挑战了比特币去中心化的核心理念。

已经提出了一些替代方案,例如抗 ASIC 的难题,并且设计得这样一种方式,使得为解决此难题而构建 ASIC 变得不可行,并且不会带来与商品硬件相比的主要性能增益。用于此目的的常见技术之一是应用一类称为内存难的计算难题的计算上难问题。此方法背后的核心思想是,由于解决难题需要大量内存,因此在基于 ASIC 的系统上实现它是不可行的。

这种技术最初是在 Litecoin 和 Tenebrix 中使用的,其中 Scrypt 哈希函数被用作抗 ASIC 的 PoW 方案。尽管最初宣传此方案为 ASIC 抗性,但最近 Scrypt ASIC 现已面世,证明了 Litecoin 最初的声明不正确。这是因为 Scrypt 是一种内存密集型机制,最初认为由于技术和成本限制,构建具有大容量内存的 ASIC 难度较大。但现在情况已经改变,因为内存变得越来越便宜,并且有能力生产纳米级电路,可以构建能够运行 Scrypt 算法的 ASIC。

抵抗 ASIC 的另一种方法是需要计算多个哈希函数来提供 PoW。这也称为 链式哈希方案。这个想法的理论基础是,在 ASIC 上设计多个哈希函数并不是很可行。最常见的例子是 Dash 中实现的 X11 内存硬函数。X11 包括 11 个 SHA-3 竞争者,其中一个算法将计算出的哈希输出到下一个算法,直到所有 11 个算法都按顺序使用。这些算法包括 BLAKE、BMW、Groestl、JH、Keccak、Skein、Luffa、CubeHash、SHAvite、SIMD 和 ECHO。

此方法最初确实对 ASIC 的发展提供了一些阻力,但现在 ASIC 矿工已经在商业上可获得,并支持 X11 和类似方案的挖矿。最近的一个例子是 ASIC Baikal Miner,它支持 X11、X13、X14 和 X15 挖矿。其他例子包括像 iBeLink DM384M X11 矿工和 PinIdea X11 ASIC 矿工这样的矿工。

可能还有另一种方法,就是设计智能或随机更改 PoW 方案或其要求的自变化谜题。这种策略将使其几乎不可能在 ASIC 中实现,因为它将需要为每个功能设计多个 ASIC,并且随机更改方案在 ASIC 中几乎不可能处理。目前尚不清楚如何在实践中实现这一点。

PoW 确实有各种缺点,其中最大的缺点就是能源消耗。据估计,目前比特币矿工消耗的总电量超过孟加拉国,达到了 54.69 太哈希TWh)。这是巨大的,而且所有的能源在某种程度上都是浪费的;事实上,除了挖矿之外并没有任何有用的目的。环保人士对这种情况提出了真实的担忧。除了电力消耗之外,碳足迹目前也非常高,每笔交易约为 387 千克 CO[2]。

以下图表显示了比特币能源消耗规模与其他国家相比的情况。这只会不断增长,据估计,到 2018 年底,能源消耗量可能达到约 125 TWh 每年。

各国的能源消耗

所示的前面的图表摘自跟踪此主题的网站。它可在 digiconomist.net/bitcoin-energy-consumption 上找到。

有人提出,PoW 难题可以被设计成具有两个目的。首先,它们的主要目的是在共识机制中,其次是进行一些有用的科学计算。通过这种方式,不仅可以将方案用于挖矿,还可以有望帮助解决其他科学问题。这种有用工作证明最近由 Primecoin 实行,其要求是找到特殊的素数链,即卡宁汉链和双胞素链。由于素数分布的研究在物理等科学学科中具有特殊意义,通过挖掘 Primecoin,矿工不仅可以获得区块奖励,还可以帮助寻找特殊的素数。

存储证明

也被称为可检索性证明,这是另一种有用工作证明类型,需要存储大量数据。由微软研究引入,这种方案为分布式存储提供了有用的好处。矿工需要存储一部分伪随机选择的大量数据以进行挖矿。

权益证明(PoS)

这种证明也被称为虚拟挖矿。这是另一种替代传统 PoW 方案的挖矿难题。它最早在 2012 年 8 月由 Peercoin 提出。在这种方案中,用户需要证明拥有一定数量的货币(硬币),从而证明他们对该货币有一定的权益。最简单的权益形式是,采用相对更容易的挖矿方式来奖励那些拥有更多数字货币的用户。这种方案的优点是双重的;首先,相对于购买高端 ASIC 设备来说,获得大量的数字货币相对困难,其次,这样做可以节省计算资源。已经提出了各种形式的权益,并在下面的小节中简要讨论。

各种权益类型

不同类型的权益将在下面的小节中介绍。

货币权益证明

货币的年龄指的是货币上次使用或持有的时间。这与通常的 PoS 形式不同,在这种方式中,对于持有另类币中最大权益的用户来说,挖矿变得更容易。在基于货币年龄的方法中,每次挖出一个区块时,货币的年龄(货币权益)都会被重置。矿工因为持有而不使用货币一段时间而获得奖励。这种机制已经在 Peercoin 中以一种创造性的方式与 PoW 结合实施。

挖矿难题(PoW)与货币的时间成反比,这意味着如果矿工使用货币进行货币权益交易,那么 PoW 的要求就会得到缓解。

存款证明(PoD)

这一方案的核心思想是,矿工新生产的区块在一定时间内无法使用。更确切地说,这些硬币在挖矿过程中被锁定了一定数量的区块。该方案允许矿工在冻结一定数量的硬币一段时间的代价下进行挖矿。这是一种 PoS(权益证明)的类型。

燃烧证明

作为计算能力的备用支出,PoB 实际上是销毁一定数量的比特币,以获得相应的另类币。这在启动新的代币项目时通常被使用,作为一种公平分配的手段。这可以被看作是一种替代的挖矿方案,因为新币的价值来自于之前销毁了一定数量的硬币。

活动证明(PoA)

该方案是 PoW 和 PoS 的混合体。在该方案中,区块最初是通过 PoW 产生的,然后每个区块会随机分配三个利益相关者来对其进行数字签名。后续区块的有效性取决于先前随机选择的区块成功签名的情况。

然而,有一个可能的问题被称为“利益无所不利”问题,即一个人可以轻易创建一个区块链的分叉。这是可能的,因为在 PoW(工作量证明)中需要适当的计算资源来进行挖矿,而在 PoS 中没有这样的要求;因此,攻击者可以尝试使用相同的硬币在多个链上进行挖矿。

无法外包的难题

这一难题的关键动机是抵抗挖矿池的发展。先前讨论过的挖矿池向所有参与者提供奖励,比例与他们消耗的计算能力成正比。然而,在这种模式中,挖矿池操作员是一个能够强制执行特定规则的中央当局,所有的奖励都归该操作员所有。此外,在此模式下,所有的矿工只信任彼此,因为他们共同致力于实现共同目标,希望挖矿池经理能获得奖励。非外包难题是一种允许矿工自己声称奖励的方案;因此,由于匿名矿工之间的内在不信任,挖矿池的形成变得不太可能。

也存在各种其他替代方案以替代 PoW,其中一些已在第一章中描述,区块链 101,而另一些将在本书的后续章节中进行解释,包括第十三章,Hyperledger和第十六章,可扩展性和其他挑战。由于这是一个正在进行研究的领域,随着区块链技术的发展,新的替代方案将不断出现。

难度调整和重新定位算法

随着比特币和另类币的出现,另一个概念引入了难度调整算法。在比特币中,难度目标的计算非常简单,只需下面的等式;然而其他的货币要么开发了自己的算法,要么实现了修改版的比特币难度算法:

T = 先前时间 * 实际时间 / 2016 * 10 分钟

比特币中难度调整的理念是,生成 2016 个区块应该大约需要两周时间(区块之间的时间约为 10 分钟)。如果挖掘 2016 个区块超过两周的时间,那么难度会降低,如果挖掘 2016 个区块少于两周的时间,那么难度会增加。当由于高区块生成速率而引入 ASIC 时,难度呈指数增长,这就是非 ASIC 防护 PoW 算法的一个缺陷。这导致了挖矿算力的集中化。

这也带来了另一个问题;如果一个新的加密货币现在开始,采用与比特币相同的基于 SHA-256 的 PoW,那么恶意用户可以很容易地使用 ASIC 矿工来控制整个网络。如果对新的另类币没有太多兴趣,某人决定消耗足够高的计算资源来接管网络,这种攻击就会更加实际。如果其他具有类似计算能力的矿工也加入了另类币网络,这种攻击可能并不可行,因为矿工们会互相竞争。

此外,多矿池也带来了更大的威胁,一群矿工可以自动切换到变得有利可图的货币。这种现象被称为矿池跳跃,它会对区块链产生不利影响,从而影响另类币的增长。矿池跳跃对网络的影响是不利的,因为跳池者只在难度低并且可以获得快速奖励时加入网络;一旦难度提高(或者重新调整),他们就会退出,然后等难度重新调整后再次加入。

例如,如果一个多矿池迅速消耗资源来挖掘新币,难度将非常快地增加;当多矿池离开货币网络时,它将几乎无法使用,因为现在难度已经增加到不再对独立矿工有利并且无法维持的程度。解决这个问题的唯一方法是启动一次硬分叉,而这通常对社区来说是不可取的。

有一些算法出现来解决这个问题,后面的章节会讨论这些算法。所有这些算法都基于对哈希率变化做出响应的想法,这些参数包括先前块的数量、先前块的难度、调整比率以及难度可以进行回调或提高的数量。

在以下部分,读者将介绍各种替代币中正在使用和提出的少数难度算法。

Kimoto 引力井

此算法用于各种替代币来调节难度。该方法首次在 Megacoin 中引入,并用于自适应地调整网络每个区块的难度。算法的逻辑如下所示:

KGW = 1 + (0.7084 * pow((double(PastBlocksMass)/double(144)), -1.228))

该算法运行在一个循环中,通过一组预定的区块(PastBlockMass)并计算新的重新调整值。该算法的核心思想是开发一种自适应难度调节机制,以响应哈希率的快速波动。Kimoto 引力井KGW)确保区块之间的时间大致相同。在比特币中,难度每 2016 个区块调整一次,但在 KGW 中,难度在每个区块中调整。

此算法容易受到时间扭曲攻击的影响,这种攻击允许攻击者在创建新区块时暂时享受较低的难度。这种攻击允许一个时间窗口,其中难度变低,攻击者可以快速以较快的速度生成许多硬币。

更多信息请参见链接cryptofrenzy.wordpress.com/2014/02/09/multipools-vs-gravity-well/

黑暗引力波

黑暗引力波DGW)是一种新算法,旨在解决 KGW 算法中的某些缺陷,比如时间扭曲攻击。这个概念最初是在 Dash 中引入的,以前被称为 Darkcoin。它利用多个指数移动平均和简单移动平均来实现更平滑的重新调整机制。该公式如下所示:

2222222/ (((Difficulty+2600)/9)²)

此公式已在 Dash 币、比特币 SegWit2X 和其他各种替代币中实施,作为重新调整难度的机制。

DGW 版本 3.0 是 DGW 算法的最新实现,与 KGW 相比,可以实现更好的难度重新调整。

更多信息请参见dashpay.atlassian.net/wiki/spaces/DOC/pages/1146926/Dark+Gravity+Wave

DigiShield

这是另一种最近在 Zcash 中使用的难度重新调整算法,经过适当的变化和实验。该算法通过查看固定数量的先前区块来计算它们生成所花费的时间,然后通过将实际时间跨度除以目标时间的平均值来重新调整难度到前一个区块的难度。在这个方案中,重新调整计算得更快,而且从哈希率的突然增加或减少中恢复速度快。这个算法可以防止多重池,这可能导致哈希率的快速增加。

网络难度根据实现方式每个区块或每分钟调整一次。关键创新是相对于 KGW 更快的调整时间。

Zcash 使用 DigiShield v3.0,该版本使用以下公式进行难度调整:

(新难度) = (先前难度) x SQRT [ (150 秒) / (上次解决时间)

有关此问题的详细讨论可在github.com/zcash/zcash/issues/147#issuecomment-245140908找到。

MIDAS

多间隔难度调整系统MIDAS)是一个相对于先前讨论的算法更复杂的算法,因为它使用了更多的参数。这种方法对哈希率的突然变化做出了更快的响应。该算法还可以防止时间扭曲攻击。

有关此事的原始帖子现在可以通过网络档案在web.archive.org/web/20161005171345/http://dillingers.com/blog/2015/04/21/altcoin-difficulty-adjustment-with-midas/找到。

有兴趣的读者可以在前述位置阅读更多信息。

这就结束了我们对各种难度调整算法的介绍。

许多替代加密货币和协议出现,试图解决比特币的各种限制。

比特币的限制

比特币的各种限制也引起了人们对替代币的兴趣,这些替代币专门用于解决比特币的限制。最突出和广泛讨论的限制是比特币缺乏匿名性。我们现在将讨论一些比特币的限制。

隐私和匿名性

由于区块链是所有交易的公开账本,并且是公开可用的,因此分析它变得微不足道。结合流量分析,交易可以追溯到其源 IP 地址,因此可能会揭示交易的发起者。从隐私的角度来看,这是一个很大的问题。

即使在比特币中建议并常见的做法是为每笔交易生成一个新的地址,从而实现一定程度的不可链接性,但这并不足够,已经开发并成功使用各种技术来追踪整个网络中的交易流动,并将其追溯到其发起者。这些技术通过使用交易图、地址图和实体图分析区块链,从而帮助将用户与交易联系起来,引发了隐私方面的担忧。前述分析中提到的技术可以通过使用有关交易的公开信息并将其与实际用户联系起来得到进一步丰富。有可用的开源区块解析器可用于从区块链数据库中提取交易信息、余额和脚本。

一个可在Rust 语言中使用的解析器提供了先进的区块链分析能力。

已经提出了各种提案来解决比特币的隐私问题。这些提案可分为三类:混合协议、第三方混合网络和固有匿名。

每个类别的简要讨论如下。

混合协议

这些方案被用来为比特币交易提供匿名性。在这种模式中,使用混币服务提供商(中介或共享钱包)。用户将硬币发送到这个共享钱包作为存款,然后,共享钱包可以将其他用户存入的价值相同的一些其他硬币发送到目的地。用户也可以通过这个中介收到他人发送的硬币。这样,输出与输入之间的链接将不复存在,交易图分析将无法揭示发送者和接收者之间的实际关系。

三名用户将其交易合并为单个更大的 CoinJoin 交易的 CoinJoin 交易

CoinJoin 是混合协议的一个例子,其中两个交易合并在一起形成一笔交易,同时保持输入和输出不变。CoinJoin 背后的核心思想是构建一个由所有参与者签署的共享交易。这种技术提高了参与交易的所有参与者的隐私性。

第三方混合协议

有各种第三方混币服务可供选择,但如果服务是集中的,那么追踪发送者和接收者之间的映射就会带来威胁,因为混币服务知道所有的输入和输出。此外,完全集中式的矿工甚至会带来服务的管理员偷取硬币的风险。

基于 CoinJoin(混合)交易的各种服务,复杂程度各不相同,例如 CoinShuffle、Coinmux 和 Dash(币)中的 Darksend。CoinShuffle 是传统混合服务的分散替代方案,因为它不需要可信第三方。

基于 CoinJoin 的方案,然而,存在一些弱点,其中最突出的是用户可能发动拒绝服务攻击,这是由于最初承诺签署交易的用户现在没有提供他们的签名,从而延迟或停止了联合交易。

内在匿名性

这个类别包括支持隐私的硬币,隐私已经内置到货币的设计中。最流行的是 Zcash,它使用零知识证明ZKP)来实现匿名性。后面的章节将对此进行详细讨论。其他例子包括 Monero,它利用环签名提供匿名服务。

下一节介绍了已经或正在提出的各种增强功能,以扩展比特币协议。

在比特币上扩展的协议

在下文讨论的几个协议中,已经提出并实施了一些协议,以增强和扩展比特币协议,并将其用于各种其他目的,而不仅仅是作为一种虚拟货币。

彩色硬币

彩色硬币是一组用于在比特币区块链上表示数字资产的方法。俗称为给比特币着色,是指使用一些元数据更新它,这些元数据代表着数字资产(智能资产)。硬币仍然作为比特币工作和运行,但另外携带一些表示某些资产的元数据。这可以是与资产相关的一些信息,与交易相关的一些计算或任何任意数据。此机制允许发行和跟踪特定的比特币。可以使用比特币的OP_RETURN操作码或可选地在多重签名地址中记录元数据。如果需要解决任何隐私问题,此元数据也可以加密。一些实现还支持在公开可用的种子网络上存储元数据,这意味着可以存储几乎无限量的元数据。通常这些是表示彩色硬币各种属性的 JSON 对象。此外,还支持智能合约。这样的实现例子是 Colu,可在colu.co/找到。

彩色硬币可以用来代表多种资产,包括但不限于商品、证书、股票、债券和投票。需要注意的是,要使用彩色硬币,需要一个解释彩色硬币的钱包,而普通的比特币钱包则不起作用。普通的比特币钱包无法区分彩色硬币非彩色硬币

可以使用www.coinprism.com/提供的服务在线设置彩色硬币钱包。通过使用此服务,可以创建并发行任何数字资产。

彩色硬币的概念非常吸引人,因为它不需要对现有比特币协议进行任何修改,可以利用已经存在的安全比特币网络。除了传统的数字资产表示外,还有可能创建根据其定义的参数和条件行为的智能资产。这些参数包括时间验证、转让限制和费用。

重要的用例可以是在区块链上发行金融工具。这将确保低交易费用、有效且数学上安全的所有权证明、快速的可转让性,无需中介即可快速支付股息给投资者。

丰富的 API 可在coloredcoins.org/找到彩色硬币。

Counterparty

这是另一个服务,用于创建充当加密货币的自定义代币,可用于各种用途,例如在比特币区块链上发行数字资产。这是一个非常强大的平台,以比特币区块链为核心,但开发了自己的客户端和其他组件来支持发行数字资产。架构包括 counterparty 服务器、counter block、counter wallet 和armory_utxsvr。 Counterparty 基于与彩色硬币相同的想法,通过嵌入数据到常规比特币交易中,但提供了更加高效的库和一套强大的工具来支持数字资产的处理。这种嵌入也被称为嵌入式共识,因为 counterparty 交易嵌入在比特币交易中。嵌入数据的方法是使用比特币中的OP_RETURN操作码。

Counterparty 生产和使用的货币被称为 XCP,并被智能合约用作运行合约的费用。撰写时,其价格为 2.78 美元。 XCP 是通过使用先前讨论过的 PoB 方法创建的。

Counterparty 允许使用 solidity 语言在以太坊上开发智能合约,并允许与比特币区块链进行交互。为实现这一目的,使用 BTC Relay 作为在以太坊和比特币之间提供互操作性的手段。这是一个巧妙的概念,其中以太坊合约可以与比特币区块链和交易进行通信。转发器(运行 BTC Relay 的节点)获取比特币块头并将其传输到以太坊网络上的智能合约,验证 PoW。此过程验证了在比特币网络上发生了交易。

可在btcrelay.org/找到。

从技术上讲,这是一种以太坊合约,能够存储和验证比特币区块头,就像比特币简单支付验证轻量级客户端使用布隆过滤器一样。SPV 客户端在前几章中详细讨论过。这个想法可以用以下图表来可视化:

BTC 中继概念

Counterparty 可以在counterparty.io/找到。

山寨币的发展

从编码的角度来看,通过简单地分叉比特币或其他币的源代码,可以非常快速地启动山寨币项目,但这可能还不够。当启动一个新的币项目时,需要考虑几件事情,以确保成功启动和币的长期存在。通常,代码库以 C++编写,就像比特币的情况一样,但几乎任何语言都可以用来开发币项目,例如 Golang 或 Rust。

编写代码或分叉现有币的代码是微不足道的,挑战性的问题是如何启动一种新货币,以吸引投资者和用户。通常,以下步骤被采取以启动一个新的币项目。

从技术角度来看,如果在另一个币的代码上进行分叉,例如比特币,有各种参数可以更改以有效地创建一个新的币。为了创建一个新币,需要调整或引入这些参数。这些参数可以包括但不限于以下内容。

共识算法

有多种共识算法可供选择,例如比特币中使用的 PoW 或 Peercoin 中使用的 PoS。还有其他可用的算法,如容量证明PoC)和其他一些算法,但 PoW 和 PoS 是最常见的选择。

哈希算法

这要么是 SHA-256、Scrypt、X11、X13、X15,或者是任何其他适合用作共识算法的哈希算法。

难度调整算法

在这个领域有多种选择可提供难度重新定位机制。最突出的例子是 KGW、DGW、Nite's Gravity Wave 和 DigiShield。此外,所有这些算法都可以根据要求进行调整以产生不同的结果;因此,可能存在许多变体。

区块间时间

这是每个区块生成之间经过的时间。对于比特币,区块每 10 分钟生成一次,对于莱特币,每 2.5 分钟生成一次。任何值都可以使用,但适当的值通常在几分钟之间;如果生成时间太快,可能会使区块链不稳定,如果太慢,可能不会吸引许多用户。

区块奖励

区块奖励是给解决挖矿难题的矿工的,他们被允许拥有一个包含奖励的 coinbase 交易。比特币最初为 50 个硬币,现在许多山寨币将这个参数设置为非常高的数字;例如,狗狗币目前为 10,000 个。

奖励减半率

这是另一个重要因素;在比特币中,它每 4 年减半一次,现在设置为 12.5 个比特币。这是一个可变的数字,可以根据要求设置为任何时间段或根本不设置。

区块大小和交易大小

这是确定网络上交易速率高低的另一个重要因素。比特币中的区块大小限制为 1 MB,但在替代币中,它可以根据要求而变化。

利率

这个属性仅适用于 PoS 系统,在这些系统中,货币的所有者可以按照网络定义的利率获得利息,以换取在网络上保留的一些货币,作为保护网络的抵押。这个利率可以控制通货膨胀。如果利率太低,那么可能会导致恶性通货膨胀。

货币

这个参数定义了货币必须保持未使用多长时间才能成为符合抵押资格。

货币的总供应量

这个数字设置了可以生成的货币的总限制。例如,在比特币中,限制是 2100 万,而在狗狗币中是无限的。这个限制是由前面讨论的区块奖励和减半时间表固定的。

创建自己的虚拟货币有两种选择:分叉现有的已建立的加密货币源代码或从头开始编写一个新的。后者选项不太流行,但第一个选项更容易,并且在过去几年中已经允许了许多虚拟货币的创建。基本上,思路是首先分叉加密货币源代码,然后在源代码的不同战略位置进行适当的更改,从而有效地创建一个新的货币。NEM 币是其中一个完全从头开始编写其代码的新创建的币种。

在下一节中,读者将介绍一些替代币项目。本章节不可能涵盖所有的替代货币,但在下一节中将讨论一些精选的币种。选择是基于其长期性、市值和创新性。每种币种都从不同的角度进行讨论,如理论基础、交易和挖掘。

姓名币

姓名币是比特币源代码的第一个分叉。姓名币背后的关键思想不是制造一种替代币,而是提供改进的去中心化、抗审查、隐私、安全和更快的去中心化命名。去中心化命名服务旨在应对传统互联网上使用的域名系统(DNS)协议的固有局限,如缓慢和集中控制。姓名币也是解决 Zooko 三角形问题的第一个解决方案,这个问题在第一章区块链 101中简要讨论过。

Namecoin 主要用于提供注册键/值对的服务。Namecoin 的一个主要用例是,它可以提供基于区块链的分布式和去中心化共识驱动的传输层安全TLS)证书验证机制。

它基于与比特币相同的技术,但具有自己的区块链和钱包软件。

Namecoin 核心的源代码可在github.com/namecoin/namecoin-core获得。

总之,Namecoin 提供以下三项服务:

  • 保证名字(键)的安全存储和传输

  • 将一些值附加到名称上,通过附加高达 520 字节的数据

  • 生产数字货币(Namecoin)

Namecoin 还首次引入了合并挖矿,这允许矿工同时在多个链上进行挖矿。这个想法很简单,但非常有效:矿工创建一个 Namecoin 区块并生成该区块的哈希。然后将该哈希添加到比特币区块中,并且矿工解决该区块的难度等于或大于 Namecoin 区块难度,以证明已经为解决 Namecoin 区块做出了足够的工作。

Coinbase 交易用于在 Namecoin 的交易哈希(或任何其他山寨币,如果与该币种合并挖矿)中包含哈希。挖矿任务是解决比特币区块,其 coinbase scriptSig包含对 Namecoin(或任何其他山寨币)区块的哈希指针。如下图所示:

合并挖矿可视化

如果矿工设法以比特币区块链难度水平解决哈希,则比特币区块建立并成为比特币网络的一部分。在这种情况下,比特币区块链会忽略 Namecoin 哈希。另一方面,如果矿工以 Namecoin 区块链难度水平解决一个区块,则在 Namecoin 区块链中将创建一个新区块。该方案的核心优势在于,矿工所花费的所有计算能力都有助于保护 Namecoin 和比特币。

交易 Namecoin

截至 2018 年 3 月,Namecoin 的当前市值为 29143884 美元,可在coinmarketcap.com/购买和出售。可在各种交易所进行交易,例如:

获得 Namecoin

即使 Namecoin 可以独立挖矿,通常也会通过利用合并挖矿技术作为比特币的一部分进行挖矿。这样,Namecoin 可以作为比特币挖矿的副产品。正如前面所述的难度图表所表明的,独立挖矿已经不再有利可图;相反,建议使用合并挖矿,使用矿池,甚至使用加密货币交易所购买 Namecoin。

Namecoin 难度如下所示:https://bitinfocharts.com/comparison/difficulty-nmc.html(自 2016 年 12 月以来)

各种挖矿池,比如slushpool.com,也提供合并挖矿的选项。这允许矿工主要挖掘比特币,同时也因此获得 Namecoin。

另一种快速获得一些 Namecoins 的方法是用你已有的硬币与 Namecoins 交换,例如,如果你已经有一些比特币或其他可以用来与 Namecoin 交换的加密货币。

一个在线服务,shapeshift.io/,可提供此服务。该服务允许使用简单易用的界面从一种加密货币转换为另一种加密货币。

例如,支付 BTC 以接收 NMC 如下所示:

  1. 首先选择存款货币,本例中是比特币,然后选择要收到的货币,本例中是 Namecoin。在顶部的编辑框中,输入您希望接收交换的 Namecoin 的 Namecoin 地址。在底部的第二个编辑框中,输入比特币退款地址,在任何情况下交易失败时,货币将退还到该地址。

  2. 一旦选定存款和交换货币,汇率和矿工费用会在选择后立即计算。汇率受市场条件驱动,而矿工费用根据选择的目标货币以及目标网络的矿工收费算法计算。

比特币到 Namecoin 交换

  1. 点击“开始交易”后,交易开始并指示用户发送比特币到特定的比特币地址。当用户发送所需金额时,转换过程如下截图所示。整个过程需要几分钟:

Namecoin 交付通知

前面的截图显示,在发送存款后,交换发生,最终显示“All Done!”消息,表明交换成功。

页面上显示了一些其他订单细节,比如存入的货币以及交换后收到的货币。在这种情况下,它是比特币到 Namecoin 的交换。值得注意的是,与每个币种图标下面也显示了相关地址。还有一些其他选项,比如可以调用邮件收据来接收交易的邮件收据。

在流程完成时,可以在 Namecoin 钱包中查看交易,如下所示:

Namecoin 钱包

确认交易可能需要一些时间(通常约 1 小时),在此期间不可能使用 Namecoins 来管理名称。一旦 Namecoins 在钱包中可用,就可以使用“管理名称”选项来生成 Namecoin 记录。

生成 Namecoin 记录

Namecoin 记录是键值对的形式。名称是形式为 d/examplename 的小写字符串,而值是大小写敏感的、UTF-8 编码的 JSON 对象,最大长度为 520 字节。名称应符合 RFC1035(tools.ietf.org/html/rfc1035)的规定。

一个一般的 Namecoin 名称可以是最多 255 字节长的任意二进制字符串,附带 1024 位的相关标识信息。一个在 Namecoin 链上的记录仅在大约 200 天或 36,000 个块后才需要更新。Namecoin 还引入了 .bit 顶级域,可以使用 Namecoin 注册,并且可以使用专用的 Namecoin 启用的解析器进行浏览。如下图所示的 Namecoin 钱包软件可用于注册 .bit 域名。

输入名称后,点击提交按钮,将要求输入配置信息,如 DNS、IP 或身份:

Namecoin 钱包:域名配置

如下面的截图所示,masteringblockchain 将在 Namecoin 区块链上注册为 masteringblockchain.bit

Namecoin 钱包:显示已注册的名称

Litecoin

Litecoin 是源自于 2011 年发布的比特币源代码的分叉。它使用 Scrypt 作为 PoW,最初在 Tenebrix 币中引入。由于较快的区块生成时间为 2.5 分钟,Litecoin 允许比特币更快的交易。此外,由于更快的区块生成时间,大约每 3.5 天就进行一次难度调整。总的货币供应量是 8400 万。

Scrypt 是第一个替代 SHA-256 基础 PoW 算法的顺序内存硬函数。它最初被提议作为一个基于密码的密钥派生函数PBKDF)。其关键思想是,如果函数需要大量内存才能运行,那么定制硬件如 ASIC 将需要更多的 VLSI 区域,这将无法建造。Scrypt 算法需要在内存中保存一个大数组的伪随机位,并以伪随机方式从中派生密钥。

该算法基于一种称为时间-内存权衡TMTO)的现象。如果放宽了内存要求,则会导致计算成本增加。换句话说,如果给程序更多的内存,TMTO 将缩短其运行时间。这种权衡使得攻击者难以获取更多内存,因为这既昂贵又难以在定制硬件上实现,或者如果攻击者选择不增加内存,则由于高处理需求而导致算法运行缓慢。这意味着 ASIC 对于该算法难以构建。

Scrypt 使用以下参数生成派生密钥(Kd):

  • 口令:这是一个要进行哈希的字符字符串

  • Salt: 这是提供给 Scrypt 函数(通常是所有哈希函数)的随机字符串,以防御使用彩虹表的暴力字典攻击。

  • N: 这是必须是大于 1 的 2 的幂的内存/CPU 成本参数。

  • P: 这是并行化参数。

  • R: 这是块大小参数。

  • dkLen: 这是派生密钥的预期长度,以字节为单位。

形式上,此函数可写为:

Kd = scrypt (P, S, N, P, R, dkLen)

在应用核心 Scrypt 函数之前,该算法将 PS 作为输入,并应用 PBKDF2 和基于 SHA-256 的 HMAC。然后将输出馈送到称为 ROMix 的算法中,该算法内部使用 Blockmix 算法使用 Salsa20/8 核心流密码来填充内存,需要大内存才能运行,从而实现了顺序内存硬特性。

该算法的此步骤的输出最终再次馈送到 PBKDF2 函数中,以产生派生密钥。该过程如下图所示:

Scrypt 算法

Scrypt 在特定参数下用于莱特币挖矿,其中 N= 1024R = 1P=1S = 随机 80 字节 生成 256 位输出。

看起来,由于选择了这些参数,为莱特币挖矿的 Scrypt ASIC 的开发并不是非常困难。在用于莱特币挖矿的 ASIC 中,可以开发出一种顺序逻辑,将数据和随机数作为输入,并应用带有 HMAC-SHA256 的 PBKDF2 算法;然后将结果比特流输入到产生哈希的 SALSA20/8 函数中,该哈希再次馈入到 PBKDF2 和 HMAC-256 函数中以产生 256 位哈希输出。与比特币 PoW 的情况类似,在 Scrypt 中,如果输出哈希小于目标哈希(已在开始时作为输入传递,并存储在内存中,并在每次迭代中检查),则函数终止;否则,随机数递增,然后再次重复该过程,直到找到低于难度目标的哈希。

Scrypt ASIC 设计简化流程图

  • 莱特币交易: 与其他货币一样,莱特币的交易可以在各种在线交易所轻松进行。莱特币的当前市值为 10448974615 美元。莱特币的当前价格(截至 2018 年 3 月)为每个莱特币 188.04 美元。

  • 挖矿: 莱特币的挖矿可以单独进行,也可以在矿池中进行。目前,常用于挖掘莱特币的 ASIC 可用。

使用 CPU 进行 Litecoin 挖矿已经不再盈利,就像现在许多其他数字货币一样。现在有在线云挖矿提供商和可用的 ASIC 挖矿机,可以用来挖掘 Litecoin。Litecoin 挖矿从 CPU 开始,经过 GPU 挖矿机的发展,最终现在已经达到了一个点,需要使用专门的 ASIC 挖矿机,例如 Ehsminer 的 ASIC Scrypt Miner Wolf,以期能够获得一些硬币。一般来说,即使使用 ASIC,也最好在矿池中进行挖矿,而不是独立挖矿,因为由于矿池采用的比例奖励方案,独立挖矿并不像在矿池中挖矿那样有盈利。这些矿工能够为 Scrypt 算法产生 2 Gh/s 的哈希速率。

Primecoin

Primecoin 是市场上第一种引入有用 PoW 的数字货币,与比特币基于 SHA256 的 PoW 相对。Primecoin 使用寻找素数作为 PoW。并非所有类型的素数都符合被选为 PoW 的要求。三种类型的素数(称为第一类 Cunningham 链,第二类 Cunningham 链和双生链)满足了加密货币中使用 PoW 算法的要求。

Primecoin 区块链通过一个连续的难度评估方案动态调整难度。基于素数的 PoW 的高效验证也非常重要,因为如果验证速度慢,那么 PoW 就不适用。因此,素数链被选为 PoW,因为随着链的增长,找到素数链变得困难,而验证仍然足够快,可以作为高效的 PoW 算法使用。

一旦 PoW 在一个区块上验证过,它就不能在另一个区块上被重用,这一点非常重要。在 Primecoin 中,通过将 PoW 证书与子区块中的父区块头部进行哈希的方式来实现这一点。

PoW 证书是通过将素数链链接到区块头部哈希来生成的。它还要求区块头部的原点能够被区块头部哈希整除。如果可以,就进行除法运算,然后将商作为 PoW 证书使用。PoW 算法的可调节难度的另一个属性是,每个区块都要引入难度调整,而不是像比特币那样每 2,016 个区块进行一次。这是一个比比特币更平稳的方法,可以在哈希算力突然增加的情况下重新调整。此外,产生的总硬币数量是由社区驱动的,Primecoin 可以生成的硬币数量没有明确的限制。

Primecoin 交易

Primecoin 可以在主要虚拟货币交易所交易。截至撰写本文时(2018 年 3 月),Primecoin 的当前市值为 $17,482,507。虽然不是很大,但由于 Primecoin 基于一种新颖的想法,并且有一支专注的社区支持,这仍然保持一定的市场份额。

一张显示与 Primecoin 相关统计数据的图表

数据来源:https://coinmarketcap.com/currencies/primecoin/

挖矿指南

第一步是下载一个钱包。Primecoin 支持在钱包内进行本地挖矿,就像原始的比特币客户端一样,但也可以通过各种在线云服务提供商在云上挖矿。

以下是一个快速的 Windows 指南,Linux 客户端也可在 primecoin.io/downloads.php 上获得。

  1. 第一步是从 primecoin.io/index.php 下载 Primecoin 钱包。

  2. 一旦钱包安装并与网络同步,可以通过以下步骤开始挖矿。可以通过单击帮助菜单并选择调试窗口菜单项在 Primecoin 钱包中打开调试窗口。在调试窗口的控制台窗口中键入 help 可以调用其他帮助,用于启用 Primecoin 挖矿功能:

Primecoin 挖矿

  1. 一旦前述命令成功执行,挖矿将在单机模式下开始。如果您使用的是配置较低的个人电脑并且 CPU 较慢,这可能不会很快也不会很有利可图,但由于这是一种使用 CPU 挖掘的加密货币,矿工可以使用配备强大 CPU 的个人电脑。作为替代,可以使用托管强大服务器硬件的云服务:

Primecoin 钱包软件,与网络同步

Primecoin 源代码可在 github.com/primecoin/primecoin 上获得。

Primecoin 是一个新颖的概念,它引入的 PoW 具有很大的科学意义。它仍在使用,市值为 $17,034,198 美元,但从 GitHub 的不活跃可以看出,没有进行进一步的开发。

读者可以通过阅读 Sunny King(化名)的 Primecoin 白皮书进一步探索 Primecoin:primecoin.io/bin/primecoin-paper.pdf

Zcash

Zcash 在 2016 年 10 月 28 日推出。这是第一种使用特定类型的 ZKPs(称为零知识简洁非交互式知识证明ZK-SNARKs)为用户提供完全隐私的货币。这些证明简洁易验证;但是,设置初始公共参数是一个复杂的过程。后者包括两个密钥:证明密钥和验证密钥。该过程需要对一些随机数进行采样以构造公共参数。问题在于这些随机数,也称为有毒废物,必须在参数生成后销毁,以防止伪造 Zcash。

为此,Zcash 团队提出了一种多方计算协议,可以从独立位置协作生成所需的公共参数,以确保不会产生有毒废物。由于这些公共参数需要由 Zcash 团队创建,这意味着仪式参与者是受信任的。这就是为什么仪式非常开放,并通过使用多方计算机制进行的原因。

此机制具有一种属性,即必须破坏所有仪式参与者才能破坏最终参数。当仪式完成时,所有参与者都会摧毁用于生成私钥的设备。这一举动消除了设备上参与者私钥部分的任何痕迹。

ZK-SNARKs 必须满足完备性、准确性、简洁性和非交互性的属性。完备性意味着存在一种明确的策略,使证明者能够满足验证者断言为真。另一方面,准确性意味着没有证明者能够说服验证者错误的声明为真。简洁性意味着证明者和验证者之间传递的消息大小很小。

最后,非交互性质意味着可以在没有任何交互或非常少的交互情况下验证断言的正确性。此外,作为零知识证明,还需要满足零知识性质(在第六章中讨论,公钥密码学)

Zcash 开发人员引入了去中心化匿名支付方案DAP 方案)的概念,该方案用于在 Zcash 网络中实现直接和私密支付。交易不透露有关支付的来源、目的地和金额的任何信息。Zcash 中有两种类型的地址,Z 地址和 T 地址。Z 地址基于 ZKPs 并提供隐私保护,而 T 地址类似于比特币的地址。Zcash 各种属性的快照(经过初始缓慢启动后)如下所示:

Zcash 属性摘要

Zcash 使用一种名为非对称 PoW(Equihash)的高效 PoW 方案,它基于广义生日问题。它允许非常高效的验证。这是一种内存硬算法,抗 ASIC。Zcash 引入了一个新颖的概念(初始慢挖),这意味着区块奖励会在一段时间内逐渐增加,直到达到第 20,000 个区块。这使得网络可以进行初始扩展和早期矿工的试验,并在需要时由 Zcash 开发人员进行调整。由于稀缺性,慢启动对价格产生了影响,因此 ZEC 在推出的第一天达到了约 25,000 美元的价格。Zcash 中实现了稍作修改的 DigiShield 难度调整算法。公式如下所示:

(下一个难度) = (上一个难度) x 根号 [ (150 秒) / (上一个解决时间) ]

交易 Zcash

Zcash 可以在 CryptoGo (cryptogo.com) 等主要数字货币交易所购买。另一个可以购买或出售 Zcash 的交易所是 Crypto Robot 365 (cryptorobot365.com)。Zcash 推出时价格非常高。如下图所示,价格一度飙升至每个 Zcash 约十个比特币。一些交易所的订单甚至高达 2,500 BTC 每个 ZEC。撰写时(2018 年 3 月)ZEC 的价格约为 311 美元:

Zcash 市值和价格

挖矿指南

有多种方法可以挖掘 Zcash。目前,CPU 和 GPU 挖掘都是可能的。各种商业云挖矿池还提供挖掘 Zcash 的合约。要在 Ubuntu Linux 上使用 CPU 进行独立挖掘,可以按照以下步骤进行:

  1. 第一步是使用以下命令安装先决条件:
 $ sudo apt-get install \ 
        build-essential pkg-config libc6-dev m4 g++-multilib \   
        autoconf libtool ncurses-dev unzip git python \ 
        zlib1g-dev wget bsdmainutils automake 

如果先决条件已安装,将显示一条消息,指示组件已是最新版本。如果尚未安装或版本旧于最新包,则安装将继续,将下载所需软件包,并完成安装。

  1. 接下来,根据以下截图中所示的命令从 Git 克隆 Zcash:
 $ git clone https://github.com/zcash/zcash.git 

请注意,如果您是第一次运行 git,则可能需要接受一些配置更改,这些更改将自动完成,但您可能需要进行交互式操作。

此命令将在本地克隆 Zcash Git 仓库。输出如下所示的截图:

克隆 Zcash Git 仓库

  1. 下一步是通过以下命令下载证明和验证密钥:
 $ ./zcutil/fetch-param.sh

此命令将产生与此处所示相似的输出:

Zcash 设置获取 ZK-SNARK 参数

  1. 运行此命令后,将下载约 911 MB 的密钥到~/.zcash-params/目录中。该目录包含用于证明和验证密钥的文件:
 $ pwd 
      /home/drequinox/.zcash-params 
      $ ls -ltr 
      sprout-verifying.key 
      sprout-proving.key
  1. 一旦前述命令成功完成,就可以使用以下命令构建源代码:
       $ ./zcutil/build.sh -j$(nproc) 

这将产生非常长的输出;如果一切顺利,将产生一个zcashd二进制文件。请注意,此命令将nproc作为参数,nproc基本上是一个查找系统中核心或处理器数量并显示该数字的命令。如果您没有该命令,则将nproc替换为系统中的处理器数量。

  1. 构建完成后,下一步是配置 Zcash。这通过在~/.zcash/目录中创建名为zcash.conf的配置文件来实现。

示例配置文件如下所示:

      addnode=mainnet.z.cash 
      rpcuser=drequinox 
      rpcpassword=xxxxxxoJNo4o5c+F6E+J4P2C1D5izlzIKPZJhTzdW5A= 
      gen=1 
      genproclimit=8 
      equihashsolver=tromp 

前述配置启用了各种功能。第一行添加了主网节点并启用了主网连接。rpcuserrpcpassword是 RPC 接口的用户名和密码。gen = 1用于启用挖矿。genproclimit是可用于挖矿的处理器数量。最后一行启用了更快的挖矿求解器;如果要使用标准 CPU 挖矿,则不需要此项。

  1. 现在可以使用以下命令启动 Zcash:
 $ ./zcashd --daemon 

启动后,可以通过zcash-cli命令行界面与 RPC 接口进行交互。这几乎与比特币命令行界面相同。一旦 Zcash 守护进程启动并运行,可以运行各种命令来查询 Zcash 的不同属性。可以使用 CLI 或区块链浏览器在本地查看交易。

Zcash 的区块链浏览器位于:explorer.zcha.in/

地址生成

可以使用以下命令生成新的 Z 地址:

$ ./zcash-cli z_getnewaddress zcPDBKuuwHJ4gqT5Q59zAMXDHhFoihyTC1aLE5Kz4GwgUXfCBWG6SDr45SFLUsZhpcdvHt7nFmC 3iQcn37rKBcVRa93DYrA 

使用带有getinfo参数运行zcash-cli命令会产生以下截图中显示的输出。它显示了诸如blocksdifficultybalance之类的有价值信息:

显示 getinfo 输出的截图

可以使用以下命令生成新的 T 地址:

$ ./zcash-cli getnewaddress  
t1XRCGMAw36yPVCcxDUrxv2csAAuGdS8Nny 

GPU 挖矿

除了 CPU 挖矿外,还提供了 GPU 挖矿选项。目前尚无官方 GPU 矿工;然而,开源开发人员已经制作了各种概念验证和可用的矿工。Zcash 公司举办了一场公开竞赛,鼓励开发人员构建并提交 CPU 和 GPU 矿工。截至撰写时尚未宣布获奖者。

读者可以通过访问网站zcashminers.org/获取更多信息。

还有另一种挖矿方式:使用来自各种在线云挖矿提供商提供的云挖矿合约。云挖矿服务提供商代表客户进行挖矿。除了云挖矿合约,矿工还可以使用自己的设备通过矿池使用 stratum 或其他协议进行挖矿。一个重要的例子是 NiceHash 提供的 Zcash 矿池,链接在:www.nicehash.com。使用该矿池,矿工可以出售他们的哈希功率。

下图显示了在 Zcash 挖矿矿池上构建并使用 CPU 矿工的示例。

下载并编译 nheqminer

可以使用以下步骤在 Ubuntu Linux 发行版上下载和编译nheqminer

$ sudo apt-get install cmake build-essential libboost-all-dev git clone https://github.com/nicehash/nheqminer.git 
$ cd nheqminer/nheqminer  
$ mkdir build 
$ cd build  
$ cmake .. make 

所有步骤都成功完成后,可以使用以下命令运行nhequminer

$ ./nhequminer -l eu -u <btc address> -t <number of threads>  

nheqminer的版本可在以下链接下载,适用于 Windows 和 Linux 系统:

github.com/nicehash/nheqminer/releases

nheqminer需要多个参数,如位置(-l)、用户名(-u)和用于挖矿的线程数(-t)。

下图显示了在 Linux 上运行 Zcash 的样本nheqminer。在此截图中,支付是以比特币地址进行的,用于出售哈希功率:

使用 BTC 地址接收出售哈希功率的支付

此处显示的截图展示了在 Windows 上运行nheqminer并将支付发到 Zcash T 地址的样本运行情况:

使用 Zcash T 地址接收出售哈希功率的支付

Zcash 以创新的方式使用了零知识证明技术,并为未来需要固有隐私的应用铺平了道路,如银行、医学或法律。

本节介绍了 Zcash 的简介;读者可以在z.cash上在线探索更多关于 Zcash 的信息。

首次代币发行(ICOs)

ICOs 类似于首次公开发行(IPO)。就像 IPO 是公司为了筹集资金而启动的一样,ICO 是为了为初创项目筹集资金而启动的。关键区别在于 IPO 受到监管,并且属于证券市场的范畴(公司的股份),而 ICO 则不受监管,不属于任何已建立市场结构的严格类别。

然而,鉴于最近几个月推出的一些骗局 ICO 方案以及对投资者保护日益增长的担忧,有一些建议认为 ICO 应被视为证券。最近,证券交易委员会(SEC)建议所有硬币、ICO、数字资产均属于证券的定义。这意味着对 ICO、比特币和其他数字硬币适用的法律将与证券适用的相同。此外,正式的“了解您的客户”(KYC)和“反洗钱”(AML)也被建议引入以解决与洗钱有关的问题。专家建议豪伊测试作为将任何 ICO 视为证券的一些标准。

另一个区别是,ICO 通常要求投资者使用加密货币投资,并使用加密货币支付回报,最常见的是 ICO 引入的新代币(新加密货币)。这也可以是法定货币,但最常见的是使用加密货币。例如,在以太坊众筹活动中,引入了一种新代币 Ether。代币拍卖众筹的术语也非常流行,这两个术语可互换使用。ICO 也被称为众筹销售。

当一个基于新区块链的应用程序或组织发布时,可以同时推出一个新代币作为访问和使用该应用程序的凭证,并以已建立的加密货币(例如比特币或以太币)或法定货币交换公开发行这个代币。优势在于,随着应用程序或产品的使用量增加,新代币的价值也会随之增加。这样,最初投资的投资者将获得良好的激励。

在 2017 年,ICO 已成为新创企业筹集资本的主要工具。第一个成功的 ICO 是以太坊,在 2014 年筹集了 1800 万美元。最近的成功案例是 Tezos,在几周内筹集了 2.32 亿美元。另一个例子是 Filecoin,筹集了超过 2.5 亿美元。

在以太坊区块链上创建新代币的过程已经标准化,因此相对容易启动一个 ICO,并以以太币、比特币或其他加密货币交换新代币。这个标准称为 ERC20,将在下一节中详细描述。值得注意的是,使用 ERC20 并不是必须的,完全可以在新的区块链上创造一个全新的加密货币来启动 ICO,但最近多个 ICO 中都使用了 ERC20,并为 ICO 构建代币提供了相对较简单的方式。

最近,ICO 在以太坊之外的平台上也提供,如 NEM(nem.io)和 Stellar(www.stellar.org)。

ERC20 代币

ERC20 代币是一个接口,定义了各种功能,规定了代币的要求。然而,它并没有提供实现细节,而是留给实施者决定。ERC 基本上是以太坊请求评论的缩写,相当于比特币的 BIPs,用于提出以太坊区块链的改进建议。

这在 EIP 20 下定义,你可以在此处阅读更多信息:github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md

由于能够创建新代币并且具有 ERC20 标准,以太坊正在成为 ICO 的选择平台,它变得更加易于访问。

ERC20 代币标准定义了描述新代币的各种属性、规则和特性的各种功能。这些包括货币的总供应量、持有者的总余额、转账功能、批准和授权功能。

还有其他标准,如 ERC223、ERC777 和 ERC20 的扩展称为 ERC827 也正在开发中。

您可以参考以下链接了解更多信息:

概要

在本章中,我们向您介绍了整个加密货币领域。我们详细讨论了许多替代币,尤其是 Zcash 和 Namecoin。加密货币是一个非常活跃的研究领域,尤其是围绕可扩展性、隐私和安全方面。一些研究也已经进行,以发明新的难度重新调整算法,以阻止加密货币中央化的威胁。

需要在隐私和尤其是区块链的可扩展性领域进行进一步研究。

现在您应该能够理解代币概念及其背后的各种动机。我们还讨论了一些实际方面,例如挖矿和启动新的货币项目,这希望能够为您奠定坚实的基础,使您能够进一步探索这些领域。代币是一个令人着迷的研究领域,它为去中心化的未来打开了许多可能性。

第十一章:开发工具和框架

本章介绍了用于以太坊智能合约开发的开发工具、语言和框架。我们将研究开发以太坊区块链智能合约的不同方法。我们将详细讨论 Solidity 语言的各种结构,这是目前以太坊智能合约开发中最流行的开发语言。

本章将介绍以下主题:

  • 开发工具、集成开发环境和客户端

    • Remix

    • Ganache

    • EthereumJS

    • TestRPC

    • MetaMask

    • Truffle

  • 先决条件

    • Node

    • Node 包管理器(NPM)

  • 其他工具和实用程序

有许多工具可用于以太坊开发。下图显示了用于以太坊的各种开发工具、客户端、集成开发环境和开发框架的分类:

以太坊开发生态系统组件的分类

上述分类并未包括所有用于以太坊开发的框架和工具。它展示了最常用的工具和框架,也是我们在本章中将要用到的工具和框架。

有许多与以太坊开发工具相关的资源可在以下地址找到:ethdocs.org/en/latest/contracts-and-transactions/developer-tools.html#developer-tools

本章的主要重点将放在 Geth、Remix IDE、Solidity、Ganache、MetaMask、solc 和 Truffle 上。其他元素,如先决条件(Node),也将简要讨论。

语言

以太坊区块链的智能合约可以用多种语言编程。有五种语言可用于编写合同:

  • Mutan:这是一种类似 Go 的语言,于 2015 年初被废弃,已不再使用。

  • LLL:这是一种低级别的 Lisp 式语言,因此被命名为 LLL。这也不再使用。

  • Serpent:这是一种简单、清洁的类似 Python 的语言。它不再用于合同开发,并且不再得到社区支持。

  • Solidity:此语言现已成为几乎是以太坊合同编写的标准。本章将重点讨论这种语言,并在后续章节中进行详细讨论。

  • Vyper:这种语言是一种类似 Python 的实验性语言,旨在为智能合约开发带来安全性、简单性和可审计性。

编译器

编译器用于将高级合同源代码转换为以太坊执行环境能理解的格式。Solidity 编译器是最常用的一个,并在此处讨论。

Solidity 编译器(solc)

solc 将高级 Solidity 语言转换为以太坊虚拟机EVM)字节码,以便在区块链上由 EVM 执行。

在 Linux 上安装

solc 可以在 Linux Ubuntu 操作系统上安装,使用以下命令:

$ sudo apt-get install solc 

如果 PPA 尚未安装,可以通过运行以下命令来安装它们:

$ sudo add-apt-repository ppa:ethereum/ethereum  
$ sudo apt-get update 

为了验证 solc 的现有版本并验证其是否已安装,可以使用以下命令:

$ solc --version
solc, the solidity compiler commandline interface
Version: 0.4.19+commit.c4cbbb05.Darwin.appleclang  

在 macOS 上安装

要在 macOS 上安装 solc,请执行以下命令:

$ brew tap ethereum/ethereum $ brew install solidity $ brew linkapps solidity  

solc 支持各种功能。一些示例如下所示:

  • 以二进制格式显示合约:
 $ solc --bin Addition.sol  

该命令将生成类似以下的输出。这显示了二进制翻译的内容。

Addition.sol 合约代码:

Solidity 编译器的二进制输出

  • 估算 gas:
 $ solc --gas Addition.sol

这将产生以下输出:

使用 solc 估算 gas

  • 生成 ABI:
 $ solc --abi Addition.sol 

以下是 Addition.abi 的内容:

      ======= Addition.sol:Addition ======= 
      Contract JSON ABI  
      [{"constant":false,"inputs":[{"name":"y","type":"uint8"},   
      {"name":"z","type":"uint8"}],"name":"addx","outputs":
      [],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":
      [],"name":"retrievex","outputs":   
      [{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"}] 
  • 编译:

另一个有用的命令,用于编译并生成一个二进制编译文件以及一个 ABI,如下所示:

 $ solc --bin --abi --optimize -o bin Addition.sol

该命令将在输出目录 bin 中产生两个文件:

    • Addition.abi:这包含智能合约的 Application Binary Interface,以 JSON 格式表示

    • Addition.bin:这包含智能合约代码的二进制表示

两个文件的输出显示在以下截图中:

Solidity 编译器的 ABI 和二进制输出

ABIApplication Binary Interface 的缩写。ABI 对智能合约的函数和事件的信息进行编码。它充当 EVM 级字节码和高级智能合约程序代码之间的接口。要与部署在以太坊区块链上的智能合约进行交互,外部程序需要 ABI 和智能合约的地址。

solc 是一个非常强大的命令,可以使用 --help 标志来探索更多选项,该选项将显示详细选项。但是,用于编译、ABI 生成和 gas 估算的前述命令应该对大多数开发和部署需求足够了。

集成开发环境(IDE)

有各种各样的 IDE 可用于 Solidity 开发。大多数 IDE 都可以在线使用,并通过 web 界面呈现。Remix(曾用名为浏览器 Solidity)是构建和调试智能合约最常用的 IDE。在此讨论它。

Remix

Remix 是基于 web 的环境,用于使用 Solidity 开发和测试合约。它是一个功能丰富的 IDE,不在实时区块链上运行;实际上,它是一个模拟环境,合约可以在其中部署、测试和调试。

可在 remix.ethereum.org 找到。

示例接口如下所示:

Remix IDE

在左侧,有一个带有语法高亮和代码格式化的代码编辑器,右侧有许多可用于部署、调试、测试和与合约交互的工具。

可以使用各种功能,例如交易交互,连接到 JavaScript VM 的选项,执行环境的配置,调试器,形式验证和静态分析。它们可以配置为连接到执行环境,例如 JavaScript VM,注入的 Web3——Mist、MetaMask 或类似环境提供了执行环境——或者 Web3 提供程序,它允许通过 IPC 或 RPC over HTTP(Web3 提供程序端点)连接到本地运行的以太坊客户端(例如 geth)。

Remix 还具有针对 EVM 的调试器,非常强大,可用于执行详细级别的跟踪和分析 EVM 字节码。下面是一个示例:

Remix IDE,调试

上面的截图显示了 Remix IDE 的不同元素。左上角显示了源代码。下面是输出日志,显示了与合约的编译和执行相关的信息消息和数据。

下面的截图显示了 Remix 调试器的更多细节。它将源代码解码为 EVM 指令。用户可以逐步执行每个指令,并且可以检查当执行时源代码的作用:

Remix 调试器

工具和库

有各种工具和库可用于以太坊。最常见的是在这里讨论的。

在本节中,我们将首先安装开发以太坊应用程序所需的先决条件。首先要求是 Node,接下来将看到。

Node 版本 7

由于大多数工具和库都需要 Node,可以使用以下命令安装它:

$ curl -sL https://deb.nodesource.com/setup_7.x | sudo -E bash - sudo apt-get install -y nodejs 

EthereumJS

有时候,在测试网上测试不可能,并且主网显然不是测试合约的地方。私有网有时候设置起来可能很耗时。当需要快速测试而又没有合适的测试网时,EthereumJS 的 TestRPC 就非常方便了。它使用 EthereumJS 模拟 Ethereum geth 客户端的行为,并允许进行更快的开发测试。TestRPC 可以通过npm作为一个 Node 软件包获得。

在安装 TestRPC 之前,Node 应该已经被安装,并且npm软件包管理器也应该可用。

可以使用此命令安装 TestRPC:

$ npm install -g ethereumjs-testrpc 

要启动 testrpc,只需发出此命令并使其在后台运行,然后打开另一个终端以处理合约:

$ testrpc  

当 TestRPC 运行时,它将显示类似于以下截图所示的输出。它将自动生成十个帐户和私钥,以及 HD 钱包。它将开始监听 TCP 端口8545上的传入连接。

TestRPC

Ganache

Ganache 是为以太坊开发的众多开发工具和库的最新增加。这在某种程度上是 TestRPC 的替代品,使用用户友好的图形用户界面来查看交易和块以及相关细节。这是一个完全工作的启用了 Byzantium 的个人区块链,用于为区块链提供本地测试环境。

Ganache 基于以太坊区块链的 JavaScript 实现,内置区块浏览器和挖矿功能,使在系统上进行本地测试非常容易。

如下截图所示,您可以在前端详细查看交易、块和地址:

Ganache,一个个人以太坊区块链

Ganache 可以从truffleframework.com/ganache/下载。

MetaMask

MetaMask 允许通过 Firefox 和 Chrome 浏览器与以太坊区块链交互。它会在运行网站的 JavaScript 环境中注入一个web3对象,从而实现对 DApps 的即时接口功能。这种注入允许 DApps 直接与区块链交互。

它可以在metamask.io/获得。

MetaMask 也允许账户管理。这在任何交易在区块链上执行之前充当验证方法。用户会看到一个安全界面来审查交易,然后批准或拒绝它,才能到达目标区块链。

它可以在github.com/MetaMask/metamask-plugin获得。

MetaMask

它允许与各种以太坊网络连接,如下截图所示。这是 MetaMask 的截图,它允许用户选择他们喜欢的网络:

MetaMask 网络如 MetaMask 用户界面所示

值得注意的一个有趣功能是 MetaMask 也可以连接到任何自定义的 RPC,这允许您运行自己的区块链,例如本地或远程的私有网络,并允许您的浏览器连接到它。它还可以用于连接到本地运行的区块链,如 Ganache 和 TestRPC。

MetaMask 允许账户管理,并记录所有这些账户的交易。这在下面的截图中显示:

MetaMask 账户和交易视图

Truffle

Truffle(在 truffleframework.com/ 上可用)是一个开发环境,使得测试和部署以太坊合约更加容易和简单。Truffle 提供合约编译和链接以及使用 Mocha 和 Chai 的自动化测试框架。它还使得更容易将合约部署到任何私有网络、公共网络或测试网络以太坊区块链中。此外,提供了资产管道,使所有 JavaScript 文件都可以被处理,使其可以被浏览器使用。

安装

在安装之前,假设node可用,可以像下面显示的那样查询。如果node不可用,则首先需要安装node才能安装truffle

$ node -version 
v7.2.1 

安装truffle非常简单,可以使用以下命令通过Node Package Managernpm)完成:

$ sudo npm install -g truffle 

这将花费几分钟的时间;安装完成后,可以使用truffle命令显示帮助信息并验证它是否正确安装:

$ sudo npm install -g truffle Password: /us/local/bin/truffle -> /usr/local/lib/node_modules/truffle/build/cli.bundled.js /usr/local/lib └── truffle@4.0.1  

在终端输入truffle以显示使用帮助:

$ truffle 

这将显示以下输出:

Truffle 帮助

或者,存储库可在 github.com/ConsenSys/truffle 上找到,可以将其克隆到本地以安装truffle。可以使用以下命令使用 Git 克隆存储库:

$ git clone https://github.com/ConsenSys/truffle.git

合约开发和部署

开发和部署合约需要采取各种步骤。广义上来说,这些可以分为四个步骤:编写、测试、验证和部署。部署后,下一个可选步骤是创建用户界面并通过 Web 服务器向最终用户呈现。在不需要人类输入或监视的合约中,有时不需要 Web 界面,但通常需要创建 Web 界面来与合约交互。

写作

写作步骤涉及在 Solidity 中编写合约源代码。这可以在任何文本编辑器中完成。对于 Vim、Atom 和其他编辑器,有各种插件和附加组件可用于提供 Solidity 合约源代码的语法高亮和格式化。

Visual studio code 已经变得非常流行,并且通常用于 Solidity 开发。有一个 Solidity 插件可供使用,可以实现语法高亮、格式化和智能。可以通过 Visual Studio Code 中的扩展选项进行安装。

Visual studio code

测试

测试通常是通过自动化手段进行的。在本章的前面,您已经了解了 Truffle,它使用 Mocha 框架来测试合约。但是,也可以通过使用 Remix 手动运行函数并验证结果来执行手动功能测试。

在下一节中,你将会被介绍到 Solidity 语言。这是对 Solidity 的简要介绍,应提供编写合约所需的基本知识。其语法与 C 和 JavaScript 非常相似,编程起来相当容易。

Solidity 语言

Solidity 是以太坊编写合约的领域特定语言的首选。然而,还有其他可用的语言,比如 Serpent、Mutan 和 LLL,但在撰写本文时,Solidity 是最流行的。它的语法更接近 JavaScript 和 C。

Solidity 在过去几年中发展成为一种成熟的语言,非常容易使用,但在成为像 Java、C 或 C Sharp 等其他成熟语言一样先进、标准化和功能丰富之前,还有很长的路要走。尽管如此,这仍然是目前编写合约最广泛使用的语言。

它是一种静态类型语言,这意味着在 Solidity 中,变量类型检查是在编译时进行的。每个变量,无论是状态变量还是局部变量,都必须在编译时指定一个类型。这在某种意义上是有益的,因为任何验证和检查都是在编译时完成的,某些类型的错误,比如数据类型的解释,可以在开发周期的早期被捕获,而不是在运行时,这可能是昂贵的,特别是在区块链/智能合约范式的情况下。语言的其他特性包括继承、库和定义复合数据类型的能力。

Solidity 也被称为面向合约的语言。在 Solidity 中,合约相当于其他面向对象编程语言中的类的概念。

类型

Solidity 有两类数据类型:值类型引用类型

值类型

这些在这里详细解释:

布尔

此数据类型有两个可能的值,truefalse,例如:

bool v = true; 
bool v = false;  

此语句将值 true 分配给 v

整数

此数据类型表示整数。以下表格显示了用于声明整数数据类型的各种关键字:

关键字 类型 详情
int 有符号整数 int8int256,这意味着关键字从 int8 增加到 int256,例如,int8int16int24
uint 无符号整数 uint8uint16、... 到 uint256,表示从 8 位到 256 位的无符号整数。变量的存储需求取决于需要存储多少位。

例如,在这段代码中,注意 uintuint256 的别名:

uint256 x;  
uint y;  
uint256 z; 

这些类型也可以用 constant 关键字声明,这意味着编译器不会为这些变量保留存储槽。在这种情况下,每次出现都将被实际值替换:

uint constant z=10+10; 

状态变量在函数体外声明,并且根据分配给它们的可访问性和合约的持续时间保持可用。

地址

此数据类型持有 160 位长(20 字节)的值。该类型具有几个成员,可用于与合约交互和查询。这些成员在这里描述:

  • 余额balance 成员返回地址的 Wei 余额。

  • 发送:此成员用于向地址(以太坊的 160 位地址)发送一定数量的以太,并根据交易结果返回truefalse,例如:

      address to = 0x6414cc08d148dce9ebf5a2d0b7c220ed2d3203da; address from = this; 
      if (to.balance < 10 && from.balance > 50) to.send(20); 
  • 调用函数callcallcodedelegatecall 用于与没有 ABI 的函数交互。由于对合约的类型安全性和安全性的影响,应谨慎使用这些函数。

  • 数组值类型(固定大小和动态大小的字节数组):Solidity 具有固定大小和动态大小的字节数组。固定大小关键字从 bytes1bytes32,而动态大小关键字包括 bytesstringbytes 关键字用于原始字节数据,string 用于以 UTF-8 编码的字符串。由于这些数组是按值返回的,调用它们将产生 gas 成本。length 是数组值类型的一个成员,并返回字节数组的长度。

静态(固定大小)数组的示例如下:

      bytes32[10] bankAccounts; 

动态大小数组的示例如下:

      bytes32[] trades;  

使用以下代码获取交易长度:

      trades.length; 

字面量

这些用于表示固定值。下面的小节描述了不同类型的字面量。

整数字面量

整数字面量是一系列范围在 0-9 的十进制数字。示例如下:

uint8 x = 2; 

字符串字面量

字符串字面量指定用双引号或单引号编写的一组字符。示例如下:

'packt' "packt" 

十六进制字面量

十六进制字面量以关键字 hex 为前缀,并在双引号或单引号内指定。示例如下:

(hex'AABBCC'); 

枚举

这允许创建用户定义的类型。示例如下:

enum Order {Filled, Placed, Expired };  
Order private ord; 
ord=Order.Filled; 

枚举类型允许对所有整数类型进行显式转换。

函数类型

有两种函数类型:内部函数和外部函数。

内部函数

这些只能在当前合约的上下文中使用。

外部函数

外部函数可以通过外部函数调用来调用。

在 Solidity 中,函数 可以标记为常量。常量函数不能更改合约中的任何内容;只有在调用时返回值,而且不消耗任何 gas。这是对 call 概念的实际实现。

声明函数的语法如下所示:

function <nameofthefunction> (<parameter types> <name of the variable>) 
{internal|external} [constant] [payable] [returns (<return types> <name of the variable>)] 

引用类型

正如名称所示,这些类型是按引用传递的,并在以下部分讨论。这些也被称为复杂类型

数组

数组表示内存位置处以相同大小和类型排列的一系列连续元素。该概念与任何其他编程语言相同。数组有两个成员名为lengthpush

uint[] OrderIds; 

结构体

这些结构可用于将一组不同类型的数据分组到一个逻辑组中。这些可以用于定义新类型,如下例所示:

pragma solidity ⁰.4.0; 
contract TestStruct { 
  struct Trade 
  { 
    uint tradeid; 
    uint quantity; 
    uint price;  
    string trader; 
  } 

  //This struct can be initialized and used as below 

  Trade tStruct = Trade({tradeid:123, quantity:1, price:1, trader:"equinox"}); 

} 

数据位置

数据位置指定特定复杂数据类型将存储在何处。根据默认值或指定的注释,位置可以是存储或内存。这适用于数组和结构体,并可以使用storagememory关键字指定。

由于在内存和存储之间进行复制可能相当昂贵,因此有时指定位置可以帮助控制燃气消耗。调用数据是另一个内存位置,用于存储函数参数。

外部函数的参数使用调用数据内存。默认情况下,函数的参数存储在内存中,而所有其他局部变量都使用存储。另一方面,状态变量需要使用存储。

映射

映射用于键值映射。这是一种将值与键关联的方法。此映射中的所有值都已初始化为零,例如以下内容:

mapping (address => uint) offers; 

此示例显示 offers 被声明为映射。另一个示例使此更清晰:

mapping (string => uint) bids;  
bids["packt"] = 10; 

这基本上是一个字典或哈希表,其中字符串值映射到整数值。名为bids的映射将字符串packt映射到值10

全局变量

Solidity 提供了一些始终可用于全局命名空间的全局变量。这些变量提供有关块和交易的信息。此外,加密函数和与地址相关的变量也可用。

显示的可用函数和变量子集如下所示:

keccak256(...) returns (bytes32) 

此函数用于计算提供给函数的参数的 Keccak-256 哈希值:

ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address) 

此函数返回椭圆曲线签名的公钥关联地址:

block.number 

这返回当前块编号。

控制结构

Solidity 语言中可用的控制结构是if...elsedowhileforbreakcontinuereturn。它们的工作方式与其他语言(如 C 语言或 JavaScript)完全相同。

一些示例显示在这里:

  • if:如果x等于0,则将值0赋给y,否则将1赋给z
      if (x == 0) 
          y = 0; 
      else 
          z = 1; 
  • do:在z大于1时递增x
      do{ 
          x++; 
      } (while z>1); 
  • while:在x大于0时递增z
      while(x > 0){ 
          z++; 
      } 
  • for、break 和 continue:执行一些工作,直到x小于或等于10。如果z5,那么这个for循环将运行10次,然后中断:
      for(uint8 x=0; x<=10; x++) 
      { 
          //perform some work 
          z++ 
          if(z == 5) break; 
      } 

它将继续类似的工作,但在条件满足时,循环将重新开始。

  • return:Return 用于停止函数的执行并返回一个可选值。例如:
      return 0; 

它将停止执行并返回值0

事件

Solidity 中的事件可用于记录 EVM 日志中的某些事件。当需要通知外部接口发生变化或事件发生时,这些事件非常有用。这些日志存储在区块链中的交易日志中。合约无法访问日志,但它们用作通知合约状态变化或事件发生(满足条件)的机制。

在这里的一个简单示例中,valueEvent事件将在函数Matcher传递的x参数等于或大于10时返回true

pragma solidity ⁰.4.0;  
contract valueChecker  
{  
    uint8 price=10; 
    event valueEvent(bool returnValue);  
    function Matcher(uint8 x) public returns (bool) 
    { 
        if (x>=price) 
        { 
            valueEvent(true);  
            return true; 
        } 
    } 
} 

继承

Solidity 支持继承。is关键字用于从另一个合约派生合约。在下面的示例中,valueChecker2是从valueChecker合约派生出来的。派生合约具有对父合约的所有非私有成员的访问权限:

pragma solidity ⁰.4.0;  
contract valueChecker 
{ 
    uint8 price = 20; 
    event valueEvent(bool returnValue);  
    function Matcher(uint8 x) public returns (bool) 
    { 
        if (x>=price) 
        { 
            valueEvent(true);  
            return true; 
        } 
    } 
} 
contract valueChecker2 is valueChecker 
{ 
    function Matcher2() public view returns (uint) 
    { 
        return price+10; 
    } 
} 

在前面的示例中,如果将 uint8 price = 20 更改为 uint8 private price = 20,那么valueChecker2合约将无法访问它。这是因为现在该成员被声明为私有,不允许任何其他合约访问。在 Remix 中您将看到的错误信息为

browser/valuechecker.sol:20:8: DeclarationError: Undeclared identifier. 
return price+10; 
       ^---^ 

库只在特定地址部署一次,它们的代码通过 EVM 的 CALLCODEDELEGATECALL 操作码调用。库背后的关键思想是代码的重复使用性。它们类似于合约,并作为调用合约的基础合约。一个库可以声明如下:

library Addition 
{ 
    function Add(uint x,uint y) returns (uint z) 
    { 
        return x + y; 
    } 
} 

然后可以在合约中调用此库,如下所示。首先需要导入它,然后可以在代码的任何地方使用它。一个简单的示例如下所示:

import "Addition.sol" 
function Addtwovalues() returns(uint) 
{ 
    return Addition.Add(100,100); 
} 

库存在一些限制;例如,它们不能拥有状态变量,也不能继承或被继承。此外,它们也不能接收以太币;这与合约相反,合约可以接收以太币。

函数

Solidity 中的函数是与合约关联的代码模块。函数声明包括名称、可选参数、访问修饰符、可选constant关键字和可选返回类型。如下例所示:

function orderMatcher (uint x)  
private constant returns(bool return value)  

在前面的示例中,function是声明函数所使用的关键字。orderMatcher是函数名,uint x是一个可选参数,private是控制外部合约访问该函数的访问修饰符说明符constant是一个可选关键字,用于指定该函数不会改变合约中的任何内容,而仅用于从合约中检索值,returns (bool return value)是函数的可选返回类型。

  • 如何定义函数:定义函数的语法如下所示:
      function <name of the function>(<parameters>) <visibility specifier> returns 
      (<return data type> <name of the variable>) 
      { 
          <function body> 
      } 
  • 函数签名:Solidity 中的函数由其签名标识,即其完整签名字符串的 Keccak-256 哈希的前四个字节。这也可以在 Remix IDE 中看到,如下面的屏幕截图所示。f9d55e21 是名为 Matcher 的函数的 32 字节 Keccak-256 哈希的前四个字节。

在 Remix IDE 中显示的函数哈希

在这个示例函数中,Matcher 的签名哈希为 d99c89cb。这些信息对于构建接口是有用的。

  • 函数的输入参数:函数的输入参数以 <数据类型> <参数名> 的形式声明。这个例子阐明了 checkValues 函数的输入参数 uint xuint y 的概念:
      contract myContract 
      { 
          function checkValues(uint x, uint y) 
          { 
          } 
      } 
  • 函数的输出参数:函数的输出参数以 <数据类型> <参数名> 的形式声明。这个例子显示了一个简单的返回 uint 值的函数:
      contract myContract 
      { 
          function getValue() returns (uint z) 
          { 
              z=x+y; 
          } 
      } 

一个函数可以返回多个值。在前面的示例函数中,getValue 只返回一个值,但一个函数最多可以返回 14 个不同数据类型的值。未使用的返回参数的名称可以选择性地省略。

  • 内部函数调用:在当前合约的上下文中,可以直接调用当前合约中的函数。这些调用导致 EVM 字节码级别的简单 JUMP 调用。

  • 外部函数调用:外部函数调用是通过合约从一个合约向另一个合约发送消息调用的。在这种情况下,所有函数参数都会被复制到内存中。如果使用 this 关键字调用内部函数,它也被视为外部调用。this 变量是一个指针,指向当前合约。它可以显式转换为地址,并且所有合约的成员都是从地址继承的。

  • 回退函数:这是一个没有参数和返回数据的合约中的未命名函数。每当接收到以太时,此函数都会执行。如果合约打算接收以太,则必须在合约内实现此函数;否则,将抛出异常并返回以太。如果合约中没有其他函数签名匹配,此函数也会执行。如果合约预期接收以太,则回退函数应该用可支付的 修饰符 声明。这个修饰符是必需的;否则,此函数将无法接收任何以太。此函数可以使用 address.call() 方法调用,例如:

      function () 
      { 
          throw; 
      } 

在这种情况下,如果根据前述条件调用了回退函数,则会调用 throw,这将使状态回滚到调用前的状态。它也可以是除 throw 之外的其他构造,例如,它可以记录一个事件,该事件可以作为反馈调用结果给调用应用程序的警报。

  • 修改器函数:这些函数用于改变函数的行为,并且可以在其他函数之前调用。通常,它们用于在执行函数之前检查某些条件或验证。在修改器函数中使用 _(下划线),当调用修改器时将其替换为实际函数体。基本上,它象征着需要被守护的函数。这个概念类似于其他语言中的守护函数。

  • 构造函数:这是一个可选函数,其名称与合约相同,并且在创建合约时执行。构造函数不能由用户后来调用,一个合约中只允许一个构造函数。这意味着没有重载功能可用。

  • 函数可见性修饰符(访问修饰符):函数可以用四个访问修饰符来定义,如下所示:

    • 外部:这些函数可以从其他合约和交易中访问。除非使用 this 关键字,否则不能在内部调用它们。

    • 公共:默认情况下,函数是公共的。它们可以在内部调用,也可以通过消息调用。

    • 内部:内部函数对来自父合约的其他派生合约可见。

    • 私有:私有函数只对声明它们的同一合约可见。

  • 函数修改器

    • 纯净:此修饰符禁止对状态进行访问或修改

    • 视图:此修饰符禁止对状态进行任何修改

    • 可支付的:此修饰符允许通过调用支付以太币

    • 常量:此修饰符不允许对状态进行访问或修改

  • 其他重要关键字/函数 throwthrow 用于停止执行。因此,所有状态更改都将被还原。在这种情况下,没有气体返回给交易发起者,因为所有剩余的气体都被消耗掉了。

Solidity 源代码文件的布局

在以下子节中,我们将看看 Solidity 源代码文件的组成部分。

版本声明

为了解决未来版本的 solc 版本可能出现的兼容性问题,pragma 可以用来指定兼容编译器的版本,例如:

pragma solidity ⁰.5.0 

这将确保源文件不会与小于 0.5.0 的版本以及从 0.6.0 开始的版本编译。

导入

在 Solidity 中,import 允许将现有 Solidity 文件中的符号导入到当前的全局范围。这类似于 JavaScript 中可用的 import 语句,例如:

import "module-name"; 

注释

注释可以以类似于 C 语言的方式添加在 Solidity 源代码文件中。多行注释用 /**/ 括起来,而单行注释以 // 开头。

以下是一个 Solidity 程序示例,展示了pragmaimport和注释的用法:

在 Remix IDE 中显示的 Solidity 程序示例

这完成了对 Solidity 语言的简要介绍。该语言非常丰富并在不断改进中。详细文档和编码指南可在网上查看:solidity.readthedocs.io/en/latest/

摘要

本章从介绍以太坊的开发工具开始,如 Remix IDE。然后我们讨论了一些框架,比如 Truffle,还有用于开发和测试的本地区块链解决方案,例如 Ganache、EthereumJS 和 TestRPC。还探讨了其他工具,比如 MetaMask。引入了 Node 的安装,因为大多数工具都是基于 JavaScript 和 Node 的。

第十二章:构建一个投丨注应用程序

有时,智能合约需要访问其他 dapp 或全球网络中的数据是必要的。但由于技术和共识挑战,让智能合约访问外部数据确实很复杂。因此,目前,以太坊智能合约没有原生支持访问外部数据。但是有第三方解决方案供以太坊智能合约访问一些热门 dapp 和全球网络的数据。在本章中,我们将学习如何使用 Oraclize 从以太坊智能合约向全球网络发出 HTTP 请求以访问数据。我们还将学习如何访问存储在 IPFS 中的文件,使用字符串库处理字符串等等。我们将通过构建一个足球投丨注智能合约和一个客户端来学习所有这些。

在本章中,我们将涵盖以下主题:

  • Oraclize 是如何工作的?

  • Oraclize 有哪些不同的数据来源,它们各自是如何工作的?

  • Oraclize 中的共识如何工作?

  • 将 Oraclize 集成到以太坊智能合约中

  • 使用字符串库Solidity,使处理字符串变得更加简单。

  • 构建一个足球投丨注应用程序。

Oraclize 简介

Oraclize 是一项旨在使智能合约能够从其他区块链和全球网络中获取数据的服务。该服务目前在比特币和以太坊的测试网和主网上已经上线。使 Oraclize 如此特殊的是您无需信任它,因为它提供了所有提供给智能合约的数据的真实性证明。

本章的目标是学习以太坊智能合约如何使用 Oraclize 服务从全球网络获取数据。

它是如何工作的?

让我们看一下以太坊智能合约如何使用 Oraclize 从其他区块链和全球网络中获取数据的过程。

要获取存在于以太坊区块链之外的数据,以太坊智能合约需要向 Oraclize 发送查询,提及数据源(表示从哪里获取数据)和数据源的输入(表示获取什么)。

向 Oraclize 发送查询意味着向 Oraclize 合约发送合同调用(即内部交易)。

Oraclize 服务器不断寻找向其智能合约发出的新查询。每当它看到新的查询时,它就会获取结果并通过调用您合约的_callback方法将其发送回给您的合约。

数据来源

以下是 Oraclize 允许智能合约获取数据的来源列表:

  • URL:URL 数据源使您能够进行 HTTP GET 或 POST 请求,即从全球网络获取数据。

  • WolframAlphaWolframAlpha数据源使您能够向WolframAlpha知识引擎提交查询并获取答案。

  • 区块链区块链 数据源允许您访问来自其他 区块链 的数据。可以提交给 区块链 数据源的可能查询有 比特币区块链高度莱特币哈希率比特币难度1NPFRDJuEdyqEn2nmLNaWMfojNksFjbL4S 余额 等。

  • IPFSIPFS 数据源使您能够获取存储在 IPFS 中的文件的内容。

  • 嵌套嵌套 数据源是一个元数据源;它不提供对其他服务的访问。它被设计为提供简单的聚合逻辑,使得可以基于任何可用的数据源进行单一查询,并生成单一的字符串作为结果;例如:

[WolframAlpha] ${[IPFS] QmP2ZkdsJG7LTw7jBbizTTgY1ZBeen64PqMgCAWz2koJBL} 中的温度

  • 计算计算 数据源使给定应用程序在安全的链下环境中进行可审计的执行;也就是说,它允许我们获取应用程序的链下执行结果。该应用程序必须在退出之前(在标准输出上)打印查询结果。执行上下文必须由 Dockerfile 描述,其中构建和运行应用程序应该立即启动您的主应用程序。Dockerfile 初始化加上应用程序执行应尽快终止:在 AWS t2.micro 实例上的最大执行超时时间为 5 分钟。在这里,我们考虑的是 AWS t2.micro 实例,因为这是 Oraclize 将用来执行该应用程序的实例类型。由于数据源的输入是包含这些文件的 ZIP 存档的 IPFS 多哈希值(Dockerfile 加上任何外部文件依赖项,Dockerfile 必须放置在存档根目录中),您应该注意准备此存档并将其推送到 IPFS。

这些数据源是在撰写本书时可用的。但未来可能会有更多的数据源可用。

真实性证明

尽管 Oraclize 是一个值得信赖的服务,但您可能仍希望检查 Oraclize 返回的数据是否真实,即它是否在传输过程中被 Oraclize 或其他人操纵。

可选地,Oraclize 提供了从 URL、区块链和嵌套和计算数据源返回的 TLSNotary 结果证明。这个证明对于 WolframAlphaIPFS 数据源不可用。目前,Oraclize 只支持 TLSNotary 证明,但在未来,他们可能支持一些其他的认证方式。目前,TLSNotary 证明需要手动验证,但是 Oraclize 已经在进行链上证明验证的工作;也就是说,你的智能合约代码可以在从 Oraclize 接收数据的同时验证 TLSNotary 证明,以便如果证明无效则丢弃这些数据。

这个工具(github.com/Oraclize/proof-verification-tool)是 Oraclize 提供的开源工具,用于验证 TLSNotary 证据,如果您愿意的话。

理解 TLSNotary 的工作原理并不是使用 Oraclize 或验证证据的必需条件。验证 TLSNotary 证据的工具是开源的;因此,如果其中包含任何恶意代码,那么它可以很容易被发现,因此可以信任这个工具。

让我们来看一下 TLSNotary 如何工作的高层概述。要理解 TLSNotary 的工作原理,首先需要了解 TLS 的工作原理。TLS 协议提供了一种让客户端和服务器创建加密会话的方式,以便其他人无法读取或操纵客户端和服务器之间传输的内容。服务器首先向客户端发送其证书(由受信任的 CA 颁发给域所有者),该证书将包含服务器的公钥。客户端使用 CA 的公钥解密证书,以便可以验证证书实际由 CA 颁发并获取服务器的公钥。然后,客户端生成对称加密密钥和 MAC 密钥,并使用服务器的公钥对其进行加密,然后将其发送给服务器。服务器只能解密此消息,因为它有解密该消息的私钥。现在客户端和服务器共享相同的对称和 MAC 密钥,除此之外,没有其他人知道这些密钥,它们可以开始相互发送和接收数据。对称密钥用于加密和解密数据,其中 MAC 密钥和对称密钥一起用于为加密消息生成签名,以便在消息被攻击者修改时,另一方可以知道。

TLSNotary 是 TLS 的修改版,由 Oraclize 使用以提供密码学证明,证明它们提供给您的智能合约的数据确实是数据源在特定时间提供给 Oraclize 的数据。实际上,TLSNotary 协议是开源技术,由 PageSigner 项目开发和使用。

TLSNotary 的工作原理是将对称密钥和 MAC 密钥分成三个方(即服务器、被审计者和审计者)。TLSNotary 的基本思想是被审计者可以向审计者证明特定结果是在特定时间由服务器返回的。

现在这里是一个关于 TLSNotary 如何实现这一目标的概述。审核员计算对称密钥和 MAC 密钥,并仅将对称密钥给审计对象。审计对象不需要 MAC 密钥,因为 MAC 签名检查确保了从服务器传输的 TLS 数据没有被篡改。使用对称加密密钥,审计对象现在可以解密来自服务器的数据。由于所有消息都由银行使用 MAC 密钥“签名”,并且只有服务器和审核员知道 MAC 密钥,正确的 MAC 签名可以作为证明,证明某些消息确实来自银行,并且没有被审计对象伪造。

对于 Oraclize 服务,Oraclize 是审计对象,而一个锁定的 AWS 实例(一个特殊设计的开源亚马逊机器镜像)是审核员。

他们提供的证明数据是 AWS 实例签名认证,证明了 TLSNotary 证明确实发生了。他们还提供了有关 AWS 实例上运行的软件的一些额外证明,即它自初始化以来是否被修改过。

定价

来自任何以太坊地址的第一个 Oraclize 查询调用完全免费。Oraclize 在测试网使用时也是免费的!这只适用于在测试环境中适度使用。

从第二次调用开始,你需要支付以太币来查询。当向 Oraclize 发送查询时(即进行内部事务调用),费用通过将以太币从调用合约转移到 Oraclize 合约的方式扣除。扣除的以太币数量取决于数据源和证明类型。

下面是一个表格,显示了发送查询时扣除的以太币数量:

数据源 没有证明 有 TLSNotary 证明
URL $0.01 | $0.05
区块链 $0.01 | $0.05
WolframAlpha $0.03 | $0.03
IPFS $0.01 | $0.01

因此,如果你发出 HTTP 请求,并且你也想要 TLSNotary 证明,那么调用合约必须有价值 $0.05 的以太币,否则会抛出异常。

开始使用 Oraclize API

要使用 Oraclize 服务,合约需要继承 usingOraclize 合约。你可以在github.com/Oraclize/Ethereum-api找到这个合约。

usingOraclize 合约充当 OraclizeIOraclizeAddrResolverI 合约的代理。实际上,usingOraclize 使得调用 OraclizeIOraclizeAddrResolverI 合约变得容易,也就是说,它提供了更简单的 API。如果你觉得舒服,你也可以直接调用 OraclizeIOraclizeAddrResolverI 合约。你可以查看这些合约的源代码以找到所有可用的 API。我们只会学习最必要的。

让我们看看如何设置证明类型,设置证明存储位置,进行查询,找到查询的成本,等等。

设置证明类型和存储位置

无论你是否需要来自 Oraclize 的 TLSNotary 证明,你都必须在发出查询之前指定证明类型和证明存储位置。

如果你不需要证明,那么把这段代码放在你的合约中:

oraclize_setProof(proofType_NONE)

如果你需要证明,那么把这段代码放在你的合约中:

oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS)

目前,proofStorage_IPFS 是唯一可用的证明存储位置;也就是说,TLSNotary 证明仅存储在 IPFS 中。

你可以执行这些方法中的任何一个,例如,在构造函数中或在任何其他时间,如果,例如,你只需要某些查询的证明。

发送查询

要向 Oraclize 发送查询,你需要调用 oraclize_query 函数。该函数至少需要两个参数,即数据源和给定数据源的输入。数据源参数不区分大小写。

以下是 oraclize_query 函数的一些基本示例:

oraclize_query("WolframAlpha", "random number between 0 and 100"); 

oraclize_query("URL", "https://api.kraken.com/0/public/Ticker?pair=ETHXBT"); 

oraclize_query("IPFS", "QmdEJwJG1T9rzHvBD8i69HHuJaRgXRKEQCP7Bh1BVttZbU"); 

oraclize_query("URL", "https://xyz.io/makePayment", '{"currency": "USD", "amount": "1"}');

以下是前述代码的工作原理:

  • 如果第一个参数是字符串,则假定它是数据源,第二个参数被假定为数据源的输入。在第一个调用中,数据源是 WolframAlpha,我们发送给它的搜索查询是 random number between 0 and 100

  • 在第二次调用中,我们向第二个参数中提供的 URL 发出 HTTP GET 请求。

  • 在第三次调用中,我们从 IPFS 获取 QmdEJwJG1T9rzHvBD8i69HHuJaRgXRKEQCP7Bh1BVttZbU 文件的内容。

  • 如果数据源之后的两个连续参数都是字符串,则假定是一个 POST 请求。在最后一次调用中,我们向 https://xyz.io/makePayment 发出了一个 HTTP POST 请求,而 POST 请求正文内容是第三个参数中的字符串。Oraclize 足够智能,可以根据字符串格式检测内容类型头。

调度查询

如果你希望 Oraclize 在将来的预定时间执行你的查询,只需将延迟(以秒为单位)从当前时间指定为第一个参数。

这是一个例子:

oraclize_query(60, "WolframAlpha", "random number between 0 and 100");

前述查询将在被接收到后的 60 秒后由 Oraclize 执行。因此,如果第一个参数是一个数字,则假定我们正在调度一个查询。

自定义 gas

从 Oraclize 到你的 __callback 函数的交易会花费 gas,就像任何其他交易一样。你需要支付给 Oraclize gas 的费用。用于发出查询的以太 oraclize_query 费用也用于在调用 __callback 函数时提供 gas。默认情况下,当调用 __callback 函数时,Oraclize 提供 200,000 gas。

此返回 gas 费用实际上由你控制,因为你在 __callback 方法中编写代码,因此可以估算。因此,当向 Oraclize 发出查询时,你还可以指定 __callback 交易上的 gasLimit 应该是多少。然而,请注意,由于 Oraclize 发送了交易,任何未使用的 gas 都将退还给 Oraclize,而不是你。

如果默认值和最小值 200,000 gas 不够用,你可以通过在此方式中指定不同的 gasLimit 来增加它:

oraclize_query("WolframAlpha", "random number between 0 and 100", 500000);

在这里,您可以看到如果最后一个参数是一个数字,则假定为自定义 gas。在前面的代码中,Oraclize 将使用 500k 的gasLimit来进行回调事务,而不是 200k。因为我们要求 Oraclize 提供更多的 gas,所以在调用oraclize_query时,Oraclize 将扣除更多的以太币(取决于需要多少 gas)。

请注意,如果提供的gasLimit太低,并且您的__callback方法很长,您可能永远看不到回调。还请注意,自定义的 gas 必须超过 200k。

回调函数

一旦您的结果准备好,Oraclize 将向您的合约地址发送一个事务,并调用以下三种方法之一:

  • 要么__callback(bytes32 myid, string result)Myid是每个查询的唯一 ID。该 ID 由oraclize_query方法返回。如果您的合约中有多个oraclize_query调用,则用于匹配此结果的查询。

  • 如果您请求 TLS Notary 证明,这是结果:__callback(bytes32 myid, string result, bytes proof)

  • 作为最后的手段,如果其他方法不存在,则回退函数为function()

这是__callback函数的示例:

function __callback(bytes32 myid, string result) { 
    if (msg.sender != oraclize_cbAddress()) throw; // just to be sure the calling address is the Oraclize authorized one 

    //now doing something with the result.. 
}

解析助手

从 HTTP 请求返回的结果可以是 HTML、JSON、XML、二进制等。在 Solidity 中,解析结果是困难且昂贵的。因此,Oraclize 提供了解析辅助程序,让它在其服务器上处理解析,并且您只获得您需要的结果部分。

要求 Oraclize 解析结果,您需要将 URL 包装在以下其中一个解析助手中:

  • xml(..)json(..)助手可让您要求 Oraclize 仅返回 JSON 或 XML 解析的部分;例如,看看以下内容:

    • 为了获得完整的响应,您使用带有api.kraken.com/0/public/Ticker?pair=ETHUSD URL 参数的URL数据源

    • 如果您只想要最后价格字段,则需要使用 JSON 解析调用,如json(api.kraken.com/0/public/Ticker?pair=ETHUSD).result.XETHZUSD.c.0

  • html(..).xpath(..)助手对 HTML 抓取很有用。只需将要作为xpath(..)参数的 XPATH 指定为您想要的;例如,看看以下内容:

    • 要获取特定推文的文本,请使用html(https://twitter.com/oraclizeit/status/671316655893561344).xpath(//*[contains(@class, 'tweet-text')]/text())
  • binary(..)助手对获取二进制文件(例如证书文件)很有用:

    • 要获取二进制文件的部分内容,可以使用slice(offset,length);第一个参数是偏移量,第二个参数是您想要返回的片段的长度(以字节为单位)。

    • 示例:仅从二进制 CRL 中获取前 300 字节,binary(https://www.sk.ee/crls/esteid/esteid2015.crl).slice(0,300)。二进制助手必须与切片选项一起使用,并且只接受二进制文件(未编码)。

如果服务器无响应或不可访问,我们将发送空响应给你。你可以使用 app.Oraclize.it/home/test_query 测试查询。

获取查询价格

如果你想知道一个查询在进行实际查询之前会花费多少成本,那么你可以使用 Oraclize.getPrice() 函数来获取所需的 wei 金额。它接受的第一个参数是数据源,第二个参数是可选的,是自定义 gas。

这的一个常见用例是通知客户端添加以太到合约中,如果没有足够的以太来进行查询的话。

加密查询

有时,你可能不想透露数据源和/或数据源的输入。例如:如果存在 API 密钥,你可能不想在 URL 中透露它。因此,Oraclize 提供了一种将查询加密存储在智能合约中的方法,只有 Oraclize 的服务器有解密的密钥。

Oraclize 提供了一个 Python 工具(github.com/Oraclize/encrypted-queries),它可用于加密数据源和/或数据输入。它生成一个非确定性加密字符串。

加密任意文本字符串的 CLI 命令如下:

    python encrypted_queries_tools.py -e -p 044992e9473b7d90ca54d2886c7addd14a61109af202f1c95e218b0c99eb060c7134c4ae46345d0383ac996185762f04997d6fd6c393c86e4325c469741e64eca9 "YOUR DATASOURCE or INPUT"

你看到的长十六进制字符串是 Oraclize 服务器的公钥。现在你可以使用上述命令的输出来替代数据源和/或数据源的输入。

为了防止加密查询的滥用(即重放攻击),首个使用特定加密查询向 Oraclize 查询的合约将成为其合法所有者。任何其他重复使用完全相同字符串的合约将不被允许使用它,并将收到空结果。因此,在重新部署使用加密查询的合约时,请记住始终生成新的加密字符串。

解密数据源

还有另一个名为 decrypt 的数据源。它用于解密一个加密字符串。但是这个数据源不会返回任何结果;否则,任何人都将有能力解密数据源并为数据源输入。

它专门设计用于在嵌套数据源内部使用,以实现部分查询加密。这是它唯一的用例。

Oraclize Web IDE

Oraclize 提供了一个 Web IDE,你可以在其中编写、编译和测试基于 Oraclize 的应用程序。你可以在 dapps.Oraclize.it/browser-Solidity/ 找到它。

如果你访问链接,你会发现它看起来与浏览器 Solidity 完全相同。实际上,它就是浏览器 Solidity 多了一个额外的功能。要理解这个功能是什么,我们需要更深入地了解浏览器 Solidity。

浏览器 Solidity 不仅让我们能够为我们的合约编写、编译和生成 web3.js 代码,而且还可以在其中测试这些合约。到目前为止,为了测试我们的合约,我们一直在设置以太坊节点并向其发送交易。但是浏览器 Solidity 可以在不连接到任何节点的情况下执行合约,一切都发生在内存中。它通过使用 ethereumjs-vm 实现了这一点,ethereumjs-vm 是以太坊虚拟机的 JavaScript 实现。使用 ethereumjs-vm,您可以创建自己的 EVM 并运行字节码。如果需要,我们可以配置浏览器 Solidity 使用提供连接的以太坊节点的 URL。用户界面非常信息丰富,因此您可以自己尝试所有这些。

Oraclize web IDE 的特殊之处在于它在内存执行环境中部署了 Oraclize 合约,因此您不必连接到测试网络或主网络节点,但如果使用浏览器 Solidity,则必须连接到测试网络或主网络节点以测试 Oraclize API。

您可以在 dev.Oraclize.it/ 找到更多关于集成 Oraclize 的资源。

处理字符串

在 Solidity 中处理字符串不像在其他高级编程语言(如 JavaScript、Python 等)中那样简单。因此,许多 Solidity 程序员创建了各种库和合约,以便轻松处理字符串。

strings 库是最受欢迎的字符串实用程序库。它让我们可以将字符串转换为称为切片的东西,从而实现连接、拼接、拆分、比较等操作。切片是一个结构体,它保存了字符串的长度和地址。由于切片只需指定偏移量和长度,复制和操作切片比复制和操作它们引用的字符串要便宜得多。

为了进一步减少 gas 成本,大多数需要返回切片的切片函数会修改原始切片而不是分配一个新的;例如,s.split(".") 将返回到第一个 "." 之前的文本,修改 s 以仅包含 "." 之后的字符串。在不想修改原始切片的情况下,可以使用 .copy() 复制,例如,s.copy().split(".")。尽量避免在循环中使用这种习惯用法;由于 Solidity 没有内存管理,这将导致分配许多后来将被丢弃的短期切片。

有必要复制字符串数据的函数将返回字符串而不是切片;如果需要,这些可以转换回切片进行进一步处理。

让我们看一些使用 strings 库处理字符串的示例:

pragma Solidity ⁰.4.0; 

import "github.com/Arachnid/Solidity-stringutils/strings.sol"; 

contract Contract 
{ 
    using strings for *; 

    function Contract() 
    { 
        //convert string to slice 
        var slice = "xyz abc".toSlice(); 

        //length of string 
        var length = slice.len(); 

        //split a string 
        //subslice = xyz 
        //slice = abc 
        var subslice = slice.split(" ".toSlice()); 

        //split a string into an array 
        var s = "www.google.com".toSlice(); 
        var delim = ".".toSlice(); 
        var parts = new string[](s.count(delim)); 
        for(uint i = 0; i < parts.length; i++) { 
            parts[i] = s.split(delim).toString(); 
        } 

        //Converting a slice back to a string 
        var myString = slice.toString(); 

        //Concatenating strings 
        var finalSlice = subslice.concat(slice); 

        //check if two strings are equal 
        if(slice.equals(subslice)) 
        { 

        } 
    } 
}

前述代码不言自明。

返回两个切片的函数有两个版本:一个是非分配版本,将第二个切片作为参数传入,修改原地;另一个是分配版本,分配并返回第二个切片;例如,让我们看一下以下示例:

var slice1 = "abc".toSlice(); 

//moves the string pointer of slice1 to point to the next rune (letter) 
//and returns a slice containing only the first rune 
var slice2 = slice1.nextRune(); 

var slice3 = "abc".toSlice(); 
var slice4 = "".toSlice(); 

//Extracts the first rune from slice3 into slice4, advancing the slice to point to the next rune and returns slice4\. 
var slice5 = slice3.nextRune(slice4);

您可以在github.com/Arachnid/Solidity-stringutils了解更多关于 strings 库的信息。

构建赌注合同

在我们的下注应用程序中,两个人可以选择在一场足球比赛上进行下注,一个人支持主队,另一个人支持客队。他们两人都应该下相同金额的赌注,获胜者将赢得所有的钱。如果比赛平局,那么他们两人将拿回他们的钱。

我们将使用 FastestLiveScores API 来查找比赛结果。它提供了一个免费的 API,让我们每小时可以免费进行 100 次请求。首先,去创建一个账号,然后生成一个 API 密钥。要创建一个账号,请访问customer.fastestlivescores.com/register,一旦账号创建完成,您将在customer.fastestlivescores.com/看到 API 密钥。您可以在docs.crowdscores.com/找到 API 文档。

在我们的应用程序中,每个人之间的每笔赌注都将部署一个赌注合同。合同将包含从FastestLiveScoresAPI 检索的比赛 ID、各方需要投资的 wei 金额以及各方的地址。一旦双方都投资了合同,他们将会得知比赛的结果。如果比赛尚未结束,那么他们将尝试在每 24 小时后检查结果。

这是合同的代码:

pragma Solidity ⁰.4.0; 

import "github.com/Oraclize/Ethereum-api/oraclizeAPI.sol"; 
import "github.com/Arachnid/Solidity-stringutils/strings.sol"; 

contract Betting is usingOraclize 
{ 
    using strings for *; 

    string public matchId; 
    uint public amount; 
    string public url; 

    address public homeBet; 
    address public awayBet; 

    function Betting(string _matchId, uint _amount, string _url)  
    { 
        matchId = _matchId; 
        amount = _amount; 
        url = _url; 

        oraclize_setProof(proofType_TLSNotary | proofStorage_IPFS); 
    } 

    //1 indicates home team 
    //2 indicates away team 
    function betOnTeam(uint team) payable 
    { 

        if(team == 1) 
        { 
            if(homeBet == 0) 
            { 
                if(msg.value == amount) 
                { 
                    homeBet = msg.sender;    
                    if(homeBet != 0 && awayBet != 0) 
                    { 
                        oraclize_query("URL", url); 
                    } 
                } 
                else 
                { 
                    throw; 
                } 
            } 
            else 
            { 
                throw; 
            } 
        } 
        else if(team == 2) 
        { 
            if(awayBet == 0) 
            { 
                if(msg.value == amount) 
                { 
                    awayBet = msg.sender;           

                    if(homeBet != 0 && awayBet != 0) 
                    { 
                        oraclize_query("URL", url); 
                    } 
                } 
                else 
                { 
                    throw; 
                } 
            } 
            else 
            { 
                throw; 
            } 
        } 
        else 
        { 
            throw; 
        } 
    } 

    function __callback(bytes32 myid, string result, bytes proof) { 
        if (msg.sender != oraclize_cbAddress()) 
        { 
            throw;     
        } 
        else 
        { 
            if(result.toSlice().equals("home".toSlice())) 
            { 
                homeBet.send(this.balance); 
            } 
            else if(result.toSlice().equals("away".toSlice())) 
            { 
                awayBet.send(this.balance); 
            } 
            else if(result.toSlice().equals("draw".toSlice())) 
            { 
                homeBet.send(this.balance / 2); 
                awayBet.send(this.balance / 2); 
            } 
            else 
            { 
                if (Oraclize.getPrice("URL") < this.balance)  
                { 
                    oraclize_query(86400, "URL", url); 
                } 
            } 
        } 
    } 
}

合同代码是不言自明的。现在使用solc.js或浏览器 Solidity 编译上述代码,具体取决于您所熟悉的情况。您将不需要链接strings库,因为其中的所有函数都设置为internal可见性。

在浏览器 Solidity 中,当指定从 HTTP URL 导入库或合同时,请确保它托管在 GitHub 上;否则,它将无法获取。在该 GitHub 文件 URL 中,请确保删除协议以及blob/{branch-name}

构建一个用于赌注合同的客户端

为了方便查找比赛 ID、部署和投资合同,我们需要构建一个 UI 客户端。所以让我们开始构建一个客户端,它将有两条路径,即主页路径用于部署合同和在比赛上下注,另一条路径用于查找比赛列表。我们将让用户使用他们自己的离线账户部署和下注,这样下注过程将以分散的方式进行,没有人可以作弊。

在我们开始构建客户端之前,请确保您已同步测试网,因为 Oraclize 仅在以太坊的测试网/主网上运行,而不在私有网络上运行。您可以通过用--testnet选项替换--dev选项来切换到测试网并开始下载测试网区块链。例如,请看以下内容:

geth --testnet --rpc --rpccorsdomain "*" --rpcaddr "0.0.0.0" --rpcport "8545"

预测结构

在本章的练习文件中,您将找到两个目录,即 Final 和 Initial。Final 包含项目的最终源代码,而 Initial 包含空源代码文件和库,可以快速开始构建应用程序。

要测试 Final 目录,您需要在其中运行 npm install,然后使用 node app.js 命令在 Final 目录内运行应用程序。

Initial 目录中,您将找到一个 public 目录和两个名为 app.jspackage.json 的文件。package.json 文件包含了我们应用的后端依赖,而 app.js 则是您要放置后端源代码的地方。

public 目录包含与前端有关的文件。在 public/css 中,您将找到 bootstrap.min.css,这是 bootstrap 库。在 public/html 中,您将找到 index.htmlmatches.ejs 文件,您将在其中放置我们应用的 HTML 代码,以及在 public/js 目录中,您将找到 web3.js 和 ethereumjs-tx 的 js 文件。在 public/js 中,您还将找到一个 main.js 文件,您将在其中放置我们应用的前端 JS 代码。您还将找到 Oraclize Python 工具来加密查询。

构建后端

让我们先构建应用程序的后端。首先,在初始目录内运行npm install来安装我们的后端所需的依赖。

这里是运行 express 服务并提供 index.html 文件和静态文件以及设置视图引擎的后端代码:

var express = require("express"); 
var app = express(); 

app.set("view engine", "ejs"); 

app.use(express.static("public")); 

app.listen(8080); 

app.get("/", function(req, res) { 
    res.sendFile(__dirname + "/public/html/index.html"); 
})

上面的代码是不言而喻的。现在让我们继续。我们的应用将有另一个页面,该页面将显示最近匹配的 ID 列表和结果(如果匹配已经结束)。这是端点的代码:

var request = require("request"); 
var moment = require("moment"); 

app.get("/matches", function(req, res) { 
    request("https://api.crowdscores.com/v1/matches?api_key=7b7a988932de4eaab4ed1b4dcdc1a82a", function(error, response, body) { 
        if (!error && response.statusCode == 200) { 
            body = JSON.parse(body); 

            for (var i = 0; i < body.length; i++) { 
             body[i].start = moment.unix(body[i].start / 
               1000).format("YYYY MMM DD hh:mm:ss"); 
            } 

            res.render(__dirname + "/public/html/matches.ejs", { 
                matches: body 
            }); 
        } else { 
            res.send("An error occured"); 
        } 
    }) 
})

在这里,我们正在进行 API 请求以获取最近匹配的列表,然后将结果传递给 matches.ejs 文件,以便它可以在用户友好的界面中呈现结果。API 结果以时间戳的形式给出了匹配的开始时间;因此,我们使用 moment 将其转换为人类可读的格式。我们从后端而不是从前端进行此请求,以便我们不会向用户公开 API 密钥。

我们的后端将为前端提供一个 API,通过该 API 前端可以在部署合同之前加密查询。我们的应用程序不会提示用户创建 API 密钥,因为这将是一个糟糕的用户体验实践。应用程序的开发者控制 API 密钥不会造成任何伤害,因为开发者无法修改来自 API 服务器的结果;因此,即使应用程序的开发者知道 API 密钥,用户仍将信任该应用程序。

这里是加密端点的代码:

var PythonShell = require("python-shell"); 

app.get("/getURL", function(req, res) { 
    var matchId = req.query.matchId; 

    var options = { 
        args: ["-e", "-p", "044992e9473b7d90ca54d2886c7addd14a61109af202f1c95e218b0c99eb060c7134c4ae46345d0383ac996185762f04997d6fd6c393c86e4325c469741e64eca9", "json(https://api.crowdscores.com/v1/matches/" + matchId + "?api_key=7b7a988932de4eaab4ed1b4dcdc1a82a).outcome.winner"], 
        scriptPath: __dirname 
    }; 

    PythonShell.run("encrypted_queries_tools.py", options, function 
      (err, results) { 
        if(err) 
        { 
            res.send("An error occured"); 
        } 
        else 
        { 
            res.send(results[0]); 
        } 
    }); 
})

我们已经看到如何使用这个工具。为了成功运行这个端点,请确保你的系统上安装了 Python。即使 Python 已经安装,端点可能仍然会显示错误,表明 Python 的加密和 base58 模块没有安装。因此,如果工具提示你安装这些模块,请确保你安装了它们。

构建前端

现在让我们构建应用程序的前端。我们的前端将允许用户查看最近比赛的列表、部署投丨注合约、投丨注比赛,并查看有关投丨注合约的信息。

我们首先来实现 matches.ejs 文件,它将显示最近比赛的列表。下面是该文件的代码:

<!DOCTYPE html>
<html lang="en">
    <head> 
         <meta charset="utf-8"> 
         <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> 
         <meta http-equiv="x-ua-compatible" content="ie=edge"> 
         <link rel="stylesheet" href="/css/bootstrap.min.css"> 
     </head> 
     <body> 
         <div class="container"> 
             <br> 
             <div class="row m-t-1"> 
                 <div class="col-md-12"> 
                     <a href="/">Home</a> 
                 </div> 
             </div> 
             <br> 
             <div class="row"> 
                 <div class="col-md-12"> 
                     <table class="table table-inverse"> 
                           <thead> 
                             <tr> 
                                 <th>Match ID</th> 
                                 <th>Start Time</th> 
                                 <th>Home Team</th> 
                                 <th>Away Team</th> 
                                 <th>Winner</th> 
                             </tr> 
                           </thead> 
                           <tbody> 
                               <% for(var i=0; i < matches.length; i++) { %> 
                                   <tr> 
                                       <td><%= matches[i].dbid %></td> 
                                       <% if (matches[i].start) { %> 
                                        <td><%= matches[i].start %></td> 
                                     <% } else { %> 
                                         <td>Time not finalized</td> 
                                     <% } %> 
                                       <td><%= matches[i].homeTeam.name %></td> 
                                       <td><%= matches[i].awayTeam.name %></td> 
                                       <% if (matches[i].outcome) { %> 
                                        <td><%= matches[i].outcome.winner %></td> 
                                     <% } else { %> 
                                         <td>Match not finished</td> 
                                     <% } %> 
                                 </tr> 
                             <% } %> 
                           </tbody> 
                     </table> 
                 </div> 
             </div> 
         </div> 
     </body> 
 </html>

前面的代码不言自明。现在让我们编写主页的 HTML 代码。我们的主页将显示三个表单。第一个表单是用于部署投丨注合约,第二个表单是用于投资投丨注合约,第三个表单是用于显示已部署的投丨注合约的信息。

这是主页的 HTML 代码。将这个代码放在 index.html 页面中:

<!DOCTYPE html> 
 <html lang="en"> 
     <head> 
         <meta charset="utf-8"> 
         <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> 
         <meta http-equiv="x-ua-compatible" content="ie=edge"> 
         <link rel="stylesheet" href="/css/bootstrap.min.css"> 
     </head> 
     <body> 
         <div class="container"> 
             <br> 
             <div class="row m-t-1"> 
                 <div class="col-md-12"> 
                     <a href="/matches">Matches</a> 
                 </div> 
             </div> 
             <br> 
             <div class="row"> 
                 <div class="col-md-4"> 
                     <h3>Deploy betting contract</h3> 
                     <form id="deploy"> 
                         <div class="form-group"> 
                             <label>From address: </label> 
                             <input type="text" class="form-control" id="fromAddress"> 
                         </div> 
                         <div class="form-group"> 
                             <label>Private Key: </label> 
                             <input type="text" class="form-control" id="privateKey"> 
                         </div> 
                         <div class="form-group"> 
                             <label>Match ID: </label> 
                             <input type="text" class="form-control" id="matchId"> 
                         </div> 
                         <div class="form-group"> 
                             <label>Bet Amount (in ether): </label> 
                             <input type="text" class="form-control" id="betAmount"> 
                         </div> 
                         <p id="message" style="word-wrap: break-word"></p> 
                         <input type="submit" value="Deploy" class="btn btn-primary" /> 
                     </form> 
                 </div> 
                 <div class="col-md-4"> 
                     <h3>Bet on a contract</h3> 
                     <form id="bet"> 
                         <div class="form-group"> 
                             <label>From address: </label> 
                             <input type="text" class="form-control" id="fromAddress"> 
                         </div> 
                         <div class="form-group"> 
                             <label>Private Key: </label> 
                             <input type="text" class="form-control" id="privateKey"> 
                         </div> 
                         <div class="form-group"> 
                             <label>Contract Address: </label> 
                             <input type="text" class="form-control"
id="contractAddress"> 
                         </div> 
                         <div class="form-group"> 
                             <label>Team: </label> 
                             <select class="form-control" id="team"> 
                                 <option>Home</option> 
                                 <option>Away</option> 
                             </select> 
                         </div> 
                         <p id="message" style="word-wrap: break-word"></p> 
                         <input type="submit" value="Bet" class="btn btn-primary" /> 
                     </form> 
                 </div> 
                 <div class="col-md-4"> 
                     <h3>Display betting contract</h3> 
                     <form id="find"> 
                         <div class="form-group"> 
                             <label>Contract Address: </label> 
                             <input type="text" class="form-control"  
 d="contractAddress"> 
                         </div> 
                         <p id="message"></p> 
                         <input type="submit" value="Find" class="btn btn-primary" /> 
                     </form> 
                 </div> 
             </div> 
         </div> 

         <script type="text/javascript" src="img/web3.min.js"></script> 
         <script type="text/javascript" src="img/ethereumjs-tx.js"></script> 
         <script type="text/javascript" src="img/main.js"></script> 
     </body> 
</html>

前面的代码不言自明。现在让我们编写用于实际部署合约、投资合约和显示合约信息的 JavaScript 代码。这里是所有这些的代码。将这个代码放在 main.js 文件中:

var bettingContractByteCode = "6060604..."; 
var bettingContractABI = [{"constant":false,"inputs":[{"name":"team","type":"uint256"}],"name":"betOnTeam","outputs":[],"payable":true,"type":"function"},{"constant":false,"inputs":[{"name":"myid","type":"bytes32"},{"name":"result","type":"string"}],"name":"__callback","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"myid","type":"bytes32"},{"name":"result","type":"string"},{"name":"proof","type":"bytes"}],"name":"__callback","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"url","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"matchId","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"amount","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"homeBet","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"awayBet","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"inputs":[{"name":"_matchId","type":"string"},{"name":"_amount","type":"uint256"},{"name":"_url","type":"string"}],"payable":false,"type":"constructor"}]; 

var web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545")); 

function getAJAXObject() 
{ 
   var request; 
   if (window.XMLHttpRequest) { 
       request = new XMLHttpRequest(); 
   } else if (window.ActiveXObject) { 
       try { 
           request = new ActiveXObject("Msxml2.XMLHTTP"); 
       } catch (e) { 
           try { 
               request = new ActiveXObject("Microsoft.XMLHTTP"); 
           } catch (e) {} 
       } 
   } 

   return request; 
} 

document.getElementById("deploy").addEventListener("submit", function(e){ 
   e.preventDefault(); 

   var fromAddress = document.querySelector("#deploy #fromAddress").value; 
   var privateKey = document.querySelector("#deploy #privateKey").value; 
   var matchId = document.querySelector("#deploy #matchId").value; 
   var betAmount = document.querySelector("#deploy #betAmount").value; 

   var url = "/getURL?matchId=" + matchId; 

   var request = getAJAXObject(); 

   request.open("GET", url); 

   request.onreadystatechange = function() { 
       if (request.readyState == 4) { 
           if (request.status == 200) { 
               if(request.responseText != "An error occured") 
               { 
           var queryURL = request.responseText; 

           var contract = web3.eth.contract(bettingContractABI); 
           var data = contract.new.getData(matchId, 
             web3.toWei(betAmount, "ether"), queryURL, { 
               data: bettingContractByteCode 
                }); 

           var gasRequired = web3.eth.estimateGas({ data: "0x" + data
             }); 

      web3.eth.getTransactionCount(fromAddress, function(error, nonce){ 

       var rawTx = { 
            gasPrice: web3.toHex(web3.eth.gasPrice), 
             gasLimit: web3.toHex(gasRequired), 
              from: fromAddress, 
               nonce: web3.toHex(nonce), 
                data: "0x" + data, 
                 }; 

      privateKey = EthJS.Util.toBuffer(privateKey, "hex"); 

       var tx = new EthJS.Tx(rawTx); 
       tx.sign(privateKey); 

      web3.eth.sendRawTransaction("0x" + 
       tx.serialize().toString("hex"), function(err, hash) { 
            if(!err) 
                {document.querySelector("#deploy #message").
                   innerHTML = "Transaction Hash: " + hash + ". 
                     Transaction is mining..."; 

            var timer = window.setInterval(function(){ 
            web3.eth.getTransactionReceipt(hash, function(err, result){ 
            if(result) 
             {window.clearInterval(timer); 
       document.querySelector("#deploy #message").innerHTML = 
         "Transaction Hash: " + hash + " and contract address is: " + 
             result.contractAddress;} 
               }) 
                }, 10000) 
                 } 
             else 
           {document.querySelector("#deploy #message").innerHTML = err; 
             } 
           }); 
          }) 

          } 
           } 
       } 
   }; 

   request.send(null); 

}, false) 

document.getElementById("bet").addEventListener("submit", function(e){ 
   e.preventDefault(); 

   var fromAddress = document.querySelector("#bet #fromAddress").value; 
   var privateKey = document.querySelector("#bet #privateKey").value; 
   var contractAddress = document.querySelector("#bet #contractAddress").value; 
   var team = document.querySelector("#bet #team").value; 

   if(team == "Home") 
   { 
         team = 1; 
   } 
   else 
   { 
         team = 2; 
   }  

   var contract = web3.eth.contract(bettingContractABI).at(contractAddress); 
   var amount = contract.amount(); 

   var data = contract.betOnTeam.getData(team); 

   var gasRequired = contract.betOnTeam.estimateGas(team, { 
         from: fromAddress, 
         value: amount, 
         to: contractAddress 
   }) 

   web3.eth.getTransactionCount(fromAddress, function(error, nonce){ 

         var rawTx = { 
           gasPrice: web3.toHex(web3.eth.gasPrice), 
           gasLimit: web3.toHex(gasRequired), 
           from: fromAddress, 
           nonce: web3.toHex(nonce), 
           data: data, 
           to: contractAddress, 
           value: web3.toHex(amount) 
       }; 

       privateKey = EthJS.Util.toBuffer(privateKey, "hex"); 

       var tx = new EthJS.Tx(rawTx); 
         tx.sign(privateKey); 

         web3.eth.sendRawTransaction("0x" + tx.serialize().toString("hex"), function(err, hash) { 
               if(!err) 
               { 
    document.querySelector("#bet #message").innerHTML = "Transaction 
      Hash: " + hash; 
        } 
      else 
       { 
       document.querySelector("#bet #message").innerHTML = err; 
      } 
     }) 
   }) 
    }, false) 

document.getElementById("find").addEventListener("submit", function(e){ 
   e.preventDefault(); 

   var contractAddress = document.querySelector("#find 
     #contractAddress").value; 
   var contract =  
      web3.eth.contract(bettingContractABI).at(contractAddress); 

   var matchId = contract.matchId(); 
   var amount = contract.amount(); 
   var homeAddress = contract.homeBet(); 
   var awayAddress = contract.awayBet(); 

   document.querySelector("#find #message").innerHTML = "Contract balance is: " + web3.fromWei(web3.eth.getBalance(contractAddress), "ether") + ", Match ID is: " + matchId + ", bet amount is: " + web3.fromWei(amount, "ether") + " ETH, " + homeAddress + " has placed bet on home team and " + awayAddress + " has placed bet on away team"; 
}, false)

前面代码的工作原理如下:

  1. 首先,我们将合约的字节码和 ABI 分别存储在 bettingContractByteCodebettingContractABI 变量中。

  2. 然后,我们创建一个连接到测试网节点的 Web3 实例。

  3. 接下来,我们有 getAJAXObject 函数(一个跨浏览器兼容的函数),它返回一个 AJAX 对象。

  4. 然后,我们将 submit 事件监听器附加到第一个表单上,该表单用于部署合约。在事件监听器的回调中,我们通过传递 matchIdgetURL 端点发出请求,以获取加密的查询字符串。然后,我们生成用于部署合约的数据。接着,我们找出所需的 gas。我们使用函数对象的 estimateGas 方法来计算所需的 gas,但你也可以使用 web3.eth.estimateGas 方法。两者在参数上有所不同;也就是说,在前一种情况下,你不需要传递交易数据。请记住,如果函数调用抛出异常,estimateGas 会返回区块 gas 限制。然后,我们计算随机数。这里,我们只是使用 getTransactionCount 方法,而不是我们之前学到的实际流程。这样做只是为了简化代码。然后,我们创建原始交易,签署它并广播。一旦交易被挖掘,我们就显示合约地址。

  5. 然后,我们为第二个表格附加了一个submit事件侦听器,用于投资合约。在这里,我们生成了交易的data部分,计算所需的 gas,创建原始交易,签名并广播。在计算交易所需的 gas 时,我们从帐户地址和 value 对象属性传递合约地址的值,因为这是一个函数调用,gas 因取决于值、from 地址和合约地址而异。请记住,在寻找调用合同函数所需的 gas 时,您可以传递to,fromvalue属性,因为 gas 取决于这些值。

  6. 最后,我们为第三个表单添加了一个submit事件侦听器,即显示已部署投丨注合同的信息。

测试客户端

现在我们已经完成了建设我们的投丨注平台,是时候进行测试了。在测试之前,请确保测试网区块链已完全下载并正在寻找新的入块。

现在使用我们之前建立的钱包服务,生成三个帐户。使用faucet.ropsten.be:3001/给每个帐户加一 ether。

然后,在Initial目录中运行node app.js,然后访问http://localhost:8080/matches,您将看到以下屏幕截图中显示的内容:

在这里,您可以复制任何比赛 ID。假设您想要测试第一场比赛,即 123945。现在访问http://localhost:8080,您将看到以下屏幕截图中显示的内容:

现在通过填写第一个表格中的输入字段并单击“部署”按钮来部署合同,如图所示。使用您的第一个帐户来部署合同。

现在从第二个账户对合同的主队进行下注,从第三个账户对客队进行下注,如以下截图所示:

现在将合约地址放在第三个表格上,然后单击“查找”按钮,以查看有关合约的详细信息。您将看到类似于以下屏幕截图的内容:

一旦两个交易都被挖掘,再次检查合同的详细信息,您将看到类似于以下屏幕截图的内容:

在这里,您可以看到该合约没有任何以太币,所有以太币都转入了下注主队的账户。

总结

在这一章中,我们深入学习了关于 Oraclize 和 strings 库。我们将它们结合起来构建了一个去中心化的投丨注平台。现在,你可以根据自己的需求前进并定制合同和客户端。为了增强应用程序,你可以向合同添加事件,并在客户端上显示通知。我们的目标是理解去中心化投丨注应用程序的基本架构。

第十三章:Hyperledger

Hyperledger 不是一个区块链,而是一个由 Linux 基金会于 2015 年 12 月发起的项目,旨在推进区块链技术。这个项目是其成员的合作努力,旨在构建一个开源的分布式账本框架,可用于开发和实施跨行业的区块链应用和系统。主要关注点是开发和运行支持全球业务交易的平台。该项目还专注于提高区块链系统的可靠性和性能。

Hyperledger 旗下的项目经历了从提案到孵化再到转入活跃状态的各个阶段。项目也可能被弃用或处于生命周期结束状态,不再积极开发。要使项目能够进入孵化阶段,必须具有完全可工作的代码库以及活跃的开发人员社区。

Hyperledger 旗下的项目

Hyperledger 旗下有两类项目。第一类是 区块链项目,第二类是 支持这些区块链的相关工具或模块

目前,Hyperledger 旗下有五个区块链框架项目:FabricSawtooth LakeIrohaBurrowIndy。在模块下,有 Hyperledger CelloHyperledger ComposerHyperledger ExplorerHyperledger Quilt。Hyperledger 项目目前拥有超过 200 个成员组织,非常活跃,有许多贡献者,并在全球范围内组织定期的见面会和讲座。

接下来简要介绍所有这些项目,之后我们将看到有关 Fabric 和 Sawtooth Lake 的设计、架构和实施的更多详细信息。

Fabric

Fabric 是由 IBMDAH (Digital Asset Holdings) 提出的一个区块链项目。该区块链框架实现旨在为具有模块化架构的区块链解决方案的开发提供基础。它基于可插拔架构,各种组件,如共识引擎和成员服务,可以根据需要插入系统。它还利用容器技术,在隔离的容器化环境中运行智能合约。目前,它的状态是 活跃,是第一个从孵化阶段毕业到活跃状态的项目。

源代码可在 github.com/hyperledger/fabric 获得。

锯齿湖

Sawtooth Lake 是由英特尔于 2016 年 4 月提出的一个区块链项目,它具有一些关键创新,重点是将分类账与交易解耦,使用交易家族在多个业务领域灵活使用,并提供可插拔的共识机制。

解耦可以更精确地解释为通过使用称为事务族的新概念将事务与共识层解耦。不再单独将事务与分类帐耦合,而是使用事务族,这允许更灵活、更丰富的语义和业务逻辑的开放设计。事务遵循事务族中定义的模式和结构。

英特尔引入的一些创新元素包括一种名为PoET的新型共识算法,即Proof of Elapsed Time,它利用英特尔提供的受信执行环境TEE)提供的英特尔软件保护扩展Intel's SGX)来提供安全和随机的领导者选举过程。它还支持有权限和无权限的设置。

该项目可在 github.com/hyperledger/sawtooth-core 上找到。

Iroha

Iroha 由 Soramitsu、Hitachi、NTT Data 和 Colu 在 2016 年 9 月贡献。Iroha 的目标是构建一个可重复使用的组件库,用户可以选择在自己的基于 Hyperledger 的分布式分类帐上运行。

Iroha 的主要目标是通过提供用 C++ 编写的重复使用的组件,重点放在移动开发上,来补充其他 Hyperledger 项目。该项目还提出了一种称为Sumeragi的新型共识算法,这是一种基于链的拜占庭容错共识算法。

Iroha 可在 github.com/hyperledger/iroha 上找到。

Iroha 已提出并正在研究各种库,包括但不限于数字签名库(ed25519)、SHA-3 哈希库、事务序列化库、P2P 库、API 服务器库、iOS 库、Android 库和 JavaScript 库。

Burrow

该项目目前处于孵化状态。Hyperledger Burrow 由 Monax 贡献,他们为企业开发区块链开发和部署平台。Hyperledger Burrow 引入了一个模块化的区块链平台和基于以太坊虚拟机EVM)的智能合约执行环境。Burrow 使用权益证明、拜占庭容错 Tendermint 共识机制。因此,Burrow 提供了高吞吐量和交易最终性。

源代码可在 github.com/hyperledger/burrow 上找到。

Indy

该项目正在 Hyperledger 的孵化过程中。Indy 是为构建去中心化身份而开发的分布式分类帐。它提供了用于构建基于区块链的数字身份的工具、实用库和模块。这些身份可以跨多个区块链、域和应用程序使用。Indy 有自己的分布式分类帐,并使用冗余拜占庭容错RBFT)进行共识。

源代码可在此处找到:github.com/hyperledger/indy-node

Explorer

该项目旨在为 Hyperledger Fabric 构建一个区块链浏览器,可用于查看和查询来自区块链的交易、区块和相关数据。它还提供网络信息和与链码交互的能力。

目前,还有其他几个项目正在 Hyperledger 的孵化中。这些项目旨在提供支持区块链网络的工具和实用程序。这些项目将在接下来的章节中介绍。

源代码可在此处找到:github.com/hyperledger/blockchain-explorer

Cello

Cello 的目标是允许轻松部署区块链。这将提供一种能力,允许区块链服务的“即服务”部署。目前,该项目处于孵化阶段。

Cello 的源代码可在此处找到:github.com/hyperledger/cello

Composer

该实用工具使区块链解决方案的开发变得更加容易,它允许使用业务语言描述业务流程,同时将低级智能合约开发细节抽象化。

Hyperledger composer 可在此处找到。

Quilt

该实用工具实现了跨不同分布式和非分布式账本网络的互操作性的 Interledger 协议。

Quilt 可在此处找到:github.com/hyperledger/quilt

目前,所有提及的项目都处于不同阶段的开发中。

随着越来越多的成员加入 Hyperledger 项目并为区块链技术的发展做出贡献,此列表预计会不断增长。现在,在下一节中,我们将看到 Hyperledger 的参考架构,该架构提供了可以遵循以构建新的 Hyperledger 项目的一般原则和设计理念。

超级账本协议

超级账本旨在构建由行业用例驱动的新区块链平台。由于社区对 Hyperledger 项目做出了许多贡献,因此 Hyperledger 区块链平台正在演变为一种用于业务交易的协议。Hyperledger 还正在演变为可用作参考的规范,以构建区块链平台,与早期仅解决特定行业或需求的区块链解决方案相比。

在接下来的章节中,我们将介绍一个由 Hyperledger 项目发布的参考架构。由于这项工作正在不断而严格地发展,因此其中可能会有一些变化,但核心服务预计将保持不变。

参考架构

Hyperledger 已经发表了一份白皮书,可在docs.google.com/document/d/1Z4M_qwILLRehPbVRUsJ3OF8Iir-gqS-ZYe7W-LE9gnE/edit#heading=h.m6iml6hqrnm2获取。

本文提供了一个参考架构,可作为构建许可分布式分类账的指南。这个参考架构由形成业务区块链的各种组件组成。这些高级组件在以下这个参考架构图中显示:

参考架构 - 来源:Hyperledger 白皮书

从左边开始,可以看到我们有五个顶层组件,它们提供各种服务。我们将详细探讨所有这些组件。

首先是身份,它在成员服务下提供授权、识别和认证服务。

接着是策略组件,它提供策略服务。

随后是分类账和交易,其中包括分布式分类账、排序服务、网络协议,以及认可和验证服务。分类账只能通过区块链网络参与者之间的共识来更新。

最后,我们有智能合约层,它在 Hyperledger 中提供链码服务,并利用安全容器技术来托管智能合约。我们稍后将更详细地看到Hyperledger Fabric部分中的所有这些内容。

一般来说,从组件的角度来看,Hyperledger 包含了这里描述的各种元素:

  • 共识层:这些服务负责促进区块链网络参与者之间的协议达成过程。共识是必须的,以确保交易的顺序和状态在区块链网络中得到验证和达成一致。

  • 智能合约层:这些服务负责根据用户的需求实现业务逻辑。交易是基于区块链上的智能合约中定义的逻辑来处理的。

  • 通信层:这一层负责在区块链网络中的节点之间进行消息传输和交换。

  • 安全和加密层:这些服务负责提供能力,允许使用各种加密算法或模块来提供隐私、保密和不可抵赖的服务。

  • 数据存储:这一层提供了使用不同数据存储来存储分类账状态的能力。这意味着数据存储也是可插拔的,并允许使用任何数据库后端。

  • 策略服务:这组服务提供管理区块链网络所需的不同策略的能力。这包括认可策略和共识策略。

  • APIs 和 SDKs:该层允许客户端和应用程序与区块链进行交互。SDK 用于提供机制来部署和执行链码,查询区块并监视区块链上的事件。

区块链服务有一定的要求。在下一节中,我们将讨论 Hyperledger Fabric 的设计目标。

Hyperledger Fabric 的需求和设计目标

区块链服务有一定的要求。参考架构是由 Hyperledger 项目的参与者提出的需求和要求驱动的,并在研究行业用例后进行了讨论。从对工业用例的研究中推导出了几类需求,这些需求将在以下部分进行讨论。

模块化方法

Hyperledger 的主要要求是模块化结构。预计作为跨行业面料(区块链),它将在许多业务场景中使用。因此,与存储、策略、链码、访问控制、共识等其他区块链服务相关的功能应该是模块化和可插拔的。规范建议模块应该是即插即用的,用户应该能够轻松地移除和添加满足业务需求的不同模块。

隐私和保密性

此需求是最关键的因素之一。传统的区块链是无许可的,而在 Hyperledger Fabric 这样的许可模型中,网络上的交易对于只有被允许查看的人可见非常重要。

在业务区块链中,交易和合同的隐私和保密性至关重要。因此,Hyperledger 的愿景是支持全面的加密协议和算法。我们在第五章和第六章中讨论了密码学,对称密码学公钥密码学

预计用户将能够根据其业务需求选择适当的模块。例如,如果业务区块链只需要在已经信任的各方之间运行并执行非常基本的业务操作,则可能无需为保密性和隐私提供先进的加密支持。因此,用户应该能够移除该功能(模块)或将其替换为更合适的模块以满足其需求。

同样,如果用户需要运行跨行业区块链,则保密性和隐私可能非常重要。在这种情况下,用户应该能够将先进的加密和访问控制机制(模块)插入到区块链(面料)中,甚至可以允许使用安全模块的硬件(HSMs)。

此外,区块链应能够处理复杂的加密算法,而不会影响性能。除了上述场景外,由于业务中的监管要求,还应该能够按照监管和合规要求的隐私和保密政策来执行。

可扩展性

这是另一个重要的需求,一旦满足,将允许合理的交易吞吐量,这将足以满足所有业务需求,也足够为大量用户提供服务。

确定性交易

这是任何区块链的核心需求,因为如果交易无论何时执行产生相同的结果,无论交易由谁在何处执行,共识都是不可能实现的。因此,在任何区块链网络中,确定性交易成为关键要求。我们在第四章 智能合同 中讨论了这些概念。

身份

为了提供隐私和保密服务,还需要一个灵活的 PKI 模型来处理访问控制功能。加密机制的强度和类型也预计会根据用户的需求和要求而变化。在某些场景中,可能需要用户隐藏他们的身份,因此,期望 Hyperledger 提供这一功能。

审计性

审计性是 Hyperledger Fabric 的另一个需求。预期保留所有身份、相关操作和任何更改的不可变审计跟踪。

互操作性

目前有许多可用的区块链平台,但它们之间无法进行通信,这可能限制了区块链全球业务生态系统的发展。预计许多区块链网络将在业务世界中为特定需求而运行,但它们能够相互通信非常重要。应该有一套所有区块链都可以遵循的共同标准,以便允许不同分类账之间的通信。预计将开发一个协议,允许在多个链之间交换信息。

可移植性

可移植性要求关注的是在不需要在代码级别更改任何内容的情况下能够在多个平台和环境中运行。预期 Hyperledger Fabric 在基础设施级别以及代码、库和 API 级别都是可移植的,这样可以支持在各种 Hyperledger 实现中进行统一开发。

丰富的数据查询

区块链网络应允许在网络上运行丰富的查询。这可以用于使用传统查询语言查询总账的当前状态,从而实现更广泛的采用和使用便利。

所有上述点描述了开发符合 Hyperledger 设计理念的区块链解决方案所需满足的要求。在接下来的部分中,我们将看一下 Hyperledger Fabric,这是首个在 Hyperledger 下获得活跃状态的项目。

Fabric

要了解 Hyperledger 项目中正在开发的各种项目,首先需要了解 Hyperledger 的基础知识是很重要的。在向读者介绍更深入的材料之前,需要对一些特定于 Hyperledger 的术语进行一些澄清。

首先,有一个“fabric”的概念。Fabric 可以定义为提供基础层的组件集合,可用于交付区块链网络。Fabric 网络有各种类型和功能,但所有 fabric 都共享诸如不可变性和共识驱动等共同属性。一些 fabric 可以提供一种模块化方法来构建区块链网络。在这种情况下,区块链网络可以具有多个可插拔模块,用于在网络上执行各种功能。

例如,共识算法可以是区块链网络中的可插拔模块,根据网络的要求,可以选择适当的共识算法并将其插入网络中。这些模块可以基于 fabric 的某些特定规范,并且可以包括 API、访问控制和各种其他组件。

Fabric 也可以设计为私有或公开的,并且可以允许创建多个业务网络。例如,比特币就是在其 fabric(区块链网络)上运行的应用程序。正如前文第一章讨论的那样,区块链 101,区块链可以是许可的或无许可的。然而,Hyperledger Fabric 的目标是开发一个许可的分布式分类账。

Fabric 也是 IBM 向 Hyperledger 基金会提供的代码贡献的名称,正式称为 Hyperledger Fabric。IBM 还通过其IBM 云服务提供区块链即服务(IBM Blockchain)。

它可以在www.ibm.com/cloud/找到。

现在让我们详细看一下 Hyperledger Fabric。

Hyperledger Fabric

该框架最初是由 IBM 和 Digital Assets 对 Hyperledger 项目的贡献。这一贡献旨在实现一种模块化、开放和灵活的方法,用于构建区块链网络。

Fabric 中的各种功能都是可插拔的,并且它还允许使用任何语言来开发智能合约。这种功能是可能的,因为它基于容器技术(Docker),可以托管任何语言。

Chaincode 在安全容器中进行沙盒化处理,其中包括安全操作系统、chaincode 语言、运行时环境以及用于 Go、Java 和 Node.js 的 SDK。如果需要,将来还可以支持其他语言,但需要进行一些开发工作。智能合约在 Fabric 中被称为 chaincode。与以太坊中的领域特定语言或比特币中的有限脚本语言相比,这种能力是一个引人注目的特性。这是一个有权限的网络,旨在解决可扩展性、隐私和机密性等问题。其背后的基本思想是模块化,这将允许在业务区块链的设计和实现中灵活性。这样可以实现可扩展性、隐私和其他所需特性,并根据要求对其进行微调。

Fabric 中的交易对于普通用户是私有的、保密的和匿名的,但它们仍然可以被授权的审计员追踪和与用户关联。作为一个有权限的网络,所有参与者都需要在成员服务中注册才能访问区块链网络。此分类帐还提供了审计功能,以满足用户所需的监管和合规性需求。

成员服务

这些服务用于为 Fabric 网络的用户提供访问控制功能。以下列出了成员服务执行的功能:

  • 用户身份验证

  • 用户注册

  • 根据用户角色分配适当的权限

成员服务利用证书机构来支持身份管理和授权操作。这个 CA 可以是内部的(Fabric CA),它是 Hyperledger Fabric 中的默认接口,或者组织可以选择使用外部证书机构。Fabric CA 发布注册证书E-Certs),这些证书由注册证书机构E-CA)生成。一旦对等体被授予身份,它们就被允许加入区块链网络。还有临时证书称为 T-Certs,用于一次性交易。

所有对等体和应用程序都使用证书机构进行识别。证书机构提供认证服务。MSP 还可以与现有的身份服务(如 LDAP)进行接口。

区块链服务

区块链服务是 Hyperledger Fabric 的核心。此类别中的组件如下。

共识服务

共识服务负责提供与共识机制的接口。这充当了一个可插拔的模块,接收来自其他 Hyperledger 实体的交易,并根据选择的机制类型执行它们的标准。

Hyperledger V1 中的共识是作为一个称为订购者的节点实现的,负责将交易按顺序组成一个区块。订购者不持有智能合约或账本。共识是可插拔的,目前 Hyperledger Fabric 中有两种类型的排序服务可用:

  • SOLO:这是一个基本的排序服务,用于开发和测试目的。

  • Kafka:这是 Apache Kafka 的一种实现,提供排序服务。需要注意的是,目前 Kafka 只提供了崩溃容错性,但并没有提供拜占庭容错性。这在准许网络中是可以接受的,因为恶意行为的可能性几乎为零。

除了这些机制之外,基于简单拜占庭容错SBFT)的机制也正在开发中,将在后续版本的 Hyperledger Fabric 中提供。

分布式账本

区块链和世界状态是分布式账本的两个主要元素。区块链简单来说是一个由区块构成的加密链接列表(如第一章介绍的,区块链 101),而世界状态是一个键值数据库。这个数据库被智能合约用来在执行过程中存储相关状态。区块链由包含交易的区块组成。这些交易包含链码,运行这些交易可以导致更新世界状态。每个节点将世界状态保存在硬盘上,使用的是 LevelDB 或 CouchDB,具体取决于实现。由于 Fabric 允许可插拔的数据存储,你可以选择任何数据存储方式进行存储。

区块由三个主要组件组成,称为区块头、交易(数据)和区块元数据。

以下图示展示了 Hyperledger Fabric 1.0 中典型区块的相关字段:

区块结构

区块头 包括三个字段,即编号、前一个哈希和数据哈希。

交易 由多个字段组成,例如交易类型、版本、时间戳、通道 ID、交易 ID、时代、有效载荷可见性、链码路径、链码名称、链码版本、创建者身份、签名、链码类型、输入、超时、背书者身份和签名、建议哈希、链码事件、响应状态、命名空间、读集、写集、起始键、结束键、读取列表和 Merkle 树查询摘要。

区块元数据 包括创建者身份、相关签名、最后配置区块编号、每个包含在区块中的交易的标志,以及最后持久化的偏移量(kafka)。

点对点协议

Hyperledger Fabric 中的 P2P 协议是使用 Google RPCgRPC)构建的。它使用协议缓冲区来定义消息的结构。

节点之间传递消息以执行各种功能。Hyperledger Fabric 中有四种主要类型的消息:发现交易同步共识。发现消息在启动时在节点之间交换,以发现网络上的其他对等节点。交易消息用于部署、调用和查询交易,共识消息在共识期间交换。同步消息在节点之间传递以保持区块链在所有节点上同步更新。

分类账存储

为了保存分类账的状态,默认情况下使用 LevelDB,该数据库在每个对等节点上都可用。另一种选择是使用 CouchDB,它提供了运行丰富查询的能力。

Chaincode 服务

这些服务允许创建用于执行链码的安全容器。此类别中的组件如下:

  • 安全容器:Chaincode 部署在提供锁定的沙箱环境以供智能合约执行的 Docker 容器中。目前,Golang 被支持为主要的智能合约语言,但如果需要,可以添加和启用任何其他主流语言。

  • 安全注册表: 这提供了包含智能合约的所有映像的记录。

事件

区块链上的事件可以由背书者和智能合约触发。外部应用程序可以通过事件适配器监听这些事件,并在需要时做出反应。

API 和 CLI

应用程序编程接口通过公开各种 REST API 提供了与织物的接口。此外,还提供了提供一组 REST API 子集并允许快速测试和与区块链有限交互的命令行界面。

组成部分的织物

有各种各样的组件可以成为 Hyperledger Fabric 区块链的一部分。这些组件包括但不限于分类账、链码、共识机制、访问控制、事件、系统监控和管理、钱包以及系统集成组件。

对等节点

对等节点参与维护分布式分类账的状态。它们还持有分布式分类账的本地副本。对等节点通过八卦协议进行通信。在 Hyperledger Fabric 网络中有三种类型的对等节点:

  • 背书对等节点 或背书者模拟交易执行并生成读写集。读取是模拟交易从分类账中读取数据,写入是在交易执行和提交到分类账时将要对分类账进行的更新集。背书者执行和背书交易。值得注意的是,背书者也是提交者。背书策略是用链码实现的,并指定交易背书的规则。

  • 提交对等方或提交者接收由背书者背书的交易,对其进行验证,然后使用读写集更新分类帐。提交者验证背书者生成的读写集以及交易验证。

  • 提交者是尚未实现的第三种类型的对等方。它在开发路线图上,并将被实现。

订购节点

订购节点从背书者那里接收交易以及读写集,将它们按顺序排列,并将其发送给提交对等方。提交对等方随后执行验证并将其提交到分类帐。

所有对等方都使用成员服务发放的证书。

客户端

客户端是利用 API 与 Hyperledger Fabric 进行交互并提出交易的软件。

通道

通道允许网络上不同方之间的保密交易流动。它们允许在相同的区块链网络中使用不同的区块链。通道只允许通道成员查看与他们相关的交易,网络的所有其他成员将无法查看这些交易。

世界状态数据库

世界状态反映了区块链上所有已提交的交易。这基本上是一个键值存储,随着交易和链码执行的结果而更新。为此,通常使用 LevelDB 或 CouchDB。LevelDB 是一个键值存储,而 CouchDB 将数据存储为 JSON 对象,允许对数据库运行丰富的查询。

交易

交易消息可分为两种类型:部署交易调用交易。前者用于将新的链码部署到分类帐上,而后者用于从智能合约调用函数。交易可以是公开的或保密的。公开交易对所有参与者开放并可用,而保密交易仅在对其参与者开放的频道中可见。

成员服务提供商(MSP)

MSP 是用于管理区块链网络上身份的模块化组件。此提供程序用于验证想要加入区块链网络的客户端的身份。我们在本章前面已经详细讨论了证书颁发机构。CA 在 MSP 中用于提供身份验证和绑定服务。

智能合约

我们在第四章中详细讨论了智能合约,智能合约。在 Hyperledger Fabric 中,实现了相同的智能合约概念,但称为链代码而不是智能合约。它们包含条件和参数以执行交易并更新分类帐。链代码通常用 Golang 和 Java 编写。

加密服务提供商

顾名思义,这是一个提供加密算法和标准以供区块链网络使用的服务。此服务提供密钥管理、签名和验证操作以及加密解密机制。此服务与成员服务一起使用,为区块链的元素(如认可者、客户端和其他节点和对等体)提供加密操作支持。

在介绍了 Hyperledger Fabric 的这个组件之后,在下一节中,我们将看到在 Hyperledger 网络上运行的应用程序是什么样子的。

区块链上的应用程序

Fabric 上的典型应用程序通常仅由一个用户界面组成,通常使用 JavaScript/HTML 编写,该用户界面通过 API 层与存储在账本上的后端链码(智能合约)进行交互:

典型的 Fabric 应用程序

Hyperledger 提供了各种 API 和命令行接口,以实现与账本的交互。这些 API 包括身份、交易、链码、账本、网络、存储和事件接口。

链码实现

链码通常是用 Golang 或 Java 编写的。链码可以是公共的(在网络上对所有人可见)、机密的或受访控制的。这些代码文件充当了用户可以通过 API 与之交互的智能合约。用户可以调用链码中的函数来导致状态更改,从而更新账本。

还有一些仅用于查询账本且不会导致任何状态更改的函数。链码实现是通过首先在代码中创建链码 shim 接口来完成的。Shim 提供了用于访问链码的状态变量和事务上下文的 API。它可以是 Java 或 Golang 代码。

为了实现链码,需要以下四个函数:

  • Init(): 当链码部署到账本上时,将调用此函数。这会初始化链码并导致状态更改,相应地更新账本。

  • Invoke(): 当执行合约时使用此函数。它将一个函数名称和参数数组作为参数。此函数会导致状态更改并写入账本。

  • Query(): 此函数用于查询已部署链码的当前状态。此函数不会对账本进行任何更改。

  • 4(): 当对等体部署自己的链码副本时执行此函数。使用此函数向对等体注册链码。

以下图示了 Hyperledger Fabric 的一般概述,请注意,顶部的对等体集群包括各种类型的节点,如认可者、提交者、Orderers 等。

Hyperledger Fabric 的高层概述

上述图表显示,位于顶部中间的对等体相互通信,每个节点都有区块链的副本。在图像的右上角,显示了成员服务,通过证书颁发机构CA)对网络上的对等方进行验证和认证。在图像的底部,放大了区块链的视图,现有系统可以为区块链产生事件,也可以监听区块链的事件,然后可以选择性地触发操作。在图像的右下方,显示了用户与应用程序的交互,该应用程序通过invoice()方法与智能合约交互,并且智能合约可以查询或更新区块链的状态。

应用程序模型

超级账本 Fabric 的任何区块链应用程序都遵循 MVC-B 架构。这是基于流行的 MVC 设计模式。该模型中的组件包括模型、视图、控制和区块链:

  • 视图逻辑:与用户界面有关。可以是桌面、Web 应用程序或移动前端。

  • 控制逻辑:这是用户界面、数据模型和 API 之间的协调者。

  • 数据模型:该模型用于管理链下数据。

  • 区块链逻辑:这用于通过控制器管理区块链和通过交易管理数据模型。

IBM 云服务提供区块链示例应用,作为其区块链即服务的一部分。该服务可在www.ibm.com/blockchain/platform/获取。该服务允许用户在易于使用的环境中创建自己的区块链网络

超级账本 Fabric 中的共识

超级账本 Fabric 中的共识机制包括三个步骤:

  1. 交易认可:这个过程通过模拟交易执行过程对交易进行认可。

  2. 排序:这是由订购者集群提供的服务,它接受认可的交易并决定交易将被写入分类帐的顺序。

  3. 验证和承诺:这个过程由提交对等方执行,首先验证来自订购者的交易,然后将该交易提交到分类帐上。

这些步骤在下面的流程图中显示:

共识流程

超级账本 Fabric 中的交易生命周期

在超级账本 Fabric 中,交易流程涉及几个步骤。这些步骤在下面的图表中显示如下

过程的快速概述可以在下面的图表中看到:

交易生命周期

以下是详细描述的步骤:

  1. 客户端提出交易建议。这是第一步,客户端提出交易并将其发送到分布式分类帐网络上的背书节点。所有客户端在提出交易之前都需要通过成员服务进行注册。

  2. 背书者模拟交易,生成读写(RW)集。这是通过执行链码来实现的,但是不是更新分类帐,而是仅创建一个读写集,其中包含对分类帐的任何读取或更新。

  3. 背书的交易发送回应用程序。

  4. 应用程序将背书的交易和读写(RW)集提交给排序服务。

  5. 排序服务将所有背书交易和读写集按照通道 ID 排序,组装成一个区块。

  6. 排序服务将组装好的区块广播给所有提交节点。

  7. 提交节点验证交易。

  8. 提交节点更新分类帐。

  9. 最后,提交节点向客户端/应用程序发送交易成功或失败的通知。

以下图表代表了上述步骤和超级账本架构从交易流程的角度:

交易流程架构

如前图所示,第一步是提出交易,客户端通过 SDK 执行此操作。在此之前,假设所有客户端和节点都已在成员服务提供商那里注册。

关于这个主题,我们对超级账本(Hyperledger Fabric)的介绍已经完成。在下一节中,我们将看到另一个名为 Sawtooth Lake 的超级账本项目。

Sawtooth Lake

Sawtooth Lake 可以在受控和非受控模式下运行。它是一个分布式账本,提出了两个新颖的概念:第一个是介绍了一种称为Proof of Elapsed TimePoET)的新型共识算法;第二个是事务家族的概念。

这些新提议的描述在以下部分给出。

PoET

PoET 是一种新颖的共识算法,允许根据节点在提出区块之前等待的时间随机选择节点。这个概念与其他基于领导者选举和抽奖的工作证明算法相反,例如比特币中使用的 PoW,其中使用了大量的电力和计算资源来选举区块提议者;例如在比特币的情况下。 PoET 是一种工作证明算法,但是,它不是使用计算机资源,而是使用可信计算模型来提供一种满足工作证明要求的机制。 PoET 利用 Intel 的 SGX 架构(软件保护扩展)提供受信任的执行环境(TEE)以确保进程的随机性和密码学安全性。

应该注意的是,Sawtooth Lake 的当前实现不需要真实的硬件 SGX 基于 TEE,因为它仅为实验目的模拟,并且因此不应在生产环境中使用。 PoET 的基本理念是通过随机等待的方式来提供领导者选举的机制,以便被选举为提议新交易的领导者。

但是,PoET 存在一个被 Ittay Eyal 强调的限制。 这个限制被称为陈旧芯片问题。

研究论文可在eprint.iacr.org/2017/179.pdf上获得。

这种限制导致硬件浪费,可能导致资源的浪费。 也存在黑客攻击芯片硬件的可能性,这可能导致系统妥协和给矿工不当的激励。

交易家族

传统的智能合约范式提供了一个基于通用指令集的解决方案,适用于所有领域。 例如,在以太坊的情况下,已经开发了一组用于 EVM 的操作码,可以用来构建智能合约以满足任何行业的任何类型需求。

虽然这个模型有其优点,但显然这种方法不太安全,因为它为账本提供了一个单一接口,使用了一个强大且富有表现力的语言,这可能为恶意代码提供了更大的攻击面。 这种复杂性和通用虚拟机范式导致了一些漏洞的发现和最近黑客攻击的利用。 一个最近的例子是DAO hack和进一步的拒绝服务DoS)攻击,这些攻击利用了一些 EVM 操作码的限制。 DAO hack 在第四章“智能合约”中进行了讨论。

下图中显示的模型描述了传统的智能合约模型,其中使用了通用虚拟机提供了所有领域的区块链接口:

传统的智能合约范式

为解决这个问题,Sawtooth Lake 提出了交易族的概念。交易族通过将逻辑层分解为特定领域的一组规则和一个组合层来创建。关键思想是业务逻辑嵌入在交易族中,从而提供了一种更安全、更强大的构建智能合约的方式。交易族包含特定领域的规则和另一层,允许为该领域创建交易。另一种看待它的方式是,交易族是实施特定领域逻辑层的数据模型和交易语言的组合。数据模型代表区块链(分类帐)的当前状态,而交易语言修改了分类帐的状态。预计用户将根据其业务需求构建自己的交易族。

以下图表表示了该模型,其中每个特定领域,如金融服务、数字版权管理DRM)、供应链和医疗行业,都有自己的逻辑层,包括特定于该领域的操作和服务。这使逻辑层同时具有限制性和强大性。交易族确保只有与所需领域相关的操作存在于控制逻辑中,从而消除了执行不必要的、任意的和潜在有害的操作的可能性:

Sawtooth(交易族)智能合约范式

英特尔为 Sawtooth 提供了三个交易族:端点注册表、Integerkey 和 MarketPlace。

  • 端点注册表用于注册分类帐服务

  • Integerkey用于测试已部署的分类帐

  • MarketPlace用于销售、购买和交易操作和服务

Sawtooth_bond已开发为证明概念,演示了债券交易平台。

可在github.com/hyperledger/sawtooth-core/tree/master/extensions/bond找到。

Sawtooth 中的共识

Sawtooth 有两种基于网络选择的共识机制。正如之前讨论的那样,PoET 是一种基于可信执行环境的抽奖功能,根据节点等待区块提案的时间随机选举领袖。

还有一种名为quorum voting的共识类型,这是由 Ripple 和 Stellar 构建的共识协议的一种改编。该共识算法允许即时的交易最终性,通常在获准网络中是可取的。

开发环境 - Sawtooth Lake

本节将简要介绍如何为 Sawtooth Lake 设置开发环境。设置开发环境需要满足一些先决条件。

本部分中的示例假定正在运行 Ubuntu 系统并具有以下内容:

一旦两个前提条件都成功下载并安装,下一步是克隆存储库。

$ git clone https://github.com/IntelLedger/sawtooth-core.git  

这将产生类似以下屏幕截图所示的输出:

GitHub Sawtooth 克隆

一旦 Sawtooth 正确克隆,下一步是启动环境。首先,运行以下命令将目录更改为正确的位置,然后启动 vagrant 虚拟机:

$ cd sawtooth-core/tools
$ vagrant up  

这将产生类似以下屏幕截图的输出:

vagrant up 命令

如果在任何时候需要停止 vagrant,则可以使用以下命令:

$ vagrant halt  

或者:

$ vagrant destroy  

halt将停止 vagrant 虚拟机,而destroy将停止并删除 vagrant 虚拟机。

最后,可以使用以下命令启动事务验证器。首先ssh进入 vagrant Sawtooth 虚拟机:

$ vagrant ssh  

当出现 vagrant 提示时,运行以下命令。首先使用以下命令构建 Sawtooth Lake 核心:

$ /project/sawtooth-core/bin/build_all  

当构建成功完成时,为了运行事务验证器,请执行以下命令:

$ /project/sawtooth-core/docs/source/tutorial/genesis.sh  

这将创建创世区块并清除任何现有的数据文件和密钥。此命令应显示类似以下屏幕截图的输出:

创世区块和密钥生成

下一步是运行交易验证器,并按照如下更改目录:

$ cd /project/saw-toothcore  

运行交易验证器:

$ ./bin/txnvalidator -v -F ledger.transaction.integer_key --config
/home/ubuntu/sawtooth/v0.json  

运行交易验证器

通过按 Ctrl + C 停止验证器节点。一旦验证器启动并运行,各种客户端可以在另一个终端窗口中启动,以与交易验证器通信并提交交易。

例如,在以下屏幕截图中,市场客户端被启动以与交易验证器通信。注意,使用以下命令创建了位于/keys/mkt.wif下的密钥:

./bin/sawtooth keygen --key-dir validator/keys mkt 

用于市场交易家族的 mktclient

这完成了我们对 Sawtooth 的基本介绍。上面显示的示例也相当基本,但演示了 Sawtooth Lake 的工作原理。

Sawtooth Lake 也在不断发展,因此建议读者留意intelledger.github.io/上可用的文档,以了解最新的发展。

这里有一个非常好的在线页面,提供了官方的 Sawtooth Lake 示例。该页面可在sawtooth.hyperledger.org/examples/访问。鼓励读者访问此页面,并探索这些样本项目。

现在在下一节中,我们将看到对 Corda 的介绍。需要注意的是,Corda 还不是 Hyperledger 的官方项目;但是,它可能很快就成为成员。因此,目前正在在 Hyperledger 下讨论这个问题,但将来可能不会成为 Hyperledger 的一部分。

Corda

根据定义,Corda 不是区块链,因为它不包含打包交易的区块,但它属于分布式分类账。它提供了区块链能提供的所有好处。传统的区块链解决方案,如前所述,具有将交易捆绑在一起形成区块的概念,每个区块都与其父区块在密码学上链接在一起,从而提供不可变的交易记录。Corda 与此不同。

Corda 是完全从头开始设计的,采用了一种新的模型来提供所有区块链的优点,但没有传统的区块链。它纯粹是为金融行业而开发的,以解决每个组织管理自己的分类账的问题,因此它们对真相有自己的看法,这导致矛盾和运营风险。此外,数据也在每个组织中重复,这导致管理个别基础设施的成本和复杂性增加。这些是 Corda 旨在通过构建分布式数据库平台解决的金融行业中的问题类型。

Corda 源代码可在 github.com/corda/corda 获取。它是用一种称为 Kotlin 的语言编写的,这是一种针对Java 虚拟机JVM)的静态类型语言。

架构

Corda 平台的主要组件包括状态对象、合同代码、法律文本、交易、共识和流程。我们现在将对它们进行更详细的探讨。

状态对象

状态对象代表表示财务协议的最小数据单元。它们是作为交易执行的结果而创建或删除的。它们参考合同代码法律文本。法律文本是可选的,并为合同提供法律约束。但是,合同代码是强制性的,以便管理对象的状态。根据在合同代码中定义的业务逻辑,它是必需的,以为节点提供状态转换机制。状态对象包含表示对象当前状态的数据结构。状态对象可以是当前的(活动的)或历史的(不再有效)。

举个例子,在下图中,状态对象代表对象的当前状态。在这种情况下,它是甲方乙方之间的简单模拟协议,其中甲方 ABC已支付乙方 XYZ 1,000 英镑。这代表了对象的当前状态;然而,引用的合同代码可以通过交易改变状态。状态对象可以被看作是一个状态机,交易消耗它们以创建更新的状态对象。

一个状态对象示例

交易

交易用于在不同状态之间执行过渡。例如,前面图表中显示的状态对象是作为交易的结果创建的。Corda 使用基于比特币的 UTXO 模型进行交易处理。与比特币类似,交易的状态转换概念相同。与比特币类似,交易可以有零个、单个或多个输入,以及单个或多个输出。所有交易都经过数字签名。

此外,Corda 没有挖矿的概念,因为它不使用区块来安排区块链中的事务。而是使用公证服务来提供事务的时间顺序。在 Corda 中,可以使用 JVM 字节码开发新的事务类型,这使得它非常灵活和强大。

共识

Corda 中的共识模型非常简单,基于稍后在本章讨论的公证服务。一般的想法是通过公证服务对事务的唯一性进行评估,如果它们是唯一的(即唯一的事务输入),则由共识服务签署为有效。在 Corda 网络上可以运行单个或多个集群化的公证服务。公证人可以使用各种共识算法,如 PBFT 或 Raft,来达成共识。

Corda 中关于共识的两个主要概念是状态有效性共识状态唯一性共识。第一个概念关注事务的验证,确保所有必需的签名都可用且状态适当。第二个概念是一种检测双重支付攻击的手段,确保事务尚未被花费且是唯一的。

流程

Corda 中的流程是一种新颖的概念,允许开发分散式工作流。Corda 网络上的所有通信都由这些流程处理。这些是可以使用代码定义任何复杂性的任何金融流动的事务构建协议。流程作为异步状态机运行,并与其他节点和用户交互。在执行过程中,它们可以根据需要暂停或恢复。

组件

Corda 网络有多个组件。所有这些组件将在接下来的部分中描述。

节点

Corda 网络中的节点采用了无信任模型,并由不同的组织运行。节点作为经过身份验证的点对点网络的一部分运行。节点使用Advanced Message Queuing Protocol (AMQP)直接相互通信,这是一个经过批准的国际标准(ISO/IEC 19464),确保不同节点之间的消息安全传输。在 Corda 中,AMQP 在Transport Layer Security (TLS) 上运行,因此确保节点之间传输的数据的隐私和完整性。

节点还利用本地关系数据库进行存储。网络上的消息以紧凑的二进制格式编码。它们通过Apache Artemis message broker (Active MQ)进行交付和管理。节点可以作为网络映射服务、公证人、Oracle 或普通节点。下图展示了两个节点之间通信的高级视图:

Corda 网络中两个节点的通信

在前图中,节点 1通过 TLS 通信频道使用 AMQP 协议与节点 2进行通信,并且节点具有用于存储的本地关系数据库。

许可服务

许可服务用于提供 TLS 证书以保障安全。为了参与网络,参与者需要有由根证书颁发机构签发的身份证明。在网络上,身份必须是唯一的,并且许可服务用于签署这些身份。用于识别参与者的命名约定基于 X.500 标准。这确保了名称的唯一性。

网络地图服务

此服务用于以文档形式提供网络地图,其中包含网络上所有节点的信息。该服务发布 IP 地址、身份证书以及节点提供的服务列表。所有节点在首次启动时通过注册到此服务来宣布自己的存在,当节点收到连接请求时,首先在网络地图上检查请求节点的存在。换句话说,该服务解析参与者的身份到物理节点。

公证服务

在传统区块链中,挖矿用于确定包含交易的区块的顺序。在 Corda 中,公证服务用于提供交易排序和时间戳服务。网络中可以有多个公证人,并且它们由复合公钥标识。公证人可以使用不同的共识算法,如 BFT 或 Raft,具体取决于应用程序的要求。公证服务签署交易以指示交易的有效性和最终性,然后将其持久化到数据库中。

为了性能原因,公证人可以以负载平衡配置运行,以在节点之间分散负载;为了减少延迟,建议节点在物理上距离交易参与者更近。

Oracle 服务

Oracle 服务要么签署包含事实的交易(如果它是真实的),要么可以自己提供事实数据。它们允许真实世界的信息输入到分布式分类帐中。关于 Oracle 的讨论可以在第四章中找到,即智能合约

交易

Corda 网络中的交易永远不会全局传输,而是在半私有网络中进行。它们只在与交易相关的参与者子集之间共享。这与传统的区块链解决方案(如以太坊和比特币)形成对比,其所有交易都会全局广播给整个网络。交易经过数字签名,要么消耗状态,要么创建新状态。

Corda 网络上的交易由以下元素组成:

  • 输入参考: 这是交易将要使用和消耗的状态的参考。

  • 输出状态: 这些是交易创建的新状态。

  • 附件:这是附加的 ZIP 文件哈希列表。ZIP 文件可以包含与交易相关的代码和其他相关文档。文件本身不作为交易的一部分,而是单独传输和存储。

  • 命令:命令代表交易的预期操作信息,作为合同的参数。每个命令都有一个公钥列表,表示需要对交易进行签名的所有方。

  • 签名:这表示交易所需的签名。所需签名总数与命令的公钥数量成正比。

  • 类型:交易有两种类型,即普通或变更公证。变更公证交易用于重新分配状态的公证。

  • 时间戳:此字段表示交易发生的时间段。这些由公证服务进行验证和强制执行。此外,如果需要严格的时间,这在许多金融服务方案中是可取的,公证应与原子钟同步。

  • 摘要:这是描述交易操作的文本描述。

保险库

保险库在节点上运行,类似于比特币中钱包的概念。由于交易不会全球广播,因此每个节点的保险库只会包含对他们而言相关的数据部分。保险库将其数据存储在标准关系数据库中,因此可以使用标准 SQL 进行查询。保险库可以包含在账本上和账本之外的数据,这意味着它也可以具有一些不在账本上的数据部分。

CorDapp

Corda 的核心模型由状态对象、交易和交易协议组成,当与合同代码、API、钱包插件和用户界面组件结合使用时,结果是构建了一个Corda 分布式应用程序CorDapp)。

Corda 中的智能合约是使用 Kotlin 或 Java 编写的。代码面向 JVM。

为了实现 JVM 字节码执行结果的确定性,对 JVM 进行了轻微修改。 Corda 智能合约的三个主要组成部分如下:

  • 定义验证逻辑以验证对状态对象的更改的可执行代码。

  • 状态对象表示合同的当前状态,可以由交易消耗,或者由交易生成(创建)。

  • 命令用于描述操作和验证数据,以定义如何验证交易的方式。

开发环境 - Corda

使用以下步骤可以轻松设置 Corda 的开发环境。所需软件包括以下内容:

Gradle 是用于构建 Corda 的另一个组件。它可以在gradle.org获取。

安装了所有这些工具后,可以开始智能合约开发。可以使用github.com/corda/cordapp-template中提供的示例模板来开发 CorDapps。

有关如何开发合同代码的详细文档可在docs.corda.net/获取。

Corda 可以使用以下命令从 GitHub 本地克隆:

$ git clone https://github.com/corda/corda.git  

克隆成功后,您应该看到类似以下的输出:

Cloning into 'corda'...
remote: Counting objects: 74695, done.
remote: Compressing objects: 100% (67/67), done.
remote: Total 74695 (delta 17), reused 0 (delta 0), pack-reused 74591 Receiving objects: 100% (74695/74695), 51.27 MiB | 1.72 MiB/s, done. Resolving deltas: 100% (42863/42863), done.
Checking connectivity... done.  

一旦存储库被克隆,就可以在 IntelliJ 中进一步开发。存储库中提供了多个示例,如 Corda 银行、利率互换、演示和交易者演示。读者可以在/samples目录下的corda下找到它们,并可使用 IntelliJ IDEA IDE 进行探索。

摘要

在本章中,我们介绍了 Hyperledger 项目的概述。首先,讨论了 Hyperledger 项目背后的核心思想,并提供了 Hyperledger 下所有项目的简要介绍。详细讨论了三个主要的 Hyperledger 项目,即 Hyperledger Fabric、Sawtooth Lake 和 Corda。所有这些项目都在不断改进,预计下一个版本会有变化。然而,上述所有项目的核心概念预计都将保持不变,或者只会轻微变化。鼓励读者访问章节中提供的相关链接,以了解最新动态。

显然,这个领域正在发生很多事情,像来自 Linux 基金会的 Hyperledger 项目发挥着推动区块链技术发展的关键作用。本章讨论的每个项目都对解决各行业面临的问题有新颖的方法,还在解决区块链技术的当前限制,如可扩展性和隐私等。预计很快将有更多项目提议给 Hyperledger 项目,预计随着这种合作和开放努力,区块链技术将得到极大发展,并将惠及整个社区。

在下一章中,我们将介绍替代的区块链解决方案和平台。由于区块链技术发展得非常迅速,并且吸引了许多研究兴趣,因此最近出现了许多新项目。我们将在下一章讨论这些项目。

第十四章:替代区块链

本章旨在介绍替代的区块链解决方案。随着比特币的成功以及对区块链技术潜力的逐渐认识,出现了一场寒武纪大爆发,导致了各种区块链协议、应用和平台的发展。一些项目并没有得到很大的发展,例如估计今年有 46%的 ICO 项目失败了,但许多项目已经成功在这一领域确立了自己的地位。

在本章中,读者将被介绍到像 Kadena、Ripple 和 Stellar 这样的替代区块链和平台。我们将探索那些要么是独立的新区块链,要么通过提供 SDK、框架和工具来支持其他现有区块链的项目,使得区块链解决方案的开发和部署变得更加容易。以太坊和比特币的成功导致了各种项目的出现,它们通过利用它们引入的底层技术和概念,通过增加用户友好的工具层来解决当前区块链的局限性或增强现有解决方案的价值。

区块链

在本节中,将介绍新的区块链解决方案,后续章节将涵盖各种平台和开发工具包,以补充现有的区块链。例如,Kadena 是一个具有创新理念的新私有区块链,其中引入了诸如可扩展 BFT 之类的概念。随着区块链技术的发展,也引入了诸如侧链、驱动链和挂钩等概念。本章将详细介绍所有这些技术和相关概念。当然,不可能涵盖所有的替代链(altchains)和平台,但本章包括了所有与区块链相关的、前几章涵盖的,或者预计很快会获得成功的平台。

我们将在本节中探讨 Kadena、Ripple、Stellar、Quorum 和其他各种区块链。

Kadena

Kadena 是一个私有区块链,成功解决了区块链系统中的可扩展性和隐私问题。Kadena 还引入了一种名为 Pact 的新的图灵不完备语言,允许智能合约的开发。Kadena 的一个关键创新是其可扩展的 BFT 共识算法,有潜力在不影响性能的情况下扩展到数千个节点。

可扩展 BFT 基于原始的 Raft 算法,是 Tangaroa 和 Juno 的后继者。Tangaroa 是 Raft 的一个实现,具有容错性(即 BFT Raft),旨在解决 Raft 算法中拜占庭节点行为引起的可用性和安全性问题,而 Juno 则是 JPMorgan 开发的 Tangaroa 的分支。共识算法在第一章的区块链 101中更详细地讨论。

这两个提案都有一个根本性的限制——在保持高性能的同时无法扩展。因此,Juno 无法获得太多的关注。私有区块链具有更理想的特性,即在节点数量增加时保持高性能,但上述提案缺乏这一特性。Kadena 通过其专有的可扩展 BFT 算法解决了这个问题,该算法预计能够在不降低性能的情况下扩展到数千个节点。

此外,保密性是 Kadena 的另一个重要方面,它能够在区块链上保护交易的隐私。这种安全服务通过使用密钥轮换、对称链上加密、增量哈希和双扳手协议的组合来实现。

密钥轮换是确保私有区块链安全性的标准机制。它作为一种最佳实践,通过定期更改加密密钥来防范任何攻击,如果密钥被泄露,则会被用来防范任何攻击。Pact 智能合约语言原生支持密钥轮换。

对称链上加密允许在区块链上加密交易数据。这些交易可以由特定私有交易的参与者自动解密。双扳手协议用于提供密钥管理和加密功能。

可扩展 BFT 共识协议确保在执行智能合约之前已经实现了足够的复制和共识。共识是通过以下流程实现的。

以下是交易在网络中的起源和流动方式:

  1. 首先,用户签署并广播一个新的交易到区块链网络,然后由一个领导节点接收并将其添加到其不可变日志中。在此时,还会为日志计算一个增量哈希。增量哈希是一种哈希函数,它允许在已经哈希过的原始消息稍微更改时计算哈希消息的情况下进行计算,这种方案比传统哈希函数更快且资源消耗更少,因为即使原始消息只有轻微更改,也需要生成一个全新的哈希消息。

  2. 一旦交易被领导节点写入日志,它就会对复制和增量哈希进行签名,并将其广播给其他节点。

  3. 其他节点在接收到交易后,验证领导节点的签名,将交易添加到自己的日志中,并将自己计算得到的增量哈希(法定证明)广播给其他节点。 最后,在收到其他节点的足够数量的证明后,交易将永久提交到分类帐中。

下图显示了这个过程的简化版,领导节点记录新交易然后复制到追随节点:

Kadena 中的共识机制

一旦达成共识,智能合同执行就可以开始,并经过一系列步骤,如下:

  1. 首先,验证消息的签名。

  2. Pact 智能合同层接管。

  3. Pact 代码经过编译。

  4. 启动交易并执行嵌入在智能合同中的任何业务逻辑。 如果出现任何失败,将立即启动回滚,将状态恢复为执行开始之前的状态。

  5. 最后,交易完成并更新相关日志。

Pact 已经被 Kadena 开源,并可在kadena.io/pact/downloads.html下载。

这可以作为独立的二进制文件下载,提供 Pact 语言的 REPL。 这里显示了一个示例,Pact 在 Linux 控制台上通过发出./pact命令来运行:

Pact REPL,显示示例命令和错误输出

Pact 语言中的智能合同通常由三部分组成:密钥集、模块和表格。 这些部分在这里描述:

  • 密钥集: 这个部分定义了表格和模块的相关授权方案。

  • 模块: 这个部分定义了智能合同代码,以函数和契约的形式包含业务逻辑。 模块内的契约由多个步骤组成,并按顺序执行。

  • 表格: 这个部分是在模块内定义的受访问控制的结构。只有在 admin keyset 中定义的管理员才能直接访问这个表格。 默认情况下,模块中的代码被授予对表格的完全访问权限。

Pact 也允许多种执行模式。 这些模式包括合同定义、交易执行和查询。 这些执行模式在这里描述:

  • 合同定义: 这种模式允许通过单个交易消息在区块链上创建合同。

  • 交易执行: 这种模式涉及执行代表业务逻辑的智能合同代码的模块。

  • 查询:此模式仅用于简单地探测合约数据,出于性能考虑在节点上本地执行。Pact 使用类似 LISP 的语法,并且在代码中准确表示将在区块链上执行的内容,因为它以人类可读的格式存储在区块链上。这与以太坊的 EVM 相反,后者将代码编译成字节码进行执行,这使得验证正在区块链上执行的代码变得困难。此外,它是图灵不完备的,支持不可变变量,并且不允许空值,这提高了交易代码执行的整体安全性。

在本章的有限长度内无法涵盖 Pact 的完整语法和功能;但是,这里展示了一个小例子,显示了使用 Pact 编写的智能合约的一般结构。此示例显示了一个简单的加法模块,定义了一个名为addition的函数,该函数接受三个参数。当执行代码时,它将添加所有三个值并显示结果。

以下示例是使用在线 Pact 编译器开发的,可在kadena.io/try-pact/上找到。

图

Pact 示例代码

运行代码时,会产生如下所示的输出:

图

代码的输出

如前面的示例所示,执行输出与代码布局和结构完全匹配,这样可以实现更大的透明度,并限制了恶意代码执行的可能性。

Kadena 是一种新型的区块链,引入了普遍确定性的新概念,在标准的基于公钥/私钥的数据来源安全性之外,还提供了另一层完全确定性的共识。它在区块链的所有层面,包括交易和共识层,提供了加密安全性。

Pact 的相关文档和源代码可以在github.com/kadena-io/pact找到。

Kadena 还于 2018 年 1 月推出了一种公共区块链,这是构建具有大规模吞吐量的区块链的又一重大进步。该提案的新颖之处在于建立了一种 PoW 并行链架构。该方案通过将节点上的单独开采的链组合成单一网络来工作。结果是具有超过 10,000 笔交易处理能力的大规模吞吐量。

原始研究论文可在kadena.io/docs/chainweb-v15.pdf找到。

Ripple

2012 年推出的 Ripple 是一种货币交换和实时毛额结算系统。在 Ripple 中,支付结算无需等待,与传统结算网络相比,传统结算网络可能需要数天时间才能完成结算。

它有一个称为瑞波币XRP)的本地货币。它还支持非 XRP 支付。这个系统被认为类似于一个被称为哈瓦拉的传统老款转账机制。这个系统通过代理人接收汇款和密码,然后联系收款人的代理人,并指示他们向提供密码的人释放资金来运作。然后收款人联系当地代理人,告诉他们密码,并收取资金。代理人类比于瑞波中的网关。这只是一个非常简单的类比;实际的协议相当复杂,但原则上是相同的。

瑞波网络由各种节点组成,这些节点根据其类型可以执行不同的功能:

  • 用户节点:这些节点用于支付交易,可以支付或接收支付。

  • 验证节点:这些节点参与共识机制。每个服务器维护一组唯一节点,它在实现共识时需要查询这些节点。唯一节点列表UNL)中的节点受到参与共识机制的服务器的信任,并且只会接受来自这个唯一节点列表的投票。

由于涉及网络运营商和监管机构,有时不认为瑞波是一个真正去中心化的网络。然而,它可以被认为是去中心化的,因为任何人都可以通过运行验证节点成为网络的一部分。此外,共识过程也是去中心化的,因为对账本提出的任何更改都必须遵循超级多数投票的方案来决定。然而,这是研究人员和爱好者之间的热门话题,对于每种思想流派都有支持和反对的论点。读者可以参考一些在线讨论进一步探索这些想法。

您可以在以下链接找到这些在线讨论:

Ripple 维护着一个由一种名为Ripple 协议共识算法RPCA)的新型低延迟共识算法所管理的全球分布式账本,共识过程通过迭代地寻求验证服务器的验证和接受,直到获得足够数量的投票来就交易所在的开放账本的状态达成一致。一旦收到足够的投票(最初为 50%,随着每次迭代逐渐增加至至少 80%),变化就会被验证并且账本被关闭。在这一点上,会向整个网络发送警报,指示账本已关闭。

RPCA 的原始研究论文可在ripple.com/files/ripple_consensus_whitepaper.pdf中找到。

总之,共识协议是一个三阶段的过程:

  • 收集阶段:在此阶段,验证节点收集所有由账户所有者在网络上广播的交易并验证它们。一旦被接受,交易被称为候选交易,并根据验证标准接受或拒绝。

  • 共识阶段:在收集阶段之后,共识过程开始,共识达成后账本被关闭

  • 账本关闭阶段:该过程每隔几秒钟异步运行一次,在轮次中,账本会相应地被打开和关闭(更新):

Ripple 共识协议阶段

在 Ripple 网络中,有许多组件共同工作,以实现共识并形成支付网络。这些组件在这里分别讨论:

  • 服务器:该组件作为共识协议的参与者。为了能够参与共识协议,需要 Ripple 服务器软件。

  • 账本:这是网络上所有账户余额的主要记录。账本包含各种元素,如账本编号、账户设置、交易、时间戳以及指示账本有效性的标志。

  • 上一个关闭的账本:一旦验证节点达成共识,账本就会关闭。

  • 开放账本:这是尚未验证且尚未就其状态达成共识的账本。每个节点都有自己的开放账本,其中包含了提议的交易。

  • 唯一节点列表:这是验证服务器使用的一组唯一的受信任节点,以便寻求投票和随后的共识。

  • 提议者:顾名思义,该组件提出要包含在共识过程中的新交易。通常是一个节点的子集(在前面的点中定义的 UNL),可以向验证服务器提议交易。

交易

交易由网络用户创建以更新账本。为了被视为共识过程中的候选项,交易预期是数字签名和有效的。每个交易都需要支付少量 XRP,这充当了防止因垃圾邮件而导致的拒绝服务攻击的保护机制。

Ripple 网络中有不同类型的交易。Ripple 交易数据结构中的一个字段称为TransactionType,用于表示交易的类型。交易通过四个步骤执行:

  1. 首先,通过遵循标准创建未签名的交易,准备交易

  2. 第二步是签名,交易被数字签名以授权它

  3. 然后,通过连接的服务器实际提交到网络

  4. 最后,执行验证以确保交易成功验证

大致而言,交易可以分为三种类型,即与支付相关的、与订单相关的和与帐户和安全相关的。所有这些类型都在下一节中描述。

与支付相关的

此类别中有几个字段会导致某些操作。所有这些字段如下所述:

  • Payment: 此交易最常用,允许一个用户向另一个用户发送资金。

  • PaymentChannelClaim: 该操作用于从支付通道中索取瑞波币(XRP)。支付通道是一种允许各方进行重复且单向支付的机制。它还可用于设置支付通道的过期时间。

  • PaymentChannelCreate: 此交易创建一个新的支付通道,并以的形式添加 XRP。一个滴相当于 0.000001 个 XRP。

  • PaymentChannelFund: 此交易用于向现有通道添加更多资金。与PaymentChannelClaim交易类似,这也可用于修改支付通道的过期时间。

与订单相关的

此类型的交易包括以下两个字段:

  • OfferCreate: 该交易表示限价订单,代表了货币交换的意向。如果订单无法完全执行,则会在共识账本中创建一个报价节点。

  • OfferCancel: 用于从共识账本中删除先前创建的报价节点,表示撤销订单。

帐户和安全相关

此类型的交易包括以下列出的字段。每个字段负责执行特定的功能:

  • AccountSet: 此交易用于修改 Ripple 共识账本中帐户的属性。

  • SetRegularKey: 用于更改或设置帐户的交易签名密钥。帐户是使用从帐户的主公钥派生的 Base-58 Ripple 地址来识别的。

  • SignerListSet: 可用于创建用于多重签名交易的签名者集合。

  • TrustSet: 这用于创建或修改账户之间的信任线。

Ripple 中的交易由各种对所有交易类型通用的字段组成。这些字段如下所示,并附有描述:

  • Account: 这是交易发起者的地址。

  • AccountTxnID: 这是一个可选字段,包含另一个交易的哈希值。它用于将交易链接在一起。

  • Fee: 这是 XRP 的金额。

  • Flags: 这是一个可选字段,用于指定交易的标志。

  • LastLedgerSequence: 这是交易可以出现的账本中的最高序列号。

  • Memos: 这代表可选的任意信息。

  • SigningPubKey: 这代表公钥。

  • Signers: 这代表多重签名交易中的签名者。

  • SourceTag: 这代表交易的发送方或原因。

  • SourceTag: 这代表交易的发送方或原因。

  • TxnSignature: 这是交易的验证数字签名。

Interledger

Interledger 是一个由四层组成的简单协议:应用层、传输层、Interledger 层和账本层。每一层负责在某些协议下执行各种功能。这些功能和协议在以下部分描述。

此协议的规范可在以下链接找到:interledger.org/rfcs/0003-interledger-protocol/draft-9.html

应用层

运行在这一层上的协议管理支付交易的关键属性。应用层协议的示例包括简单支付设置协议SPSP)和开放网络支付方案OWPS)。SPSP 是一种 Interledger 协议,通过在它们之间创建连接器,允许在不同账本之间进行安全支付。OWPS 是另一种方案,允许在不同网络之间进行消费者支付。

一旦这一层上的协议成功运行,将按顺序调用传输层的协议以启动支付流程。

传输层

这一层负责管理支付交易。目前可用的协议有乐观传输协议OTP)、通用传输协议UTP)和原子传输协议ATP)。OTP 是最简单的协议,它在没有任何托管保护的情况下管理支付转账,而 UTP 则提供托管保护。ATP 是最先进的协议,它不仅提供托管传输机制,还利用可信的公证人进一步确保了支付交易的安全性。

Interledger 层

该层提供互操作性和路由服务。该层包含诸如Interledger 协议ILP)、Interledger 报价协议ILQP)和Interledger 控制协议ILCP)等协议。ILP 数据包提供了传输中的最终目标(目的地)。ILQP 用于在实际转账之前由发送方发起的报价请求。ILCP 用于在支付网络上的连接器之间交换与路由信息和支付错误相关的数据。

分类帐层

该层包含了使连接器之间进行通信和支付交易执行的协议。连接器基本上是实现在不同分类帐之间转发支付的协议的对象。它可以支持各种协议,如简单分类帐协议、各种区块链协议、传统协议和不同的专有协议。

Ripple 连接由各种即插即用的模块组成,通过使用 ILP 实现分类帐之间的连接。它使各方在交易之前交换所需数据成为可能,包括可见性、费用管理、交付确认和使用传输层安全性进行安全通信。第三方应用程序可以通过各种连接器连接到 Ripple 网络,这些连接器在不同分类帐之间转发支付。

在前述章节中描述的所有层构成了 Interledger 协议的架构。总的来说,Ripple 是一个针对金融行业的解决方案,使实时支付成为可能,而无需任何结算风险。由于这是一个非常功能丰富的平台,在本章节中无法覆盖所有方面。

Ripple 平台的文档可在ripple.com/找到。

星际

Stellar 是基于区块链技术的支付网络,采用了一种新颖的共识模型称为联邦拜占庭协议FBA)。FBA 通过创建信任方的法定人数来工作。Stellar 共识协议SCP)是 FBA 的一种实现。

Stellar 白皮书中指出的关键问题是当前金融基础设施的成本和复杂性。这种限制需要一个全球金融网络,解决这些问题而不损害金融交易的完整性和安全性。这一要求导致了 SCP 的发明,这是一种可证明安全的共识机制。

SCP 的原始研究论文可在www.stellar.org/papers/stellar-consensus-protocol.pdf找到。

它具有以下四个主要属性:

  • 去中心化控制:这允许任何人参与,没有中央方

  • 低延迟:这解决了快速交易处理的迫切要求

  • 灵活信任:这使用户可以选择他们信任的特定目的方

  • 渐进式安全性:这利用数字签名和哈希函数来为网络提供所需的安全级别。

Stellar 网络允许通过其原生数字货币来传输和表示资产的价值,称为Lumens,缩写为XLM。当交易在网络上广播时,Lumens 会被消耗,这也作为阻止服务拒绝攻击的一种威慑手段。

在其核心,Stellar 网络维护着一个分布式分类账,记录着每一笔交易,并在每个 Stellar 服务器(节点)上复制。共识是通过验证服务器之间的交易并使用更新更新分类账来实现的。Stellar 分类账也可以充当分布式交易所订单簿,允许用户存储他们的购买或出售货币的报价。

有各种工具、SDK 和软件构成了 Stellar 网络。

核心软件可在 github.com/stellar/stellar-core 获取。

Rootstock

在详细讨论RootstockRSK)之前,重要的是定义并介绍一些对 Rootstock 设计至关重要的概念。这些概念包括侧链、驱动链和双向锚定。侧链的概念最初是由 Blockstream 开发的。

Blockstream 的在线存在位于 blockstream.com

双向锚定是一种机制,通过该机制价值(硬币)可以在一个区块链之间传输到另一个区块链,反之亦然。实际上没有硬币在链之间转移。这个想法围绕着在比特币区块链(主链)中锁定相同数量和价值的硬币,并在次要链中解锁等值的令牌的概念。

牢记这个定义,侧链可以如下部分所述定义。

侧链

这是一个与主区块链并行运行的区块链,允许在它们之间传输价值。这意味着一个区块链中的代币可以在侧链中使用,反之亦然。这也被称为锚定侧链,因为它支持双向锚定资产。

Drivechain

这是一个相对较新的概念,其中对于解锁在主链中的锁定比特币的控制被给予了矿工,他们可以投票何时解锁它们。这与侧链相反,在侧链中,共识是通过简单支付验证机制来验证的,以便将硬币转回主链。

Rootstock 是一个智能合约平台,它在比特币区块链中具有双向钉住。其核心思想是增加比特币系统的可扩展性和性能,并使其能够与智能合约一起使用。Rootstock 运行一个名为Rootstock 虚拟机RVM)的图灵完备确定性虚拟机。它还兼容 EVM,并允许以太坊智能合约在 Rootstock 上运行。智能合约也可以在比特币区块链的经过时间测试的安全性下运行。Rootstock 区块链通过与比特币合并挖矿来工作。这使得 Rootstock 区块链能够实现与比特币相同的安全级别。特别是防止双重支付和实现结算终局性。由于更快的区块时间和其他设计考虑因素,它可以实现可扩展性,每秒高达 400 笔交易。

如果你想进一步探索,可在uploads.strikinglycdn.com/files/ec5278f8-218c-407a-af3c-ab71a910246d/RSK%20White%20Paper%20-%20Overview.pdf上查阅研究论文。

RSK 已发布了名为 Bamboo 的主网络,RSK MainNet 目前还处于测试阶段。

可在www.rsk.co/上找到。

Quorum

这是通过增强现有以太坊区块链构建的区块链解决方案。Quorum 引入了几项改进,如交易隐私和新的共识机制。Quorum 引入了一种名为 QuorumChain 的新共识模型,它基于大多数投票和基于时间的机制。另一个名为“星座”(Constellation)的功能也被引入,它是一个通用机制,用于提交信息并允许节点之间的加密通信。此外,节点级别的权限受智能合约的管理。与公共以太坊区块链相比,它还提供了更高层次的性能。

几个组件构成了 Quorum 区块链生态系统。这些列在以下小节中。

交易管理器

该组件可访问加密的交易数据。它还管理节点上的本地存储,并与网络上的其他交易管理器进行通信。

加密飞地

正如其名称所示,该组件负责提供加密服务以确保交易隐私。它还负责执行密钥管理功能。

QuorumChain

这是 Quorum 的关键创新。这是一种 BFT 共识机制,允许通过区块链网络上的交易验证和流通投票。在这个方案中,使用智能合约来管理共识过程,并且节点可以被赋予投票权来投票哪个新区块应该被接受。一旦投票者收到了足够数量的选票,该区块被视为有效。节点可以担任两种角色,即投票者或制造者。投票者节点有权投票,而制造者节点是创建新区块的节点。按设计,一个节点可以具有权利、无权利或只有一种。

网络管理器

此组件为权限网络提供了访问控制层。

Quorum 网络中的节点可以担任多种角色,例如,允许创建新区块的制造者节点。使用密码学和某些交易仅供相关参与者查看的概念提供交易隐私。这个想法类似于 Corda 在 第十三章中讨论过的私有交易的概念,Hyperledger。由于它允许在区块链上进行公共和私有交易,因此状态数据库已分为代表私有和公共交易的两个数据库。因此,有两个单独的 Patricia-Merkle 树来表示网络的私有状态和公共状态。私有合同状态哈希用于在交易参与方之间的私有交易中提供共识证据。

Quorum 网络中的交易包括多种元素,如收件人、发送者的数字签名(用于识别交易发起者)、可选的以太数量、允许查看交易的参与者的可选列表,以及在私有交易情况下包含哈希的字段。

交易在达到目的地之前要经过几个步骤。这些步骤如下所述:

  1. 用户应用程序(DApps)通过区块链网络提供的 API 将交易发送到 Quorum 节点。这还包括接收地址和交易数据。

  2. 然后,API 加密有效负载并应用任何其他必要的加密算法,以确保交易的隐私,并发送给交易管理器。此步骤还计算了加密有效负载的哈希值。

  3. 在接收到交易后,交易管理器验证交易发送者的签名并存储消息。

  4. 先前加密的有效负载的哈希被发送到 Quorum 节点。

  5. 一旦 Quorum 节点开始验证包含私有交易的区块,它会从交易管理器请求更多相关数据。

  6. 一旦交易管理器收到此请求,它将加密的有效负载和相关的对称密钥发送给请求者的 Quorum 节点。

  7. 一旦 Quorum 节点拥有所有数据,它就会解密有效负载并将其发送到 EVM 进行执行。这就是 Quorum 如何在区块链上使用对称加密实现隐私,同时能够使用原生以太坊协议和 EVM 分别进行消息传输和执行的方式。

一个类似的概念,在几个方面有所不同,之前以HydraChain的形式提出过,它基于以太坊区块链,并允许创建许可的分布式账本。

Quorum 可以在 github.com/jpmorganchase/quorum 下载。

Tezos

Tezos 是一个通用的自修改的加密账本,这意味着它不仅允许就区块链状态达成分散共识,还允许就协议和节点随时间演变达成共识。Tezos 已经开发出来解决比特币协议的局限性,比如由于 PoW 导致的硬分叉问题、成本问题和挖矿算力集中问题、脚本能力有限和安全问题。它是用一种纯函数语言 OCaml 开发的。

原始研究论文可在 www.tezos.com/static/papers/white_paper.pdf 获取。

Tezos 分布式账本的架构分为三层:网络层、共识层和交易层。这种分解允许协议以去中心化的方式演变。为此,在 Tezos 中实现了一个通用网络外壳,负责维护区块链,该区块链由共识层和交易层的组合表示。该外壳提供了网络和协议之间的接口层。

也引入了种子协议的概念,用作允许网络上的利益相关者批准协议的任何更改的机制。

Tezos 区块链从一个种子协议开始,而传统区块链是从创世区块开始的。

这个种子协议负责定义区块链中的修正程序,甚至修正协议本身。Tezos 的奖励机制基于 PoS 算法,因此没有挖矿需求。

Tezos 开发了一个合约脚本语言用于编写智能合约,这是一种基于堆栈的图灵完备语言。Tezos 中的智能合约是经过形式验证的,这允许对代码进行数学上的正确性验证。

Tezos 最近通过 ICO 完成了 2.32 亿美元的众筹。他们的公共网络预计将于 2018 年第一季度发布。

Tezos 代码可以在 github.com/tezos/tezos 获取。

Storj

云存储的现有模型都是集中式解决方案,可能或可能不像用户期望的那样安全。需要一个安全、高度可用且最重要的是分散化的云存储系统。Storj 旨在提供基于区块链的、分散化的和分布式存储。它是由社区共享的云,而不是一个中央组织。它允许在充当自治代理的节点之间执行存储合同。这些代理(节点)执行各种功能,如数据传输、验证和执行数据完整性检查。

核心概念基于称为分布式哈希表DHTs)的Kademlia,但是在 Storj 中通过添加新的消息类型和功能来增强此协议。它还实现了点对点的发布/订阅pub/sub)机制,称为Quasar,该机制确保消息成功到达对存储合同感兴趣的节点。这是通过称为topics的基于布隆过滤器的存储合同参数选择机制来实现的。

Storj 在网络中以加密格式存储文件。在文件存储在网络上之前,它会使用 AES-256-CTR 对称加密进行加密,然后以分布式方式逐片存储在网络上。将文件分解为片段的过程称为sharding,这会增加网络的可用性、安全性、性能和隐私。此外,如果节点失败,则该片段仍然可用,因为默认情况下,在网络上的三个不同位置存储单个片段。

它维护了一个区块链,作为一个共享账本,并实现了标准的安全功能,如公钥/私钥加密和哈希函数,类似于任何其他区块链。由于该系统基于节点之间的硬盘共享,任何人都可以通过共享其额外的硬盘空间并使用 Storj 的加密货币Storjcoin XSJCX)获得报酬。SJCX 被开发为 Counterparty 资产,并使用 Counterparty(基于比特币区块链)进行交易。这已经迁移到了以太坊。

可以在 blog.storj.io/post/158740607128/migration-from-counterparty-to-ethereum 中找到详细的讨论。

Storj 代码可在 github.com/Storj/ 获取。

MaidSafe

这是另一个类似于 Storj 的分布式存储系统。用户通过为网络贡献存储空间而获得 Safecoin 报酬。支付机制受到 资源证明 的管理,该机制确保用户提交给网络的磁盘空间可用,如果不可用,则相应的 Safecoin 支付将下降。文件在传输到网络进行存储之前会被加密和分割成小部分。

与 MaidSafe 一起引入了机会性缓存的概念,这是一种创建经常访问数据的副本物理上更接近访问请求来源的机制,这导致了网络的高性能。SAFE 网络的另一个新颖特性是,它会自动删除网络上的任何重复数据,从而减少存储需求。

而且,还引入了翻本的概念,基本上意味着数据不断在网络中移动,以便恶意对手无法针对数据。它还在网络中保留了数据的多个副本,以提供冗余备份,以防节点离线或失败。

BigchainDB

这是一个可扩展的区块链数据库。它本身并不严格算是一个区块链,而是通过提供一个分散式数据库来补充区块链技术。从本质上说,它是一个分布式数据库,但具有区块链的附加属性,例如分散化、不可变性和处理数字资产。它还允许使用 NoSQL 来查询数据库。

它旨在在分散式生态系统中提供数据库,其中不仅处理是分散的(区块链)或文件系统是分散的(例如 IPFS),而且数据库也是分散的。这使整个应用生态系统变得分散。

这可以在www.bigchaindb.com/找到。

MultiChain

MultiChain 已经作为私有区块链的开发和部署平台而开发。它基于比特币代码,解决了安全性、可扩展性和隐私问题。它是一个高度可配置的区块链平台,允许用户设置不同的区块链参数。它支持通过细粒度许可层进行控制和隐私保护。MultiChain 的安装非常快捷。

安装文件的链接可在www.multichain.com/download-install/找到。

Tendermint

Tendermint 是一个为应用程序提供 BFT 共识机制和状态机复制功能的软件。它的主要动机是开发一个通用、安全和高性能的复制状态机。

Tendermint 有两个组件,在下一节描述。

Tendermint Core

这是一个共识引擎,可以在网络中的每个节点上安全地复制交易。

Tendermint Socket Protocol (TMSP)

这是一个应用程序接口协议,允许与任何编程语言进行接口,以处理交易。

Tendermint 允许应用程序过程和共识过程解耦,这使得任何应用都可以从共识机制中受益。

Tendermint 共识算法是一种基于轮次的机制,其中验证节点在每个轮次提出新的区块。使用锁定机制来确保防止在同一高度的区块链上选择了两个不同的区块用于提交的情况。每个验证节点维护一个包含交易的完整本地复制的区块账本。每个区块包含一个标头,其中包括前一个区块哈希、区块提议的时间戳、当前区块高度和区块中所有交易的 Merkle 根哈希。

最近,Tendermint 已经被用于Cosmoscosmos.network),这是一个区块链网络,允许不同链之间在 BFT 共识算法上运行的互操作性。这个网络上的区块链被称为区域。Cosmos 中的第一个区域称为 Cosmos Hub,实际上是一个公共区块链,负责为其他区块链提供连接服务。为此,Hub 使用了跨区块链通信IBC)协议。IBC 协议支持两种类型的交易,称为IBCBlockCimmitTxIBCPacketTx。第一种类型用于向任何一方提供区块链中最新块哈希的证明,而后一种类型用于提供数据原始认证。从一个区块链到另一个区块链的数据包首先通过向目标链发布证明来发布。接收(目标)链检查此证明以验证发送链是否确实发布了数据包。此外,它有自己的本地货币叫做 Atom。这个方案通过允许多个区块链连接到 Hub 来解决可扩展性和互操作性问题。

Tendermint 可以在tendermint.com/找到。

平台和框架

本节涵盖了各种已开发的平台,旨在增强现有区块链解决方案的体验。

Eris

Eris 不是单一的区块链,它是由 Monax 开发的用于开发基于区块链的生态系统应用程序的开放模块化平台。它提供了各种框架、SDK 和工具,可以加速区块链应用程序的开发和部署。

Eris 应用平台背后的核心思想是通过区块链后端实现生态系统应用程序的开发和管理。它允许与多个区块链集成,并使各种第三方系统能够与其他各种系统交互。

该平台使用用 Solidity 语言编写的智能合约。它可以与以太坊或比特币等区块链进行交互。交互可以包括连接命令、启动、停止、断开连接和创建新区块链。在 Eris 中,与区块链的设置和交互相关的复杂性已被抽象化。所有命令对不同的区块链都是标准化的,在平台上可以使用相同的命令,而不管目标区块链类型如何。

一个生态系统应用可以包括 Eris 平台,从而实现 API 网关,以允许传统应用连接到密钥管理系统、共识引擎和应用引擎。Eris 平台提供了各种工具包,用于为开发人员提供各种服务。这些模块描述如下:

  • Chains: 这允许创建和与区块链进行交互。

  • Packages: 这允许开发智能合约。

  • Keys: 用于密钥管理和签名操作。

  • Files: 这允许与分布式数据管理系统一起工作。它可用于与 IPFS 和数据湖等文件系统进行交互。

  • Services: 这提供了一组服务,允许管理和整合生态系统应用程序。

Eris 还开发了几个 SDK,允许开发和管理生态系统应用程序。这些 SDK 包含经过完全测试并满足业务特定需求和要求的智能合约。例如,金融 SDK、保险 SDK 和物流 SDK。还有一个基本 SDK,作为管理生态系统应用程序生命周期的基本开发工具包。

Monax 开发了自己的权限区块链客户端,称为eris:db。这是一个基于 PoS 的区块链系统,允许与多种不同的区块链网络集成。eris:db客户端由四个组件组成:

  • Consensus: 这基于前面讨论过的 Tendermint 共识机制

  • Virtual machine: Eris 使用 EVM,因此支持 Solidity 编译的合约

  • Permissions layer: 作为权限账本,Eris 提供了一个可以用于在网络上分配不同实体的特定角色的访问控制机制

  • Interface: 这提供了各种命令行工具和 RPC 接口,以便与后端区块链网络进行交互

以太坊区块链和eris:db之间的关键区别在于eris:db使用了一个实用拜占庭容错(PBFT)算法,该算法实施为基于存款的权益证明(DPOS 系统),而以太坊使用 PoW。此外,eris:db使用了 ECDSA ed22519曲线方案,而以太坊使用了secp256k1算法。最后,它是有权限访问控制层的,而以太坊是公共区块链。

Eris 是一个功能丰富的应用平台,提供了大量的工具包和服务来开发基于区块链的应用程序。

它可以在monax.io/上找到。

总结

本章以替代区块链的介绍开始,分为讨论区块链和平台两个主要部分。区块链技术是一个非常繁荣的领域,因此现有解决方案的变化非常迅速,几乎每天都会引入新的相关技术或工具。在本章中,介绍了精心挑选的平台和区块链。考虑了一些与前几章涵盖的材料相辅相成的解决方案,例如支持区块链开发的 Eris。还讨论了新的区块链,如 Kadena,各种新的协议,如 Ripple,以及侧链和驱动链等概念。

本章涵盖的材料旨在为读者感兴趣的领域提供更深入研究的坚实基础。正如前面所说,区块链是一个发展迅猛的领域,还有许多其他区块链提议项目,如 Tau-Chain、HydraChain、Elements、CREDITS 等等,本章未涉及。鼓励读者关注该领域的发展,以及迅速增长的区块链技术的进步,以保持自己的更新。

在下一章中,我们将探讨区块链如何在其原始用途之外使用,即加密货币。我们将涵盖各种用例,特别是区块链在物联网中的使用。

第十五章:区块链 - 货币之外

数字货币是区块链技术的首次应用,可以说并没有意识到其真正的潜力。随着比特币的发明,区块链的概念首次被引入,但直到 2013 年才意识到了区块链技术在许多不同行业中的真正潜力,而不仅仅是加密货币。从那时起,人们提出了区块链技术在各个行业的许多用例,包括但不限于金融、物联网、数字版权管理、政府和法律。

在本章中,通过使用案例,选择了四个主要行业,即物联网、政府、卫生和金融,进行讨论。

2010 年,开始讨论 BitDNS,一个互联网域名的分散命名系统。然后,Namecoin (wiki.namecoin.org/index.php?title=History)于 2011 年 4 月开始,其愿景与比特币不同,比特币的唯一目的是提供电子现金。这可以被认为是除了纯粹的加密货币之外第一个区块链用途的例子。

从 2013 年开始,许多想法涌现出来。自 2013 年以来,这一趋势呈指数级增长。

物联网

物联网IoT)简称最近因其改变商业应用和日常生活的潜力而受到了很多关注。物联网可以被定义为一个由计算智能物理对象(如汽车、冰箱、工业传感器等任何物体)组成的网络,这些对象能够连接到互联网,感知现实世界的事件或环境,对这些事件做出反应,收集相关数据,并通过互联网进行通信。

这个简单的定义具有巨大的影响,并引发了令人兴奋的概念,如可穿戴设备、智能家居、智能电网、智能联网汽车和智能城市,这些概念都基于物联网设备的这一基本概念。在剖析物联网的定义之后,四个功能浮出水面,这些功能由物联网设备执行。这些功能包括感知反应收集通信。所有这些功能都是通过物联网设备上的各种组件执行的。

感知由传感器执行。反应或控制由执行器执行,收集是各种传感器的功能,通信是由提供网络连接的芯片执行的。值得注意的是,物联网中所有这些组件都可以通过互联网访问和控制。物联网设备本身可能在某种程度上有用,但如果它是更广泛的物联网生态系统的一部分,则更有价值。

典型的物联网可以由许多物理对象相互连接和连接到集中的云服务器组成。如下图所示:

典型的物联网网络

出处:IBM

物联网的元素分布在多个层中,且存在可用于开发物联网系统的各种参考架构。可使用五层模型来描述物联网,其中包含物理对象层,设备层,网络层,服务层和应用层。每个层级负责各种功能,并包含多个组件。这些显示在以下图中:

物联网五层模型

现在我们将详细检查每个层。

物理对象层

这些对象包括任何现实世界中的物体。包括人、动物、汽车、树木、冰箱、火车、工厂、家庭,实际上任何需要监控和控制的东西都可以连接到物联网。

设备层

此层包含构成物联网的东西,如传感器、传感器、执行器、智能手机、智能设备和射频识别RFID)标签。传感器可以有许多类别,如体感传感器、家庭传感器和基于其执行的工作类型的环境传感器。该层是物联网生态系统的核心,各种传感器用于感知现实环境。该层包括可以监测温度、湿度、液体流动、化学物质、空气、压力等的传感器。通常,设备上需要模拟至数字转换器ADC)将现实世界的模拟信号转换为微处理器可以理解的数字信号。

此层的执行器提供了启用对外部环境进行控制的手段,例如启动电机或打开门。这些组件还需要数字模拟转换器,以将数字信号转换为模拟信号。当物联网设备需要控制机械部件时,这种方法尤其重要。

网络层

该层由用于在物联网生态系统中设备之间和与云端或服务器之间提供互联网连接的各种网络设备组成。这些设备可以包括网关、路由器、集线器和交换机。该层可以包括两种通信类型。

首先是水平通信手段,包括无线电,蓝牙,Wi-Fi,以太网,局域网,Zigbee 和个人局域网(PAN),可用于提供物联网设备之间的通信。其次,我们有与下一层的通信,通常是通过互联网,提供机器与人或其他上层之间的通信。第一层可以选择性地包含在设备层,因为它实际上是位于设备层上的,设备可以在同一层相互通信。

管理层

该层为物联网生态系统提供管理层。这包括能够处理从物联网设备收集的数据并将其转化为有意义的洞见的平台。此外,设备管理、安全管理和数据流管理也包括在此层中。它还管理设备与应用层之间的通信。

应用层

此层包括在物联网网络顶部运行的应用程序。根据需求,此层可以包含许多应用程序,如交通运输、医疗保健、金融、保险或供应链管理。当然,这个列表并不是任何想象力的完整列表;有许多物联网应用可以归入此层。

随着廉价传感器、硬件和带宽的可用性,物联网近年来在各个领域获得了广泛的应用,目前在许多不同领域都有应用,包括医疗保健、保险、供应链管理、家庭自动化、工业自动化和基础设施管理。此外,技术的进步,如 IPv6 的可用性、更小更强大的处理器和更好的互联网接入,也在物联网的普及中发挥了关键作用。

物联网的好处从节省成本到使企业能够根据物联网设备提供的数据做出关键决策并因此提高绩效。即使在家庭使用中,物联网设备配备的家用电器也可以提供有价值的节能数据。例如,用于能源监测的智能电表可以提供有关能源使用情况的宝贵信息,并将其传达回服务提供商。来自数百万物品(物联网设备)的原始数据被分析并提供有意义的见解,有助于及时和有效地做出业务决策。

通常的物联网模型基于中心化范式,物联网设备通常连接到云基础设施或中央服务器以报告和处理相关数据。这种集中化带来了某些利用可能性,包括黑客攻击和数据盗窃。此外,对个人数据在单一中心化服务提供商上缺乏控制也增加了安全和隐私问题的可能性。虽然有方法和技术可以构建基于普通物联网模型的高度安全的物联网生态系统,但区块链对物联网可以带来特定且更加可取的好处。基于区块链的物联网模型不同于传统的物联网网络范式。

根据 IBM 的说法,区块链对物联网的作用在于帮助建立信任、降低成本并加速交易。此外,区块链技术的核心——去中心化,可以消除物联网网络中的单点故障。例如,一个中央服务器可能无法应对数十亿个物联网设备(物)以高频率产生的数据量。此外,区块链提供的点对点通信模型可以帮助降低成本,因为无需建立高成本的集中式数据中心或实施复杂的公钥基础设施来保障安全。设备可以直接或通过路由器相互通信。

据各种研究机构和公司的估计,到 2020 年,将有大约 220 亿台设备连接到互联网。随着数十亿台设备连接到互联网,很难想象集中式基础设施将能够满足对带宽、服务和可用性的高需求而不会产生过多的支出。基于区块链的物联网将能够解决当前物联网模型中的可扩展性、隐私性和可靠性问题。

区块链使“物”能够直接通信和交易,而且在智能合约的可用性下,谈判和金融交易也可以直接在设备之间进行,而无需中间商、权威或人工干预。例如,如果酒店中的一个房间空置,它可以出租自己,谈判租金,并为支付了足够资金的人打开门锁。另一个例子可能是,如果洗衣机用完了洗涤剂,它可以在智能合约中编程的逻辑基础上找到最优价格和价值后在线订购洗涤剂。

上述的五层物联网模型可以通过在网络层之上添加一个区块链层来适应基于区块链的模型。该层将运行智能合约,并为物联网生态系统提供安全性、隐私性、完整性、自主性、可扩展性和去中心化服务。在这种情况下,管理层可以仅由与分析和处理相关的软件组成,而安全性和控制可以移至区块链层。该模型可以在以下图表中可视化:

基于区块链的物联网模型

在这个模型中,其他层可能保持不变,但会引入一个额外的区块链层作为物联网网络所有参与者之间的中间件。

在摘除了前面提到的所有层之后,它也可以被视为点对点的物联网网络。在这个模型中,所有设备都在没有中央指挥和控制实体的情况下相互通信和协商,如下图所示:

基于区块链的直接通信模型,来源:IBM

采用基于区块链的去中心化方法,还可以实现成本节约。通过区块链,设备管理变得更容易。可以通过使用区块链优化物联网网络的性能。在这种情况下,不需要为数百万台设备集中存储物联网数据,因为存储和处理要求可以分布到区块链上的所有物联网设备上。这可以完全消除处理和存储物联网数据的大型数据中心的需求。

基于区块链的物联网还可以防止服务拒绝攻击,黑客可以更有效地针对集中服务器或数据中心,但使用区块链的分布式和去中心化性质,此类攻击不再可能。此外,如果按估计,很快将有数十亿台设备连接到互联网,从传统的集中式服务器管理所有这些设备的安全性和更新几乎是不可能的。区块链可以通过允许设备以安全的方式直接相互通信,甚至从彼此请求固件和安全更新来解决此问题。在区块链网络上,这些通信可以被记录下来,保证不可变性和安全性,从而为系统提供了可审计性、完整性和透明度。这种机制在传统的点对点系统中是不可能的。

总之,物联网和区块链的融合可以带来明显的好处,学术界和工业界已经在进行大量的研究和工作。已经提出了各种提供基于区块链的物联网解决方案的项目。例如,IBM 蓝色地平线和 IBM Bluemix 是支持区块链物联网平台的物联网平台。各种初创公司如 Filament 已经提出了关于如何构建使物联网设备能够直接和自主地通过智能合约进行交易的分散网络的新颖想法。

在接下来的部分,提供了一个实际的例子,说明了如何构建一个简单的物联网设备并将其连接到以太坊区块链。这个物联网设备连接到以太坊区块链,当区块链上的用户发送了适当数量的资金时,用于打开一扇门(在本例中,门锁由 LED 表示)。这只是一个简单的例子,需要一个更严格测试的版本才能将其投入生产,但它演示了如何将物联网设备连接、控制和响应于以太坊区块链上的某些事件。

物联网区块链实验

本示例使用了树莓派设备,树莓派是一种单板计算机SBC)。树莓派是一种低成本的计算机,旨在促进计算机教育,但也因其作为构建物联网平台的首选工具而广受欢迎。以下图片显示了树莓派 3 型 B 型。您也可以使用早期型号,但尚未经过测试:

树莓派 Model B

在接下来的部分中,将讨论一个例子,其中树莓派将作为连接到以太坊区块链的 IoT 设备,并响应智能合约调用的示例。

首先,需要设置树莓派。这可以通过使用 NOOBS 来完成,NOOBS 提供了一个安装 Raspbian 或其他操作系统的简单方法。

可以从链接www.raspberrypi.org/downloads/noobs/下载并安装。

或者,你可以从链接www.raspberrypi.org/downloads/raspbian/安装 Raspbian。

另一个可用的选择在github.com/debian-pi/raspbian-ua-netinst也可以用来安装 Raspbian OS 的最小非 GUI 版本。

对于本例,已经使用 NOOBS 来安装 Raspbian,因此,其余的操作假设 Raspbian 已经安装在树莓派的 SD 存储卡上。下面截图中的命令输出显示了操作系统正在运行的架构。在这种情况下,它是armv71;因此,将下载适用于 ARM 的 Geth 二进制文件。

可以通过在 Raspberry Pi Raspbian 操作系统的终端窗口中运行命令uname -a来确认平台。

树莓派架构

安装了 Raspbian 操作系统后,下一步是为树莓派 ARM 平台下载适当的 Geth 二进制文件。

下载和安装步骤详细描述如下:

  1. Geth 下载。请注意,在下面的示例中下载了特定版本,但也有其他可下载的版本,可以从geth.ethereum.org/downloads/下载。

我们可以使用wget来下载geth客户端映像:

      $ wget https://gethstore.blob.core.windows.net/builds/geth-linux- arm7-1.5.6-2a609af5.tar.gz

也可以使用其他版本,但建议你下载此版本,因为这是本章示例中使用的版本。

  1. 解压缩并提取到一个目录。使用下面显示的tar命令将自动创建名为geth-linux-arm7-1.5.6-2a609af5的目录:
      $ tar -zxvf geth-linux-arm7-1.5.6-2a609af5.tar

此命令将创建一个名为geth-linux-arm7-1.5.6-2a609af5的目录,并将 Geth 二进制文件和相关文件解压缩到该目录中。Geth 二进制文件可以复制到/usr/bin或 Raspbian 上的适当路径中,以便在操作系统中的任何地方都可用。下载完成后,下一步是创建创世区块。

  1. 需要使用创世区块。可以从网络上的其他节点复制创世文件。下图显示了这一点。或者,也可以生成一个全新的创世区块。
      { 
           "nonce": "0x0000000000000042", 
           "timestamp": "0x00", 
           "parentHash":   
           "0x0000000000000000000000000000000000000000000000000000000000000000", 
           "extraData": "0x00", 
           "gasLimit": "0x8000000", 
           "difficulty": "0x0400", 
           "mixhash":        
           "0x0000000000000000000000000000000000000000000000000000000000000000", 
           "coinbase": "0x3333333333333333333333333333333333333333", 
           "alloc": { 
           }, 
           "config": { 
               "chainId": 786, 
               "homesteadBlock": 0, 
               "eip155Block": 0, 
               "eip158Block": 0 
           } 
      }
  1. genesis.json文件复制到树莓派后,可以运行以下命令来生成起源块。重要的是使用先前生成的相同起源块,否则节点将实际上在不同的网络上运行:
 $ ./geth init genesis.json

将显示类似于以下截图中所示的输出:

初始化起源文件

  1. 创建起源块后,有必要向网络中添加对等节点。可以通过创建一个名为static-nodes.json的文件来实现,其中包含供树莓派上的geth用于同步连接的对等方的 enode ID:

静态节点配置

可以通过在 Geth JavaScript 控制台上运行以下命令来获取此信息,此命令应该在树莓派要连接的对等方上运行:

      > admin.nodeInfo

这将显示类似于以下截图中所示的输出:

geth nodeInfo

完成这一步之后,可以按照以下部分中提供的进一步说明来连接树莓派到私有网络上的其他节点。在本示例中,树莓派将连接到网络 ID 786 . 关键是使用先前创建的相同起源文件和不同的端口号。相同的起源文件将确保客户端连接到与起源文件相同的网络。

不同的端口不是严格要求的,但是,如果两个节点在私有网络下运行,并且需要从网络外部访问,则将使用 DMZ、路由器和端口转发的组合。因此,建议使用不同的 TCP 端口以确保端口转发工作正常。第一次节点设置中显示的--identity开关在以前并未介绍过,它允许为节点指定一个标识名称。

第一个节点设置

首先,需要使用以下命令在第一个节点上启动geth客户端:

$ geth --datadir .ethereum/privatenet/ --networkid 786 --maxpeers 5 --rpc --rpcapi web3,eth,debug,personal,net --rpcport 9001 --rpccorsdomain "*" -- port 30301 --identity "drequinox"  

这将产生类似于以下内容的输出:

第一个节点上的 geth

启动后,应保持其运行,并应从树莓派节点上启动另一个geth实例。

树莓派节点设置

在树莓派上,需要运行以下命令来启动geth并将其与其他节点进行同步(在本例中仅一个节点)。以下是命令:

$ ./geth --networkid 786 --maxpeers 5 --rpc --rpcapi web3,eth,debug,personal,net --rpccorsdomain "*" --port 30302 --identity "raspberry"  

这应产生类似于以下屏幕截图中显示的输出。当输出中包含显示区块同步已启动的行时,这意味着节点已成功连接到其对等节点。

树莓派上的 geth。

这可以通过在两个节点上的 geth 控制台中运行命令来进一步验证,如下面的截图所示。只需在树莓派上运行以下命令即可连接到 geth 客户端:

$ geth attach 

这将打开用于与 geth 节点交互的 JavaScript geth 控制台。我们可以使用 admin.peers 命令来查看连接的对等节点:

在树莓派上运行的 geth 控制台 admin peers 命令

类似地,可以通过在第一个节点上运行以下命令来连接到 geth 实例:

$ geth attach ipc:.ethereum/privatenet/geth.ipc  

一旦控制台可用,可以运行 admin.peers 命令来显示其他连接节点的详细信息,如下面的截图所示:

在其他对等节点上运行的 geth 控制台 admin peers 命令

一旦两个节点都启动,可以安装进一步的先决条件来设置实验。需要安装 Node.js 和相关的 JavaScript 库。

安装 Node.js

这里列出了所需的库和依赖项。首先需要在树莓派 Raspbian 操作系统上更新 Node.js 和 npm。为此,可以按照以下步骤进行操作:

  1. 使用以下命令在树莓派上安装最新的 Node.js:
      $ curl -sL https://deb.nodesource.com/setup_7.x | sudo -E bash -

这应该显示类似以下的输出。输出内容相当多,因此以下截图仅显示了输出的顶部部分:

安装 Node.js

  1. 通过 apt-get 运行更新:
      $ sudo apt-get install nodejs

可通过运行以下命令执行验证,以确保正确安装了 Node.js 和 npm 的正确版本,如下面的截图所示:

npm 和 node 安装验证

需要注意的是,这些版本并非必须;最新版本的 npm 和 Node.js 中的任何版本都应该可以使用。但是,本章的示例使用 npm 4.0.5 和 node v7.4.0,因此建议读者使用相同版本,以避免任何兼容性问题。

  1. 安装以启用 JavaScript 代码访问以太坊区块链的 Ethereum web3 npm:

确保安装了截图中显示的特定版本的 web3 或类似版本,例如 0.20.2。这很重要,因为默认情况下将安装 1.0.0-beta.26 版本(写作时的版本),该版本为 beta 版本,正在开发中。因此,本例应使用 web3 0.20.2 或 0.18.0 稳定版本。读者可以通过 $ npm install web3@0.20.2 命令安装此版本。

npm install web3

  1. 类似地,可以安装 npm onoff,以与树莓派进行通信并控制 GPIO:
      $ npm install onoff

安装 Onoff

安装了所有先决条件之后,可以进行硬件设置。为此,可以使用面包板和一些电子元件构建一个简单的电路。

硬件组件列示如下:

  • LED: 轻发光二极管的缩写,可以用作事件的视觉指示。

  • 电阻: 需要一个 330 欧姆的元件,根据其额定值对通过的电流提供阻力。对于本实验无需了解其背后的理论;任何标准的电子工程文本都详细介绍了所有这些主题。

  • 面包板: 这提供了一种不需要焊接就可以建立电子电路的方法。

  • T 形导线: 此导线如下图所示插入到面包板上,并提供了树莓派的通用输入/输出GPIO)管脚的标记视图。

  • 排线连接器: 这只是用于通过 GPIO 在树莓派和面包板之间提供连通性。所有这些组件如下图所示:

所需组件

电路

如下图所示,LED 的正腿(长腿)连接到 GPIO 的21管脚,负腿(短腿)连接到电阻,然后连接到 GPIO 的GND)管脚。一旦连接设置好,可以简单地使用排线连接到树莓派的 GPIO 连接器。

面包板上的组件连接

一旦连接正确设置,并且树莓派已经更新了适当的库和 Geth,下一步就是开发一个简单的智能合同,该合同期望一个值。如果提供给它的值不是它期望的,它就不会触发一个事件。然而,如果传递的值与正确的值匹配,事件就会触发,这个事件可以被在通过 Node.js 运行的客户端 JavaScript 程序读取。当然,Solidity 合同可能非常复杂,也可以处理发送到它的以太,如果以太的数量等于所需数量,那么事件就能触发。然而,在这个例子中,目标是展示使用智能合同来触发事件,然后通过 Node.js 上运行的 JavaScript 程序读取这些事件,然后借此可以使用各种库来触发物联网设备上的操作。

智能合同源代码如下:

简单 IOT 的 Solidity 代码

可以使用在线 Solidity 编译器(Remix IDE)来运行和测试本合同。与该合同交互所需的应用二进制接口ABI)也可在详情部分找到,如下截图所示:

来自 Remix IDE 的 ABI

以下是合同的 ABI:

[ 
    { 
        "constant": false, 
        "inputs": [ 
            { 
                "name": "x", 
                "type": "uint8" 
            } 
        ], 
        "name": "getRent", 
        "outputs": [ 
            { 
                "name": "", 
                "type": "bool" 
            } 
        ], 
        "payable": false, 
        "stateMutability": "nonpayable", 
        "type": "function" 
    }, 
    { 
        "anonymous": false, 
        "inputs": [ 
            { 
                "indexed": false, 
                "name": "returnValue", 
                "type": "bool" 
            } 
        ], 
        "name": "roomRented", 
        "type": "event" 
    } 
] 

树莓派节点可以通过web3接口连接到私有区块链有两种方法。第一种是树莓派设备在本地运行自己的geth客户端并维护其分类账,但对于资源受限的设备,在某些情况下,不可能运行完整的geth节点甚至是轻节点。在这种情况下,可以使用第二种方法,该方法使用web3提供程序连接到适当的 RPC 通道。这将在客户端 JavaScript Node.js 程序中稍后显示。

这两种方法的比较如下图所示:

房屋租赁物联网应用程序的应用架构(带本地分类账的物联网设备)

房屋租赁物联网应用程序的应用架构(不带本地分类账的物联网设备)

公开 RPC 接口会引发明显的安全问题;因此,建议仅在私有网络上使用此选项,如果需要在公共网络上使用,则应采取适当的安全措施,例如仅允许已知 IP 地址连接到geth RPC 接口。可以通过禁用对等发现机制和 HTTP-RPC 服务器监听接口的组合来实现这一点。

可以使用geth help获取有关此的更多信息。传统的网络安全措施,如防火墙、传输层安全性TLS)和证书也可以使用,但在本示例中未讨论。现在,Truffle 可以用于将合同部署到私有网络 ID 786,此时树莓派连接到该网络。可以通过使用以下显示的命令简单执行 Truffle 部署;

$ truffle migrate  

应该产生类似以下截图的输出:

Truffle 部署

一旦合同正确部署,可以开发 JavaScript 代码,该代码将通过web3连接到区块链,监听区块链中智能合同的事件,并通过树莓派点亮 LED。index.js文件的 JavaScript 代码如下所示:

var Web3 = require('web3');
if (typeof web3 !== 'undefined')
{
    web3 = new Web3(web3.currentProvider);
}else
{
    web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:9002")); 
    //http-rpc-port
}
var Gpio = require('onoff').Gpio; 
var led = new Gpio(21,'out');
var coinbase = web3.eth.coinbase;
var ABIString = '[{"constant":false,"inputs":[{"name":"x","type":"uint8"}],"name":"getRent","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"returnValue","type":"bool"}],"name":"roomRented","type":"event"}]';
var ABI = JSON.parse(ABIString);
var ContractAddress = '0x975881c44fbef4573fef33cccec1777a8f76669c';
web3.eth.defaultAccount = web3.eth.accounts[0];
var simpleiot = web3.eth.contract(ABI).at(ContractAddress);
var event = simpleiot.roomRented( {}, function(error, result) { if (!error)
{
    console.log("LED On");
    led.writeSync(1);
}
});

请注意,在上面的示例中,变量var ContractAddress的合同地址'0x975881c44fbef4573fef33cccec1777a8f76669c'是特定于部署的,当读者运行此示例时将会不同。只需在文件中将地址更改为部署合同后看到的内容即可。

还要注意树莓派上启动的 Geth 的 HTTP-RPC 服务器监听端口。默认情况下,它是 TCP 端口8545。记得根据您的树莓派设置和 Geth 配置更改此端口。在上面的示例代码中,它设置为9002,因为树莓派上运行的 Geth 在该示例中正在监听9002。如果您的树莓派上的监听端口不同,请将其更改为该端口:

web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:9002"));

当 Geth 启动时,它会显示它正在监听的 HTTP 端口。这也可以通过在 geth 中使用 --rpcport 并将端口号值作为标志的参数来配置。

这段 JavaScript 代码可以放在树莓派上的一个文件中,例如 index.js。它可以通过以下命令运行:

$ node index.js  

这将启动程序,该程序将在 Node.js 上运行,并监听来自智能合约的事件。一旦程序正确运行,就可以使用 Truffle 控制台调用智能合约,如下图所示。

在这种情况下,将调用 getRent 函数,并传入参数 10,这是预期的值:

与合约的交互

合约被挖出后,将触发 roomRented,从而打开 LED 灯。

在这个例子中,它是一个简单的 LED 灯,但它可以是任何可以通过执行器控制的物理设备,比如房间锁。如果一切顺利,LED 将在智能合约函数调用的结果下打开,如下图所示:

带有 LED 控制的 Raspberry Pi

另外,在节点端,它会显示类似于下图的输出:

$ node index.js
LED On 

正如前面的例子所示,可以建立一个私有网络的物联网设备,每个节点上运行一个 geth 客户端,并可以监听来自智能合约的事件,并相应地触发一个动作。所示的例子故意简单,但演示了使用物联网设备以及智能合约驱动的物理设备控制来构建以太坊网络的基本原理。

在下一节中,将讨论区块链技术在政府、金融和卫生等领域的其他应用。

政府

目前正在研究区块链的各种应用,可以支持政府职能,并将当前的电子政府模式提升到一个新的水平。首先,在本节中,将提供一些电子政府的背景信息,然后将讨论一些用例,如电子投票、国土安全(边境控制)和电子身份证(公民身份证)等。

政府或电子政府是一种利用信息和通信技术向公民提供公共服务的范例。这个概念并不新鲜,并已在世界各国实施,但是随着区块链的出现,一条新的探索途径已经打开。许多政府正在研究利用区块链技术管理和提供公共服务的可能性,包括但不限于身份证、驾驶证、各个政府部门之间的安全数据共享和合同管理。区块链的透明度、可审计性和完整性是可以有效管理各种政府职能的属性。

边境控制

自动边境管制系统已经使用了几十年,以阻止非法入境并防止恐怖主义和人口贩卖。

机读旅行证件,特别是生物识别护照,为自动边境管制铺平了道路;但是当前系统在某种程度上受到限制,区块链技术可以提供解决方案。国际民航组织ICAO)在文件 ICAO 9303(www.icao.int/publications/pages/publication.aspx?docnum=9303)中定义了机读旅行证件MRTD)标准,并已被世界上许多国家实施。

每个护照都包含各种安全和身份属性,可用于识别护照持有人,并且可以防止篡改护照的尝试。这些包括生物特征,如视网膜扫描、指纹、面部识别,以及标准的国际民航组织指定的特征,包括机读区MRZ)和其他可在护照第一页看到的文本属性。

当前边境管制系统的一个关键问题是数据共享,其中系统由单一实体控制,数据不会被立即共享给执法机构。这种无法共享数据的能力使得跟踪疑似旅行文件或个人变得具有挑战性。另一个问题与立即实施旅行文件黑名单相关,例如,当有必要立即跟踪和控制疑似旅行文件时。目前,没有可用的机制立即将疑似护照列入黑名单或撤销,并将其广播到全球边境管制口岸。

区块链可以通过在智能合约中维护黑名单来解决这个问题,该黑名单可以根据需要进行更新,并且任何更改都将立即对所有机构和边境管制点可见,从而实现对疑似旅行文件移动的即时控制。可以说,传统的机制,如公钥基础设施(PKIs)和点对点网络,也可以用于此目的,但它们不能提供区块链可以提供的好处。使用区块链,整个系统可以简化,而不需要复杂的网络和 PKI 设置,这也将导致成本降低。此外,基于区块链的系统将提供加密保证的不可变性,有助于审计并遏制任何欺诈行为。

由于可扩展性问题,目前可能无法将所有旅行文件的完整数据库存储在区块链上,但可以使用后端分布式数据库,如 BigchainDB、IPFS 或 Swarm。在这种情况下,可以在简单的智能合约中存储一个旅行文件的哈希,其中包含个人的生物特征 ID 的哈希,然后可以使用文件系统(如 IPFS)中可用的详细数据的文件哈希来引用文档的哈希。这样,当网络中的任何地方将旅行文件列入黑名单时,该信息将立即可用,并具有整个分布式分类帐的真实性和完整性的密码保证。这种功能也可以在反恐活动中提供足够的支持,从而在政府的国土安全职能中发挥重要作用。

Solidity 中的一个简单合约可以定义一个用于存储身份和相关生物识别记录的数组。这个数组可以用来存储关于护照的识别信息。身份可以是护照或旅行文件的 MRZ 的哈希,与 RFID 芯片的生物识别记录连接起来。一个简单的布尔字段可以用来识别被列入黑名单的护照。一旦这个初始检查通过,传统系统可以执行进一步详细的生物识别验证,最终当对护照持有人的入境决定做出时,该决定可以传播回区块链,从而使网络上的所有参与者可以立即分享决定的结果。

建立基于区块链的边境控制系统的高级方法可以可视化如下图所示。在这种情况下,护照被提供给 RFID 和页面扫描仪进行扫描,后者读取数据页面并提取机器可读信息以及存储在 RFID 芯片中的生物识别数据的哈希值。在这个阶段,还会拍摄护照持有者的实时照片和视网膜扫描。然后,将此信息传递给区块链,其中一个智能合约负责通过首先检查其黑名单护照列表来验证旅行文件的合法性,然后从后端 IPFS 数据库请求更多数据进行比较。请注意,诸如照片或视网膜扫描之类的生物识别数据不存储在区块链上,而是只在后端(IPFS 或 BigchainDB)存储对此数据的引用。

如果所呈现的护照数据与 IPFS 中的文件或 BigchainDB 中持有的数据匹配,并且通过智能合约的逻辑检查,则可以打开边境闸门。

使用区块链的自动边境控制

经过验证,此信息在整个区块链上传播,并立即对边境控制区块链上的所有参与者可用。这些参与者可以是各国国土安全部门的全球联盟。

投票

在任何政府中投票是一个关键功能,允许公民参与民主选举过程。尽管投票已经发展成为一个更加成熟和安全的过程,但它仍然存在需要解决的限制以达到期望的成熟水平。通常,当前投票系统的限制围绕欺诈、运营流程的弱点以及尤其是透明度展开。多年来,已经建立了安全投票机制(机器),使用了承诺安全和隐私的专用投票机,但它们仍然存在可以被利用来颠覆这些机器安全机制的漏洞。这些漏洞可能对整个投票过程产生严重影响,并导致公众对政府的不信任。

基于区块链的投票系统可以通过引入端到端的安全性和透明度来解决这些问题。安全性以公钥加密的形式提供,这是区块链的标准。此外,区块链保证的不可变性确保了一旦投票就不能再次投票。这可以通过使用生物特征和智能合约维护已经投票列表来实现。例如,智能合约可以维护一个已经投票的列表,其中包含生物特征 ID(例如指纹),并可以使用该列表来检测和阻止重复投票。其次,零知识证明ZKPs)也可以在区块链上用于保护选民的隐私。

一些公司已经提供了这样的服务,一个例子是 polys.me/blockchain/online-voting-system

最近,塞拉利昂通过区块链技术举行了总统选举,使其成为第一个使用区块链技术进行选举的国家(www.coindesk.com/sierra-leone-secretly-holds-first-blockchain-powered-presidential-vote/)。

公民身份识别(身份证)

当前,各国发行电子身份证或国民身份证。这些卡片安全,并具有许多安全功能,可防止复制或篡改企图。然而,随着区块链技术的出现,可以对此过程进行多项改进。

数字身份不仅限于政府发行的身份证,它也适用于在线社交网络和论坛。可以为不同目的使用多个身份。基于区块链的在线数字身份允许控制个人信息的分享。用户可以看到谁使用了他们的数据以及出于什么目的,并可以控制对其访问。这是目前由中心控制的基础设施无法实现的。关键好处在于政府发放的单一身份可以通过单一政府区块链轻松、透明地用于多项服务。在这种情况下,区块链充当平台,政府为多项服务,如养老金、税收或福利,提供了永久的记录。通过数字身份进行的每一次更改和交易都有永久记录,从而确保了系统的完整性和透明性。此外,公民可以在区块链上公证出生证明、结婚证书、契约等许多其他文件,并将其与数字身份关联作为存在的证明。

目前,各个国家都有成功实施的身份计划,运作良好,有人认为也许身份管理系统并不需要区块链。尽管目前区块链技术还不够成熟,但可能并未准备好用于现实世界的身份系统。然而,各国政府正在进行研究,探索区块链在身份管理方面的应用。

此外,像被遗忘权这样的法律可能因为区块链的不可变特性而很难整合。

其他杂项

区块链技术可以用于改善各种政府功能的成本和效率,包括税收征收、福利管理和发放、土地所有权记录管理、生活事件登记(婚姻、出生)、机动车登记和许可证等。这并不是一个详尽的清单,随着时间的推移,政府的许多功能和流程都可以适应基于区块链的模式。区块链的关键好处,比如不可变性、透明性和去中心化,有助于改善大多数传统政府系统。

健康

医疗行业也被确定为另一个可以通过采用区块链技术获益的主要行业。区块链提供了一个传统点对点网络无法提供的不可变、可审计和透明的系统。此外,与传统的复杂 PKI 网络相比,区块链提供了一种成本效益高、基础设施更简单的基础设施。在医疗保健领域,主要问题包括隐私泄露、数据泄露、高成本和欺诈,这些问题都是由于互操作性、过度复杂的流程、透明度、可审计性和控制不足而引起的。另一个迫切的问题是假药;尤其是在发展中国家,这是一个主要的关注点。

随着区块链在医疗领域的适应性,可以实现多种好处,从节约成本、增加信任、理赔处理速度更快、高可用性、由于操作程序复杂性而导致的没有操作错误,到预防假药的分发。

从另一个角度来看,提供数字货币作为挖矿激励的区块链可以用来提供处理能力以解决可以帮助找到某些疾病治愈方法的科学问题。例如,FoldingCoin 就是一个例子,它通过奖励其挖矿者 FLDC 代币来共享其计算机的处理能力,以解决需要异常大计算量的科学问题。

FoldingCoin 的网址为 foldingcoin.net/

另一个类似的项目叫做 CureCoin,网址为 www.curecoin.net/。目前还不清楚这些项目在实现其目标方面将会有多成功,但这个想法非常有前途。

金融

区块链在金融行业有许多应用。区块链在金融领域是目前行业内最热门的话题,主要银行和金融组织正在研究如何适应区块链技术,主要是因为它具有极具潜力的节省成本的潜力。

保险

在保险行业,区块链技术可以帮助阻止欺诈性索赔,提高理赔处理速度,并实现透明度。想象一下,所有保险公司之间共享的账本可以提供一个快速高效的机制来处理公司间的索赔。此外,随着物联网和区块链的融合,可以想象到一个智能设备生态系统,在这个生态系统中,所有这些设备可以通过区块链上的智能合约进行协商和管理其保险政策。

区块链可以减少处理索赔所需的总体成本和工作量。索赔可以通过智能合约自动验证和支付,以及与保险投保人的身份相关联。例如,借助 Oracle 和可能的物联网,智能合约可以确保在发生事故时记录相关遥测数据,并根据这些信息释放付款。如果智能合约在评估付款条件后得出结论认为不应释放付款,则还可以暂停付款。例如,在授权修车厂未修复车辆或在指定区域外使用等情况下等等。智能合约可以评估多种条件来处理索赔,选择这些规则取决于保险人,但总体想法是智能合约与物联网和 Oracle 结合起来可以自动化整个车辆保险行业。

几家初创公司,如 Dynamis,已提出基于以太坊区块链运行的智能合约的点对点保险平台。最初,这被建议用于失业保险,并不需要在模型中有承保人。

它可在 dynamisapp.com/ 上获取。

交易后结算

这是区块链技术最受追捧的应用。目前,许多金融机构正在探索使用区块链技术简化、自动化和加速昂贵而耗时的交易后结算流程的可能性。

为了更好地理解问题,简要描述了交易生命周期。交易生命周期包括三个步骤:执行、清算和结算。执行涉及两个当事方之间的交易承诺,并可通过前台订单管理终端或交易所输入到系统中。清算是下一步,根据价格和数量等某些属性,将交易匹配给卖方和买方。在这个阶段,还会确定涉及付款的帐户。最后,结算是买方和卖方最终交换证券以换取付款的地方。

在传统的交易生命周期模型中,需要中央清算所来促进各方之间的交易,它承担了双方的信用风险。当前方案有些复杂,卖方和买方必须采取复杂的路径来进行交易。这包括各种公司、经纪人、结算所和托管人,但通过区块链,一个具有适当智能合约的单一分布式账本可以简化整个过程,并使买卖双方可以直接交流。

值得注意的是,交易后结算流程通常需要两到三天,并且依赖于中央清算机构和对账系统。通过共享账本的方法,区块链上的所有参与者可以立即看到有关交易状态的一个真实版本。此外,点对点结算是可能的,这将减少交易结算所需的复杂性、成本、风险和时间。最后,通过在区块链上使用适当的智能合同,可以消除中间人。此外,监管机构还可以查看区块链以进行审计和监管要求。

这在实施 MIFID-II 监管要求时可能非常有用(www.fca.org.uk/markets/mifid-ii)。

金融犯罪预防

了解您的客户KYC)和反洗钱AML)是防范金融犯罪的关键因素。在 KYC 的情况下,目前,每个机构维护着自己的客户数据副本,并通过中心化数据提供商进行验证。这可能是一个耗时的过程,并可能导致新客户入职过程延迟。

区块链可以通过在所有金融机构之间安全地共享包含客户已验证和真实身份的分布式分类账来解决这一问题。只有通过参与者之间的共识才能更新这个分布式账本,从而提供透明性和可审计性。这不仅可以降低成本,还可以更好地、更一致地满足监管和合规要求。

在 AML 的情况下,由于区块链的不可变、共享和透明特性,监管机构可以轻松获准访问私有区块链,从中获取相关监管报告的数据。这还将减少与从各种传统和不同系统获取数据并将其聚合和格式化用于报告目的相关的成本和复杂性。区块链可以提供加密安全、真实验证、可审计的系统中所有金融交易的单一共享视图,从而降低当前采用的监管报告方法所带来的成本和复杂性。

媒体

媒体行业的关键问题围绕着内容分发、权利管理和向艺术家支付版税。例如,数字音乐可以无限制地复制,任何尝试应用复制保护的努力都以某种方式被破解。没有对音乐人或词曲作者制作的内容的分发进行控制;可以无限制地复制所需次数,并且对版税支付产生影响。此外,支付并不总是有保证的,并且是基于传统的播放时长数据。围绕复制保护和版税支付的所有这些问题可以通过将消费者、艺术家和行业中的所有参与者连接起来解决,从而实现透明和对流程的控制。区块链可以提供一个网络,数字音乐在密码学上被保证只由付费的消费者拥有。这种支付机制由智能合约而不是集中式媒体机构或管理机构控制。支付将根据嵌入在智能合约中的逻辑和下载次数自动进行。

最近的一个这样的倡议的例子是 Musicoin (musicoin.org)。

此外,数字音乐文件的非法复制可以完全停止,因为一切都以透明的方式记录和不可变地拥有在区块链上。例如,音乐文件可以存储有所有者信息和时间戳,可以在整个区块链网络中进行跟踪。此外,拥有某些内容的合法副本的消费者与其所拥有的内容在密码学上是绑定的,除非得到所有者的许可,否则不能转移到另一个所有者名下。一旦所有数字内容都被不可变地记录在区块链上,版权和转移就可以通过区块链轻松管理。智能合约可以控制对所有相关方的分发和支付。

摘要

区块链技术有许多应用,正如在本章中讨论的那样,它们可以在各个行业中实施,为现有解决方案带来多重好处。本章讨论了可以从区块链中受益的五个主要行业。首先讨论了物联网(IoT),这是另一种革命性的技术;通过将其与区块链相结合,可以解决一些基本限制,为物联网行业带来巨大的好处。物联网受到更多关注,因为它是最突出、最准备好的适应区块链技术的候选者。

已经出现了实际的使用案例和平台,以平台即服务PaaS)的形式出现,用于基于区块链的物联网,例如 IBM Watson IoT 区块链。IBM Blue Horizon 现在也可供实验使用,这是一个分散的基于区块链的物联网网络。其次,讨论了政府部门的应用,各种政府流程,如国土安全、身份证和福利发放可以变得更加透明、安全和强大。

此外,还讨论了金融领域的问题,以及区块链技术可能提供的解决方案。尽管金融行业正在充满热情和活力地探索使用区块链的可能性,但离生产就绪的基于区块链的系统还有很长的路要走。最后,还讨论了健康领域和音乐产业的某些方面。所有这些用例以及行业中更多的内容都依赖于区块链技术的核心属性,例如去中心化、透明度、可靠性和安全性。然而,在区块链技术完全适应之前,需要解决一些挑战;这些将在下一章中讨论。

第十六章:可扩展性及其他挑战

本章旨在介绍在区块链成为主流技术之前需要解决的各种挑战。尽管已经开发了各种用例和概念验证系统,并且该技术在许多场景下运行良好,但仍然需要解决一些存在于区块链中的根本性限制,以使这项技术更具适应性。

在这些问题清单的顶部是可扩展性,然后是隐私。这两者都是需要解决的重要限制,特别是在区块链被设想用于对隐私要求较高的行业时。在金融、法律和医疗等领域,对交易机密性有特定要求,而可扩展性通常是一个关注点,因为区块链未达到用户期望的充足性能水平。这两个问题正在成为阻碍区块链技术更广泛接受的因素。

将在本章中全面介绍当前提出的和正在进行的针对这两个特定领域的研究。除了隐私和安全性之外,其他挑战包括监管、整合、适应性和一般安全性。尽管在比特币区块链中安全性无懈可击,并经受住了时间的考验,但仍然存在一些情况可能会导致安全性在某些微妙的情景下受到损害的注意事项。此外,对于其他区块链,如以太坊,存在一些合理的安全性问题,涉及智能合约、拒绝服务攻击和大规模攻击面。所有这些将在下面的章节中详细讨论。

可扩展性

这个问题在过去几年中一直是激烈辩论、严格研究和媒体关注的焦点。

这是可能决定区块链更广泛适用性的最重要的问题之一,否则只能由财团限制性地进行个人使用。由于在这一领域进行了大量研究,提出了许多解决方案,这些解决方案将在下一节中讨论。

从理论上讲,解决可扩展性问题的一般方法通常围绕协议级别的增强。例如,解决比特币可扩展性的常见方法是增加其区块大小。其他提议包括将某些处理转移到链下网络的链下解决方案,例如链下状态网络。基于上述解决方案,一般而言,提议可以分为两类:链上解决方案,其基于改变区块链操作的基本协议的想法,以及链下解决方案,其利用链下的网络和处理资源以增强区块链。

最近,米勒等人在其位置论文关于扩展分散式区块链doi.org/10.1007/978-3-662-53357-4_8)中提出了解决区块链限制的另一种方法。在本文中,表明了区块链可以被划分为称为平面的各种抽象层。每个平面负责执行特定的功能。这些包括网络平面、共识平面、存储平面、视图平面和边平面。这种抽象允许在每个平面上单独且有条不紊地解决瓶颈和限制。下面的子节中简要概述了每个层,并参考了比特币系统。

网络平面

首先,讨论了网络平面。网络平面的一个关键功能是交易传播。在前述论文中已经确定,在比特币中,由于节点在传播和重复交易之前进行交易验证的方式,导致了网络带宽的低效利用,首先在交易广播阶段,然后在挖矿后的区块中。

应该注意到,BIP 152(Compact Block Relaygithub.com/bitcoin/bips/blob/master/bip-0152.mediawiki)已经解决了这个问题。

共识平面

第二层被称为共识平面。该层负责挖矿和达成共识。该层的瓶颈围绕着 PoW 算法的限制,增加共识速度和带宽会导致牺牲网络安全性,因为分叉数量增加。

存储平面

存储平面是第三层,用于存储总账。该层的问题围绕着每个节点需要保存整个总账的需求,这导致了某些效率低下,例如增加的带宽和存储需求。比特币有一种可用的方法叫做修剪,它允许节点在不需要保留完整区块链的情况下运行。修剪意味着当比特币节点下载并验证了区块链后,它会删除已经验证过的旧数据。这节省了存储空间。从存储角度来看,这项功能带来了重大改进。

视图平面

接下来是视图平面,提出了一个基于这样一个建议的优化,即比特币矿工不需要完整的区块链来运行,并且可以从完整的总账构建视图,作为系统整体状态的表示,这对于矿工的功能是足够的。视图的实现将消除挖矿节点存储完整区块链的需求。

最后,提出了前述研究论文的作者的旁观面。该面板代表着链下交易的概念,其中支付或交易通道的概念被用来卸载参与者之间的交易处理,但仍由主比特币区块链支持。

上述模型可用于以结构化的方式描述当前区块链设计的限制和改进。此外,过去几年中提出了几种可以解决当前以太坊和比特币等区块链设计限制的一般策略。这些方法也在以下部分中以个别方式进行特征化和讨论。

区块大小增加

这是增加区块链性能(交易处理吞吐量)最受争议的提案。目前,比特币每秒只能处理约三到七笔交易,这是适应比特币区块链处理微交易的主要限制因素。比特币的区块大小硬编码为 1 MB,但如果增加区块大小,它可以容纳更多交易并且可以缩短确认时间。有几个比特币改进提案BIPs)支持增加区块大小。这些包括 BIP 100、BIP 101、BIP 102、BIP 103 和 BIP 109。

历史参考资料和讨论的优秀账户可在en.bitcoin.it/wiki/Block_size_limit_controversy找到。

在以太坊中,区块大小不是通过硬编码来限制的;相反,它由燃气限制来控制。理论上,以太坊中的区块大小没有限制,因为它取决于燃气的数量,而燃气可以随着时间增加。这是可能的,因为如果在前一个区块中已经达到了限制,矿工被允许为后续区块增加燃气限制。比特币隔离见证通过将见证数据与交易数据分开处理来解决了这个问题,从而为交易提供了更多的空间。比特币的其他提案包括比特币无限制、比特币 XT 和比特币现金。读者可以参考第八章,介绍比特币,以获取更多详情。

获取更多信息,请参考以下链接:

区块间隔减少

另一个提案是减少每个区块生成之间的时间。可以减少区块之间的时间以实现更快的区块最终确认,但由于分叉数量的增加,可能会导致安全性降低。以太坊的区块时间已达到约 14 秒。

这是比特币区块链的重大改进,比特币区块链生成新区块需要 10 分钟的时间。在以太坊中,由于区块之间的时间较短导致的孤立区块问题通过使用贪婪最重观察子树GHOST)协议得到缓解,即孤立区块(叔块)也被用于确定有效链。一旦以太坊转向股权证明PoS),这将变得无关紧要,因为不再需要挖矿,几乎可以立即完成交易的最终确定。

可逆布隆查找表

这是另一种旨在减少比特币节点之间传输数据量的方法。可逆布隆查找表IBLTs)最初是由加文·安德森提出的,这种方法的关键吸引力在于,如果实施,它不会导致比特币的硬分叉。其关键思想是基于这样一个事实:没有必要在节点之间传输所有交易;相反,只需传输那些尚未在同步节点的交易池中可用的交易。这样可以在节点之间更快地同步交易池,从而提高比特币网络的整体可扩展性和速度。

分片

分片并不是一种新技术,在可扩展性方面已经被分布式数据库如 MongoDB 和 MySQL 使用。分片背后的关键思想是将任务分割成多个块,然后由多个节点进行处理。这样做可以提高吞吐量并减少存储需求。在区块链中,采用了类似的方案,其中网络的状态被分成多个分片。状态通常包括余额、代码、nonce 和存储。分片是运行在同一网络上的区块链的松散耦合分区。关于分片间通信和每个分片历史的共识存在一些挑战。这是一个开放的研究领域。

状态通道

这是另一种用于加速区块链网络上交易的方法。基本思想是使用侧通道来更新状态并处理主链之外的交易;一旦状态被最终确定,它就会被写回主链,从而将耗时的操作从主区块链中卸载出来。

状态通道通过执行以下三个步骤工作:

  1. 首先,区块链状态的一部分被锁定在智能合约下,确保参与者之间的协议和业务逻辑。

  2. 现在开始参与者之间的链下交易处理和交互,暂时只在他们之间更新状态。在此步骤中,几乎可以执行任意数量的交易而无需区块链,这是使该过程快速并成为解决区块链可扩展性问题的最佳候选方案的原因。然而,可以说这不是真正的在区块链上的解决方案,例如,分片,但最终结果是一个更快,更轻,更健壮的网络,这可能在微支付网络,物联网网络和许多其他应用中非常有用。

  3. 一旦达到最终状态,状态通道将关闭,并将最终状态写回主区块链。在此阶段,区块链的锁定部分也将被解锁。

此过程如下图所示:

状态通道

这种技术已经在比特币闪电网络和以太坊的雷电网络中使用。

私有区块链

私有区块链本质上是快速的,因为不需要真正的去中心化,参与网络的成员也不需要挖矿;相反,他们只能验证交易。这可以被视为公共区块链中可扩展性问题的一种变通方法;然而,这并不是解决可扩展性问题的方法。另外,需要注意的是,私有区块链仅适用于特定领域和设置,例如所有参与者都已知的企业环境。

股权证明

工作量证明PoW)不同,基于 PoS 算法的区块链基本上更快。 PoS 在第十章 替代硬币中有更详细的解释。

侧链

通过允许许多侧链与主区块链一起运行,并允许使用可能相对不太安全且更快的侧链执行交易但仍与主区块链挂钩,侧链可以间接提高可扩展性。侧链的核心思想称为双向锚定,它允许从父链向侧链和反向传输币。

子链

这是由彼得·R·里宗最近提出的一种相对较新的技术,其基本思想是基于弱块的概念,这些弱块在层层叠加直到找到一个强块为止。弱块可以定义为那些未能通过标准网络难度标准进行挖掘但已经完成足够工作以满足另一个更弱难度目标的块。矿工可以通过将弱块层层叠加在一起来构建子链,除非找到符合标准难度目标的块。

在这一点上,子链被关闭并成为强块。这种方法的优点包括减少了对交易首次验证的等待时间。这种技术还减少了孤块的产生几率,并加快了交易处理速度。这也是间接解决可扩展性问题的一种方式。子链不需要任何软分叉或硬分叉来实现,但需要社区的接受。

子链研究论文可在www.ledgerjournal.org/ojs/index.php/ledger/article/view/40处获取。

树链(树)

还有其他提高比特币可扩展性的提议,例如将区块链布局从线性顺序模型更改为树状结构的树链。该树基本上是从主比特币链延伸下来的二叉树。这种方法类似于侧链实现,消除了对主要协议更改或区块大小增加的需求。它允许改进的交易吞吐量。在这个方案中,区块链本身被分割并分布在网络中以实现可扩展性。

此外,验证树链上的区块不需要挖矿;相反,用户可以独立验证区块头。然而,这个想法目前尚未准备好投入生产,需要进一步研究以使其实用化。

最初的想法是在研究论文eprint.iacr.org/2016/545.pdf中提出的。

除了前述的一般技术外,Christian Decker (scholar.google.ch/citations?user=ZaeGlZIAAAAJ&hl=en) 在他的书籍《论比特币的可扩展性和安全性》中还提出了一些比特币特定的改进。该提议基于加速传播时间的想法,因为当前的信息传播机制导致了区块链分叉。这些技术包括验证最小化、区块传播的流水线化和连接性增加。这些变化不需要基本协议级别的更改;相反,这些变化可以独立于比特币节点软件中实施。

关于验证最小化,已经注意到区块验证过程导致了传播延迟。这背后的原因是节点花费了很长时间来验证区块和区块内的交易的唯一性。有人建议,一旦完成了初始的 PoW 和区块验证检查,节点就可以发送清单消息。通过只执行第一次难度检查,而不必等待交易验证完成,可以改善传播效率。

区块传播

除了前述的提案外,还提出了块传播的流水线化,这是基于预期一个区块的可用性的想法。在这个方案中,区块的可用性已经宣布,而不必等待实际的区块可用性,从而减少节点之间的往返时间。最后,交易发起者和节点之间的长距离也导致了块传播的减速。Christian Decker 进行的研究表明连接增加可以减少区块和交易的传播延迟。这是可能的,因为如果任何时候比特币节点连接到许多其他节点,那么它将减少节点之间的距离,并且可以加快网络上的信息传播速度。

解决可扩展性问题的一种优雅的方案很可能是一些或所有前述一般方法的组合。针对解决区块链中的可扩展性和安全性问题所采取的一些举措现在几乎已经准备好实施或已经实施。例如,比特币隔离见证SegWit)是一个可以大大提高可扩展性的提案,只需要软分叉才能实施。所谓隔离见证背后的关键思想是将签名数据与交易分离,从而解决交易可变性问题并允许增加区块大小,从而提高吞吐量。

Bitcoin-NG

另一个提案,基于微区块和领导者选举的 Bitcoin-NG,最近引起了一些关注。其核心思想是将区块分成两种类型,即领导者块(也称为关键块)和微区块:

  • 领导者块:这些负责工作证明,而微区块包含实际的交易。

  • 微区块:这些不需要任何工作量证明,并由每个区块生成周期选举产生的领导者生成。该区块生成周期是由领导者块发起的。唯一的要求是使用选举产生领导者的私钥对微区块进行签名。选举产生的领导者(矿工)可以以非常高的速度生成微区块,从而提高性能和交易速度。

另一方面,以太坊的一份紫红色论文由 Vitalik Buterin 在上海的以太坊 Devcon2 上提出;它描述了一个可规模化的以太坊的愿景。紫红色提案基于分片和 PoS 算法的结合。该论文确定了一些目标,如通过 PoS 实现的效率提升,最大可能的快速区块时间,经济最终性,可伸缩性,跨分片通信和抗审查。

Mauve paper 可以在docs.google.com/document/d/1maFT3cpHvwn29gLvtY4WcQiI6kRbN_nbCf3JlgR3m_8/edit#找到。

Plasma

另一个最近的可扩展性提案是Plasma,由 Joseph Poon 和 Vitalik Buterin 提出。该提案描述了在根区块链(以太坊主网)上运行智能合约的想法,并在子区块链上执行大量的交易,将少量的承诺反馈到父链上。在这个方案中,区块链被排列成树状层次结构,只在根(主)区块链上进行挖矿,并向子链传递安全性证明。这也被称为 Layer-2 系统,就像状态通道也在 Layer 2 上运行,而不是在主链上。

研究论文可在plasma.io找到。

隐私

区块链的交易隐私是人们非常期望的特性。然而,由于其本质,特别是在公开的区块链中,一切都是透明的,因此抑制了它在一些隐私至关重要的行业中的使用,比如金融、医疗等。针对隐私问题已经提出了不同的解决方案,并且已经取得了一些进展。其中包括不可区分性混淆IO)、同态加密、零知识证明(ZKPs)和环签名等多种技术。

所有这些技术都有其优点和缺点,并将在以下章节中讨论。

不可区分性混淆

这种密码学技术可能成为解决区块链中所有隐私和机密性问题的万能药,但这项技术尚未准备好投入生产部署。IO 允许对代码进行混淆,这是密码学中一个非常成熟的研究课题,如果应用于区块链,可以作为一个不可破解的混淆机制,将智能合约转化为黑匣子。

IO 背后的关键思想是研究人员称之为多线性拼图,它基本上通过将程序代码与随机元素混合来混淆程序代码,如果程序按预期运行,它将产生预期的输出,但以任何其他方式执行都会使程序看起来是随机的垃圾。这个想法最初是由 Shai 等人在他们的研究论文候选不可区分性混淆和所有电路的功能加密中提出的。

此研究论文可在doi.org/10.1109/FOCS.2013.13找到。

同态加密

这种类型的加密允许对加密数据进行操作。想象一下,数据被发送到云服务器进行处理的情况。服务器对其进行处理并返回输出,而不知道它处理的数据是什么。这也是一个值得研究的领域,全同态加密允许对加密数据进行所有操作,但尚未完全投入生产使用;然而,在这个领域已经取得了重大进展。一旦在区块链上实施,它可以允许在密文上进行处理,从而在本质上保护交易的隐私和保密性。例如,存储在区块链上的数据可以使用同态加密进行加密,然后可以对该数据执行计算,而无需解密,从而在区块链上提供隐私服务。这个概念也已经在一个名为 Enigma 的项目中实现,该项目可在线访问 (www.media.mit.edu/projects/enigma/overview/),由麻省理工学院媒体实验室开发。Enigma 是一个对等网络,允许多个参与方在不透露数据任何内容的情况下对加密数据进行计算。

原始研究可在此处找到 crypto.stanford.edu/craig/

零知识证明

ZKPs 最近在 Zcash 中成功实施,见 Chapter 10, 替代货币。更具体地说,SNARK(简称 简洁非交互式知识论证)已经被实现,以确保区块链上的隐私。

同样的思想也可以在以太坊和其他区块链上实现。在以太坊上整合 Zcash 已经是由以太坊研发团队和 Zcash 公司进行的非常活跃的研究项目。

原始研究论文可在此处找到 eprint.iacr.org/2013/879.pdf.

另一篇优秀的论文在这里 chriseth.github.io/notes/articles/zksnarks/zksnarks.pdf.

在零知识证明家族中最近新增了零知识简洁透明知识论证 (ZK-STARKs),这是对 ZK-SNARKs 的改进,因为 ZK-STARKs 消耗的带宽和存储要远远少于 ZK-SNARKs。而且,它们不需要像 ZK-SNARKs 那样的初始、有些有争议的可信设置。此外,ZK-STARKs 比 ZK-SNARKs 快得多,因为它们不使用椭圆曲线,而是依赖哈希。

ZK-STARKs 的原始研究论文可以在这里找到 eprint.iacr.org/2018/046.pdf.

状态通道

使用状态通道进行隐私保护也是可能的,这仅仅是因为所有交易都是在链下运行,主要的区块链完全看不到交易,除了最终状态的输出,从而确保隐私和保密性。

安全的多方计算

安全多方计算的概念并不新颖,它是基于数据在参与方之间的秘密共享机制下分割成多个部分,然后在不需要在单个机器上重建数据的情况下对数据进行实际处理的概念。处理后产生的输出也在参与方之间共享。

使用硬件提供机密性

可信计算平台可用于提供在区块链上实现交易机密性的机制,例如,可以使用英特尔的软件保护扩展SGX),它允许代码在一个称为飞地的硬件保护环境中运行。一旦代码在孤立飞地中成功运行,它可以生成一个被英特尔云服务器所证实的证明,称为报价。然而,担心信任英特尔将导致某种程度上的中心化,并且不符合区块链技术的真正精神。尽管如此,这个解决方案有其优点,在现实中,许多平台已经使用英特尔芯片,因此在某些情况下信任英特尔可能是可以接受的。

如果这项技术应用于智能合约,那么一旦节点执行了智能合约,它可以生成报价作为正确和成功执行的证据,其他节点只需验证即可。这个想法还可以通过使用任何可信执行环境TEE)来进一步扩展,这可以提供与飞地相同的功能,在近场通讯NFC)和安全元件上甚至可以在移动设备上使用。

CoinJoin

CoinJoin 是一种技术,用于通过互动混合来使比特币交易匿名化。这个想法是基于向来自多个实体的输入和输出形成单个交易而不引起任何改变。它消除了发送方和接收方之间的直接联系,这意味着一个地址不再能与交易相关联,这可能导致用户的识别。CoinJoin 需要多个愿意通过混合支付创建单个交易的参与方之间的合作。因此,应该注意到,如果 CoinJoin 计划中的任何单个参与者未能遵守承诺,即不按照所需签署交易,那么就可能导致拒绝服务攻击。

在这个协议中,没有必要有一个单一的受信任的第三方。这个概念与一个充当受信任的第三方或中介的服务混合是不同的,它允许比特币用户之间的交易混合。这种交易混合导致了追踪和将支付与特定用户联系起来的防止。

保密交易

保密交易利用 Pedersen 承诺来提供保密性。承诺方案允许用户承诺一些值,同时保持秘密,并具有以后披露的能力。设计承诺方案需要满足的两个属性是绑定和隐藏。

绑定确保提交者一旦提交就无法更改所选值,而隐藏属性确保任何对手无法找到提交者所做承诺的原始值。 Pedersen 承诺还允许添加操作,并在承诺上保留交换性质,这使得它特别适用于在比特币交易中提供机密性。换句话说,它支持对值进行同态加密。使用承诺方案可以隐藏比特币交易中的支付值。这个概念已经在 Elements 项目中实现了(https😕/elementsproject.org/).

MimbleWimble

MimbleWimble 方案在比特币 IRC 频道上有些神秘地提出,自那时以来已经获得了很大的流行。MimbleWimble 扩展了保密交易和 CoinJoin 的概念,允许在不需要任何互动的情况下聚合交易。然而,它不支持与标准比特币协议的各种其他特性一起使用比特币脚本语言。这使得它与现有的比特币协议不兼容。因此,它可以作为比特币的一个侧链实现,或者作为另一种替代加密货币。

该方案可以同时解决隐私性和可扩展性问题。 使用 MimbleWimble 技术创建的块不像传统比特币区块链中那样包含交易; 相反,这些块由三个列表组成:输入列表、输出列表和称为剩余量的内容,其中包含签名列表和输出与输入之间的差异。 输入列表基本上是对旧输出的引用,输出列表包含机密交易输出。 这些块通过使用签名、输入和输出进行验证,以确保块的合法性。 与比特币相比,MimbleWimble 交易输出仅包含公钥,并且旧输出与新输出之间的差异由参与交易的所有参与者签名。

安全性

尽管区块链通常是安全的,并根据需要在整个区块链网络中使用非对称和对称加密,但仍然有一些细微差别可能会危及区块链的安全。

有一些交易篡改、日食攻击以及比特币可能发生双重花费的示例,在某些情况下,已经被各种研究人员证明是可行的。 交易篡改打开了双重提取或存款的可能性,允许黑客在比特币网络确认之前更改交易的唯一标识符,从而导致一种看起来似乎不存在交易的情况。 BIP 62 是提出解决此问题的提案之一,与 SegWit 一起。 应该注意,这只在未确认交易的情况下成为问题,也就是说,操作流程依赖于未确认交易的情况下。 对于仅依赖于已确认交易的正常应用程序而言,这不是问题。

在比特币中,信息日食攻击可能导致双重花费。 日食攻击背后的想法是欺骗比特币节点仅连接到攻击者节点 IP。 这打开了攻击者进行 51% 攻击的可能性。 这在比特币客户端 v0.10.1 中已经得到了一定程度的解决。

智能合约安全性

最近,智能合约安全性方面的工作已经开始,特别是正在讨论和研究智能合约的形式验证。 这一切特别是由于臭名昭著的 DAO 黑客攻击而引发。

形式验证是验证计算机程序以确保其满足某些形式化语句的过程。 这现在是一个新概念,有许多可用于其他语言的工具来实现这一点; 例如,Frama-C (frama-c.com) 可用于分析 C 程序。 形式验证的关键思想是将源程序转换为一组可由自动证明者理解的语句。

为此,通常使用 Why3 (why3.lri.fr),Solidity 的形式验证器也利用了它。一个实验性但可操作的验证器已经在浏览器 Solidity 中提供。

智能合约安全现在至关重要,还采取了许多其他举措来制定可以分析 Solidity 程序并查找漏洞的方法。最近和重要的一个例子是 Oyente,这是研究人员构建的一个工具,并已在他们的论文《使智能合约更智能》中介绍。

Oyente 可在 github.com/melonproject/oyente 找到。

本文发现并分析了智能合约中的几个安全漏洞。这些包括事务顺序依赖性、时间戳依赖性、异常处理不当,如调用堆栈深度限制利用,以及重入漏洞。事务顺序依赖性漏洞基本上利用了合同的感知状态可能不是执行后合同的状态的情况。

此弱点是一种竞争条件。它也被称为前置负载,并且由于事务在块内的顺序可以被操纵而成为可能。由于所有事务首先出现在内存池中,因此可以在它们被包含在块中之前监视内存池中的事务。这允许在另一个事务之前提交一个事务,从而控制智能合约的行为。

时间戳依赖性漏洞可能存在于块的时间戳被用作合同内某些决策的来源的情况下,但时间戳可以被矿工操纵。调用堆栈深度限制是另一个可能被利用的漏洞,因为 EVM 的最大调用堆栈深度为 1,024 帧。如果在合同执行时达到堆栈深度,则在某些情况下,send 或 call 指令可能会失败,导致资金未支付。调用堆栈深度 bug 已在 EIP 50 硬分叉中得到解决 github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md

利用重入漏洞在 DAO 攻击中被利用,将数百万美元转移到子 DAO。重入漏洞基本上意味着在函数的上一次(第一次)调用完成之前可以重复调用该函数。在 Solidity 智能合约中的 Ether 提取函数中,这特别不安全。

除了上述的漏洞外,在编写合同时还应注意几个其他问题。这些漏洞包括向另一个合同发送资金时要小心,因为 send 可能会失败,即使使用 throw 作为捕获所有机制,也无法正常工作。

其他标准软件 bug,如整数溢出和下溢,也非常重要,对 Solidity 中任何整数变量的使用都应谨慎实施。例如,使用 uint8 解析超过 255 个元素的数组的简单程序可能会导致无限循环。这是因为 uint8 限制为 256 个数字。

在接下来的几节中,将分别使用 Remix IDE、Why3 和 Oyente 展示两个合约验证的示例。

形式验证和分析

Solidity 代码的安全性分析现在作为 Remix 中的一个功能提供。代码将被分析以查找漏洞,并在 remix IDE 的分析选项卡中报告:

Remix IDE 分析选项

含有重入漏洞的相同合约的示例输出显示在前述截图底部。

此工具分析了几类漏洞,包括安全性、燃气和经济性。如前述截图所示,分析工具成功检测到了重入漏洞,详细信息显示在屏幕底部。

Why3 也可用于形式分析 Solidity 代码。

Why3 可在 why3.lri.fr/try/ 获取。

在以下示例中,显示了一个简单的 Solidity 代码,该代码将 z 变量定义为 uint 的最大限制。当此代码运行时,将返回 0,因为 uint z 将溢出并重新从 0 开始。这也可以使用 Why3 进行验证,如下所示:

具有形式验证功能的 Solidity 在线编译器

在 Solidity 在线编译器中曾提供将 Solidity 代码转换为 Why3 兼容代码的功能,但现已不再提供。因此,以下示例仅供完整性目的和阐明一个重要的 bug 类别,这些 bug 可以在传统工具中未被检测到。在此示例中,以整数溢出为例。

以下示例显示了 Why3 成功检查并报告整数溢出错误。此工具正在积极开发中,但仍然非常有用。此外,此工具或任何其他类似工具都不是万能药。即使形式验证通常也不应被认为是万能药,因为首先应适当定义规范:

Why3

Oyente 工具

目前,Oyente 作为 Docker 镜像提供方便的测试和安装。它可在 github.com/melonproject/oyente 获取并下载以供测试。

在以下示例中,从 Solidity 文档中提取的一个包含重入漏洞的简单合约已经被测试,并且显示 Oyente 成功分析了代码并发现了漏洞:

带有可重入漏洞的合约,来源:solidity 文档

此示例代码包含可重入漏洞,这基本上意味着如果一个合约正在与另一个合约交互或转移以太币,它实际上是将控制权交给了该另一个合约。这使得被调用的合约可以立即调用回来自被调用合约的函数,而无需等待完成。例如,此漏洞可以允许多次调用前面示例中所示的 withdraw 函数,导致多次获得以太币。这是可能的,因为在函数结束之前股份值未设置为 0,这意味着任何后续调用都将成功,导致不断提款。

显示了 Oyente 运行分析此处所示合约的示例,如下图所示,分析成功发现了可重入漏洞。建议通过结合 solidity 文档中描述的 Checks-Effects-Interactions 模式来处理此漏洞:

Oyente 工具检测 solidity 漏洞

Oyente 也可在智能合约分析工具中使用,网址为 oyente.melon.fund。此处显示了示例输出。

通过此示例,我们结束了对 solidity 安全性和分析工具的介绍。这是一个非常丰富的研究领域,预计随着时间的推移会有越来越多的工具可用。

Oyente 分析

总结

在本章中,读者已经被介绍了区块链技术的安全性、保密性和隐私性方面。讨论了隐私,这是将公共区块链应用于各行业的另一个主要阻碍因素。接下来,讨论了智能合约安全性,这是目前一个非常热门的话题。这是一个深度广泛的主题,但已经给出了各个方面的简要介绍,这应该为进一步研究这一领域奠定了坚实的基础。

例如,形式化验证本身是一个广阔的研究领域。此外,还提供了形式化验证的示例,以便读者了解可用的工具。值得注意的是,前面提到的工具正在积极开发中,并且缺乏各种理想的功能。此外,文档相当稀缺;因此,鼓励读者密切关注发展情况,特别是与形式化验证和以太坊 mauve 论文相关的发展,因为它即将迅速发展。区块链安全,尤其是智能合约安全领域现在非常成熟,以至于可以撰写一整本书来讨论此主题。

学术界和商业领域中有许多专家和研究人员在探索这一领域,很快将会有许多自动化工具可用于验证智能合约。目前已经有一个在线工具可用于分析智能合约代码以查找安全漏洞,网址为securify.ch

第十七章:构建联盟区块链

联盟(通常由多个参与者组成,如银行、电子商务网站、政府实体、医院等)可以利用区块链技术解决许多问题,使事情变得更快更便宜。尽管他们弄清楚了区块链如何帮助他们,以太坊的区块链实现并不特别适合所有情况。尽管还有其他区块链实现(例如 Hyperledger)专门为联盟进行构建,但在本书中我们将看到如何使用以太坊来构建联盟区块链。基本上,我们将使用 parity 来构建联盟区块链。虽然还有其他替代方案,如摩根大通的 quorum,我们将使用 parity,因为在撰写本书时,它已存在了一段时间,并且许多企业已经在使用它,而其他替代方案尚未被任何企业使用。但是对于您的需求,parity 可能并不是最好的解决方案;因此,在决定使用哪种解决方案之前,请调查所有其他解决方案。

在本章中,我们将涵盖以下主题:

  • 为什么以太坊不适用于联盟区块链?

  • 什么是 parity 节点,它有哪些特性?

  • 什么是权威证明共识协议,并且 parity 支持哪些 PoA 类型?

  • Aura 共识协议是如何工作的?

  • 下载和安装 parity

  • 使用 parity 构建联盟区块链

联盟区块链是什么?

要了解什么是联盟区块链,或者换句话说,联盟需要什么样的区块链实现,我们来看一个例子。银行希望构建一个区块链,使资金转账变得更简单、更快捷、更便宜。在这种情况下,他们需要以下内容:

  1. 速度:他们需要一个可以在近实时内确认交易的区块链网络。目前,以太坊区块链网络的区块时间为 12 秒,客户通常要等待几分钟才能确认一笔交易。

  2. 许可:他们希望区块链是有许可的。许可本身意味着不同的事情。例如:许可可以包括获得加入网络的许可,可以包括获得创建区块的许可,也可以包括获得发送特定交易的许可等等。

  3. 安全:对于私有网络来说,工作量证明(PoW)并不安全,因为参与者数量有限;因此,产生的哈希算力不足以使其安全。因此,需要一种可以保持区块链安全和不可变性的共识协议。

  4. 隐私:尽管网络是私有的,在网络本身仍然需要隐私。有两种隐私:

  5. 身份隐私:身份隐私是使身份无法追踪的行为。我们之前看到的获得身份隐私的解决方案是使用多个以太坊账户地址。但是,如果使用多个以太坊账户,则智能合约将无法通过所有权验证,因为无法知道这些账户是否实际上属于同一用户。

  6. 数据隐私:有时,我们不希望数据对网络中的所有节点可见,而只对特定节点可见。

总的来说,在本章中,我们将学习如何解决以太坊中的这些问题。

什么是权威证明共识?

PoA 是一种区块链共识机制,共识是通过参考验证器列表(当它们与物理实体相关联时称为权威)来实现的。验证器是一组被允许参与共识的账户/节点;它们验证交易和区块。

与 PoW 或 PoS 不同,没有涉及挖矿机制。有各种类型的 PoA 协议,它们的差异取决于它们的实际工作方式。Hyperledger 和 Ripple 都是基于 PoA 的。Hyperledger 基于 PBFT,而 Ripple 使用迭代过程。

Parity 简介

Parity 是从头开始为正确性/可验证性、模块化、低资源占用和高性能而编写的以太坊节点。它是用 Rust 编程语言编写的,这是一种具有效率重点的混合命令式/OO/函数式语言。它由 Parity Technologies 专业开发。在撰写本书时,parity 的最新版本是 1.7.0,我们将使用此版本。我们将学习构建联盟区块链所需的所有内容。要深入了解 parity,您可以参考官方文档。

它比 go-ethereum 具有更多功能,如 web3 dapp 浏览器,更高级的账户管理等。但是使它特殊的是它支持权威证明PoA)以及 PoW。Parity 目前支持 Aura 和 Tendermint PoA 协议。未来,它可能支持更多的 PoA 协议。目前,Parity 建议使用 Aura 而不是 Tendermint,因为 Tendermint 仍在开发中。

对于权限区块链来说,Aura 比 PoW 是一个更好的解决方案,因为它拥有更好的区块时间,并且在私有网络中提供了更好的安全性。

理解 Aura 的工作原理

让我们从高层次了解 Aura 的工作原理。Aura 要求在每个节点中都指定相同的验证器列表。这是一组参与共识的账户地址。一个节点可能是验证节点,也可能不是。即使是验证节点,也需要有这个列表,以便它自己能达成共识。

如果验证者列表将永远保持不变,那么可以将此列表作为静态列表包含在创世文件中,或者将其提供在智能合约中,以便可以动态更新并使每个节点都知道它。在智能合约中,您可以配置有关谁可以添加新验证者的各种策略。

区块时间可以在创世文件中进行配置。由你决定区块时间。在私有网络中,3 秒的区块时间效果很好。在 Aura 中,每三秒钟选择一个验证者,这个验证者负责创建、验证、签名和广播该区块。我们不需要太了解实际的选择算法,因为它不会影响我们的 dapp 开发。但这是计算下一个验证者的公式,(UNIX_TIMESTAMP / BLOCK_TIME % NUMBER_OF_TOTAL_VALIDATORS)。选择算法足够智能,给每个人平等的机会。当其他节点接收到一个区块时,它们会检查它是否来自下一个有效的验证者;如果不是,则会拒绝它。与 PoW 不同,当验证者创建一个区块时,它不会受到以太币的奖励。在 Aura 中,决定在没有交易时是否生成空块是由我们决定的。

你一定会想知道,如果由于某些原因,下一个验证节点无法创建和广播下一个区块会发生什么。为了理解这一点,让我们举个例子:假设 A 是第五个区块的验证者,而 B 是第六个区块的验证者。假设区块时间为五秒。如果 A 未能广播一个区块,那么当 B 的轮到时,它将在五秒后广播一个区块。所以实际上没什么严重的事情发生。区块时间戳将揭示这些细节。

你可能也会想知道网络是否有可能出现多个不同的区块链,就像 PoW 中当两个矿工同时挖矿时会发生的情况一样。是的,这种情况可能会发生很多次。让我们举个例子,了解一种可能发生这种情况的方式以及网络如何自动解决这个问题。假设有五个验证者:A、B、C、D 和 E。区块时间为五秒。假设首先选择了 A,它广播了一个区块,但由于某种原因该区块未能到达 D 和 E;因此他们会认为 A 没有广播区块。现在假设选择算法选择了 B 来生成下一个区块;那么 B 将在 A 的区块之上生成下一个区块,并广播给所有节点。D 和 E 将拒绝它,因为前一个区块的哈希值将不匹配。由此,D 和 E 将形成一个不同的链,而 A、B 和 C 将形成另一个不同的链。A、B 和 C 将拒绝来自 D 和 E 的区块,而 D 和 E 将拒绝来自 A、B 和 C 的区块。节点之间将这个问题解决为 A、B 和 C 所持有的区块链比 D 和 E 所持有的区块链更准确;因此 D 和 E 将用 A、B 和 C 所持有的区块链替换他们的版本。这两个版本的区块链将有不同的准确性得分,而第一个区块链的得分将比第二个区块链的得分更高。当 B 广播它的区块时,它还将提供其区块链的得分,由于其得分更高,D 和 E 将用 B 的区块链替换了他们的区块链。这就是冲突如何解决的。区块链的链分数是使用 (U128_max * BLOCK_NUMBER_OF_LATEST_BLOCK - (UNIX_TIMESTAMP_OF_LATEST_BLOCK / BLOCK_TIME)) 计算的。首先按长度对链进行评分(区块越多,得分越高)。对于长度相等的链,选择最后一个区块更旧的链。

你可以在 github.com/paritytech/parity/wiki/Aura 深入了解 Aura。

运行 Parity

Parity 需要 Rust 版本 1.16.0 来构建。建议通过 rustup 安装 Rust。

安装 rust

如果你还没有安装 rustup,你可以这样安装。

Linux

在基于 Linux 的操作系统上,运行此命令:

curl https://sh.rustup.rs -sSf | sh

Parity 还需要安装 gccg++libssl-dev/openssllibudev-devpkg-config 软件包。

OS X

在 OS X 上,运行此命令:

curl https://sh.rustup.rs -sSf | sh

Parity 还需要 clang。Clang 随 Xcode 命令行工具提供,也可以使用 Homebrew 安装。

Windows

确保你已安装了带有 C++ 支持的 Visual Studio 2015。接下来,从 static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe 下载并运行 rustup 安装程序,启动 "VS2015 x64 Native Tools Command Prompt",并使用以下命令安装和设置 msvc 工具链:

rustup default stable-x86_64-pc-windows-msvc

下载、安装和运行 Parity

现在,一旦您在操作系统上安装了 rust,您就可以运行这个简单的一行命令来安装 parity:

cargo install --git https://github.com/paritytech/parity.git parity

要检查 Parity 是否安装,请运行此命令:

parity --help

如果 Parity 安装成功,那么您将看到子命令和选项列表。

创建私有网络

现在是时候建立我们的财团区块链了。我们将创建两个用 Aura 连接的验证节点。我们将把它们都设置在同一台计算机上。

创建帐户

首先,打开两个 shell 窗口。第一个是给第一个验证者,第二个是给第二个验证者。第一个节点将包含两个帐户,第二个节点将包含一个帐户。第一个节点的第二个帐户将被分配一些初始以太,以便网络将拥有一些以太。

在第一个 shell 中,运行此命令两次:

parity account new -d ./validator0 

两次都会要求您输入密码。现在只需为两个帐户输入相同的密码。

在第二个 shell 中,只运行此命令一次:

parity account new  -d ./validator1 

就像以前一样,输入密码。

创建规范文件

每个网络节点共享一个通用规范文件。该文件告诉节点有关创世块,验证者是谁,等等的信息。我们将创建一个智能合约,其中包含验证者列表。有两种类型的验证者合同:非报告合同和报告合同。我们只需要提供一个。

区别在于,非报告合同仅返回验证者列表,而报告合同可以对良性(良性不端行为可能只是从指定验证者那里收不到一个块)和恶意不端行为(恶意不端行为将释放两个不同的块以同一步骤为基础)采取行动。

非报告合同应至少具有此接口:

{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"","type":"address[]"}],"payable":false,"type":"function"}

getValidators函数将在每个块中调用,以确定当前列表。然后,切换规则由实现该方法的合同确定。

报告合同应至少具有此接口:

[ 
    {"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"","type":"address[]"}],"payable":false,"type":"function"}, 
    {"constant":false,"inputs":[{"name":"validator","type":"address"}],"name":"reportMalicious","outputs":[],"payable":false,"type":"function"}, 
    {"constant":false,"inputs":[{"name":"validator","type":"address"}],"name":"reportBenign","outputs":[],"payable":false,"type":"function"} 
]

当有良性或恶意行为时,共识引擎分别调用reportBenignreportMalicious函数。

让我们创建一个报告合同。以下是一个基本示例:

contract ReportingContract { 
   address[] public validators = [0x831647ec69be4ca44ea4bd1b9909debfbaaef55c, 0x12a6bda0d5f58538167b2efce5519e316863f9fd]; 
   mapping(address => uint) indices; 
   address public disliked; 

   function ReportingContract() { 
       for (uint i = 0; i < validators.length; i++) { 
           indices[validators[i]] = i; 
       } 
   } 

   // Called on every block to update node validator list. 
    function getValidators() constant returns (address[]) { 
      return validators; 
   } 

   // Expand the list of validators. 
   function addValidator(address validator) { 
      validators.push(validator); 
   } 

   // Remove a validator from the list. 
   function reportMalicious(address validator) { 
      validators[indices[validator]] = validators[validators.length-1]; 
      delete indices[validator]; 
      delete validators[validators.length-1]; 
      validators.length--; 
   } 

   function reportBenign(address validator) { 
       disliked = validator; 
   } 
}

这段代码是不言而喻的。确保在验证人员数组中用第一个验证节点的地址替换地址,因为我们将使用这些地址进行验证。现在使用您感觉舒服的方式编译上述合同。

现在让我们创建规范文件。创建一个名为spec.json的文件,并将以下代码放入其中:

{ 
    "name": "ethereum", 
    "engine": { 
        "authorityRound": { 
            "params": { 
               "gasLimitBoundDivisor": "0x400", 
               "stepDuration": "5", 
               "validators" : { 
               "contract": "0x0000000000000000000000000000000000000005" 
                } 
            } 
        } 
    }, 
    "params": { 
        "maximumExtraDataSize": "0x20", 
        "minGasLimit": "0x1388", 
        "networkID" : "0x2323" 
    }, 
    "genesis": { 
      "seal": { 
       "authorityRound": { 
         "step": "0x0", 
          "signature": "0x00000000000000000000000000000000000000000
             000000000000000000000000000000000000000000000000000000
                00000000000000000000000000000000000" 
            } 
        }, 
        "difficulty": "0x20000", 
        "gasLimit": "0x5B8D80" 
    }, 
    "accounts": { 
        "0x0000000000000000000000000000000000000001": { "balance": "1", "builtin": { "name": "ecrecover", "pricing": { "linear": { "base": 3000, "word": 0 } } } }, 
        "0x0000000000000000000000000000000000000002": { "balance": "1", "builtin": { "name": "sha256", "pricing": { "linear": { "base": 60, "word": 12 } } } }, 
        "0x0000000000000000000000000000000000000003": { "balance": "1", "builtin": { "name": "ripemd160", "pricing": { "linear": { "base": 600, "word": 120 } } } }, 
        "0x0000000000000000000000000000000000000004": { "balance": "1", "builtin": { "name": "identity", "pricing": { "linear": { "base": 15, "word": 3 } } } }, 
        "0x0000000000000000000000000000000000000005": { "balance": "1", "constructor" : "0x606060405260406040519081016040528073831647" }, 
        "0x004ec07d2329997267Ec62b4166639513386F32E": { "balance": "10000000000000000000000" } 
    } 
}

以下是上述文件的工作方式:

  • engine 属性用于设置共识协议和协议特定的参数。在这里,引擎是 authorityRound,即 aura。gasLimitBoundDivisor 决定了燃料限制的调整,具有常见的 ethereum 值。在 validators 属性中,我们有一个 contract 属性,即报告合同的地址。stepDuration 是以秒为单位的区块时间。

  • params 属性中,只有网络 ID 有关紧要关头;其他参数对于所有链都是标准的。

  • genesis 具有一些标准值用于 authorityRound 共识。

  • accounts 用于列出网络中存在的初始帐户和合同。前四个是标准的以太坊内置合同;这些应包括以使用 Solidity 合同编写语言。第五个是报告合同。确保您在 constructor 参数中用您的字节码替换字节码。最后一个帐户是验证器 1 shell 中生成的第二个帐户。它用于向网络提供以太币。将此地址替换为您自己的地址。

在我们进一步进行之前,请创建另一个名为 node.pwds 的文件。在该文件中,放置您创建的帐户的密码。验证者将使用此文件解锁帐户以签署区块。

启动节点

现在我们已经准备好启动我们的验证节点了。在第一个 shell 中,运行以下命令来启动第一个验证节点:

parity  --chain spec.json -d ./validator0 --force-sealing --engine-signer "0x831647ec69be4ca44ea4bd1b9909debfbaaef55c" --port 30300 --jsonrpc-port 8540 --ui-port 8180 --dapps-port 8080 --ws-port 8546 --jsonrpc-apis web3,eth,net,personal,parity,parity_set,traces,rpc,parity_accounts --password "node.pwds"

以下是前述命令的工作方式:

  • --chain 用于指定规范文件的路径。

  • -d 用于指定数据目录。

  • --force-sealing 确保即使没有交易也会产生区块。

  • --engine-signer 用于指定节点将使用的地址来签署区块,即验证者的地址。如果可能存在恶意验证者,则建议使用 --force-sealing;这将确保正确的链是最长的。确保您将地址更改为您生成的地址,即此 shell 上生成的第一个地址。

  • --password 用于指定密码文件。

在第二个 shell 中,运行以下命令来启动第二个验证节点:

parity  --chain spec.json -d ./validator1 --force-sealing --engine-signer "0x12a6bda0d5f58538167b2efce5519e316863f9fd" --port 30301 --jsonrpc-port 8541 --ui-port 8181 --dapps-port 8081 --ws-port 8547 --jsonrpc-apis web3,eth,net,personal,parity,parity_set,traces,rpc,parity_accounts --password "/Users/narayanprusty/Desktop/node.pwds" 

在这里,请确保将地址更改为您生成的地址,即在此 shell 上生成的地址。

连接节点

最后,我们需要连接两个节点。打开一个新的 shell 窗口并运行以下命令以查找连接到第二个节点的 URL:

curl --data '{"jsonrpc":"2.0","method":"parity_enode","params":[],"id":0}' -H "Content-Type: application/json" -X POST localhost:8541

您将获得这种类型的输出:

{"jsonrpc":"2.0","result":"enode://7bac3c8cf914903904a408ecd71635966331990c5c9f7c7a291b531d5912ac3b52e8b174994b93cab1bf14118c2f24a16f75c49e83b93e0864eb099996ec1af9@[::0.0.1.0]:30301","id":0}

现在运行以下命令,将 enode URL 中的编码 URL 和 IP 地址替换为 127.0.0.1:

curl --data '{"jsonrpc":"2.0","method":"parity_addReservedPeer","params":["enode://7ba..."],"id":0}' -H "Content-Type: application/json" -X POST localhost:8540

您应该获得以下输出:

{"jsonrpc":"2.0","result":true,"id":0}

节点应在控制台中指示 0/1/25 个对等体,这意味着它们彼此连接。这是一个参考图像:

许可和隐私

我们看到 parity 如何解决速度和安全性问题。目前,parity 没有提供任何与权限和隐私相关的特定内容。让我们看看如何在 parity 中实现这一点:

  1. 权限控制:Parity 网络可以通过配置每个节点服务器以仅允许来自特定 IP 地址的连接来实现权限控制。即使 IP 地址没有被阻止,要连接到网络中的一个节点,新节点也需要一个之前我们看到的 enode 地址,这是无法猜测的。因此,默认情况下,存在基本的保护。但是没有强制执行此措施。网络中的每个节点都必须在其端口注意此事。通过智能合约可以对谁可以创建区块和谁不能进行类似的权限控制。最后,节点可以发送什么样的交易目前无法配置。

  2. 身份隐私:有一种技术可以通过仍然启用所有权检查来实现身份隐私。在设置所有权时,所有者需要指定一个非确定性的非对称加密的公钥。每当它想要通过所有权检查时,它将提供常规文本的加密形式,合约将解密该文本并查看帐户是否为所有者。合约应确保不会检查相同的加密数据两次。

  3. 数据隐私:如果你只是使用区块链来存储数据,你可以使用对称加密来加密数据并与希望查看数据的人分享密钥。但是无法对加密数据进行操作。如果需要对输入数据进行操作并仍然保护隐私,那么各方必须完全设置一个不同的区块链网络。

摘要

在本章中,我们学习了如何使用奇偶校验和光环运行以及一些实现奇偶校验和隐私的技术。现在,你至少可以自信地为使用区块链构建联合体构建一个概念验证。现在,你可以继续探索其他解决方案,例如 Hyperledger 1.0 和 Quorum 用于构建联合体区块链。目前,以太坊正式致力于使其更适合联合体;因此,请密切关注各种区块链信息来源,了解市场上的任何新动态。

第十八章:当前格局和未来展望

区块链技术正在改变并将继续改变我们日常业务的进行方式。它挑战了现有的商业模式,并有望在成本节约、效率和透明度方面带来巨大的好处。本章将探讨这项技术的最新发展、新兴趋势、问题和未来预测。

我们通过提出与区块链技术相关的一些开放研究问题和改进来结束本书。

新兴趋势

区块链技术正在快速变化和密集开发,因为学术界和商业界对它的浓厚兴趣。随着技术的日渐成熟,最近开始出现一些趋势。例如,私有区块链最近因其在金融领域的特定用例而引起了相当多的关注。此外,企业区块链是另一个新趋势,旨在开发满足企业级效率、安全性和集成要求的区块链解决方案。这里列举了一些趋势并进行了讨论。

应用特定区块链 (ASBCs)

目前,注意到了对 ASBCs 的倾向,即专门为一个应用程序开发区块链或分布式账本,并专注于特定行业,例如 Everledger (www.everledger.io),它是一种被开发用于为钻石和其他高价值物品提供不可变的追踪历史和审计追踪的区块链。这种方法挫败了任何欺诈企图,因为与物品的所有权、真实性和价值相关的一切都在区块链上得到了验证和记录。这一结果对保险和执法机构非常宝贵。

企业级区块链

由于隐私和可扩展性问题,原始形式的区块链尚未准备好在企业级别使用,最近出现了一种新趋势,即开发企业级区块链,各种公司已开始提供可部署和集成到企业级别的企业级区块链解决方案。这种类型的解决方案已经解决了测试、文档、集成和安全等要求,并可以在企业级别以最小或不需任何更改的方式实施。

这一概念与公共区块链相对立,后者是无监管的,不符合特定的企业级安全要求。这也意味着企业级区块链通常应该在私有配置中实施;然而,公共企业级区块链实施也是可能的。近年来,许多科技初创公司开始提供企业级区块链解决方案,如 Bloq、Tymlez、Chain、Colu、ChainThat、ChromaWay 等。这一趋势正在持续增长,未来几年将会看到更多类似的技术倡议。

私有区块链

随着对隐私和保密性的需求,主要关注点是开发私有分布式分类账,可在一组受信任的参与者中使用。由于公共区块链由于其开放和相对较不安全的特性,不适用于金融、医药和法律等行业,私有区块链有望解决这一局限,并使最终用户更接近于实现区块链的益处,同时满足所有安全和隐私要求。

公共区块链较不安全,因为通常它们不提供隐私和保密服务。私有区块链允许参与者或参与者的子集完全控制系统,因此在需要隐私和控制的金融等行业中使用是可取的。

以太坊可在私有和公有模式下使用,而有一些项目专门开发为私有区块链,例如 Hyperledger 和 Corda。我们在第十三章 Hyperledger中讨论了这两个项目。

初创公司

近年来,出现了许多科技初创公司,它们致力于区块链项目,并提供特定于这项技术的解决方案。提供区块链咨询和解决方案的初创公司数量显著增加。

您可以访问链接angel.co/blockchains,该链接目前显示了 1927 家区块链初创公司的列表。

强烈的研究兴趣

区块链技术已经引起学术界和商业界的强烈研究兴趣。近年来,这种兴趣已经急剧增加,现在世界各地的主要机构和研究人员都在探索这项技术。这种兴趣的增长主要是因为区块链技术可以帮助企业提高效率、降低成本,并使事务透明化。学术兴趣主要集中在解决密码学、共识机制、性能和解决区块链中其他限制的困难问题上。

由于区块链技术属于更广泛的分布式系统范畴,许多分布式计算研究人员将他们的研究重点转向了区块链技术。例如,伦敦大学学院(UCL)设有专门的部门,名为 UCL 区块链技术研究中心,致力于区块链技术的研究。

另一个例子是苏黎世联合计算组(disco.ethz.ch)已发表了关于区块链技术的重要研究成果。最近,一本名为Ledger Journal的杂志刊登了其研究论文的第一期。

该文件可在www.ledgerjournal.org/ojs/index.php/ledger上找到。

如今,在各种学术和商业机构中,都成立了致力于区块链研究和开发的团队和部门。

尽管这里提到的倡议远非详尽无遗,但这仍然是对研究人员极大兴趣的一个明确指示,并且预计在 2018 年及以后会看到更多的研究和开发。另一个名为加密货币与合同倡议IC3)的组织,也在研究智能合约和区块链技术。IC3 旨在解决区块链和智能合约的性能、保密性和安全问题,并开展了多个项目来解决这些问题。

有关 IC3 所进行项目的更多信息可在www.initc3.org/上找到。

标准化

目前,区块链技术还不够成熟,无法轻松地与现有系统集成。甚至在当前技术水平下,两个区块链网络也无法轻松地相互通信。标准化将有助于改进区块链技术的互操作性适应性集成性。最近已经做出一些尝试来解决这个问题,其中最显著的是成立了 ISO/TC 307,这是一个技术委员会,旨在标准化区块链和分布式分类账技术。

委员会的目标在于增强用户、应用程序和系统之间的互操作性和数据交换。另一方面,最近成立的联盟和开源协作努力,如 R3 和 Hyperledger,通过与其他参与者分享想法、工具和代码,有助于推动该技术的标准化。R3 与 80 多家拥有类似目标的银行的联盟合作,这在某种程度上实现了标准化。另一方面,Hyperledger 有一个参考架构,可以用来构建区块链系统,并得到 Linux 基金会和行业内许多其他参与者的支持。

另一个例子是开链标准,这是为金融网络开发的协议。已经有了链 OS1 标准,这是与世界各地主要金融机构合作建立的。该标准可以加快交易结算速度,并直接进行点对点的交易路由。它旨在解决区块链技术中的监管、安全和隐私需求。OS1 还提供了智能合约开发框架,并使参与者轻松满足 AML 和 KYC 要求。

智能合约标准化工作也已经开始,李等人撰写的一篇开创性论文正式定义了智能合约模板,并提出了未来智能合约相关研究和发展的愿景和必要性。

本文可在 arxiv.org/abs/1608.00771v2 查阅。

此外,关于这个话题的一些讨论已经在 第十六章,可扩展性和其他挑战 以及 第四章,智能合约 中进行。

所有提到的努力都清楚地表明,行业标准很快将出现,进一步使区块链技术的采用更容易更快速。标准还将导致区块链行业呈指数增长,因为标准的可用性将消除诸如互操作性等障碍。

增强

过去几年中,已经提出了各种增强和建议,以进一步发展现有的区块链。这些建议大多是为了应对安全漏洞,并解决区块链技术的固有局限性。区块链技术存在一些限制,如可扩展性、隐私性和互操作性,必须在其成为像任何其他技术一样的主流技术之前加以解决。

近年来,针对区块链技术的可扩展性问题进行了大量的努力,这些努力已经在 第十六章,可扩展性和其他挑战 中进行了讨论。此外,开发人员定期提出了针对这些系统的各种关注的 BIPs(比特币改进提案)和 EIPs(以太坊改进提案)等与区块链相关的改进提案。

这两种链的一些最近和显著的改进提案将在本章后面讨论。此外,像状态通道这样的最新进展是区块链技术正在迅速改进,并很快将发展成为一种成熟且更实用的技术的例子。

实际应用

近年来,特别是在 2017 年,已经使用区块链技术开发了许多概念验证。一些应用特定的实现 emerged,比如 Everledger 用于钻石追踪和 filament 用于物联网,但在各个领域仍然存在不足。

现在看来这并不遥远,因为已经开发并证明了许多概念的可行性;下一步是在现实场景中实施这些概念。例如,最近,七家银行同意建立一个名为数字贸易链DTC)的项目,将简化贸易金融流程。

有关 DTC 的信息可在www.bankingtech.com/2017/10/ibm-and-eight-banks-unleash-we-trade-platform-for-blockchain-powered-commerce/上获得。

也已经开始提供具体的、真实的、端到端的实现,甚至在金融行业,例如澳大利亚证券交易所ASX)用区块链替换其传统的交易后系统。

有关该项目的信息可在www.asx.com.au/services/chess-replacement.htm上获得。

联盟

近年来,已经启动了各种各样的联盟和共享开源努力。预计这一趋势将在未来几年继续增长,会有越来越多的联盟、委员会和开源努力很快出现。一个典型的例子是 R3,该组织已与全球最大的金融机构联合开发了 Corda。

技术挑战的答案

由于社区对区块链技术的强烈研究和兴趣,对各种挑战的答案已经开始出现。例如,状态通道的概念已经发展起来,作为对区块链上可伸缩性和隐私问题的回应。使用状态通道,比特币闪电网络和以太坊的雷电网络已经几乎可以实现。

这是一个正在进行中的工作,更新在github.com/raiden-network/raiden/milestones上可用。

此外,出现了各种区块链解决方案,如 Kadena,直接解决了区块链中的机密性问题。其他概念,如 Zcash、CoinJoin 和保密交易,也已开发并在《第十章》,替代币 中讨论过。这一趋势也将在未来几年继续增长,即使几乎所有基本的区块链技术挑战都得到了解决,对区块链技术的进一步增强和优化也永远不会停止。

融合

区块链与其他技术的融合带来了重大好处。在核心层面,区块链提供了弹性、安全性和透明度,当与其他技术结合时,将产生强大的互补技术。例如,当通过区块链实施时,物联网(IoT)可以获得许多好处,如完整性、去中心化和可伸缩性。人工智能AI)预计也将从区块链技术中获益,事实上,在区块链技术内部,人工智能可以以自治代理AAs)的形式实施。更多例子和上述融合技术将在本章后续部分详细讨论。

区块链技术教育

虽然区块链技术在全球几乎每个行业中的技术人员、开发者和科学家中引起了极大的兴趣,但缺乏正规的学习资源和教育材料。由于这是一项新技术,许多知名机构,如普林斯顿大学,现在正在开设各种课程,向想要了解这项技术的任何人介绍这项技术。

例如,普林斯顿大学已经开设了一个在线交付的加密货币和数字货币课程(online.princeton.edu/course/bitcoin-and-cryptocurrency-technologies)。许多私人组织也提供类似的在线和课堂培训课程。由于区块链技术的受欢迎和接受度,将很快看到更多这样的努力。

就业

就业市场出现了一种新的趋势,招聘人员现在正在寻找能够为区块链编程的区块链专家和开发人员。这对金融行业尤为重要,最近许多初创企业和大型组织开始聘请区块链专家。随着技术的被接受和成熟度的提高,这种趋势预计将会增长。对缺乏区块链开发人员的担忧也在日益增加,这无疑将随着技术的进步和越来越多的开发人员通过自学获得经验或从培训提供者获得正规培训而得到解决。

密码经济学

随着区块链的出现,出现了新的研究领域,其中最引人注目的是密码经济学,即研究治理去中心化数字经济的协议。随着区块链和加密货币的出现,该领域的研究也在增长。Vitalik Buterin 将密码经济学定义为数学、密码学、经济学和博弈论的结合。

vitalik.ca/files/intro_cryptoeconomics.pdf 上有一份出色的演示。

密码学研究

尽管在比特币发明之前,加密学是一个备受关注和研究的领域多年,但区块链技术已经再次引起了人们对这一领域的兴趣。随着区块链及相关技术的出现,加密学的兴趣也显著增加。特别是在金融加密领域,新的研究正在定期进行和发布。

正在研究诸如零知识证明、完全同态加密和功能性加密等技术,以在区块链中使用。作为 Zcash 的一种形式,已经在实际水平上实现了零知识证明。可以看出,区块链和加密货币已经促进了加密学和特别是金融加密学的进步。

新的编程语言

对于开发智能合约的编程语言的开发也越来越受到关注。这些努力更加集中在领域特定语言上,例如以太坊的 Solidity 和 Kadena 的 Pact。这只是一个开始,随着技术的进步,很可能会开发出许多新语言。

硬件研究与开发

当人们意识到 2010 年现有方法对挖掘比特币不够高效时,矿工开始转向优化挖矿硬件。这些最初的努力包括使用 GPU,然后在 GPU 达到极限后使用现场可编程门阵列FPGAs)。在那之后很快,特定应用集成电路ASICs)出现了,显著增加了挖矿能力。预计这一趋势将进一步增长,因为现在对进一步优化 ASICs 进行了更多的研究,包括并行化和减小芯片尺寸。

此外,由于新的加密货币现在相当频繁地出现,其中许多使用的是可以从 GPU 处理能力中受益的 PoW 算法,因此预计 GPU 编程计划也将增长。例如,最近 Zcash 已经激发了对使用 NVIDIA CUDA 和 OpenCL 进行 GPU 挖掘设备和相关编程的兴趣。目标是并行使用多个 GPU 以优化挖矿操作。此外,在使用受信任的计算硬件(例如英特尔的软件保护扩展SGX))来解决区块链上的安全问题的领域也进行了一些研究。此外,英特尔的 SGX 已被用于一种称为已过时间证明PoET)的新颖共识算法,该算法已在第十三章 Hyperledger 中讨论过。另一个项目是 21 个比特币计算机,它被开发出来,作为开发人员学习比特币技术并轻松开发应用程序的平台。

预计硬件研发趋势将继续,很快将探索更多硬件方案。

形式化方法和安全性的研究

随着智能合约编程语言中安全问题和漏洞的认识,人们现在对在生产部署之前对智能合约进行形式化验证和测试表现出了浓厚的兴趣。为此,已经在进行各种努力,包括为以太坊的 Solidity 开发的 Why3。Hawk 是另一个例子,旨在实现智能合约的保密性。

区块链的替代方案

随着区块链技术近年来的进步,研究人员开始思考是否可能创建能够提供区块链提供的保证和服务的平台,但无需使用区块链。这导致了 R3 的 Corda 的开发,实际上 Corda 并不是真正的区块链,因为它不是基于包含交易的区块的概念;相反,它是基于状态对象的概念,该状态对象根据网络参与者的要求和规则在 Corda 网络中传播,代表网络的最新状态。其他例子包括 IOTA,它是一个物联网区块链,使用有向无环图(DAG)作为名为 Tangle 的分布式分类帐,而不是传统的区块链与区块。据称,这个分类帐已经解决了可扩展性问题,同时具有高级别的安全性,甚至可以抵御基于量子计算的攻击。应该注意的是,比特币也在某种程度上受到量子攻击的保护,因为量子攻击只能针对暴露的公钥进行,而这些公钥仅在区块链上发送和接收交易时才会暴露。如果公钥没有被揭示,比如在未使用的地址或仅用于接收比特币的地址中,那么可以保证量子安全。换句话说,对于每个交易使用不同的地址可以保护免受量子攻击。此外,在比特币中,如果需要,很容易切换到另一个量子签名协议。

互操作性努力

近期对区块链互操作性的限制的认识导致了跨多个区块链工作的系统的开发。一个最近的例子是 Qtum,它是一个与以太坊和比特币区块链兼容的区块链。它利用比特币的未使用交易输出(UTXO)机制进行价值转移,并使用 EVM 进行智能合约。这意味着以太坊项目可以被移植到 Qtum 上而不需要进行任何更改。

区块链即服务

随着云平台成熟度的提高,许多公司已经开始提供区块链即服务BaaS)。最突出的例子是微软的 Azure,其中提供以太坊区块链作为服务,以及 IBM 的 Bluemix 平台,提供 IBM BaaS。这种趋势预计在未来几年会继续增长,会有更多公司提供 BaaS。电子政府即服务eGaaS)是另一个例子,实际上就是 BaaS,但提供针对治理功能的特定应用区块链(egaas.org)。该项目旨在组织和控制任何活动,而无需文件流转和官僚开销。

减少电力消耗的努力

从比特币的区块链可以明显看出,PoW 机制非常低效。当然,这种计算保护了比特币网络,但这种计算没有其他好处,并且浪费了大量电能。为了减少这种浪费,现在更加关注绿色选项,如不需要像比特币的 PoW 算法那样庞大资源的 PoS 算法。这种趋势预计会增长,尤其是随着 PoS 计划应用于以太坊。

其他挑战

除了第十六章中讨论的安全性和隐私性、可扩展性和其他挑战之外,在区块链被主流采用之前,还有其他几个障碍需要解决。这些包括监管、政府控制、技术不成熟、与现有系统的整合以及实施成本。

监管

监管被认为是需要解决的最重要挑战之一。核心问题在于,区块链,尤其是加密货币,尚未被任何政府认可为合法货币。尽管在某些情况下,它已被美国和德国等国家分类为货币,但距离被普遍接受的正规货币仍有很长一段路要走。此外,当前的区块链状态尚未被承认为金融机构可用的平台。尚无金融监管机构接受它作为可被授权使用的平台。

然而,世界各地的监管机构已经采取了各种举措进行研究并提出法规。尽管一些政府曾试图对比特币征税,但目前比特币处于完全无监管状态。在英国,根据欧盟增值税指令,比特币交易免征增值税VAT),但这在英国脱欧后可能会发生变化。然而,在某些情况下,资本利得税CGT)仍然适用。

金融监管机构普遍预计很快将针对区块链技术提出一些监管尝试,尤其是在英国金融行为监管局(FCA)最近宣布可能批准一些使用区块链的公司之后。

一个普遍的担忧是区块链技术尚未准备好用于生产部署。尽管比特币区块链已经发展成为一个可靠的区块链平台,并且被用于生产,但它并不适用于每一种场景。尤其是在金融和健康等敏感环境中,这一点尤为真实。然而,这种情况正在迅速改变,正如我们在本章中已经看到的各种新区块链项目的例子,这些项目已经在现实生活中得到了实施,例如 ASX 区块链后期解决方案。预计这种趋势将随着本章前面讨论的大量努力改善技术并解决诸如可扩展性和隐私等技术限制而增长。

安全性也是另一个普遍关注的问题,许多研究人员已经强调了这一点,尤其适用于金融和健康领域。欧洲网络与信息安全局(ENISA)的一份报告强调了应该解决的分布式分类账具体问题。

报告可在www.enisa.europa.eu/news/enisa-news/enisa-report-on-blockchain-technology-and-security获得。

报告中强调的一些问题包括智能合约管理、密钥管理、反洗钱(AML)和反欺诈工具。此外,报告还强调了对监管、审计、控制和治理的需求。

与现有的遗留系统集成也是一个主要关注点。目前尚不清楚区块链如何与现有的金融系统集成。

采用的障碍或多或少与监管、安全性和互操作性相关。与现有系统的集成可以通过多种方式进行。

黑暗面

具有审查抗性和去中心化等关键属性的区块链技术可以帮助提高许多领域的透明度和效率,但这种技术的相对无监管性意味着它也可能被犯罪分子用于非法活动。例如,假设某些非法内容在互联网上发布,可以立即通过联系相关当局和网站服务提供商来关闭,但在区块链中却不可能做到这一点。

一旦某事存在于区块链上,几乎不可能撤销。这意味着一旦不可接受的内容发布到区块链上,就无法移除。如果区块链用于分发不道德内容,那就没有人能关闭它。这带来了一个严峻的挑战,看来在这种情况下,一些监管和控制是有益的,但区块链怎么能被规范呢?这是另一个关键问题。首先制定监管法律,再看区块链技术是否适应可能不明智,因为这可能会破坏这项技术的创新和进步。让区块链技术先发展起来会更明智,就像互联网一样,当它达到临界质量时,治理机构可以呼吁对区块链技术的实施和使用进行一些规范。

有许多例子,暗网与比特币一起用于进行非法活动。例如,丝绸之路用于在互联网上出售非法药物,使用比特币进行支付,而暗网使用洋葱 URL,只能通过 Tor 可见。尽管丝绸之路在执法机构数月的努力后被关闭,但新的类似网站开始出现。现在,其他类似的选择也可以提供服务;因此,通常这类问题仍然是一个大问题。

想象一下,一个非法网站存在于 IPFS 和区块链上;没有简单的方法关闭它。很明显,缺乏控制和监管会促进犯罪活动,类似丝绸之路的问题会不断出现。像 Zcash 这样的完全匿名交易能力的进一步发展可能为犯罪分子提供另一层保护,但与此同时在各种合法场景中可能非常有用。这取决于谁在使用这项技术;匿名性在许多场景中都可能有好处,例如在卫生行业,患者记录应该保持私密和匿名,但如果这也可被犯罪分子用来隐藏他们的活动,那就可能不太合适了。

一种解决方案可能是引入智能机器人、人工智能甚至内嵌有监管逻辑的合同。它们很可能是由监管机构和执法机构编程的,作为一种提供治理和控制的手段留存在区块链上。例如,可以设计区块链,使得每个智能合同都必须经过一个控制合同,该合同会审查代码逻辑并提供一种监管机制来控制智能合同的行为。

可能也可以让监管机构检查每个智能合约的代码,一旦智能合约代码获得监管机构颁发的某一级别的真实性证明,便可部署到区块链网络上。这种二进制签名的概念类似于已经建立的代码签名概念,其中可执行文件被数字签名以确认代码是真实的,而不是恶意的。这个想法更适用于半私有或受监管的区块链情境,在这种情况下,监管机构需要一定程度的控制,例如在金融领域。这意味着需要在可信第三方(监管机构)中放置一定程度的信任,这可能不太可取,因为这会偏离完全分散化的概念。但为了解决这个问题,区块链本身可以用来提供分散化、透明化和安全的证书颁发和数字签名机制。

区块链研究

尽管近年来区块链技术取得了重大创新,但这个领域仍有很大的研究空间。下面列出了一些选择的研究课题,并提供了一些关于现有挑战和最新技术状态的信息。以下子章节还提出了一些解决这些问题的想法。

智能合约

在定义智能合约的关键要求和模板开发方面已取得了重大进展。然而,需要进一步研究如何使智能合约更加安全。

中心化问题

尤其是比特币挖矿集中化问题,人们越来越担心比特币如何再次去中心化。

密码学功能的限制

比特币区块链中使用的密码学非常安全且经得起时间的考验。在其他区块链中,也使用了类似的安全技术,并且同样非常安全。然而,特定的安全问题,如椭圆曲线数字签名方案中产生和使用重复签名随机数的可能性(导致私钥恢复攻击)、哈希函数中的碰撞以及可能破坏基础密码算法的量子攻击仍然是一个令人兴奋的研究领域。

共识算法

在 PoS 算法或 PoW 的替代方面的研究也是一个重要的研究领域。特别是由于目前比特币网络的能耗预计将在 2018 年底达到近 125 TWh。目前,这几乎相当于以色列的电力消耗量。也有人提出,与比特币的 PoW 类似的无效或单一目的的工作相比,网络算力可以用来解决一些数学或科学问题,这是非常合理的。此外,PoS 算法等替代方案已经获得了很大的关注,并将在主要区块链中实施,例如以太坊的 Casper。然而,迄今为止,PoW 仍然是保护公共区块链最佳选择。

可扩缩性

在 第十六章 可扩展性和其他挑战 中已经进行了详细讨论;简而言之,在本节中可以说已经取得了一些进展,但仍需要更多的研究来实现链上可扩展性,进一步改进链下解决方案,如状态通道等。已经提出了一些倡议,如增加区块大小和仅限交易的区块链(无区块)来解决增加区块链自身容量的可扩展性问题,而不是使用侧通道。不需要区块的实现示例包括 IOTA(Tangle)。这是一个 DAG,用于存储交易,相比传统的区块链解决方案,其中一个区块用于存储交易。与比特币等基于块的区块链相比,这使得它本质上更快,其中区块生成之间的等待时间至少大约是 10 分钟。

代码混淆

使用不可区分混淆的代码混淆可以用作在区块链中提供保密性和隐私性的手段。然而,这仍然不切实际,需要重大研究工作才能实现这一目标。

显著项目

以下是当前正在进行中的区块链领域的显著项目列表。除了这些项目之外,还有大量初创公司和公司在区块链领域工作,并提供与区块链相关的产品。

以太坊上的 Zcash

以太坊研发团队最近的一个项目是在以太坊上实施 Zcash。这是一个令人兴奋的项目,开发人员正在试图使用已在 Zcash 项目中使用的 ZK-SNARKs 为以太坊创建一个隐私层。通过在以太坊上实现 Zcash,目标是创建一个允许具有至关重要的隐私性的应用程序,如投票的平台。

这也将允许在以太坊上创建匿名代币,可用于多种应用程序。

CollCo

这是德国证交所开发的一个基于 Hyperledger 代码库的项目,用于管理商业银行的现金转账。抵押币CollCo)提供了一个基于区块链的平台,可以在传统欧洲交易所清算中心(Eurex Clearing CCP)提供的传统功能的基础上实现商业银行货币的实时转移。这是一个重大项目,可以用来解决后期交易结算流程中的低效问题。

Cello

截至 2017 年 2 月,这是 Hyperledger 项目的最新补充。该项目旨在提供按需的 BaaS,使用户方便地部署和管理多个区块链。预计 Cello 将支持所有未来和当前的 Hyperledger 区块链,例如 Fabric 和 Sawtooth Lake。

Qtum

这个项目基于将比特币和以太坊区块链的功能结合起来的想法。Qtum 利用比特币代码库,但使用以太坊的 EVM 来执行智能合约。以太坊智能合约可以利用比特币的 UTXO(未花费交易输出)模型来运行。

它可以在qtum.org/找到。

比特币-NG

这是另一个解决比特币区块链的可伸缩性、吞吐量和速度问题的提案。下一代NG)协议基于一种领导者选举机制,可以在交易发生时立即验证交易,与比特币协议相比,区块之间的时间和区块大小是与可伸缩性相关的主要限制。

Solidus

这是一种新的加密货币,解决了自私挖矿问题同时解决了可扩展性和性能问题。它还解决了机密性问题。它基于无许可拜占庭共识。该协议在当前状态下相对复杂,并且是开放领域的研究方向。

原始研究论文可以在eprint.iacr.org/2017/317.pdf找到。

Hawk

这是一个旨在解决区块链智能合约隐私问题的项目。这是一个智能合约系统,可以对区块链上的交易进行加密。Hawk 可以自动生成与区块链交互的安全协议,无需手动编程密码协议。

Town-Crier

这是一个旨在向智能合约提供真实世界、真实数据的项目。该系统基于英特尔的 SGX 可信硬件技术。这是区块链智能合约请求来自在线来源的数据的进一步步骤,同时保护机密性。

SETLCoin

这是由高盛(Goldman Sachs)建立的系统,并在证券结算的加密货币申请下申请专利。顾名思义,这种加密货币可以用于快速高效的结算。该技术利用虚拟钱包在对等方之间通过网络交换资产,并通过拥有 SETLCoin 的所有权实现即时结算。

TEEChan

这是使用受信任执行环境TEE)提供可扩展和高效解决方案来扩展比特币区块链的新颖想法。这类似于支付通道的概念,其中使用链下通道进行交易的更快速传输。这个想法的主要吸引力在于它可以在比特币区块链上实现,而无需对比特币网络进行任何更改,因为它是一种链下解决方案。

然而,需要注意的是,这个解决方案确实需要信任英特尔进行远程验证,因为英特尔的 SGX CPU 用于提供 TEE。这在分散式区块链中并不是一个理想的特性;但是,值得注意的是,即使使用远程验证,交易的机密性仍然得以保留,因为远程验证器(英特尔)无法看到用户之间通信的内容。这个限制使得人们有争议,这是否是一个完全分散化和无信任的解决方案。

Falcon

Falcon 是一个项目,通过在网络上广播比特币区块的快速中继网络来帮助比特币扩展。其核心思想围绕着一种减少孤立区块的技术,从而有助于提高比特币网络的整体可扩展性。用于此目的的技术被称为应用级贯穿式路由。

Bletchley

这个项目由微软推出,表明了微软对区块链技术的承诺。Bletchley 允许使用 Azure 云服务以用户友好的方式构建区块链。Bletchley 引入的一个重要概念称为加密模块,可以将其视为外部区块链的高级版本,可以通过安全通道由智能合约调用。这些可以用任何语言编写,并在安全容器中执行。

有两种类型的加密模块:实用加密模块合约加密模块。第一种类型用于提供基本服务,如来自外部源的加密和基本数据提取,而后者是一个更智能的版本,在链上创建智能合约时会自动生成,并且存在于链下,但仍链接到链上合约。由于这种链下存在,无需在区块链网络的所有节点上执行合约加密模块。因此,这种方法会提高区块链的性能。

白皮书可在github.com/Azure/azure-blockchain-projects/blob/master/bletchley/bletchley-whitepaper.md找到。

Casper

这是以太坊正在开发的权益证明算法。该领域已经进行了重大研究,并预计将于 2017 年实施。节点在基于 Casper 的以太坊网络中成为绑定验证者,并需要支付保证金,以便能够提出新的区块。

Casper 研究论文可在github.com/ethereum/research/blob/master/papers/casper-basics/casper_basics.pdf找到。

杂项工具

一些之前未讨论过的工具列在以下子部分中,并简要介绍,以让读者了解可用于区块链开发的各种开发选项。此列表包括平台、实用程序和工具。

适用于 Microsoft Visual Studio 的 Solidity 扩展

此扩展提供 DApps 的智能感知、自动完成和模板,并在熟悉的 Visual Studio IDE 中工作,使开发者更容易熟悉以太坊开发。

您可以从marketplace.visualstudio.com/items?itemName=ConsenSys.Solidity下载此扩展。

MetaMask

这是一个与 Mist 类似的 DApp 浏览器,但从 DApp 浏览的角度来看,允许用户在浏览器内运行以太坊 DApp,而无需运行完整的以太坊节点。

这可从metamask.io/获得,并可作为 Chrome 插件安装。

Stratis

这是一个区块链开发平台,允许创建自定义私有区块链,并与主要的 Stratis 区块链(Stratis 链)一起工作,以提高安全性。它允许轻松配置主要区块链,如比特币、以太坊和 Lisk。此外,它允许使用 C# .NET 技术进行开发。它还可以通过 Microsoft Azure 作为 BaaS 提供。

这个网站可在stratisplatform.com/找到。

Embark

这是一个针对以太坊的开发框架,允许类似于 Truffle 的功能。它允许智能合约的自动部署,更容易地与 JavaScript 集成,尤其是更容易地与 IPFS 集成。这是一个功能非常丰富的框架,还提供了许多其他功能。它可以通过 npm 安装。

这个框架可在 GitHub 找到:github.com/iurimatias/embark-framework

DAPPLE

这是以太坊的另一个框架,通过处理更复杂的任务,可以更轻松地开发和部署智能合约。它可以用于包管理、合约构建和部署脚本。

它也可通过 npm 获取。也可在 GitHub 上获取,网址为 github.com/nexusdev/dapple

Meteor

这是一个单页应用的全栈开发框架。它可用于以太坊 DApp 的开发。Meteor 中有一个开发环境,它使得复杂 DApps 的开发更加轻松。

它可以在 www.meteor.com/ 上获取,以太坊特定的 DApp 构建信息可在 github.com/ethereum/wiki/wiki/Dapp-using-Meteor 上获取。

uPort

这个平台是建立在以太坊上的,并提供了一个去中心化的身份管理系统。这允许用户完全控制其身份和个人信息。这基于声誉系统的理念,使用户能够互相证明并建立信任。

这可在 www.uport.me/ 上获取。

INFURA

该项目旨在提供企业级以太坊和 IPFS 节点。INFURA 包括以太坊节点、IPFS 节点和一个名为 Ferryman 的服务层,提供路由和负载平衡服务。

与其他行业的融合

第十六章,可扩展性和其他挑战,详细讨论了区块链与物联网的融合。简而言之,由于区块链的真实性、完整性、隐私性和共享性,物联网网络将大大受益于区块链技术。这可以通过运行在区块链上的物联网网络,并利用分散的网状网络进行通信来实现,从而实现实时的机器对机器M2M)通信。由于 M2M 通信而产生的所有这些数据可以在机器学习过程中使用,以增强人工智能 DAO 或简单的 AAs 的功能。AAs 可以在区块链提供的分布式人工智能DAI)环境中充当代理,并使用机器学习过程随时间学习。

AI 是计算机科学的一个领域,致力于构建可以根据其观察到的情景和环境做出理性决策的智能代理。机器学习通过利用原始数据作为学习资源,在 AI 中发挥着至关重要的作用。基于 AI 的系统的一个关键要求是可用于机器学习和模型构建的真实数据。来自物联网设备、智能手机和其他数据采集手段的数据激增意味着人工智能和机器学习变得越来越强大。

然而,数据的真实性是一个要求。一旦消费者、生产者和其他实体进入区块链,作为这些实体相互作用结果生成的数据可以立即作为机器学习引擎的输入,并具有真实性的保证。这就是人工智能与区块链融合的地方。可以说,如果物联网设备被黑客攻击,它可以向区块链发送格式错误的数据。这个问题得到缓解,因为物联网设备是区块链的一部分(作为节点),并且具有应用于区块链网络中标准节点的所有安全属性。这些属性包括激励良好行为、拒绝格式错误的交易以及对交易进行严格验证和各种其他检查,这些都是区块链协议的一部分。因此,即使物联网设备以某种方式被黑客攻击,它也将被区块链网络视为拜占庭节点,并且不会对网络造成任何不利影响。

此外,结合智能 Oracle、智能合约和 AAs 的可能性将催生人工智能分散自治组织AIDAOs),它们可以代表人类自行运行整个组织。这是人工智能的另一面,在未来可能成为常态。然而,需要更多的研究来实现这一愿景。

此外,还预计区块链技术与其他领域(如 3D 打印、虚拟现实、增强现实和游戏行业)的融合。例如,在多人在线游戏中,区块链的分散方法可以实现更多的透明度,并确保没有中央机构通过操纵游戏规则获取不公平的优势。所有这些主题目前都是活跃的研究领域,预计这些领域很快会有更多的兴趣和发展。

未来

2017 年被预测为区块链技术在实际生产环境中得到应用,并从之前的概念验证(PoC)和理论阶段迈入实践阶段的一年。公司确实实施了一些试点项目,但尚未看到大规模的生产实施。预计在 2018 年,将有一些组织实施全面的基于区块链的项目。2019 年,预计将有近 20%的中央银行使用区块链。

原创研究可在这里找到papers.ssrn.com/sol3/papers.cfm?abstract_id=3040224

未来,这一趋势预计只会增长。在这一部分,根据当前领域的进展和进步速度,很少有仔细的预测。

所有这些预测可能会在 2020 年至 2050 年之间成真:

  • 物联网将在多个区块链上运行,并将催生出 M2M 经济。这可以包括能源设备、自动驾驶汽车和家居配件。

  • 医疗记录将在各种由健康提供者联合经营的私有区块链之间安全共享,同时保护患者的隐私。这很可能是一个单一的私有区块链,被所有服务提供者共享,包括药房、医院和诊所。

  • 选举将通过分散式网络应用程序进行,后端是透明且安全的区块链。

  • 金融机构将运行许多私有区块链,用于在参与者之间共享数据和内部流程。

  • 金融机构将利用半私有区块链,为 AML 和 KYC 功能提供身份信息,并在世界各地的许多或所有金融机构之间共享。

  • 移民和边境控制相关活动将记录在区块链上,并且护照控制将通过所有口岸和世界各地边境机构之间共享的区块链进行。

  • 政府将运行跨部门区块链,提供养老金发放、福利发放、土地所有权记录、出生登记和其他公民服务。这样一来,公民之间的可审计性、信任和安全感将得到发展。

  • 密码学和分布式系统的研究将达到新的高度,大学和教育机构将提供专门的加密经济学、加密货币和区块链课程。

  • 人工智能 DAO 将在区块链上流行,它们将代表人类做出理性决策。

  • 政府运行的公开可用的受监管的区块链将被公民日常使用,执行他们的日常活动,例如税收支付、电视许可证注册和婚姻登记。

  • 想要在区块链上运行他们的业务或日常交易的任何人都将被提供 BaaS 作为标准。实际上,可以设想,就像互联网一样,区块链将无缝地融入我们的日常生活中,人们将在不太了解基础技术和基础设施的情况下使用它们。

  • 区块链通常将用于为艺术和媒体提供数字版权管理(DRM)服务,并可用于向消费者提供内容,实现消费者与生产者之间的直接沟通。这将消除任何中央方管理宝贵商品的许可和权利管理的需求。

  • 诸如比特币之类的现有加密货币将继续增值,并且随着状态通道和可扩展性工作的推出,预计这一趋势将继续增长。

  • 加密货币投资将大幅增加,一个新的加密经济社会将崛起。

  • 比特币价值将达到每枚数以万计的美元。

  • 数字身份将在区块链上进行常规管理,不同的政府职能,如选举、税收和资金发放将通过区块链平台进行。

  • 2018 年,金融机构和清算机构将开始为他们的客户推出基于区块链的解决方案。

摘要

区块链将改变世界。革命已经开始,预计只会以指数级别增长。本章探讨了各种项目和当前的区块链技术现状。

首先,讨论了一些预计随着技术的进步将持续的趋势。全球许多研究人员和组织对区块链技术表现出浓厚的研究兴趣,并在本章节中介绍了一些研究课题。此外,还讨论了与物联网和人工智能等其他领域的融合。

最后,对区块链技术增长的一些预测已经做出。这些预测中大多数可能在未来十年内实现,而有些可能需要更长时间。区块链技术有改变世界的潜力,一些积极的征兆已经从成功的 PoC 实施和越来越多的爱好者和开发者对这项技术的兴趣中显现出来。很快,区块链将和现在的互联网一样融入到我们的生活中。本章节只是对区块链巨大潜力的一次简要概述,在不久的将来,预计会出现指数增长和进一步采用这项技术。

posted @ 2024-05-01 15:27  绝不原创的飞龙  阅读(3)  评论(0编辑  收藏  举报