10.10 区块链的组装与选择
比特币去中心化的共识机制的最后一步是将区块集合至有最大工作量证明的链中。一旦一个节点验证了一个新的区块, 它将尝试将新的区块连接到到现存的区块链,将它们组装起来。
节点维护三种区块:第一种是连接到主链上的,第二种是从主链上产生分支的(备用链),最后一种是在已知链中没有 找到已知父区块的。在验证过程中,一旦发现有不符合标准的地方,验证就会失败,这样区块会被节点拒绝,所以也不 会加入到任何一条链中。
任何时候,主链都是累计了最多难度的区块链。在一般情况下,主链也是包含最多区块的那个链,除非有两个等长的链 并且其中一个有更多的工作量证明。主链也会有一些分支,这些分支中的区块与主链上的区块互为“兄弟”区块。这些区 块是有效的,但不是主链的一部分。 保留这些分支的目的是如果在未来的某个时刻它们中的一个延长了并在难度值上超 过了主链,那么后续的区块就会引用它们。在“10.10.1 区块链分叉”,我们将会看到在同样的区块高度,几乎同时挖出区 块时,候选链是如何产生的。
当节点接收到新区块,它会尝试将这个区块插入到现有区块链中。节点会看一下这个区块的“previous block hash”字 段,这个字段是该区块对其父区块的引用。同时,新的节点将尝试在已存在的区块链中找出这个父区块。大多数情况 下,父区块是主块链的“顶点”,这就意味着这个新的区块延长了主链。举个例子,一个新的区块——区块277,316引用 了它的父区块——区块277,315。收到277316区块的大部分节点都已经将277315最为主链的顶端,因此,连接这个新区块并延长区块链。
有时候,新区块所延长的区块链并不是主链,这一点我们将在“10.10.1 区块链分叉”中看到。在这种情况下,节点将新的区块添加到备用链,同时比较备用链与主链的难度。如果备用链比主链积累了更多的难度,节点将收敛于备用链,意味 着节点将选择备用链作为其新的主链,而之前那个老的主链则成为了备用链。如果节点是一个矿工,它将开始构造新的 区块,来延长这个更新更长的区块链。
如果节点收到了一个有效的区块,而在现有的区块链中却未找到它的父区块,那么这个区块被认为是“孤块”。孤块会被 保存在孤块池中,直到它们的父区块被节点收到。一旦收到了父区块并且将其连接到现有区块链上,节点就会将孤块从 孤块池中取出,并且连接到它的父区块,让它作为区块链的一部分。当两个区块在很短的时间间隔内被挖出来,节点有 可能会以相反的顺序接收到它们,这个时候孤块现象就会出现。
选择了最大难度的区块链后,所有的节点最终在全网范围内达成共识。随着更多的工作量证明被添加到链中,链的暂时 性差异最终会得到解决。挖矿节点通过“投票”来选择它们想要延长的区块链,当它们挖出一个新块并且延长了一个链, 新块本身就代表它们的投票。
相互竞争的链之间是存在差异的,下节我们将看到节点是怎样通过独立选择最长难度链来解决这种差异的。
10.10.1 区块链分叉
因为区块链是去中心化的数据结构,所以不同副本之间不能总是保持一致。区块有可能在不同时间到达不同节点,导致节点有不同的区块链全貌。解决的办法是,每一个节点总是选择并尝试延长代表累计了最大工作量证明的区块链,也就 是最长的或最大累计工作的链(greatest cumulative work chain)。节点通过累加链上的每个区块的工作量,得到建立这个链所要付出的工作量证明的总量。只要所有的节点选择最长累计工作的区块链,整个比特币网络最终会收敛到一致的状态。分叉即在不同区块链间发生的临时差异,当更多的区块添加到了某个分叉中,这个问题便会迎刃而解。
提示由于全球网络中的传输延迟,本节中描述的区块链分叉自动会发生。 我们也将在本章稍后再看看故意引起的分叉。
在接下来的几个图表中,我们将通过网络跟踪“fork”事件的进展。 该图是比特币网络的简化表示。 为了便于描述,不同的区块被显示为不同的形状(星形,三角形,倒置三角形,菱形),遍布网络。 网络中的每个圆表示一个节点。
每个节点都有自己的全局区块链视图。 当每个节点从其邻居接收区块时,它会更新其自己的区块链副本,选择最大累积工作链。 为便于描述,每个节点包含一个图形形状,表示它相信的区块处于主链的顶端。 因此,如果在节点里面看到星形,那就意味着该节点认为星形区块处于主链的顶端。
在第一张图(图10-2)中,网络有一个统一的区块链视角,以星形区块为主链的“顶点”。
图10-2
当有两个候选区块同时想要延长最长区块链时,分叉事件就会发生。正常情况下,分叉发生在两名矿工在较短的时间 内,各自都算得了工作量证明解的时候。两个矿工在各自的候选区块一发现解,便立即传播自己的“获胜”区块到网络 中,先是传播给邻近的节点而后传播到整个网络。每个收到有效区块的节点都会将其并入并延长区块链。如果该节点在 随后又收到了另一个候选区块,而这个区块又拥有同样父区块,那么节点会将这个区块连接到候选链上。其结果是,一 些节点收到了一个候选区块,而另一些节点收到了另一个候选区块,这时两个不同版本的区块链就出现了。在图10-3中,我们看到两个矿工(NodeX和NodeY)几乎同时挖到了两个不同的区块。这两个区块是顶点区块——星形区块的子区块,可以 延长这个区块链。为了方便查看,我们把节点X产生的区块标记为三角形,把节点Y生产的区块标记为倒三角形。
图10-3
例如,我们假设矿工节点X找到扩展区块链工作量证明的解,即三角形区块,构建在星形父区块的顶端。与此同时,同样进行星形区块扩展的节点Y也找到了扩展区块链工作量证明的解,即倒三角形区块作为候选区块。现在有两个可能的块,节点X的三角形区块和节点Y的倒三角形区块,这两个区块都是有效的,均包含有效的工作量证明解并延长同一 个父区块。这个两个区块可能包含了几乎相同的交易,只是在交易的排序上有些许不同。
当两个区块开始在网络传播时,一些节点首先接收到三角形区块,另外一些节点首先接收倒三角形区块。如下图10-4所示,比特币网络上的节点对于区块链的顶点产生了分歧,一派以三角形区块为顶点,而另一派以倒三角形区块为顶点。
图10-4
在图中,假设节点X首先接收到三角形块,并用它扩展星形链。节点X选择三角形区块为主链。之后,节点X也收到倒三角区块。由于是第二次收到,因此它判定这个倒三角形区块是竞争失败的产物,认为是无效区块。然而,倒三角形的区块不会被丢弃。它被链接到星形链的父区块,并形成备用链。虽然节点X认为自己已经正确选择了获胜链,但是它还会保存“丢失”链,使得“丢失”链如果可能最终“获胜”,它还具有重新打包的所需的信息。
在网络的另一端,节点Y根据自己的视角构建一个区块链。首先获得倒三角形区块,并选择这条链作为“赢家”。当它稍后收到三角形区块时,它也将三角形区块连接到星形链的父区块作为备用链。
双方都是“正确的”或“不正确的”。两者都是自己关于区块链的有效立场。只有事后,才能理解这两个竞争链如何通过额外的工作得到延伸。
节点X阵营的其他节点将立即开始挖掘候选区块,以“三角形”作为扩展区块链的顶端。通过将三角形作为候选区块的父区块,它们用自己的哈希算力进行投票。它们的投票标明支持自己选择的链为主链。
同样,节点Y阵营的其他节点,将开始构建一个以倒三角形作为其父节点的候选节点,扩展它们认为是主链的链。比赛再次开始。分叉问题几乎总是在一个区块内就被解决了。网络中的一部分算力专注于“三角形”区块为父区块,在其之上建立新的区 块;另一部分算力则专注在“倒三角形”区块上。即便算力在这两个阵营中平均分配,也总有一个阵营抢在另一个阵营前发现工作量证明解并将其传播出去。在这个例子中我们可以打个比方,假如工作在“三角形”区块上的矿工找到了一个“菱形”区块 延长了区块链(星形-三角形-菱形),他们会立刻传播这个新区块,整个网络会都会认为这个区块是有效的,如下图10-5所示。
图10-5
选择“三角形”作为上一轮中胜出者的所有节点将简单地将区块链扩展一个块。然而,选择“倒三角”的节点现在将看到两个链:星形-三角形-菱形和星型-到三角形。星形-三角形-菱形这条链现在比其他链条更长(更多累积的工作)。因此,这些节点将星形-三角形-菱形设置为主链,并将星型-倒三角形链变为备用链,如图10-6所示。这是一个链的重新共识,因为这些节点被迫修改他们对块链的立场,把自己纳入更长的链。任何从事延伸星形-倒三角形的矿工现在都将停止这项工作,因为他们的候选人是“孤儿”,因为他们的父母“倒三角形”不再是最长的连锁。 “倒三角形”内的交易重新插入到内存池中用来包含在下一个块中,因为它们所在的块不再位于主链中。整个网络重新回到单一链状态,星形-三角形-菱形,“菱形”成为链中的最后一个块。所有矿工立即开始研究以“菱形”为父区块的候选块,以扩展这条星形-三角形-菱形链。
图10-6
从理论上来说,两个区块的分叉是有可能的,这种情况发生在因先前分叉而相互对立起来的矿工,又几乎同时发现了两 个不同区块的解。然而,这种情况发生的几率是很低的。单区块分叉每周都会发生,而双块分叉则非常罕见。比特币将区块间隔设计为10分钟,是在更快速的交易确认和更低的分叉概率间作出的妥协。更短的区块产生间隔会让交 易清算更快地完成,也会导致更加频繁地区块链分叉。与之相对地,更长的间隔会减少分叉数量,却会导致更长的清算时间。