区块链可以去中心化,很大程度上依赖于自建的“共识机制”。Paxos是古代希腊的一个城邦,城邦中有众多议员,议员会对法律提案进行决议,提案通过通讯员进行提交。当某个提案者的提案获得大部分议员的赞同时,代表议案通过。这里涉及到的三个角色,议员,提案者,通讯员,可以对应到区块链网络。每个节点可以去计算hash值,将其作为一个提案,提交给区块链网络中其他的所有节点,这个过程中每个节点都在进行计算和提交:
1.Paxos问题保证这样的分布式网络中节点可能存在故障的情况下在最快的时间内达成共识。
2.BFT保证允许少数节点作恶(企图伪造消息)场景下的一致性达成问题。
Paxos算法
什么是Paxos算法
Paxos问题是指分布式系统中存在故障(fault),但是不存在恶意(corrupt)节点场景(消息可能重复或者丢失但是没有错误消息)下的共识达成(consensus)问题。最早是Leslise Lamport用Paxos岛的故事模型来进行描述而命名。
Paxos可以保证在一半正常节点存在时,系统能达成共识。
单个提案者+多个接收者
系统中只指定某个特定的节点时提案者,那么一致性肯定可以达成(只有一个方案,要么达成要么失败)。提案者只要收到了来自多数接收者的投票即可认为是通过,因为系统中不存在其他的提案。
多个提案者+单个接收者
限定某个节点作为接收者。这种情况下,共识也很容易达成,接收者接收到多个提案,选择第一个提案作为决议,拒绝掉后续的提案。
缺陷也是容易发生单点故障,包括接受者故障或者首个提案节点发生故障。
上面这两种情形实际上类似主从模式,虽然并不是很可靠,但是原理十分简单,在zookeeper等应用中广泛存在。这里主要介绍提案者和接收者扩展到多个的情形。
多个提案者+多个接受者
这种情况最接近于区块链共识机制,在区块链的所有节点中每个节点都可以去计算hash值,并发布给网络中的所有节点,当某个值获得大部分节点的赞同(校验hash值,可参考上篇文章)时,通过并写入数据库。
像这样的场景下,同一个时间片段内可能会有多个节点会去提交自己算出的hash值,企图通过大部分节点的校验。那么当同一个节点收到多个提案的时候如何进行区分?如果只接受第一个这样的方式,也会造成节点对提案的混乱。所以我们需要定一个意见领袖,也就是先来后到,当某个节点已经有提案被提交的时候,后续提交的节点可以广播这个节点的提案,这样不断扩散,也加速了达成共识的速度。
我们为每个提交的hash记录根据时间分配一个序号?我们可以尝试为每个节点进行编号,配合在前面加上时间戳来达到递增的目的。
两阶段提交
想象节点在发出自己的提案的时候,收到一些反馈。一种结果是自己的提案被大多数接收,另一种结果是没被接收。但是即便收到了来自大多数的反馈,也不能认为就是最终确认,因为这些接收者并不知道自己刚才反馈的就是全局的大多数,也就是意见领袖。
那么我们引入一个新的阶段,提案者在前一阶段拿到所有的反馈之后,判断这个提案是可能被大多数接受的提案,需要对其进行最终确认。
将Paxos分为准备(prepare)和提交(commit)两个阶段。准备阶段解决大家对哪个提案进行投票的问题(统一意见领袖),提交阶段解决确认最终值的问题。
准备阶段
接受者时刻保留收到过的提案的最大编号和接受过的最大提案编号。如果收到的提案号比目前保留的最大的提案号还大,则返回自己已接受的提案值(如果还未收到过任何提案,则为空)给提案者,更新当前最大提案号,并说明不再接收小于最大提案号的提案。提案者以这样的方式去锁定大部分节点的支持。
提交阶段
提案者如果收到大多数的回复(表示大部分人听到它的请求),则可准备发出带有刚才
提案号的接受消息。如果收到的回复中不带有新的提案,说明锁定成功,则使用自己的提案内容(hash值);如果返回中有提案内容,则替换提案值为返回中编号最大的提案值。接受者收到接受消息后,如果发现提案号不小于已接受的最大提案号,则接受该提案, 并更新接受的最大提案。
一旦多数接受了共同的提案值,则形成决议,成为最终确认的提案。
总结
区块链网络模型在对hash值达成共识的过程中可以类比多个提案者+多个接受者模型。当某个节点A计算出了某个hash值,会根据时间戳生成一个唯一的编号,然后将这个hash值提交给网络中其他节点进行审核。当然这个过程中可能也有别的节点B尝试进行提交。为了统一对某个hash值进行共识判断,我们首先要统一意见领袖,也就是尽量让整个系统统一对某个hash值进行判断。当统一之后再对这个hash值进行提交,这时系统中所有节点在准备阶段都已经保留了接受的提案编号,从而辨识当前提交的提案是否为意见领袖也就是第一阶段大家统一要处理的提案。在大多数节点统一之后这个hash值便会被直接写入数据库。
BFT(Byzantine Generals Problem)拜占庭问题
拜占庭问题更为广泛,讨论的是允许少数节点作恶的(消息被伪造)场景下的一致性达成问题。拜占庭算法讨论的是最坏情况下的保障。
中国将军问题
拜占庭将军问题之前,就已经存在中国将军问题:两个将军要通过信使来达成进攻还是撤退的约定,但信使可能迷路或被敌军阻拦(消息丢失或伪造),如何达成一致。
拜占庭问题
拜占庭将军(Byzantine Generals Problem)问题,是 Leslie Lamport 1982 年提出用来解释一致性问题的一个虚构模型。拜占庭是古代东罗马帝国的首都,由于地域宽广,守卫边境的多个将军(系统中的多个节点)需要通过信使来传递消息,达成某些一致的决定。但由于将军中可能存在叛徒(系统中节点出错),这些叛徒将努力向不同的将军发送不同的消息,试图会干扰一致性的达成。
拜占庭问题即为在此情况下,如何让忠诚的将军们能达成行动的一致。
对于拜占庭问题,如果节点总数为N,叛变的将军数为F,那么当N和F呈现怎样的分布时会让忠诚的将军们保证正确的决策。
我们很容易可以推理到N>2F,当某个忠诚的节点希望得到正确的决策,会有F个篡改节点进行干扰,那么需要满足N-F>F才能保证忠诚的一方可以胜利。
PoW(Proof of Work)算法
比特币区块链网络在设计之初提出了创新的PoW(Proof of Work)算法思路。一个限制了一段时间内整个网络中出现的提案个数(增加提案成本,减少坏节点对系统的干扰)另外一个是放宽对最终一致性确认的需求,约定好大家都确认并沿着已知最长的链进行拓宽。这样,如果有人试图去篡改一条链,那么他的计算速度永远要大于网络中节点的计算速度。
这里的话个人理解,如果有人试图篡改一条链,在主链上生产一个分支链,是不是意味着他需要自己编写自己的账本数据计算hash值然后不断添加伪造链,那么这样的链是永远不可能被读到的。因为总是默认读最长的链,伪造的速度不可能大于真实存在的链的增长速度,因为算力上的差距是很大的。而且即使伪造链的长度要大于真实链,那么根据大多数原则,这条链也肯定会立即被系统中所共识的链取代。
总结
BFT和PoW算法为区块链的共识机制奠定了算法基础。这部分的东西个人觉得理解起来还是比较抽象的,需要具体化到很多现实的场景下可能会更好理解。我将Paxos共识的准备阶段类比为拿票,提案者先扫描所有决策者的队列去拿票(每个决策者只有一张票),先来的人(如果当前没人拿票)先拿到票,后来的人没办法拿票,只能查看当前票被谁拿走了,然后帮那个人先提交提案。