区块链核心技术演进之路-共识机制演进

一般而言,在介绍区块链时经常会提到两个例子:一是由古老的记账模式延伸到分布式账本,二是拜占庭将军问题(Byzantine Generals Problem)。使用分布式账本目的是让每个节点都能够验证交易,而拜占庭将军问题与账本的一致性有关,即本文要讨论的共识机制(Consensus)。

区块链上的共识机制主要解决由谁来构造区块,以及如何维护区块链统一的问题,该问题的理论基础是拜占庭容错(Byzantine Fault-Tolerant,BFT)。BFT从上世纪80年代开始被研究,目前已经是一个被研究得比较透彻的理论,存在解的前提条件及具体实现都已有现成算法。不过本文不打算从BFT说起,因为要分析的是区块链共识机制的演进过程,而中本聪并没有采用BFT。其实在我研究比特币伊始,即便在理解了POW机制之后的很长一段时间内,并不了解拜占庭将军问题。后文分析 HyperLedger Fabric的PBFT以及小蚁项目的DBFT时再全面阐述拜占庭将军问题及传统分布式一致性算法(PAXOS、RAFT)。

共识机制的核心是区块的构建和检验,POW系统构建区块的过程一般称为“挖矿”(mine),POS 系统PPC的区块构建方式一般称为“铸造”(mint),而NXT的区块构建方式一般称为“锻造”(forge)。

POW

共识机制在以前一般被称为证明方式(Proof),因为比特币采用工作量证明(即Proof-Of-Work,简写为POW)。随着大家对分布式账本一致性问题的不断探索,很多方法被提出来,尤其近期有很多区块链项目回归了对传统BFT算法的改进,在思路上已经跳出了“证明”的语义,因此进一步高度概括为共识机制。我记得第一次碰到工作量证明这一概念时感到很费解,对这种表述方式很头疼,掌握了POW机理后才真正明白,通俗讲就是“通过工作以获得指定成果,用成果来证明曾经付出的努力”。其实我们日常工作生活中经常使用工作量证明,比如学生考试成绩,毕业证以及驾照等,这种证明方式的一个显著特征是往往需要很大的工作量才能拿到指定成果,但这个成果很容易验证。因为我们一般很难去实时监督一个人是否真的付出了这些工作量,所以只能使用工作量的结果来证明。

再回到比特币的设计思路,中本聪已经使用非对称密码解决了电子货币的所有权问题,用区块时间戳解决了交易的存在性问题,用分布式账本解决了剔除第三方结构后交易的验证问题,剩下需要解决的问题是双重支付,这要求所有节点账本统一,而真正的平等又必须赋予人人都有记账的权利,记账是一件简单的事情,每个人都可以做,显然最终会存在众多大同小异的账本,但我们只需要其中的一个账本就够了。

中本聪想到给记账加入成本,总账本由各个分页按照时间先后排序,给每个账本分页设立一个评判标准,以区分账本分页是否合格,这给记账增加了难度,同时给每个账本分页加入一个随机元素,用以调节记账难度以保证一定时间段内只有一个人生成合格的账本分页。增加的成本就是工作量,合格的账本分页就是工作量证明。对于比特币而言,所谓的账本分页就是一个区块,区块通过巧妙设计形成区块链,合格的区块可以表述为:

F(Nonce) < Target

其中Nonce是随机元素,Target是合格区块的量化,每个记账节点的Target一致。此外POW的成功运行还需要配合如下两条约定, Best chain原则:将最长的链条视为正确的链条。

激励原则:找到合格的区块有奖励收益。

第1条约定为硬性规则,无条件遵守,大家要么不玩,要玩就遵守这条原则,毕竟共同的目标是找到一致性账本,而最长的链条代表最大的工作量,如果没有这条约定,每个人都只会构造自己的区块链,无法统一。第2条为工作量激励,既然记账有成本,那唯有收益才能驱动大家都去记账,参与记账构造区块变成投资行为,其成本和收益风险在第1条约束下形成博弈,驱动所有节点按约定规则老老实实够造区块,最终达到纳什均衡。

具体实现方式,比特币采用哈希(Hash)算法,关于哈希算法的原理和特点在前一篇文章(挖矿演进)已经详细讨论。逻辑上比特币是对整个区块进行哈希运算,但真正实现并非将整个区块数据作为哈希函数的参数,区块大体可分为区块链头和交易列表两部分,交易列表通过构造成Merkle树最终浓缩成Merkleroot内置于区块头,区块头只有6个字段,共80字节,如此设计首先带来的好处是方便哈希运算,每次运算只需要80字节的参数输入,而不是整个区块的数据,但交易列表的任何变化又能体现在哈希运行结果上。

p1

比特币采用SHA256哈希运算,且每次都是连续进行两次SHA256运算才能作为最终结果,前一次运算的结果作为后一次运算的输入,即Double SHA256,一般简称SHA256D,扩展上面的公式,比特币合格区块判断依据如下:

SHA256D(nVersion,hashPreBlock,hashMerkleRoot,nTimes,nBits,Nonce)<MAXTARGET/Diff

其中式子左边的6个参数(区块头)在前一篇文章已经解释,MAXTARGET为最大目标值,常量;Diff代表难度,全网难度一致。MAXTARGET/Diff即通常所说的当前目标值。

很显然,POW的核心要义为:算力越大,挖到块的概率越大,维护区块链安全的权重越大。相对其他共识机制而言,POW逻辑简单,容易实现,容错达50%,其安全有严格的数学论证。

POS

POW并非完美,其中被指责最多的主要有两点,一是浪费能源,二是风险和收益博弈必然导致联合挖矿,而大算力矿池可能会对系统的去中心化构成威胁。

于是在2011年,一个名为Quantum Mechanic的数字货币爱好者在Bitcointalk论坛提出Proof-of-Stake(POS)证明机制,该机制被充分讨论之后证明具有可行性。如果说POW主要比拼算力,算力越大,挖到一个块的概率越大,POS则是比拼余额,通俗说就是自己的手里的币越多,挖到一个块的概率越大。POS合格区块可以表述为:

F(Timestamp) < Target * Balance

与POW相比,式子左边的搜索空间由Nonce变为Timestamp,Nonce值域是无限的,而Timestamp极其有限,一个合格区块的区块时间必须在前一个区块时间的规定范围之内,时间太早或者太超前的区块都不会被其他节点接纳。式子右边的目标值引入一个乘积因子余额,可见余额越大,整体目标值(Target * Balance)越大,越容易找到一个区块。因为Timestamp有限,POS铸造区块成功率主要与Balance有关。

POS只是代表一种共识机制理念,具体有多种实现方式,下面重点解析两种比较经典的实现思路。

Peercoin

Peercoin(点点币,PPC)于2012年8月发布,最大创新是其采矿方式混合了POW工作量证明及POS权益证明方式,其中POW主要用于发行货币,未来预计随着挖矿难度上升,产量降低,系统安全主要由POS维护。目前区块链中存在两种类型的区块,POW区块和POS区块。PPC的作者为同样不愿意公开身份的密码货币极客Sunny King,同时也是Primecoin的发明者。

要掌握Peercoin的POS机制,需要重点理解Sunny King专门为PPC设计的几个核心概念:Coinstake,Kernel,Stake Modifier,Modifier Interval,Stake Reward,Coinage等。

Coinstake

为了实现POS,Sunny King专门设计了一种特殊的交易,叫Coinstake,Coinstake的设计借鉴于中本聪的Coinbase设计。本质上Coinbase和Coinsake都是一笔交易,只是对他们的输入输出做了一些硬性限制。

而Coinstake的设计又需要有别于Coinbase,这样才不会扰乱系统原有的POW机制,简单对比一下两者结构上的不同,

Coinbase结构要求:

输入数量必须等于1,且输入的prevout字段(指定前一笔交易的输出)必须置空值。 输出数量必须大于等于1。

p2

Coinstake结构要求:

输入数量大于等于1,且第一个输入的prevout字段不能为空,即要求Kernel必须存在。 输出数量大于等于2,且第一个输出必须置空值。

这两种特殊交易在区块链中存放的位置也有特殊要求,中本聪规定每个区块的第一笔交易必须放置Coinbase,反之,Coinbase不能出现在区块的其他位置。Sunny King显然不想破坏这个规则,他增加了一条规则,对于POS区块,第二笔交易必须放置Coinstake,反之,Coinstake不能出现在其他地方。换言之,只要第二笔交易是Coinstake,那么这个区块就当POS区块来处理。

Coinbase和Coinstake都不会被单独广播,而只存在于区块中,因此客户端节点一般都不允许进入内存池,当花费这两种交易时,都需要检测是否已经成熟。

Kernel Protocal

Coinstake的第一个输入(Input 0)叫Kernel,Kernel在POS机制里确实起到核心作用,合格区块的判定与之息息相关。PPC合格区块判断条件为:

SHA256D(nStakeModifier + txPrev.block.nTime + txPrev.offset + txPrev.nTime + txPrev.vout.n + nTime)< bnTarget * nCoinDayWeight

式子左边的每一个参数都有明确的设计目的,其中,

nStakeModifier:专门为POS设计的调节器,按照以上公式,如果没有参数nStakeModifier,当一个人收到一笔币得到网络确认之后,他立即就能提前计算得知自己在未来何时可以锻造区块,这显然不符合设计目标,Sunny King希望POS矿工和POW矿工一样做盲目探索,以实时在线维护区块链,nStakeModifier的设计就是为了防止POS矿工提前计算。nStakeModifier可以理解为POS区块的一个属性,每一个区块对应一个nStakeModifier值,但nStakeModifier并不是每个区块都变动,不过协议规定每隔一定时间(Modifier Interval)必须重新计算一次,取值与前一个nStakeModifier以及最新区块哈希值有关,因此POS矿工无法提前计算,因为他不知道未来的区块哈希值。

也就是说,在PPC系统中,除了存在区块链,币链(币的交易签名历史),还隐藏着一个很少被提及的链条——权益调节器链条。

值得一提的是,Sunny King是在PPC后来的版本才加入这个调节器的,一开始他使用nBits。

txPrev:Kernel对应的前一笔交易。

txPrev.block.nTime:txPrev所在区块的时间戳,一笔交易被纳入区块的时间是交易发起者不能确定的,节点有可能通过提前计算预估到未来对自己有利的时间戳,这个参数就是为了防止节点利用这种预估优势提前生成大批交易。

txPrev.offset:txPrev在区块中的偏移量,用以降低网路节点同时生成coinstake的概率。

txPrev.nTime:txPrev构造时间,设计目标如txPrev.offset。

txPrev.vout.n:Kernel在txPrev中的输出下标,设计目标如txPrev.offset。

再看等式右边, bnTarget:全网当前目标难度基准值,类似POW中的当前难度值,由nbits记录。 nCoinDayWeight:Kernel的币龄。

由以上式子可知,Sunny King一方面希望能给POS矿工提供充足的随机性,另一方面搜索空间严格局限于Coinstake的时间戳字段,以保证影响找到合格区块链的最大因素是Kernel的币龄。

节点在锻造区块时,首先从自己所有的UTXO中选定一个作为Kernel,构造coinstake,计算hash,如果不合格,重新构造coinstake,重构时时间戳Time会改变,也可以改变Kernel,以得到不同的Coinstake,如此往复,直到找到合格区块。

Coinage

上面提到了币龄,也叫币天,假如1.5个币存在于区块链中10天,币龄数值为:

Coinage = 1.5*10 = 15

PPC采用币龄,而不是直接采用余额(Balance)来计算。一个UTXO一旦被花费,其币龄被清零,新的UTXO币龄从0开始算起。

stakeReward

权益激励,俗称获得利息,计算公式如下:

stakeReward = nCoinAge * 33 / (365 * 33 + 8) * 0.01 * COIN

公式可简化为:

stakeReward = (0.01 * nCoinAge / 365) * COIN

其中nCoinAge是Coinstake所有输入的币龄总和,由公式可知收益按1%年率计算。理想状态下,假设所有的币全年都参与挖矿,代币总量每年有1%通胀率,这一设计为很多人所诟病,而且,这一设计并不能激励矿工积极参与挖矿以维护区块链的安全,因为如果不考虑手续费,持币用户每隔几个月打开节点铸币,或者实时在线铸币,理论上收益都是一样的。

stakeMinAge

POS系统也存在51%币龄攻击风险,为了增加攻击难度,Sunny King对每一笔UTXO的铸币资格做了最小年龄(stakeMinAge)限制:一个UTXO在区块链存在的时间小于stakeMinAge则没有铸币资格,PPC最小币龄为8小时。

后来有些竞争币种加入了最大年龄(stakeMaxAge)限制:一个UTXO在区块链存在的时间大于stakeMaxAge则币龄始终按stakeMaxAge计算。

在Sunny King设计的POS机制中,一笔UTXO就像是一个矿工,该矿工每成功铸造一个区块后必须休息一段时间,因此,整套系统必须保证足够多的“矿工”同时在线铸造区块,才有可能获得平滑的出块速度。

Nextcoin

2013年9月,一个名为BCNext的用户在Bitcointalk论坛发起一个帖子,宣布将发行一种全新的纯POS币种,后来取名为Nextcoin,简称NXT。与当时其他山寨币直接Fork自Bitcoin源码的开发思路不同,BCNext另起炉灶,采用JAVA语言从头开发NXT,并对区块结构,交易结构,非对称密码等做了很多改进。NXT有很多创新点,这里只讨论其中最重要的创新——透明锻造(Transparent Forging)。

NXT的POS实现方式与PPC完全不同,合格区块判定方法为:

hit < baseTarget * effectiveBalance * elapseTime

其中, hit: NXT抛弃中本聪的UTXO设计方案,采用账户(Account)余额方案,每一个账号对应一个私钥。每一个区块都有一个生成签名(generationSignature)字段,hit的生成与这个字段有关。当用户需要锻造区块时,首先计算自己独一无二的hit,计算过程如下:

用户用自己的私钥对上一个区块的generationSignature进行签名,获得自己本区块的generationSignature。 对上一步结果进行SHA256运算,得hashdata。 取hashdata的前8个字节(共64比特位)作为hit变量。

生成签名的设计有点类似于PPC的stakeModifier,也就是说,NXT区块链下隐藏着一个签名链条。

式子右边, baseTarget:全网难度基准值,这个难度按照每分钟一个区块目标调节。 effectiveBalance:账户有效余额,一笔币转到账户需要足够多的确认才有铸币权利,叫有效余额。 elapseTime:当前时间与上一个区块时间间隔,按照currentTime-lastBlockTime计算。

分析以上式子,如果依然将式子左边视为挖矿,右边视为目标值,可知用户压根就没有搜索空间,因为当全网产生一个最新区块时,对于锻造下一个区块,每个用户自身的hit就固定了。式子右边,每个用户的目标值与自身的账户有效余额成正比关系,而且,随着时间往前推移,目标值不断变大,不等式最终一定会成立,即理论上每个节点都可以挖那个区块,但规定优先选择最早生成的区块。p3

用上图类比NXT的锻造机制,每个圆柱体自身高度(hit)是固定的,假设限高杆不断升高(目标值target随着时间不断增大),最终所有圆柱体都能通过(合格区块),但高度最矮的圆柱体可以率先通过。

节点段造区块流程为:账户必须实时在线,当全网有最新区块产生时,每个账户立即计算自己对应的hit,然后根据公式elapseTime = hit/(baseTaret * effectiveBalance)计算得知自己锻造区块的期望时间值,并将这个期望时间广播给网络其他节点,如此,全网每个节点都知道其他节点的期望时间,从而也就得知下一个区块优先由谁来锻造。账户在自己的时间窗口锻造好区块并立即广播全网,其他节点检验一个新区块是否有效,首先要检验证区块的生成签名是否有效,还要检验新区块的时间戳是否与产生区块的节点之前发布的期望时间吻合。每次客户端检测到网络中有新的区块产生,都会重新计算自己的期望时间并向全网发布。

因为hit是用户用自己的私钥签名的结果,因此对于不同用户来说具有很大随机性,即便余额很少的用户,如果运气足够好,hit值很小,也有可能快速锻造区块。

NXT区块的生成完全摒弃了竞争的理念,有点“上帝早已安排好一切”的味道,下一个区块由谁来生成冥冥中早就注定了,全网节点能做的就是静静等待那一刻的到来。

p4

如图,如果节点A没有在自己的锻造时间窗口内广播区块怎么办,没问题,网络会等B的区块,但是如果A和B间隔不远,或者由于网络传输原因部分节点先收到A的区块,部分节点先收到B的区块呢,网络就分叉了,此时Bestchain的原则依然是首选最长的链条,长度一致的分支,优先选择最高区块时间戳最小的分支。那如果节点对所有分支都锻造并广播区块呢,那就变成了一种攻击行为,网络最新区块附近的分叉会加剧。缓解问题的办法是让节点只挖最优分支,这一点没法体现在协议中,只能依靠诚实节点的自律。

摒弃了竞争的理念,NXT共识不得不高度依赖于时间轴,节点虽可预知自己在未来何时可生成区块,但必须要等到那个时候才能广播区块,如果节点提前广播,网络其他节点将不会接受,BCNext在客户端实现上做了限制:对于最新区块,客户端只接受本机当前时间前后15秒范围内广播的区块,这种限制也没法体现在协议上,只能依靠客户端实时辅助实现。

也难怪,NXT代币全部预挖,如果采用类似比特币那样由矿工慢慢发行模式,免不了竞争段造区块,而一旦竞争,区块链将立即陷入分叉。NXT整套共识规则的成功运行其实背后有一个潜在的利益博弈,即,持币者就是系统使用者,也是系统的受益者,大家应该联合起来共同维护区块链,做一个诚实的节点。

也许你会想到一种攻击方法:即便手里持币量很少,但可通过生成大批账号并往每个账号转少量币,以每次都能找到很小的hit,也能快速锻造区块,如此一来POS就退化到类似POW的尴尬境地。BCNext首先从非对称签名算法下手,采用ED25519代替比特币的ECDSA,前者的计算难度比后者大。此外成熟期提高到1440个区块(1天),即一个账号有效余额一旦成功锻造一个区块,该部分余额需要等1天才能重新获得锻造资格。

短暂的分叉还是不可避免的,NXT最新区块附近会有很多分支,一笔交易需要多一些确认才足够安全,NXT官方推荐10个确认。

POS2.0

PPC的成功运行很快就吸引了一批追随者,其中较为出名的包括新星币(Novacoin,NVC)、黑币(blackcoin,BLK)等。黑币社区认为币龄可能会被恶意的节点滥用以获得更高的网络权重并成功实施双花攻击,于是发布POS2.0白皮书,对PPC做了几个细节优化,解决了一些潜在的安全问题,其中最重要的改进是用余额代替币龄,合格区块的条件由:

F(Timastamp) < Target * 币数 * 币的年龄

变为:

F(Timastamp) < Target * 币数

如此一来,一笔UTXO无论放置多久其锻造区块的能力不变,此举可激励节点必须更多的保持在线进行铸币,提高系统安全性,将攻击途径减少到最低限度,并且能够显著提高网络保持运行的节点数量。

POS3.0

黑币社区后来进一步升级,推出POS3.0版本,对交易手续费,难度调整做了一些优化,其中最显著的改变是将1%年利率奖励机制变为固定数额奖励(每个区块固定奖励1.5BLK),此举不但降低代币通胀率(考虑到会有代币永久丢失,低额奖励机制回归总量恒定的设计思路),同时意味着持币节点必须实时在线才能获得收益。

DPOS

比特股(Bitshares)项目于2013年8月开始启动,这是一个野心勃勃的项目,对区块链做了很多改造,并引入许多新概念和特征,尤其令人眼花缭乱的 Bitshares X、多态数字资产交易平台、资产锚定等新名词,一时令人无比兴奋而又困惑。此时POW和POS都已成功运行许久,彼此优劣已被反复讨论,两大阵营时至今日依然争论不休。按照项目规划,比特股对交易容量和区块速度有极高要求,显然POW或POS都达不到要求,于是比特股发明了一种新的共识机制——Delegated Proof-Of-Stake(DPOS),即股份授权股权证明。

DPOS很容易理解,类似于现代企业董事会制度,比特股系统将代币持有者称为股东,由股东投票选出101名代表,然后由这些代表负责产生区块。那么需要解决的核心问题主要有:代表如何被选出,代表如何自由退出“董事会”,代表之间如何协作产生区块等。

持币者若想成为一名代表,需先拿自己的公钥去区块链注册,获得一个长度为32位的特有身份标识符,用户可以对这个标识符以交易的形式进行投票,得票数前101位被选为代表。 代表们轮流产生区块,收益(交易手续费)平分。如果有代表不老实生产区块,很容易被其他代表和股东发现,他将立即被踢出“董事会”,空缺位置由票数排名102的代表自动填补。

从某种角度来说,DPOS可以理解为多中心系统,兼具去中心化和中心化的优势。

总结

最后从几方面来简单对比分析以上几种共识机制的优劣和特点:

安全性

POW的安全性存在完整的数学证明,这一点是POS和DPOS无可比拟的优势。区块链共识机制一般要同时考虑抵御DDOS攻击和双重支付攻击,POW存在51%算力攻击威胁,比特币目前超强的算力使得破坏该系统需付出巨大代价。POS也会存在51%币龄攻击,而DPOS安全性完全取决于代表的诚实程度。NXT理论可以实现快速交易,但需要锻造节点曝光自己的IP,如此一来容易成为DDOS攻击对象,DPOS的代表也容易成为DDOS攻击对象。

环保性

在不可能三角理论(去中心化,安全,环保不能同时兼备)中,POW彻底抛弃节约能源的需求,通过巨大算力来维护系统安全和去中心化特征。POS和DPOS几乎不费多余电力,但不可避免在另外两个特性做出牺牲。

共识速度

POW很难缩短区块时间,POS相对而言可以缩短区块时间,尤其NXT会比PPC的实现方式更快,DPOS也可以在很短时间内达成共识,比特股目前30秒产生一个区块。不过POS更容易产生分叉,尤其NXT,所以交易需要等更多确认才被认为安全。

交易容量

这是区块链未来发展需要解决的核心问题,巨大的交易容易意味着巨大的带宽和存储空间,POW的交易容量很难扩展,而NXT由于每个节点都可以预知下一个区块由谁锻造,可以直接将交易发给锻造节点,因此NXT交易容量有很大扩展性。从某种角度来说,DPOS可以理解为多中心系统,兼具去中心化和中心化的优点,如果代表节点都运行强大的服务器且彼此带宽足够大,理论上交易处理能力可比拟传统中心化系统,比如Visa。

出块平滑度

POW由于哈希算法特性,可以得到平滑出块速度,而且可以间隔一段时间再调整全网难度,POS出块主要与余额有关,而用户余额差距梯度比较大,所以POS一般每个块都要调整全网基础难度。DPOS依靠有限代表人的协同作用,如果代表人不会频繁进出,几乎可以做到固定死出块间距。

最终性

POW和PPC通过竞争达成共识,不存在最终性,理论上如果有足够算力,现在可以从头挖比特币区块链,不过可以依靠检测点实现最终性。NXT和DPOS严格依赖时间轴,依靠节点实时在线检测,所以存在最终性。

综合各方优势,个人认为POW适合应用于公链,如果搭建私链,因为不存在验证节点的信任问题,可以采用POS比较合适,而联盟链由于存在不可信局部节点,采用DPOS比较合适。

原文地址:https://www.cnblogs.com/hzcya1995/p/13312674.html