比特币和区块链(3):比特币的共识机制
上一篇我们详细介绍了不可篡改的账本区块链的数据结构的实现。其核心技术第一是数字签名,比特币采用的是椭圆曲线数字签名算法。第二是加密级别的哈希,比特币采用的是SHA256。
然而在我们的系统里,依然只有一个寡头负责记账。我们固然不用担心交易记录被伪造,因为有数字签名。我们也不用担心区块被篡改,因为可以通过哈希值校验。但是我们无法防止这个寡头故意不记账或者故意丢区块。所以这个系统是一个人人可以查账,但是大家却必须相信寡头不作恶的系统。
比特币系统显然不会停留在这个设计上。所以寡头需要被取代掉。比特币的做法是参与整个比特币网络的所有的参与者,不但可以随便查账,而且人人记账。
这解决了寡头的问题,但是同时带来了新的问题。每个人手里有一个账本的话,到底谁的账本才是真相。这就是比特币的共识问题。这也是比特币系统里面最难理解的部分,并且也是部分新区块链项目试图创新增强的部分。
在我们进入比特币共识问题之前,我们先简单的讲一下分布式系统里共识问题的背景。按照图灵奖获得者Lamport的说法,所有的分布式系统的问题归根到底都是共识问题。由此可见,分布式系统下的共识问题是非常的重要。与此同时,分布式系统的共识问题也非常的难。
这里我们先给一个分布式共识的定义。在分布式计算机系统里,分布式共识是某种协议,参与这个协议的节点可以提议某个值,经过一系列的步骤之后,所有的节点达成共识,选取了同样的值,并且这个选取的值必须是节点们提议的值里面的某一个,而不是凭空冒出来的。
这个共识问题有多难呢?我就抄袭一下任何分布式系统都会讲的一个著名的拜占庭将军的故事。
一组拜占庭将军分别各率领一支军队共同围困一座城市。为了简化问题,将各支军队的行动策略限定为进攻或撤离两种。因为部分军队进攻部分军队撤离可能会造成灾难性后果,因此各位将军必须通过投票来达成一致策略,即所有军队一起进攻或所有军队一起撤离。
因为各位将军分处城市不同方向,他们只能通过信使互相联系。在投票过程中每位将军都将自己投票给进攻还是撤退的信息通过信使分别通知其他所有将军,这样一来每位将军根据自己的投票和其他所有将军送来的信息就可以知道共同的投票结果而决定行动策略。
系统的问题在于,将军中可能出现叛徒,他们不仅可能向较为糟糕的策略投票,还可能选择性地发送投票信息。假设有9位将军投票,其中1名叛徒。8名忠诚的将军中出现了4人投进攻,4人投撤离的情况。
这时候叛徒可能故意给4名投进攻的将领送信表示投票进攻,而给4名投撤离的将领送信表示投撤离。这样一来在4名投进攻的将领看来,投票结果是5人投进攻,从而发起进攻;而在4名投撤离的将军看来则是5人投撤离。这样各支军队的一致协同就遭到了破坏。具体来说,这些将军就没有达成共识。
当然将军们之间的投票协议不一定只需要一轮,现实里可以很复杂。如果一个协议可以在混进坏人的情况下,依然保证将军们做出一致的决定,这个协议在计算机领域就被称为是拜占庭容错的。
计算机领域关于共识问题的研究由来已久,有很多的成果。其中最为著名的是Lamport提出的Paxos协议。这个协议很大程度上支撑了谷歌的三驾马车,进而带领大家进入了大数据时代。
但是正确的实现Paxos是一件非常不容易的事情。所以一个斯坦福大学的PhD用了整个PhD的时间和一整篇PhD论文去研究怎么样在工业界的环境下实现Paxos,并提出了一个更为简化的Raft协议。
通常意义上实现的Paxos协议并非拜占庭容错。当然,也有拜占庭容错版本的Paxos。Paxos协议通过多轮投票,保证如果这个投票过程终止的话,大家必定会达成一致。但是协议也可能无限制的进行下去。这些东西和本文主要内容关系不大,我就不再深入展开了。
比特币是一个互联网系统,所以拜占庭将军问题那样的情况是存着的。谁也不能保证比特币系统里面的节点没有混进坏人。加之互联网上网络拥塞,机器不能连接等等各种各样的问题,这就使得比特币的共识问题从理论研究的角度来看是个很难的问题。
我们更严谨的定义一下比特币场景下的共识问题。具体来说,在比特币这个P2P网络里。我们假设每个节点本地都有一个大家已经达成共识的基准区块链,和一堆待处理的交易。比特币系统的共识是指通过某种方式,大家就区块链里的下一个区块达成一致。
从理论上讲,比特币的共识问题应该很难。但是中本聪实现的比特币的共识算法并不复杂,并且在现实里运行了很多年,如今依旧稳固。这导致了最近几年大家都蜂拥而至的要做区块链技术。大家要做的,不是那个不可篡改的账本,是这个共识问题的实现。
下面我们先讨论一个简化版的共识算法。大体步骤如下。
- 提议的交易信息被广播到比特币网络的每个节点
- 每个节点把自己收到的交易信息写入一个新区块,写入新区块的交易信息如果成功加入到区块链里,就被成功执行了
- 每一轮开始的时候,整个比特币网络里面某个节点被系统随机选择,被选择的节点把它自己的新区块广播给大家
- 每个收到新区块的节点会对新区块里记录的交易。如果所有的新区块里记录的交易进行验证,验证无误以后把这个新区块加到自己的本地账本里。
这个算法里,系统如何随机选取节点的问题我们后面再展开。但是我们可以看到,如果整个系统里面没有坏人,并且网络是完美的,那么我们可以想象,这个系统里本地每个人的区块链是一致的。
但是现实生活没有那么美好。我们先考虑一下简单的情况。如果大家都是好人,但是因为网络的问题,有些节点可能收到了一个新的区块却没有收到老的区块。这会导致这个新区块无法被加入进去。好人节点会努力的向它的兄弟姐妹们把自己的区块同步到最新的状态。比特币网络遵循一个简单的原则,整个系统里最长的那条区块链,就是所有好人节点需要同步到的,也是整个系统承认的有效区块链。其他不够长的就是无效的,里面记录的交易也是无效的。
另外一个情况是这个系统里有坏人。我们研究一下系统有坏人以后会发生什么。坏人作恶有几种可能性。先看第一种,坏人想偷别人的钱。这件事情是没办法做到的,因为坏人没法伪造交易记录,只要对方的私钥没有被偷。
第二种情况是坏人实行Deny of Service(拒绝服务)攻击。在坏人被选中产生区块的时候,坏人故意拒绝为某些特定的人服务。这个问题也不大,因为下次随机选中的好人,会把这些交易信息放到它产生的区块里来。
第三种情况就更有意思了,坏人如果自己就是交易发起方的话,它可以的事情就比较多了。比如说它可以在网络上广播两个冲突的交易,其一是从上次交易后付给张三3块钱,其二是付给李四3块钱。坏人的主要目的是希望自己能花双份的钱。
这些交易对吃瓜群众来说,其实很难区分到底里面哪个是真花钱,哪个是假花钱,因为吃瓜群众并不知道现实世界里面到底哪个交易是真实的。但是不管怎么样,两条交易记录不会同时进入一个区块,因为它们是冲突的。这种块无法通过吃瓜群众的检验,从而无法被加进来。
至于有些吃瓜群众选择了张三的交易,有些选择了李四的交易,这是完全有可能的。而且因为随机节点的选择问题加上网络延时等等,可能造成了两个新的区块产生,其中一部分吃瓜群众接受了张三这条记录,一部分吃瓜群众接受了李四这条记录。
所以我们看到,区块链的记账本开始发生了分裂。在比特币的区块链里,遵循一条简单的原则,整个系统里最长的那条区块链是大家公认的真相。所以我们站在张三的角度想一想,当张三在网络上听到广播说坏人付给了自己3块钱的时候,张三能不能肯定自己的这个交易最终会被写入到最长的那条区块链里,从而交易成功。现实世界里,张三给坏人发货呢?
张三在这个时候并不能确定。假设过了一段时间,张三收到了一个新的区块,里面包含了这个记录,张三经过校验之后把自己本地的账本接上了这个新区块。这个时候张三的信心应该大一点了。因为至少目前来看自己的记录已经进入到了张三自己认为的最长的区块里。
比特币系统允许每个节点随时向其他节点询问他们的最长的区块链是什么,从而同步到系统里更长的那一条链。假设经过同步,这个时候张三又收到了第二个新区块。这个新区块张三又一次的连接到了自己的账本。张三查账发现给自己付钱的那条交易记录并没有丢失。这个时候,他心里对于自己的交易记录可以永久的在整个系统最长的那条链里存在下去的信心又大了一点。
所以只要张三一直看下去,给他付钱的那条交易记录在经过各种向兄弟姐妹同步最长链,和每次加入新的区块的过程里都没有丢的话,他对这笔交易被永久的记录在整个区块链的最长的那条链的信心也越来越大。
这个过程,现实里通常每个收钱方默认的经验值是6次确认。如果6个新的区块加进来以后,交易记录依然在区块链里,那么张三可以认为自己的记录被踢出系统最长的区块的概率很低。
从这个例子里面,我们说明两点。第一是坏人不可能伪造记录,也无法通过拒绝服务的方式破坏比特币网络。但是坏人的确可以产生重复而矛盾的交易记录。而比特币网络对于任何一条交易记录最后被顺利提交进区块链的保证,是一个概率问题。比特币网络不保证每条提议的记录都被区块链记下来,哪怕这条记录是合法的。而现实里,收钱方确定和自己相关的交易是否成功,也是个概率问题,越多的新的区块加进来,这个记录依然在,其信心就越足。一般实践里采用6次确认。
比特币的共识问题的简化版大体上讲得差不多了。遗留下来的问题有两个。第一个是,比特币系统的共识如果能够稳定有效的保持下去,需要比特币系统里面的每个节点尽可能是好人。但是为什么这些节点要做好人呢?第二个问题是,这个随机选取某个节点来生成并广播下一个区块的随机选取过程又是什么。被选到的节点凭什么愿意努力干活生成这个区块,而不是偷懒耍滑摸鱼。
这两个问题的本质是一样的。比特币的解决方式总结起来两句话:
- 做好人,系统给你巨额的奖励
- 大家来抢这个巨额奖励的机会,手快有手慢无。
前者鼓励大家做好人,后者解决了随机选择一个节点的问题。
具体的做法是这样的,每个创建了新的区块的人,如果它创建的区块最终进入到了系统里面那条最长的区块链里,它可以获得很多的钱:
- 每条它成功写入的交易,都要给它叫一笔手续费
- 每个新区块的创建者都会获得一笔额外的比特币。这个比特币的数目每四年减少一半,最开始的4年是50个比特币,之后是25个,我们现在在第三个四年,12.5个。
如果比特币值1万美元一个,那么现在每次成功的让大家接受一个自己创建的区块,就可以获得至少12万5000美元。
所以比特币的挖矿,通俗一点来讲,就是创建了一个新的区块,并被整个系统接受了。挖矿的奖励,就是系统凭空产生的比特币。
那么到底谁创建的区块可以被接受呢?怎么样才能保证绝对公正公平而大家都愿意来干活呢?为什么现在比特币挖矿需要大量烧电,又需要专门的矿机呢?矿机到底是什么?这是本节最后一个问题。
比特币网络采用的技术是Proof of Work,这个技术本身并非比特币发明,是1993年就有的技术。我这里给一个不是特别严谨的解释。
简单来说,我们知道,一个区块创建出来,需要算一个哈希来防伪。比特币用的是SHA256算法。出来的结果有256比特。
区块链里有填充随机数的一段空间,这段空间在区块里没有任何的其他意义。它的唯一不同就是为这个区块产生不同的哈希值。而比特币网络要求产生的哈希值的前面若干个比特全部为0。
我们简单回复一下SHA256哈希的几个特点:
- 没有简单的办法从哈希值生成合法的输入
- 输入的微小变化可以导致输出哈希值的巨大变化。
所以为了生成合法的哈希值,生成新区块的节点必须通过穷举的办法,反复改变随机区域的值,然后一次又一次的计算,一直到找到一个复合前面若干位为0的哈希值。如果找到了,就可以全网广播自己的区块了。
大家可以看到,这是一个只能硬算无法投机的过程。每个节点产生合法区块的概率和它掌握的算力成正比。
比特币的网络是怎么决定前面到底要多少位为0呢?它的做法很简单,每两周同步一次,同步的原则是不管网络算力如何改变,比特币的区块要稳定在10分钟产生一个。所以如果网络内算力多了,那前面的0的个数也就多了。
比特币最初大家在个人计算机上挖矿,总算力并不多,所以每个人都能挖到点。后来有人上了GPU来做哈希。GPU比CPU快很多,用CPU挖矿的人生成新区块并被系统接受的概率就低了。再后来大家都用定制的矿机了,GPU也被淘汰了。这种拼算力的做法就是Proof of Work。Proof of Work是比特币为人所诟病的地方之一。
在这个系统里,如果比特币很值钱,那么会有很多的人为了赚钱而大把投入算力,努力的做好人。这个系统也就会处在一个很稳定的状态了。如果比特币分文不值,那么坏人们进来破坏这个系统,也没多少利益。没有利益坏人又何必要来呢?
我们来总结一下今天的内容。比特币系统挪去了寡头,每个人一起记账。记账方式本身不复杂。这个系统里,每个特定的交易是否被记账,是个概率问题。比特币系统通过奖励好人比特币的方式鼓励大家做好人,又通过让好人玩数学游戏竞争的方式,解决随机选择节点来构建新区块的问题。
比特币系统为大家诟病,新的区块链2.0和3.0蜂拥而至的主要原因有几个:
- 比特币的交易速度很慢,10分钟一个区块的产生,交易的确认需要时间
- 比特币需要大量的烧电,用Proof of Work的协议来达到随机选择节点的目的
- 在比特币这个分布式共识系统里,能够做的只有转账问题
所以新的区块链,解决比特币交易速度的有之,解决Proof of Work的有之,扩展共识问题适用范围,引入智能合约的也有之。
转自:飞总聊IT