第3章:比特币的机制(二)

3.4

比特币区块

到目前为止,本章中我们已经研究了如何构建和赎回个别交易。但正如我们在第2章中看到的那样,交易被分组成区块。为什么是这样?基本上,这是一个优化。如果矿工不得不单独就每个交易达成共识,那么系统可以接受新交易的比例将会低得多。此外,区块的哈希链比交易的哈希链短得多,因为可以将大量的交易放入每个区块中。这将使得验证区块链数据结构更有效率。

区块链是两个基于哈希的不同数据结构的巧妙组合。第一个是区块的哈希链。每个区块都有区块头,哈希指针指向一些交易数据,以及一个指向序列中前一个区块的哈希指针。第二个数据结构是一个每个区块树,包含该区块中的所有交易。这是一个Merkle树,并允许我们以有效的方式对区块中的所有交易进行摘要。正如我们在第1章中看到的,为了证明一个交易被包含在一个特定的区块中,我们可以提供一个通过树的路径,其长度在区块中的交易数量上是对数的。总而言之,区块由头部数据组成,后面是以树结构排列的交易列表。

图3.8 比特币区块链包含两个不同的哈希结构。第一个是将不同区块相互链接的区块哈希链。第二个是每个区块的内部,是区块内的交易Merkle树。

头部主要包含我们上一章中简要讨论的挖掘难题相关的信息,我们将在第5章中重新讨论。回想一下,区块的哈希头部必须以大量的零开始,以使区块有效。头部还包含矿工可以更改的“随机数”、时间戳和“位”,这是该区块被发现难度的指示。头部是挖掘中唯一哈希过的。所以要验证一个区块链,我们需要做的就是查看头部。包含在头部中的唯一交易数据是交易树的根——“mrkl_root”字段。

图3.9 coinbase交易。一个coinbase交易创造新的硬币。它不会兑换以前的输出,且它有一个空的哈希指针来表示这一点。它具有可以包含任意数据的coinbase参数。Coinbase的价值是区块奖励加上此区块中包含的所有交易费用。

区块的另一个有趣的事情是他们在Merkle树中有一个特殊的交易,称为“coinbase”交易。这与Scroogecoin中的CreateCoins类似。因此这就是在比特币中发生的新硬币创造。它看起来像一个正常的交易,但有几点区别:(1)它总是有一个单一的输入和一个单一的输出,(2)输入不会兑换先前的输出,因而包含一个空的哈希指针,因为它是铸造新的比特币而不是消耗现有的硬币,(3)输出的值目前是25个多一点的比特币。输出值是矿工从区块中获得的收入。它由两部分组成:平均开采奖励,由系统设定,每210,000个区块(约4年)减半,以及从每次区块中交易收取的交易费用。4)有一个特殊的完全任意的“coinbase”参数——矿工可以把任何想要的东西放在那里。

有趣的是,在比特币开采的第一个区块中,“coinbase”参数引用了泰晤士报上一个涉及大臣银行的故事。这被解释为比特币创世区块的政治评论动机。这也是第一个区块矿石开采在2009年1月3日之后的一种证明。使用coinbase参数成为矿工支持不同新功能的一种方式。

为了更好地了解区块格式和交易格式,最好的方法是自己探索区块链。有很多网站可以访问这些数据,例如blockchain.info。你可以查看交易的图表,查看哪些交易对其他交易进行赎回,用复杂脚本的脚本查找交易,并查看区块结构,查看区块是如何引用其他区块的。由于区块链是公共数据结构,开发人员已经搭建了漂亮的包装器来以图形的方式进行探索。

3.5

比特币网络

到目前为止,我们一直在谈论参与者发布交易的能力,并将其加入区块链,这好像魔法一样的发生。实际上,这是通过比特币网络发生的。它是一个p2p对等网络,它继承了许多从各种其他目的提出的对等网络的想法。在比特币网络中,所有节点都是对等的。这里面没有层次结构,没有特殊的节点或主节点。它运行在TCP上并具有随机拓扑性,其中每个节点与其他随机节点对等。新节点可以随时加入。事实上,事实上,您可以下载Bitcoin客户端,将您的计算机作为一个节点启动,它将具有与Bitcoin网络上其他所有节点相同的权限和功能。

网络随着时间的推移而变化,由于节点的进入和离开而变得非常动态。没有明确的离开网络的方法。相反,如果节点在一段时间内没有被听到——三个小时是硬编码到普通客户端的期限时间——其他节点就开始忘记它。网络以这种方式优雅地处理离线的节点。

回想一下,节点连接到随机节点,并且没有任何类型的地理拓扑。现在你启动一个新的节点并想加入网络。你从一个你知道的节点开始一个简单的消息。这通常称为你的种子节点,并且有几种不同的方法可以通过查找种子节点的列表来尝试连接。你发送一条特殊消息,说:“告诉我你所了解的网络中所有其他节点的地址。”你可以使用你想要了解的新节点重复此过程。然后,你可以选择一个与之对应,你将因此成为Bitcoin网络中功能完整的一员。牵扯到随机性,有几个步骤,理想的结果是你与一个随机的节点集对应。要加入网络,你需要知道的是如何与一个已经在网络上的节点联系。

网络有什么好处?当然是为了维持区块链。所以要发布一个交易,我们想让整个网络听到。这通过简单的洪水算法(有时称为八卦协议)来实现。如果Alice想向Bob支付一些钱,她的客户端会创建它的节点,并将该交易发送给所有与其对等的节点。这些节点中的每一个执行一系列检查以确定是否接受和传达该交易。如果检查通过,节点又将其发送到它的所有对等节点。听到一个交易的节点将它放在他们已经听到但尚未出现在区块链上的交易池中。如果一个节点听到的交易已经在它的交易池,则不会进一步广播它。这样可以确保洪水协议终止,交易不会永远环绕网络。请记住,每个交易都由其哈希唯一标识,因此在池中查找交易很容易。

当节点听到一个新的交易时,他们是如何决定是否应该传播它?这里有四个检查步骤。第一个也是最重要的检查是交易验证——交易必须对当前区块链有效。节点为每个先前赎回的输出运行脚本,并确保脚本返回true。其次,他们检查这里兑换的输出是否还没有被花费。第三,如前所述,它们不会转发已经看到的交易。第四,默认情况下,节点将仅接受并继承基于小白名单脚本的“标准”脚本。

所有这些检查都只是健全检查。运行良好的节点都实现了这些,以使网络保持正常运行,但没有任何规则说节点必须遵循这些具体步骤。由于它是一个对等网络,任何人都可以加入,因此,节点可能会转发双重支出,非标准交易或完全无效的交易。这就是为什么每个节点必须自己检查。

由于网络中存在延迟,因此节点可能会以不同的待处理交易池视图结束。当尝试双重支付时,这变得特别有趣和重要。假设Alice试图向Bob和Charlie支付相同的比特币,并且大致同时发出这两笔交易。一些节点首先听到AliceBob的交易,而其他节点首先会听到AliceCharlie的交易。当一个节点听到这些交易之一时,它会将其添加到它的交易池中,如果它稍后听到另一个交易,它将被认为是一个双重支付。节点将舍弃后一个交易,并且不会传达它或将其添加到其交易池中。因此,节点将暂时不同意将哪些交易放入下一个区块中。这称为比赛条件。

好消息是,这完全没问题。无论谁挖下一个区块,基本上都会打破平局,决定这两桩待处理交易中的哪一个最终将被永久性地丢进一个区块。让我们说AliceCharlie的交易成为一个区块。当AliceBob交易的节点听到有关此区块的信息时,它们将从内存池中删除交易,因为它是双重支付。当AliceCharlie交易的节点听到有关此区块的信息时,它们会将交易从内存池中删除,因为它已经被嵌入到区块链中。所以一旦这个区块传播到网络就不会再有分歧了。

因为默认行为是让节点挂他们首先听到任何消息,所以网络位置很重要。如果两个冲突的交易或区块在网络中的两个不同位置被公布,那么它们将在整个网络中开始泛洪,并且节点首先看到哪个交易将取决于它在网络中的位置。

当然,这假设每个节点都实现这些逻辑,在这些逻辑中,它们首先保留任何他们听到的内容。但是,没有中央权威机构强制执行这一点,节点可以自由地实现他们想要的任何其他逻辑,以选择哪些交易要保留以及是否要转发交易。我们将在第5章中更加关注采矿者的激励。

边栏零确认交易和替换费。在第2章中,我们研究了零确认交易,收件人一旦在网络上广播就接受该交易。这不是为了针对双重支付的安全设计。但正如我们所看到的那样,在交易冲突的情况下,矿工的默认行为是包含他们首先收到的交易,这使得双重支付针对零确认交易适当的困难。因此,由于方便,零确认交易变得普遍。

自2013年以来,已经有兴趣将默认政策更改为替代费用(RBF),如果他们听到包含较高费用的冲突交易,节点将替换其交易池中的待处理交易。这是矿工的理性行为,至少在短期意义上,它给了他们更好的收费。但是,在实践中,替代费用会使得双重支付针对零确认攻击更加容易。

因此,无论是防止或阻止在RBF世界中的双重支付的技术问题,以及比特币是否应该尽可能支持零确认,还是放弃它的哲学问题,替代收费问题就引起了争议。我们不会深入讨论这场旷日持久的争论,但Bitcoin最近通过了“选择加入”RBF网络,交易可以标记自己(使用序列号字段)有资格使用更高费用的交易来替换。

到目前为止,我们一直在讨论交易的广播。每当矿工找到新的区块时,宣布新区块的逻辑与传播新的交易几乎完全相同,并且都受到相同竞争条件的限制。如果两个有效区块同时开采,则只有其中一个可以包含在长期共识链中。最终将包括哪些区块将取决于其他节点建立在哪个区块上,而不会进入共享链的区块将是孤立的。

验证区块比验证交易更复杂。除了验证标题并确定哈希值在可接受的范围外,节点必须验证区块中包含的每个交易。最后,一个节点只有当区块建立在最长的分支上时,才会转发这个区块,这是基于区块视图(实际上是一个块树)看起来像什么的。这样可以避免分叉的建立。但就像交易一样,节点可以根据需要实现不同的逻辑——它们可能会传达无效的区块或从区块链中较早点构建的区块。这将构建一个分叉,但没关系。该协议被设计为能承受这一点。

图3.10区块传播时间该图显示了一个区块到达网络中各种节点百分比所需的平均时间。

洪水算法的延迟是多少?图3.10中的图表显示新区块传播到网络中每个节点的平均时间。这条线显示了25个、50个和75个百分位数的传播时间。可以看出,传播时间基本上与区块的大小成比例。这是因为网络带宽是瓶颈。较大的区块占用超过30秒,才能传播到网络中的大多数节点。所以这不是一个特别有效的协议。在互联网上,30秒是相当长的时间。在比特币的设计中,拥有一个简单的网络,结构简单,节点相等,可以随进随出,优先于效率。因此,在到达网络中最远的节点之前,区块可能需要经过许多节点。如果网络是为了效率而自上而下地设计,我们可以确保任何两个节点之间的路径很短。

网络大小很难衡量网络有多大,因为它是动态的,且没有中央权威。一些研究人员提出了一些估计。在高端方面,有人说,在某个月份,超过一百万个IP地址将至少暂时作为比特币节点。另一方面,似乎只有大约5000到10,000个节点永久连接,且完全验证他们听到的每个交易。这看起来可能是一个令人惊讶的低数字,但是在这篇文章中,没有证据表明完全验证节点的数量正在上升,事实上它可能正在下降。

存储要求 完全验证节点必须保持永久连接,以便听到所有数据。节点离线的时间越长,重新加入网络需要追赶的就越多。这样的节点还必须存储整个区块链,并且需要良好的网络连接以能够听到每个新的交易并将其转发给对等体。存储需求目前低于数十个GB(参见图3.11),这在单一商用台式机的能力范围内。

图3.11.区块链的大小。完全验证节点必须存储整个块链,截至2014年底,该链为26千兆字节。

最后,完全验证节点必须保持一整套未使用的交易输出集合,这是可以花费的硬币。理想情况下,这应该存储在RAM中,这样当听到网络上新的交易时,节点可以快速查找它试图声明的交易输出,运行脚本,查看签名是否有效,并将交易添加到交易池中。截至2014年年中,有超过4400万的交易在区块链中,其中1200万未使用。幸运的是,它仍然足够小以适应高效数据结构中不到1G的RAM。

轻量节点。与完全验证节点相反,存在轻量级节点,也称为瘦客户端或简单支付验证(SPV)客户端。 实际上,比特币网络上绝大多数的节点都是轻量级节点。 这不同于完全验证节点,因为它们不存储整个区块链。他们只存储需要他们验证的,他们关心的特定交易的部分。如果你使用钱包程序,通常会包含一个SPV节点。该节点下载代表向你的地址付款的区块头和交易。

SPV节点没有完全验证节点的安全级别。由于节点具有区块头,因此可以检查这些区块是否难以挖掘,但不能检查区块中包含的每个交易实际上都是有效的,因为它没有交易历史并且不知道未用的交易输出的集合。SPV节点只能验证实际影响它们的交易。所以他们本质上信任完全验证节点来验证所有其他的交易。这不是一次糟糕的安全交易。他们假设有完全验证节点在做艰苦的工作,如果矿工们挖掘这个区块遇到了麻烦,这是一个非常昂贵的过程,他们可能也做了一些验证,以确保这个区块不会被拒绝。

作为SPV节点的成本节省是巨大的。区块头只有区块链大小的大约1/1000。所以不用存储几十G的字节,只有几十M字节。即使智能手机也可以轻松充当Bitcoin网络中的SPV节点。

由于Bitcoin依赖于一个开放的协议,理想情况下,会有许多不同的实现无缝地交互。这样一来,如果有一个bug在其中,就不太可能使整个网络瘫痪。好消息是协议已成功重新实施。C++和Go中有实现,人们正在处理很多其他的事情。坏消息是,网络上的大多数节点正在运行Bitcoin库,由C ++编写,由Bitcoin Core开发人员维护,其中一些节点正在运行以前未更新的旧版本。无论如何,大多数人正在运行这个普通客户端的一些变体。

3.6

限制和改进

最后,我们将讨论Bitcoin协议的一些内置限制,以及改进它们的挑战性。在2009年比特币提出时,任何人真正意识到它可能会发展成为全球重要货币之前,Bitcoin协议中存在许多硬编码的限制。其中包括每个块的平均时间,块的大小,区块中签名操作的数量,以及货币的可分性,比特币的总数和区块奖励结构的限制。

对现有比特币总数的限制以及采矿奖励的结构很可能永远不会改变,因为改变它们的经济影响太大了。矿工和投资者对该系统做了很大的赌注,假设比特币的奖励结构和比特币的有限供应将保持其计划的方式。如果这种情况发生变化,将会对人们带来巨大的经济影响。因此,社会基本上同意这些方面,无论是否被明智地选择,都不会改变。

还有其他一些变化似乎使每个人都更好,因为一些初步的设计选择看起来不太符合事后的观点。其中首要的是影响系统吞吐量的限制。Bitcoin网络进程每秒可以处理多少笔交易?该限制来自区块大小的硬编码限制。每个区块限于一兆字节,大约一百万字节。每个交易至少为250个字节。将1000000划分为250份,我们可以看到每个区块的限制为4000个交易,而且每10分钟发现一个,所以每秒剩下约7笔交易,这就是Bitcoin网络所能处理的。改变这些限制似乎只用调整源代码文件中的某个常量。然而,很难在实践中做出这样的改变,我们将很快解释原因。

那么每秒七笔交易如何?比任何主要信用卡处理器的吞吐量相比都相当低。据说Visa的网络平均每秒处理大约2000笔交易,在繁忙期间每秒能处理10000笔交易。即使是比Visa更新更小的Paypal,在高峰时段每秒可处理100笔交易。 这比Bitcoin多一个数量级。

人们长期担心的另一个限制是比特币的加密算法的选择是固定的。只有几个哈希算法可用,只有一个签名算法ECDSA,在特定的椭圆曲线上,称为secp256k1。有人担心,在比特币的生命周期中,人们希望这将是很长的——这个算法可能会被破解。密码学家可能会想出一个我们没有预见到的巧妙的新攻击,使得算法不安全。哈希函数也是如此;事实上,在过去十年中,哈希函数已经在密码分析方面取得了稳步的进展。包含在比特币中的SHA-1已经有一些已知的加密缺陷,尽管不是致命的。为了改变这一点,我们必须扩展Bitcoin脚本语言来支持新的加密算法。

更改协议。我们如何才能在Bitcoin协议中引入新功能?您可能会认为这很简单-只需发布新版本的软件,并告诉所有节点进行升级。 实际上,这是相当复杂的。在实践中,不可能假设每个节点都将升级。 网络中的某些节点将无法获取新软件或无法及时获取。当一些节点运行旧版本时,大多数节点升级的影响很大程度上取决于软件变更的性质。我们可以区分两种类型的变化:那些会导致硬分叉和那些会导致软分叉。

硬分叉。我们可以做出的一种类型的改变引入了先前被认为无效的新功能。也就是说,新版本的软件将识别区块为有效,而旧软件将拒绝其有效性。现在考虑当大多数节点升级,但有些没有升级时会发生什么。不久之后,最长的分支将包含被旧节点视为无效的区块。因此,旧节点将脱离并使用区块链中的一个分支来排除具有新功能的区块。在升级他们的软件之前,他们会认为他们的(较短)分支是最长的有效分支。

这种变化被称为硬分叉变化,因为它使区块链分裂。根据运行的协议版本,网络中的每个节点都将在其一侧或另一侧。当然,这些分支机构永远不会再加入到一起。这被社区认为是不可接受的,因为旧的节点如果不升级他们的软件,将有效地从比特币网络中切割出来。

软分叉。我们可以对Bitcoin进行的第二种类型的更改是增加使验证规则更严格的功能。也就是说,它们限制一组有效的交易或一组有效的区块,使得旧版本将接受所有区块,而新版本将拒绝某些。这种变化称为软叉,它可以避免硬叉引入的永久分裂。

试想当我们引入一个新的软分叉改变软件版本时会发生什么。运行新软件的节点将执行一些新的更严格的规则。如果大多数节点切换到新软件,这些节点将能够执行新的规则。引入软叉依靠足够的节点切换到新版本的协议,以便他们能够执行新的规则,知道旧节点将无法执行新的规则,因为他们没有被听说过。

老矿工有挖掘到无效区块的风险,因为它们包括的一些交易在新的,更严格的规则下是无效的。但是,旧的节点至少会弄清楚他们的某些区块被拒绝,即使他们不明白原因。这可能会促使他们的运营商升级他们的软件。此外,如果他们的分支被新的矿工超越,老矿工就会转向它。这是因为新矿工认为有效的区块也被老矿工认为是有效的。因此,不会有硬叉;相反,会有很多小的临时的分叉。

通过软叉进行的更改的典型例子是付费到脚本哈希(pay-to-script-hash),我们在本章前面讨论过。Bitcoin协议的第一个版本中没有Pay-to-script-hash。这是一个软叉,因为从旧节点的角度来看,有效的付费到脚本哈希交易仍将正确验证。如旧节点所解释的那样,脚本很简单——它会哈希一个数据值,并检查哈希是否匹配输出脚本中指定的值。旧节点不知道(现在需要)运行值本身的附加步骤,看看它是否是一个有效的脚本。我们依靠新的节点来执行新的规则,即脚本实际上是赎回这个交易。

那么我们可以用软叉添加什么?付费到脚本哈希是成功的。新的加密方案也可以通过软叉添加。我们还可以在Coinbase参数中添加一些额外的元数据,以使其有意义。今天,coinbase参数接受任何值。但是,将来我们可以说,这个coinbase必须有一些具体的格式。提出的一个想法是,在每个新的区块中,coinbase包含整套未使用交易的树的Merkle根。这只会导致软叉,因为旧节点可能可能会挖掘一个受网络拒绝没有新coinbase参数需要的区块,但是他们会赶上并加入网络中正在开采的主链。

其他更改可能需要硬叉。比如向Bitcoin添加新的操作码,更改区块或交易大小的限制或各种错误修复。修复我们之前讨论的错误,MULTISIG指令从堆栈中弹出一个额外的值,都需要一个硬叉来实现。这就是为什么,即使一个令人讨厌的bug,更容易将其放在协议中,让人们围绕它进行工作,而不是对Bitcoin进行硬叉更改。即使他们是好的,硬叉更改也是不太可能在当前比特币的气氛中发生的。但是,从头开始,这些想法已经在替代密码货币中测试过并被证明是成功的。我们将在第10章中讨论更多的细节。

边栏:比特币区块大小的难题。由于比特币日益普及,截止2016年初,区块的1M空间被填满已经变得普遍存在(特别的是因为随机性,一个区块需要超过10分钟才能找到)首先,导致一些交易必须等待一个或多个附加区块以进入区块链。增加区块大小的限制将需要硬叉。

关于是否以及如何解决区块链有限交易带宽的问题已经得到Bitcoin社区足够的关注。这个讨论从多年前开始的,但是在达成共识方面却没有什么进展,且变得更加激进,已升级成马戏团。我们将在第7章讨论比特币的社区、政治和治理。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20180824A1GJAB00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券