3.1 BTC实现实际应用中的一致性
以之前的“分布式售票系统”举例来说明最终一致性。也许当你在查询车票时,用户节点存储的数据库是“有票”状态,但在你完成购票之前另一名用户已经完成了购票操作,售票节点的数据库已经更新。当你点下付款按钮时,售票节点通知用户节点更新系统的状态,这时就会提醒你“车票已售完”。“双十一”抢购时天猫等购物网站的系统也有类似设计。
我们并不需要在任何时刻都保证节点读取同样的系统状态,而是保证所有拜占庭故障经过有限时间后就系统的状态达成一致,称为最终一致性。
从这个例子还可以看出,在某个时间段内,节点可能保存的系统的状态不同,因此发出的提案可能存在冲突,需要一个冲突解决机制避免冲突的提案对系统状态的影响,并使节点最终对某个系统状态达成共识。
BTC网络是一个任何节点都可自由加入、不记名的区块链网络,要达成一个全部节点参与的、满足一致性的共识是很难的。PoW机制通过一些巧妙的机制,实现了应用环境可信强度的一致性。
为什么最终一致性可以替代一致性,系统如何选择出一个状态成为最终的共识呢?为了解答这个问题,我们首先需要了解区块链的结构和PoW的工作原理。
3.2 密码学是PoW一致性的基础
BTC是一个分布式对等账本。一个加入BTC网络的用户可以生产任意个成对的公钥和私钥。私钥由用户保存,是不应该泄露给他人的。私钥可以用于对消息签名,签名不可伪造,并且是可以通过私钥对应的公钥验证的。密码学保证签名具有以下特点:
有效性。如果用户用私钥签名了一个消息,那么其他任何人使用私钥对应的公钥、消息原文来验证签名,该签名必须是有效的。
不可伪造性。如果没有掌握某个私钥,就无法对一条之前该私钥没有签过名的消息生成一个签名,并且使它可以被公钥验证为有效。也就是说,仅仅掌握了公钥是无法伪造相应私钥的签名的。在实际情况中,找到公钥对应私钥的代价通常非常巨大,以至于我们认为这是“无法完成的”。
在BTC的世界中,公钥代表节点的身份。地址通常是公钥经过数次哈希处理得到的字符串,与公钥存在对应关系。地址也被用于标识一定数量的比特币的归属。
在BTC的网络里,一笔交易是一个特殊的数据结构,它包含了若干个输入和若干个输出,描述的是一次BTC使用权的转移情况。
一个输出是一个包含了一定数额的BTC和一个使用条件组成的列表。使用条件一般与某个地址相关联。输出存在已使用和未使用两个状态。BTC账本并不记录某个地址对应的BTC余额,地址的余额是某一时刻与它关联的所有未使用输出的BTC数额之和。所有未使用的交易输出(Unspent Transaction Outputs,UTXO)就构成了BTC这个区块链网络的一个状态。网络中的(全功能)节点各自维护一个状态的副本,并在某一时刻就系统的状态达成最终一致。
一个输入同样也是一个列表,包含对之前一个未使用输出的引用,以及能够证明交易创建者满足该输出使用条件的有效签名。即证明交易创建者对他引用的未使用输出中BTC的使用权,被引用的输出会从UTXO中删除。一笔交易还要满足以下条件:输出所包含的总金额应小于等于输入所包含的总金额。这时输入与输出的差额作为交易费作为激励费用奖励给记账的节点。满足以上输入与输出的交易被看作是“合法的”。
当一个地址要发布一笔交易时,它所做的其实是向BTC整个网络中的节点广播该条交易,该条交易会被标记为“未确认的”(Unconfirmed)。BTC网络并不是收到一条广播就立刻更新系统的状态,而是有区块以及内存池的设计。
在某一个时刻,所有BTC节点都维护着一个记录UTXO的账本,并有一个接收未确认交易的内存池(Mempool),当收到一条交易广播时,节点就会把该交易加入自己的内存池。由于网络通信的原因,各个节点内存池中的交易都不完全相同。
一“轮”共识过程开始于节点对“哪些未确认的交易应该被确认”发出提案。在BTC网络中,交易都是被“打包”放进区块进行处理的。区块(Block)是一个精心设计的数据结构,它包含两部分。第一部分是一个哈希指针,它包含上一区块的哈希值,可以表明自己上一个区块的信息。第二部分是一个Merkle树,它的叶节点是被打包进该区块的所有交易的哈希值,非叶子节点则是根据它的两个子节点计算出的哈希值。通过Merkle各节点的哈希可以方便地验证该区块内所有交易的完整性。这样的一个个区块由哈希指针连接组成的“链”被形象地称为区块链。
一个区块还包含了一个coinbase交易(币基交易),这个交易仅包含一个名义上的输入,它不指向之前任何一笔未确认的输出,输出的总金额等于一个固定的数值(当前是12.5,表示打包一个区块获得的奖励),加上该区块里所有交易的交易费。币基交易不消耗未确认的输出,因此这部分固定的奖励BTC是被新“创造”出来的,将被支付给打包这个区块的节点。这也是唯一一种“发行”新的BTC的方式。
因为这种奖励的存在,使得节点之间有竞争“记账权”的动力,每个节点都希望自己打包的区块成为系统的长期共识(最终一致性共识),因为只有这样自己才能获得币基交易的奖励。BTC采用工作量证明模式限制一段时间内能够发出提案的节点数量,从而避免同一时间段节点发出不同的提案数目过多,影响最后节点决策的效率与最终一致性。
任何一个希望发出决定下一个区块内容的提案的节点都需要完成一个“数字解谜”的小游戏。这个小游戏的目的在于:
任何一个成功解谜的节点都可以通过展示谜底,证明它至少完成了一定量的“计算”,即为工作量证明。
整个网络希望可以通过算法调整谜题的难度,可以动态地根据网络中节点的计算能力进行调整,保证出现一个节点解开谜题的时间期望是相对恒定的。
这个谜题不应该设计成总是只能由计算能力最强的节点解开,也不能被巧妙的算法破解,每个节点成功解谜的概率应与其计算能力成正比。
这个谜底应该是可验证的。当一个节点宣布解开谜题时,它会将区块以及谜底广播到其他节点,其他节点应该能迅速的验证谜底的正确性。
密码学再一次给了我们惊喜。哈希函数便是满足以上所有条件的一个“谜面”。前面提到一个区块包括一个哈希指针,以及一棵包含区块内交易及哈希值的Merkle树。现在BTC网络给所有节点发布了一个谜题:在区块的前面加上一个随机数nonce,计算整个区块的哈希值,谜底便是使区块哈希值小于特定的目标值的那个随机数。这样第一个找出对应nonce的节点就幸运地取得了下一个区块的记账权,节点找出nonce的概率与它计算哈希值的速度成正比,也称为节点的算力,这样解谜的过程也被称为挖矿。节点可以将自己挖掘的区块广播出去,其他节点在验证谜题的正确性与区块内交易的合法性之后,就会以:
停止自己正在进行的解谜工作。
将此轮记账节点打包的区块加入到自己维护的区块链账本最后。
清理本地的内存池,删除已经被确认的交易、以及与已经被打包的区块冲突的交易。
下一个区块的开头引用这个 区块的哈希指针。
方式表达自己对这个区块提案的支持,从而决策过程完成,该区块中的所有交易变为已确认的状态,我们说这些交易得到了1个区块的确认。随后各节点在延长后的新链上开始新一轮的解谜过程。
3.3 最长链原则与“矿工”间的博弈
在刚才提到的“一轮”共识过程中,我们发现,如果单单只靠工作量证明机制,并不能保证系统的最终一致性。因为当节点收到来自其他节点的区块时,没有任何强制性措施让它接受这一区块并加到自己维护的历史区块链之后,另外,由于节点可能存在网络通信等故障,它可能并没有接收到其他节点发出的提案。
BTC网络中通过最长链原则解决系统最终一致性的问题。每个区块都包含有一个指向前一区块的哈希指针,并由此可以追溯到创世区块,我们定义从创世区块到这个区块所形成的“链”上的区块总数为该区块的区块高度。BTC网络规定,当网络中存在所谓的“分叉”时,即多个区块同时引用了同一个区块的哈希指针,只有最长链(即区块高度最高的链)上的交易会被承认。
这样每个节点在选择自己将在哪一个区块进行自己的解谜工作时,如果节点预期自己找出一个谜底所花费的成本低于能从挖掘一个区块中获取的收益,那么它会主动在当前的最长链上进行解谜游戏,因为只有最长链上的交易能够得到确认。
由于这种哈希函数解谜本质上是一个分布式的随机计算过程,同时由两个不同节点解出两个谜底的情况也是可能出现的,这样就导致了分叉的产生。这样一个节点可能根据本地收到分叉区块的顺序选择一个分叉进行解谜工作,但这种分叉是不可持续的。在不同的分支上,同时发现新区块的概率将呈指数级下降。避免网络分叉也是限制一段时间内能够发布提案的节点个数的原因之一。
工作在较短链上的节点一方面损失了可能获得的区块奖励,另一方面增加了在最长链上解谜的节点挖掘区块的概率,因为谜题的难度没有那么快调整。博弈论告诉我们,如果在短链上解谜的节点是理性的,那么它们应该立即抛弃这条较短的链,切换回最长链。因此,整个系统必然会在一个时刻,使所有接入网络的节点对系统的状态达成一致,所达成的共识就是当前的最长链。
此外,这也表明PoW是一种概率性的共识机制。一笔交易经过n次交易确认后,没能成为最终共识的概率随n指数性降低。中本聪经过计算推荐n的取值为6,也就是一笔交易要等待约60分钟才会被看作“一致性”的共识。BTC为了实现更强的一致性而延长了交易得到确认的时间,牺牲了一部分可用性。
3.4 PoW如何防止拜占庭故障破坏共识
设想一个开放性、节点可无需身份验证自由加入的区块链网络,恶意节点的存在是必然的。假设有这样一个攻击者,希望通过操纵区块链网络使自己获益,他可能采取这样几种攻击方式。
女巫攻击:得名于电影《女巫》。《女巫》讲述了一个患有身份认同障碍的化名“女巫”(Sybil)的女性进行心理治疗的故事,她同时具有16种不同的人格。
在某些分布式对等系统中,投票的表决权是与节点个数成正比的。如果网络对新加入的节点的身份不做任何验证,可以任意地创建新的节点,或是攻击者可以攻破身份验证系统,使他创建的节点们看起来像是拥有不同的“身份”,但其实都是由同一个人控制的,这会给系统的安全带来极大的威胁。这种攻击方式称为“女巫攻击”。
在采用PoW共识机制的区块链网络中,仅仅创建节点是不能给攻击者带来额外收益的,因为攻击者的实际算力并没有真的增加,所以PoW是能够抵抗女巫攻击的。
盗取属于其他节点的权益:这一点在区块链网络里也是无法做到的。即使攻击者已经获得了下一个区块的记账权利,要构造出一笔能够通过其他节点检验的合法交易来使用不属于他的货币也是无法实现的。因为这要求攻击者伪造出货币持有者的签名,如果该区块链网络采取的密码学机制是安全的,除非拥有该地址对应的私钥,否则无法构造出可以通过公钥检验的签名。
拒绝服务攻击:攻击者拒绝将特定节点发起的交易请求打包进区块,以干扰这些节点正常使用区块链网络的功能。但其实只要轮到下一次正常节点获得记账权,这些之前未确认的交易都会被打包进区块。
双重支付攻击:考虑攻击者向一个商家发起一笔交易x,支付一定数额的BTC购买某项商品,并且这笔交易x已经被打包进区块,并由一个正常节点广播到网络并得到1次确认,商家看到确认以后把商品出售给了攻击者。如果攻击者此时马上发起另一笔双重支付交易y,它使用与交易x相同的输入(重复消费已使用的输出),但是输出却指向一个攻击者拥有的地址。在交易x已经被确认的情况下,交易y会被记账节点认为是不合法的。
如果攻击者选择将交易x和y分别向一半的节点广播,虽然这两笔交易在其他节点看来都是合法交易,但最后还是只有包含了其中一笔交易的区块会被先挖出。如果恰好有两个节点同时挖出了包含这两笔交易的不同区块(这样的概率已经很低了),则网络发生分叉。攻击者向商家展示交易x获得1次确认的那条链,此时将会有各一半节点在两条链上挖矿,下一个区块被挖出时,最长链也就确定了。但此时已得到1次确认的交易x可能会因为在较短的链上而被取消。为了避免这种情况,商家只需要看到交易经过2次区块确认再交付商品就可以了。
由于BTC的最终一致性,互相冲突的双重支付x和y最终只有一笔会被纳入到长期的共识链当中。一笔交易无法做到同时被支付给两个地址,如果双重支付攻击成功,那么攻击者没有花费BTC就得到了商品,而商家收到BTC的交易成为了无效交易。
如果攻击者拥有一定比例的算力,他可以主动丢弃打包了交易x的区块,重新在前一个区块上挖矿,并且将双重交易y放进新的区块里。如果攻击者掌握的算力足够多,或者运气足够好,能够在包含交易y的链上挖出足够多的区块,使原来包含转账给商家的交易x的链成为短链,被所有节点放弃,从而使双重支付攻击成功。
对于商家来说,可以采用等待多次区块确认的方式避免自己遭受到这种攻击。一笔经过n个区块确认的交易,一般的采用双重支付攻击手段的攻击者如果要丢弃这笔交易及之后的n个区块,重新构造出双重支付交易,并通过算力优势重新追上较长链的区块高度的可能性随n增大指数性降低。但如果攻击者掌握了超过一半的算力,那么他正在挖矿的那条链成为最长链只是时间问题。这也就是下面提到的获取记账权的攻击方式,在PoW共识中又称51%攻击。
获取记账权:如果攻击者采用各种方式尽可能地提高自己获得记账权的概率。当攻击者有51%以上的概率获得记账权时,分叉攻击和双重支付攻击都会变得容易进行,因此我们说PoW共识机制的容错能力为1/2。BTC以一个较巧妙的方式减少了这类攻击发生的可能,一方面,基于工作量证明的共识机制要求节点获得记账权的概率与节点的计算能力成正比,发动此类攻击的成本过高。另一方面,只要出现51%算力的节点,即使没有出现分叉攻击等事件,人们也可能对BTC网络失去信任,导致其价格与内在的价值下降。攻击者虽然掌握了记账权,但是获取的收益却远远不及成本。
BTC、ETH以及其他采用各种共识机制的数字通证的稳定长期运行告诉我们,现有的多种共识机制使区块链网络可以在实际环境中达成可信的共识。