首页 > 其他分享 >adv-bc-dev-merge-0

adv-bc-dev-merge-0

时间:2024-05-01 15:44:45浏览次数:19  
标签:adv 比特 可以 dev 节点 merge 使用 区块 交易

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

原文: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

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

警告或重要提示如下。

贴士和技巧如下。

联系我们

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

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

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

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

如果您有兴趣成为作者:如果您在某个专题上有专业知识,并且有兴趣撰写或投稿书籍,请访问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 []:[email protected]  

可以使用以下命令查看证书:

$ 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

标签:adv,比特,可以,dev,节点,merge,使用,区块,交易
From: https://www.cnblogs.com/apachecn/p/18169378

相关文章

  • eth-proj-bg-merge-0
    面向初学者的ETH项目(全)原文:zh.annas-archive.org/md5/5b197ea4ae8836b6854907e58ea8a1dc译者:飞龙协议:CCBY-NC-SA4.0前言本书旨在让你深入了解以太坊区块链世界,并让你使用以太坊制作自己的加密货币。在本书中,你将学习各种概念,并直接应用这些知识,同时还将介绍以太坊区块......
  • Audio Output Devices API
    AudioOutputDevicesAPI:音频输出设备API允许Web应用程序提示用户应使用什么输出设备进行音频播放。<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"/><metaname="viewport"content="width=device-width,i......
  • 使用浏览器无密码登录Azure DevOps Server
    1.概述AzureDevOpsServer作为软件开发管理平台服务器,除了支持主流的IDE开发工具外,普通用户使用最频繁的客户端工具是网页浏览器。由于AzureDevOpsServer集成AD域服务器实现用户认证,用户每次使用浏览器登录服务器时都需要输入用户的域账户和密码。但是,对于已经使用域账户登录......
  • Devexpress GridView 单元格输入检验
    实现效果打开设计器找到CellValueChanged事件编写代码privatevoidgvmain_CellValueChanged(objectsender,DevExpress.XtraGrid.Views.Base.CellValueChangedEventArgse){stringseq=gvmain.GetRowCellValue(e.RowHandle,colQaSeq).......
  • Offline web technology for Mobile devices
    一、当前问题1、弱网或断网,当用户进入电梯或无网区,长时间白屏或无法显示页面2、正常网络,从点击app到显示首页文字图片,白屏时间大约7-9秒 二、原因分析1、从技术视角,分析一下网页启动的几个关键耗时阶段 2、没有做离线化技术,而手机端用户进入弱网与无网区......
  • 界面组件DevExpress Blazor UI v23.2 - 网格、工具栏功能全新升级
    DevExpress BlazorUI组件使用了C#为BlazorServer和BlazorWebAssembly创建高影响力的用户体验,这个UI自建库提供了一套全面的原生BlazorUI组件(包括PivotGrid、调度程序、图表、数据编辑器和报表等)。DevExpress Blazor控件目前已经升级到v23.2版本了,此版本进一步增强了可访问......
  • C - Merge the balls
    C-Mergetheballshttps://atcoder.jp/contests/abc351/tasks/abc351_c 思路使用stack记录序列路径对栈顶两个元素尝试做缩减处理。 Codehttps://atcoder.jp/contests/abc351/submissions/52873456intn;stack<longlong>sq;intmain(){cin>>n;......
  • EDevourer风险分析报告及典型用户
    1.风险分析人:客户/用户反馈多样性:由于用户群体可能包括不同年龄段、英语水平和游戏喜好的人群,因此他们的反馈可能多样化,需要花费更多精力去理解和整合这些反馈。团队成员经验和技能:团队成员在游戏开发的时侯有可能会遇到许多bug或者遇到设想的功能无法实现,可能导致开发过程中......
  • kube-state-metrics和cAdvisorc结合使用的好处
    kube-state-metrics是Kubernetes监控系统的重要组成部分,它提供了对集群中对象状态的实时监控。具体来说,kube-state-metrics通过监听APIServer生成有关资源对象的状态指标,比如Deployment、Node、Pod等。kube-state-metrics只是简单提供一个metrics数据,并不会存储这些指标数据,所以......
  • 使用 .NET 的 Dev Proxy 构建和测试弹性应用
    使用.NET的DevProxy构建和测试弹性应用https://devblogs.microsoft.com/dotnet/build-test-resilient-apps-dotnet-dev-proxy/在构建连接到API的应用时,我们通常专注于让应用正常工作。但是,当API速度慢、返回错误或不可用时会发生什么?你最不想看到的就是当你的应用程序......