Qtum 量子链研究院:Tendermint 技术详解(上篇)
区块链系统可以归结为如下图所示的六层架构模型,自下而上分别是 数据层、网络层、共识层、激励层、合约层和应用层 。部分区块链应用并不完整地包含这六层结构,但是 数据层、网络层和共识层 可以说是构建所有区块链应用的必要因素。
目前,大部分的区块链应用都是采用整体的设计方法,就是说,这些区块链应用实现成单一的程序,一个程序实现了区块链各层的所有功能,包括P2P连接,交易数据的处理和广播,共识达成,具体的应用功能实现等等。
例如比特币,一整套代码就实现了所有比特币的功能。从软件工程的角度来看,这种 非模块化的设计是不合理的 ,这会使代码复用变得困难,代码的分支管理也变得复杂,同时还限制的区块链应用开发使用的语言。
针对这个问题,Tendermint对区块链的功能模块进行解耦,将共识和P2P部分从具体的区块链应用状态细节中分离出来,以适用各种分布式应用。
Tendermint由两部分组成: 区块链共识引擎和通用的应用程序接口 。
共识引擎被称为Tendermint Core,用于确保同一个交易在不同机器上记录的顺序相同。
通用的应用程序接口也被称为应用区块链接口(Application Blockchain Interface,ABCI),其作用是使交易可以用任何编程语言进行处理。
Tendermint Core通过ABCI接口与应用层进行交互,应用程序可以用任何语言编写,开发者可以很方便地开发自己的区块链应用。
Tendermint Core
Tendermint Core实现区块链大部分功能,包括:共识算法,RPC,数据库,同步,P2P等等。本节主要介绍Tendermint共识算法。
1、Tendermint共识算法
Tendermint使用一种基于拜占庭容错(BFT)的共识算法,其工作模式类似于循环投票机制。参与Tendermint共识过程的角色主要有两个:
Validator(验证者): 网络中的节点,可参与共识过程中的投票,不同的验证者在投票过程可能具备不同的投票权重(vote power)。
Proposer(提议人): Tendermint使用一种确定的非阻塞轮询选择算法从validators中选出proposer,该算法根据validators的投票权重所占比例来选择proposer,投票权重越大的validator被选为proposer的频率越高。
Tendermint区块链是通过基于round(回合)的机制来确定下一个区块。每个round由三个过程组成: propose(提议),prevote(预投票)和precommit(预提交) 。
理想情况下,链上的区块生成状态如下:
NewHeight -> (Propose -> Prevote -> Precommit) -> Commit -> NewHeight ->...
其中,NewHeight为区块被全网接受后,区块高度+1。Propose -> Prevote -> Precommit为一个round,这里加括号表示在某一区块高度成功提交一个区块可能需要多个round,也就是说,一个round可能无法成功地提交区块。
区块链处于某一区块高度时,为决定出下一区块,系统会进入如上图所示的共识过程。
第一阶段为propose阶段,在该阶段由系统选出的proposer提议将某一交易区块作为链上的下一区块,并将该提议广播出去。接下来需要进入两个投票阶段:prevote和precommit。在prevote阶段,对于proposer提议的区块,若validator验证为有效区块,那么validator会对其进行prevote;相反,若为无效区块或者validator没有及时收到提议的区块,那么validators的prevote为空(Nil)。
在precommit阶段,若validator收到该区块超过2/3的prevote,那么validator会对区块进行precommit;反之,则precommit为Nil。
上图中有一对夫妇在跳polka(波卡)舞,validator做的事情就像在跳polka舞。当超过2/3的validators对提议的区块进行了prevote,可以称为一个Polka。 每次precommit必须由同一round的Polka证明 。
在precommit阶段的最后,每个节点需要作出决定。若节点收到了超过2/3的precommit,那么节点进入commit阶段;否则,节点继续进入下一round的propose阶段。
因此,系统处于propose阶段是由两种条件驱动,一种是区块被提交到链上后重新提交新的区块,新的区块高度+1;另一种是区块提交失败后重启round,此时区块高度不变。
此时,我们可以分析在共识过程中为什么成功提交一个区块可能需要多个round,原因有以下几点:
选出的proposer不在线;
proposer提议的区块无效;
proposer提议的区块没有及时传播出去;
提议的区块有效,但在到达Precommit阶段前,validator节点没有及时收到超过2/3的prevote。或者是,prevote超过2/3可以进入下一状态,却出现至少有一个validator投了Nil票或恶意投票;
提议的区块有效,并且prevote超过了2/3,但是validator节点没有收到超过2/3的precommit。
每个round开始期间,若validators在一个timeout时间内没有收到提议,validators将通过投票来决定是否跳过当前的proposer。这种对超时的依赖使得Tendermint是一种弱同步协议,而不是一种异步协议。但是,每个round在收到提议之后,就进入完全异步模式,validators只能在取得超过2/3的共识后才能继续往前。
Tendermint共识算法可以容忍1/3以内的节点错误,这个错误包括节点离线和节点作恶。
在拜占庭节点数少于节点总数的1/3时,为了避免出现在同一区块高度不同round分别提交两个不同区块的情况,Tendermint引入了锁机制。Validators会被锁定在其最近precommit的区块上。当收到区块超过2/3的prevote后,validators为该区块进行precommit,validator即锁定在该区块上了。Validators节点每次最多只能锁定一个区块,且只能prevote他们被锁定的区块,这样可以阻止validators在上一round中precommit一个区块,在下一round中又prevote另一个区块,从而避免出现在同一区块高度提交两个不同区块的情况。Validators只有看到更高round(相对于其当前被锁定区块的round数)的polka才能解锁,该polka包括收到超过2/3的prevote或Nil prevote两种类型的polka。
因此,如果拜占庭节点数少于1/3,基于Tendermint的区块链永远不会分叉。