区块链的组装与选择
比特币去中心化的共识机制的最后一步是将区块集合至有最大工作量证明的链中。一旦一个节点验证了一个新的区块,它将尝试将新的区块连接到到现存的区块链,将它们组装起来。
节点维护三种区块:第一种是连接到主链上的,第二种是从主链上产生分支的(备用链),最后一种是在已知链中没有找到已知父区块的。在验证过程中,一旦发现有不符合标准的地方,验证就会失败,这样区块会被节点拒绝,所以也不会加入到任何一条链中。
任何时候,主链都是累计了最多难度的区块链。在一般情况下,主链也是包含最多区块的那个链,除非有两个等长的链并且其中一个有更多的工作量证明。主链也会有一些分支,这些分支中的区块与主链上的区块互为“兄弟”区块。这些区块是有效的,但不是主链的一部分。 保留这些分支的目的是如果在未来的某个时刻它们中的一个延长了并在难度值上超过了主链,那么后续的区块就会引用它们。在“8.10.1 区块链分叉”,我们将会看到在同样的区块高度,几乎同时挖出区块时,候选链是如何产生的。
当节点接收到新区块,它会尝试将这个区块插入到现有区块链中。节点会看一下这个区块的“previous block hash”字段,这个字段是该区块对其父区块的引用。同时,新的节点将尝试在已存在的区块链中找出这个父区块。大多数情况下,父区块是主块链的“顶点”,这就意味着这个新的区块延长了主链。举个例子,一个新的区块——区块277,316引用了它的父区块——区块277,315。大部分收到了区块277,316的节点将区块277,315作为主链的顶点,连接这个新区块并延长区块链。
有时候,新区块所延长的区块链并不是主链,这一点我们将在“8.10.1 区块链分叉”中看到。在这种情况下,节点将新的区块添加到备用链,同时比较备用链与主链的难度。如果备用链比主链积累了更多的难度,节点将收敛于备用链,意味着节点将选择备用链作为其新的主链,而之前那个老的主链则成为了备用链。如果节点是一个矿工,它将开始构造新的区块,来延长这个更新更长的区块链。
如果节点收到了一个有效的区块,而在现有的区块链中却未找到它的父区块,那么这个区块被认为是“孤块”。孤块会被保存在孤块池中,直到它们的父区块被节点收到。一旦收到了父区块并且将其连接到现有区块链上,节点就会将孤块从孤块池中取出,并且连接到它的父区块,让它作为区块链的一部分。当两个区块在很短的时间间隔内被挖出来,节点有可能会以相反的顺序接收到它们,这个时候孤块现象就会出现。
选择了最大难度的区块链后,所有的节点最终在全网范围内达成共识。随着更多的工作量证明被添加到链中,链的暂时性差异最终会得到解决。挖矿节点通过“投票”来选择它们想要延长的区块链,当它们挖出一个新块并且延长了一个链,新块本身就代表它们的投票。
相互竞争的链之间是存在差异的,下节我们将看到节点是怎样通过独立选择最长难度链来解决这种差异的。
8.10.1 区块链分叉
因为区块链是去中心化的数据结构,所以不同副本之间不能总是保持一致。区块有可能在不同时间到达不同节点,导致节点有不同的区块链视角。解决的办法是,每一个节点总是选择并尝试延长代表累计了最大工作量证明的区块链,也就是最长的或最大累计难度的链。节点通过将记录在每个区块中的难度加总起来,得到建立这个链所要付出的工作量证明的总量。只要所有的节点选择最长累计难度的区块链,整个比特币网络最终会收敛到一致的状态。分叉即在不同区块链间发生的临时差异,当更多的区块添加到了某个分叉中,这个问题便会迎刃而解。
在下面的图例中,我们可以了解网络中发生分叉的过程。图例代表简单的全球比特币网络,在真实的情况下,比特币网络的拓扑结构不是基于地理位置组织起来的。相反,在同一个网络中相互连接的节点,可能在地理位置上相距遥远,我们采用基于地理的拓扑是为了更加简洁地描述分叉。在真实比特币网络里,节点间的距离按“跳”而不是按照真实位置来衡量。为了便于描述,不同的区块被标示为不同的颜色,传播这些区块的节点网络也被标上颜色。
在第一张图(图8-2)中,网络有一个统一的区块链视角,以蓝色区块为主链的“顶点”。
![]()
图8-2 形象化的区块链分叉事件——分叉之前
当有两个候选区块同时想要延长最长区块链时,分叉事件就会发生。正常情况下,分叉发生在两名矿工在较短的时间内,各自都算得了工作量证明解的时候。两个矿工在各自的候选区块一发现解,便立即传播自己的“获胜”区块到网络中,先是传播给邻近的节点而后传播到整个网络。每个收到有效区块的节点都会将其并入并延长区块链。如果该节点在随后又收到了另一个候选区块,而这个区块又拥有同样父区块,那么节点会将这个区块连接到候选链上。其结果是,一些节点收到了一个候选区块,而另一些节点收到了另一个候选区块,这时两个不同版本的区块链就出现了。
在图8-3中,我们看到两个矿工几乎同时挖到了两个不同的区块。这两个区块是顶点区块——蓝色区块的子区块,可以延长这个区块链。为了便于跟踪这个分叉事件,我们设定有一个被标记为红色的、来自加拿大的区块,还有一个被标记为绿色的、来自澳大利亚的区块。
![]()
图8-3 形象化的区块链分叉事件:同时发现两个区块
假设有这样一种情况,一个在加拿大的矿工发现了“红色”区块的工作量证明解,在“蓝色”的父区块上延长了块链。几乎同一时刻,一个澳大利亚的矿工找到了“绿色”区块的解,也延长了“蓝色”区块。那么现在我们就有了两个区块:一个是源于加拿大的“红色”区块;另一个是源于澳大利亚的“绿色”。这两个区块都是有效的,均包含有效的工作量证明解并延长同一个父区块。这个两个区块可能包含了几乎相同的交易,只是在交易的排序上有些许不同。
当这个两个区块传播时,一些节点首先收到“红色”区块,一些节点收到“绿色”区块。如图8-4所示,比特币网络上的节点对于区块链的顶点产生了分歧,一派以红色区块为顶点,而另一派以绿色区块为顶点。
![]()
图8-4 形象化的区块链分叉事件:两个区块的传播将网络分裂了
从那时起,比特币网络中邻近(网络拓扑上的邻近,而非地理上的)加拿大的节点会首先收到“红色”区块,并建立一个最大累计难度的区块,“红色”区块为这个链的最后一个区块(蓝色-红色),同时忽略晚一些到达的“绿色”区块。相比之下,离澳大利亚更近的节点会判定“绿色”区块胜出,并以它为最后一个区块来延长区块链(蓝色-绿色),忽略晚几秒到达的“红色”区块。那些首先收到“红色”区块的节点,会即刻以这个区块为父区块来产生新的候选区块,并尝试寻找这个候选区块的工作量证明解。同样地,接受“绿色”区块的节点会以这个区块为链的顶点开始生成新块,延长这个链。
分叉问题几乎总是在一个区块内就被解决了。网络中的一部分算力专注于“红色”区块为父区块,在其之上建立新的区块;另一部分算力则专注在“绿色”区块上。即便算力在这两个阵营中平均分配,也总有一个阵营抢在另一个阵营前发现工作量证明解并将其传播出去。在这个例子中我们可以打个比方,假如工作在“绿色”区块上的矿工找到了一个“粉色”区块延长了区块链(蓝色-绿色-粉色),他们会立刻传播这个新区块,整个网络会都会认为这个区块是有效的,如图8-5所示。
![]()
图8-5 形象化的区块链分叉事件:新区块延长了分支
所有在上一轮选择“绿色”区块为胜出者的节点会直接将这条链延长一个区块。然而,那些选择“红色”区块为胜出者的节点现在会看到两个链:“蓝色-绿色-粉色”和“蓝色-红色”。如图8-6所示,这些节点会根据结果将“蓝色-绿色-粉色”这条链设置为主链,将“蓝色-红色”这条链设置为备用链。这些节点接纳了新的更长的链,被迫改变了原有对区块链的观点,这就叫做链的重新共识。因为“红”区块做为父区块已经不在最长链上,导致了他们的候选区块已经成为了“孤块”,所以现在任何原本想要在“蓝色-红色”链上延长区块链的矿工都会停下来。全网将“蓝色-绿色-粉色”这条链识别为主链,“粉色”区块为这条链的最后一个区块。全部矿工立刻将他们产生的候选区块的父区块切换为“粉色”,来延长“蓝色-绿色-粉色”这条链。
图8-6 形象化的区块链分叉事件:全网在最长链上重新共识
从理论上来说,两个区块的分叉是有可能的,这种情况发生在因先前分叉而相互对立起来的矿工,又几乎同时发现了两个不同区块的解。然而,这种情况发生的几率是很低的。单区块分叉每周都会发生,而双块分叉则非常罕见。
比特币将区块间隔设计为10分钟,是在更快速的交易确认和更低的分叉概率间作出的妥协。更短的区块产生间隔会让交易清算更快地完成,也会导致更加频繁地区块链分叉。与之相对地,更长的间隔会减少分叉数量,却会导致更长的清算时间。