区块链的帐本要如何维持一致性是相当重要的问题,所谓的分叉,是指纪录区块链帐本的节点,对帐本的共识出现分歧,简单来说,又是全网出现两种或多种版本的帐本,这时就必须依赖所谓的「链分叉选择规则(fork choice rule)」,透过规则的设计,促使矿工们达成共识,在不同帐本中选择一份作为该区块链的权威帐本。而区块链分叉又分为自然产生的「临时性分叉」,以及区块链版本升级时所导致的「硬分叉」,本文将着重探讨「临时性分叉」的原因与解决方式。
在 PoW 的共识机制中,矿工会互相竞争,解出一道题目,谁先解出来,谁就有下一个区块的记帐权。问题来了,有没有有两个矿工同时解出题目,同时产生新区块呢?
答案是,有可能。因为这道题目是随机的,而且网路是异步的,势必会有矿工因为同时解出题目,因而同时产出新区块,此时双方便会各自广播自己挖到的新区块到网路上给其他节点验证,节点验证过后,便会认可该区块为新区块。
以上图为例,甲节点(图上可能要标记)挖出了C区块,乙节点(图上可能要标记)挖出D区块,同时广播到网路中验证,我们说过,网路的信息在传递上不会同步,会有延迟的可能,因此网路中的状态就会变成:
C队→先接收到C区块的节点会认可C为新区块 (否定D区块,并将其放在孤块 池中)
D队→先接收到D区块的节点会认可D为新区块 (否定C区块,并将其放在孤块池中)
此时矿工之间就会产生分歧,区块链状态就会长这样
以上图为例,A是B的前一个区块,又称为「父区块」,现在出现一个情况,C跟D区块都同时以B作为父区块被广播到全网,问题来了,接下来的矿工应该要以哪一个区块做为父区块,继续往下延伸呢?就是所谓的区块链临时分叉,在比特币 PoW 算法网路中的共识规则是这样的:
如果分叉情况出现,那么网路上的人们继续保持两个分支,一但其中一个分支累积的工作量超越另一个分支,任何情况下,节点只在累计工作量多的那条链上工作。
简单来说C队以C区块为父区块继续挖矿,D队以D区块继续挖矿,哪一队先挖出第二个区块,全网便认定其为主链,这就是所谓的「最长链共识」。
以上图为例,假设D队率先挖出E区块,并广播至全网给其他节点验证,C队接收到E区块后,便会将D区块从孤块池中取出,并以D分支作为主链 (因为C分支已经不是最长链),C区块便成为孤块。
你可能会好奇,为什么C队的矿工要乖乖遵守最长链共识,因为在正常状况下,大多数矿工都会选择按照共识规则工作,如果有矿工选择在较短的那条分支挖矿,即便挖出新区块,也不会被大多数矿工认可,自然也拿不到奖励,因此在正常情况下,理性矿工都会选择遵循「最长链共识」。
遇到分叉时,短链区块内验证的交易若尚未被长链验证,那会发生什么事?我们来看看中本聪本人的解释
(图片来源)
如果短链的交易不在长链裡,会重新被放进交易池(内存池),等待矿工打包进入后面的区块,该笔交易的确认数也会重新计算。这就是为什么比特币需要等待六个区块,才能完全确认交易,因为一般来说,用户不会知道区块链是不是处于分叉状态,如果包含交易A的区块在下一个区块后,成为孤块,交易A除了可能需要重新验证之外,还会有面临双花攻击的风险。
至于为什么是六个区块,这其实并不是硬性规定,有些交易所只要有两个确认或三个确认就能够成功入帐了,六个确认所代表的是该交易在全网共识中处于安全状态。当然六这个数字也是经过计算得来的,详情请见比特币白皮书。
以上介绍的,是区块链在自然情况下产生的临时性分叉。若区块链因为版本更新,抑或是社群共识分裂而产生「硬分叉」时,由于硬分叉本身不是在自然情况下发生且过程中涉及矿工的意识选择,因此无法单纯透过「最常链共识」解决分叉问题,详情请见下一篇文章「硬分叉与软分叉」。
区块链是一个存在于互连网中的大型分散式系统,存在于每一个网路参与者(矿工)的电脑中,换句话说,一但区块链要进行版本更新或系统修改,所有网路参与都必须下载并运行新版本的区块链客户端,区块链系统才能完成版本更新。然而,分佈式共识系统升级时困难的地方在于,很难要求网路参与者在同一时间完成更新,只要有参与者没有即时更新客户端,网路上就会存在不同版本的区块链,换句话说,区块链会出现分叉。因此,区块链进行更新时,必须协调好所有的系统参与者,否则可能会影响到区块链系统的安全性。
另一个分佈式共识系统升级困难的地方在于,必须让所有网路参与者达成共识,如果只有一部分矿工同意更新,另外一部分旧矿工不同意更新,矿工之间便会产生共识问题。而区块链更新时的共识问题大致上会有以下四种可能:
新矿工接受旧矿工挖出的区块
新矿工不接受旧矿工挖出的区块
旧矿工接受新矿工挖出的区块
旧矿工不接受新矿工挖出的区块
新矿工产生的区块可以兼容旧矿工产出的区块,而旧矿工产生的区块无法兼容新矿工产出的区块。
当系统中出现了新版本的更新,并且和前版本不能兼容,旧矿工无法接受新矿工挖出的全部或部分区块,区块链就会出现硬分叉。以比特币为例,若更改协议的重要参数,例如区块大小、挖矿题目的难度或出块速度等,这些规则中的任何一个的更改都可能导致新区块无法被前版本的共识规则接受。例如,如果更新后,区块容量限制从 1MB 增加到 4MB,则运行新版本的矿工将接受 4MB 的区块,但运行旧版本的矿工则会拒绝该块。
在新矿工佔有大部分算力的情况下,旧矿工有两个选择,第一种就是接受更新并升级客户端软体,这个情况意味着社群对版本更新达成共识,区块链可以安全且顺利完成更新。
如果就矿工坚持维护旧版本的系统,那区块链将因此分裂为两条链。 (在这个情况下,新矿工与旧矿工已经无法达成共识了,即便接受更新的新矿工算力 > 51%,旧矿工依然不愿意接受新版本,因此不适用「最长链共识」。)
若大部分的人都选择更新,那新版本的算力势必比较强,剩下的就看旧版本的算力够不够支持维护一条链的安全,倘若还是有一定数量的矿工坚持维护旧版本,那区块链就会分裂成两条链。当区块链分裂为两条链,且在有各自的矿工维护各自的链的情况下,就会产生两种不一样的币(大部分硬分叉,例如以太坊的君士坦丁堡硬分叉,矿工都会愿意接受新版本的区块链,矿工之间没有共识问题,就不会有分裂的情况),这就是所谓的「分叉币」,例如比特币社群在 2017 年的扩容方案理念产生分歧,无法达成共识导致硬分叉,比特币现金 (Bitcoin Cash) 因此诞生。
对用户而言,这种社群分裂的硬分叉,最有感的就是可以领分叉币,举个例子,分叉前你在钱包有 “1 BTC”,分叉后你将拥有 “1 BTC +1 BCH ”。在没有得到所有生态中的参与者同意的情况下,硬分叉有很大的风险,很容易导致该区块链的生态系分裂、算力分裂以及陷入重放攻击的危险中。所以这是一种极具争议和危险的区块链升级技术,因此区块链社群对于硬分叉非常谨慎。
在新矿工算力> 51%时,新矿工产生的区块不能兼容旧矿工产出的区块,旧矿工可以兼容新矿工产出的区块。
如果以「更严格的规则」进行更新,实现协议修改或添加不影响结构的功能时,则旧矿工将接受新矿工所产的区块;相反的,由于新矿工所认定的协议较严格,新矿工将会拒绝旧矿工所产的区块,此时旧矿工在正常情况下,会选择升级,否则其所产的区块会无法被新矿工接受,无法获得挖矿奖励。(遇到例如意识形态或开发观点不同等特殊情况时,旧矿工仍然有可能会选择不接受新矿工产出的区块,继续维护旧版本的链,进而导致硬分叉甚至分裂。)
以比特币为例,理想的情况是,旧矿工会意识到他们的区块被拒绝了,便会选择升级。随着越来越多的矿工升级,这将进一步孤立旧版本的区块,在利益的驱使下,会诱使更多旧矿工升级,于是,系统便能以较温和的方式完成更新。
例如,社区决定将块大小从目前的 1MB 限制减少到 0.5MB。佔多数的新矿工会拒绝旧矿工产出的 1MB 区块,并选择其他矿工产出的符合条件的区块。
软分叉的更新时常发生。最初比特币没有区块大小的限制,是在之后透过软分叉引入1MB的限制,还通过软分叉成功添加了 pay-to-script-hash 函数,该函数在不改变结构的情况下增强了代码。这种类型的更新通常只需要大多数矿工进行升级,其他矿工便会随之升级,这使得它更可行,破坏性更小。
软分叉与硬分叉相比,软分叉的过程中,在正常情况下,只会存在一条链,没有分成两条链的风险,且软分叉不要求所有矿工同一时间升级,而是以较温和的方式逐步升级,不影响软分叉过程中的系统稳定性和有效性。
然而两者并没有孰优孰劣之分,而是适用性的问题,假如进行大规模的区块链更新,势必会牵涉到不被旧协议接受的规则,即便我们都知道软分叉比硬分叉来的安全,还是只能选择以硬分叉进行区块链升级。
不过也不需要把硬分叉想得太过可怕,因为只要全网矿工对升级有相同的共识,就不会分叉成两条区块链,影响到安全性。
总归一句,对区块链升级而言,重要的不是硬分叉还是软分叉,而是矿工与矿工之间的共识是否一致,这部分称之为「区块链治理」,若共识处理不好则容易导致革命,这也是为什么区块链的升级相较传统软体还要来的困难。