tendermint共识解析

本文关于tendermint的共识部分,主要参考如下:
1. Ethan Buchman:Tendermint: Byzantine Fault Tolerance in the Age of
Blockchains

2. tendermint中文文档
3.tendermint的一个论文
4. 万向区块链对参考0中论文的翻译
5. tendermint官方doc

本文着重介绍tendermint的共识方面的细节。


image.png

tendermint共识状态机解析

上图中每个step,其实都是共识状态机中的一个状态,状态转换周期如下:

NewHeight -> (Propose -> Prevote -> Precommit)+ -> Commit -> NewHeight ->...

gossip 都广播哪些内容?

我们知道在驱动状态机最重要两个因素,一个是通信(tendermint中的P2P是以gossip协议和reactor模式为基础);另一个就是event(设计上任何异步通讯的过程都离不开event),这两部分的内容后面有机会的话会单独写文章解析,现在我们先来看看gossip都广播哪些内容,以使节点都能跟进当前的共识状态。
以下引用自官方文档,逐条说明本人结合源码对其的解析:

  • Nodes gossip PartSet parts of the current round's proposer's proposed block. A LibSwift inspired algorithm is used to quickly broadcast blocks across the gossip network.

说明:partset代表block的一些简要信息,其结构如下:

type PartSet struct {
  total int
  hash  []byte

  mtx           sync.Mutex
  parts         []*Part
  partsBitArray *bits.BitArray
  count         int
}
  • Nodes gossip prevote/precommit votes. A node NODE_A that is ahead of NODE_B can send NODE_Bprevotes or precommits for NODE_B's current (or future) round to enable it to progress forward.

说明:这条要结合下面状态机的prevote、precommit状态解析中的step ends一起理解。因为prevote,precommit都需要2/3+的票数通过,才能进行状态转换。

  • Nodes gossip prevotes for the proposed PoLC (proof-of-lock-change) round if one is proposed.

说明:gossip prevotes的另一个用处是polka unlock.

  • Nodes gossip to nodes lagging in blockchain height with block commits for older blocks.

说明:gossip block,落后的节点同步新block。

  • Nodes opportunistically gossip HasVote messages to hint peers what votes it already has.

说明:节点偶尔gossip HasVote消息

  • Nodes broadcast their current state to all neighboring peers. (but is not gossiped further)

说明:节点gossip 当前所在状态(未来版本不再gossip此部分)

共识状态解析

接下来让我们逐条分析各个共识状态。

1. propose step(height:H,round:R)

客户端发起一笔交易gentx,通过rpc发到tendermint节点后进入mempool cache,tm调用checktx的abci接口验证交易,如果验证成功就进入mempool,proposer节点选择打包交易到区块中,并将区块附到proposalMsg中,对此msg进行签名,然后通过gossip把此msg广播到区块链网络中。

一个proposal包含一个(H,R)的block,和一个可选的最近的PoLC-Round < R,当然前提是proposer知道此可选参数(PoLC:proof of lock change,指的2/3+ prevote某个block),这样适当保住了共识网络的liveness。

Upon entering Propose:

指定的proposer 提议了一个block(H,R).

The Propose step ends:

  1. timeoutProposeR 超时,则进入-->Prevote(H,R)
  2. 当收到了proposal block,并且改validator的所有prevote step 都在PoLC-Round,则进入-->Prevote(H,R)。(要理解这点,重点要理解某个validator有可能involve在若干个round,相当于说你其他轮中都过了prevote的step,才能进入新一轮的prevote step?但如果有锁的情况下即使进入了prevote轮,你也不能prevote了)
  3. After common exit conditions

Note:
注意每轮共识开始时,validator节点在本地会有一个本地同步时钟,用来记时ProPose timeout, 如果在timeout时间周期内没有收到proposer节点的提议,对该提议的预投票为空(nil),validator节点会投票决定是否进入下一轮共识,validator也可以通过治理模块投票移出或者替换拜占庭验证者。而propose timeout也会随着每轮共识而增加。所以可以理解为此过程是同步过程。
但是在其后的prevote和precommit的两阶段共识是完全异步的,从而减少对时钟同步的依赖,或者网络延迟。但这也同样存在一个问题,如果这两阶段共识中就是得不到1/3以上validator的投票,整个区块链网络将瘫痪(此处其实有待看源码仔细研究,因为这两个阶段也是有timeout定时器的,重点关注step end的条件,以此来分析可能引起网络hang住的场景)。这个问题的本质其实就是FLP不可能定理。FLP 原理实际上说明对于允许节点失效情况下,纯粹异步系统无法确保一致性在有限时间内完成。
所以tendermint其实在一定程度是假定节点中大部分都是正常节点。

2. prevote step (height:H,round:R)

每个节点收到propose消息后,会先对区块进行验证,如果验证通过才开始prevote签名,然后广播到网络中。

Upon entering Prevote, each validator broadcasts its prevote vote.

  1. First, if the validator is locked on a block since LastLockRound but now has a PoLC for something else at round PoLC-Round where LastLockRound < PoLC-Round < R, then it unlocks.(这条好理解,就是解锁条件,重点还是要理解异步)。
  2. If the validator is still locked on a block, it prevotes that. (这条是因为锁的规则,他只能prevote自己lock住的block,但是会引起重复prevote?这个还得结合源码研究)。
  3. Else, if the proposed block from Propose(H,R) is good, it prevotes that.(没啥好解释的,就是验证了proposal后正常prevote)
  4. Else, if the proposal is invalid or wasn't received on time, it prevotes <nil>.(proposal无效,或者定时器超时,就prevote<nil>)

The Prevote step ends:

  • After +2/3 prevotes for a particular block or <nil>. -->; goto Precommit(H,R)
  • After timeoutPrevote after receiving any +2/3 prevotes. --> goto Precommit(H,R)
  • After common exit conditions

3. Precommit Step (height:H,round:R)

Upon entering Precommit, each validator broadcasts its precommit vote.

  1. If the validator has a PoLC at (H,R) for a particular block B, it (re)locks (or changes lock to) and precommits B and sets LastLockRound = R.(说明了什么时候上锁)
  2. Else, if the validator has a PoLC at (H,R) for <nil>, it unlocks and precommits <nil>.(说明了什么时候precommit nil,简言之,就是获得了POLC的<nil>)
    3.Else, it keeps the lock unchanged and precommits <nil>.(最后剩下的情况也就是超时了吧?)

A precommit for <nil> means "I didn’t see a PoLC for this round, but I did get +2/3 prevotes and waited a bit".(这句可以理解为没有获得非nil的POLC,而且等待了timeout时间段)

The Precommit step ends:

  1. After +2/3 precommits for <nil>. --> goto Propose(H,R+1)(注意,并没有commit nil。prevote nil、precommit nil进入下一轮,因此tendermint中没有类似PBFT中的viewchange )
  2. After timeoutPrecommit after receiving any +2/3 precommits. --> goto Propose(H,R+1)(我理解此处+2/3 precommits是笔误?应该是+2/3 prevotes?)
  3. After common exit conditions

Common exit conditions

  1. After +2/3 precommits for a particular block. --> goto Commit(H)
  2. After any +2/3 prevotes received at (H,R+x). --> goto Prevote(H,R+x)
  3. After any +2/3 precommits received at (H,R+x). --> goto Precommit(H,R+x)
    第一点,可理解为在R内要追赶最新状态,尽快commit。
    后两点可理解为要追赶更新的R。

4. Commit Step (height:H)

  1. Set CommitTime = now()
  2. Wait until block is received. --> goto NewHeight(H+1) //注意此处要等到本轮的块到了才会进入NewHeight step.

5. NewHeight Step (height:H)

Move Precommits to LastCommit and increment height.
Set StartTime = CommitTime+timeoutCommit
Wait until StartTime to receive straggler commits. --> goto Propose(H,0)

小结

在异步网络中,一个最大的问题就是同高度上,在不同的round提交了不同的block。tendermint引入了锁的机制。

什么时候锁?

每个validator锁定在他获得PoLC的block中,然后只能对该block precommit,在后面的R中,如果没有unlock也只能prevote此block。

什么时候解锁?

提交了一个当前锁定的块后
在下一轮(准确说应该是PoLC round)看到PoLC(proof of lock change,在新的一轮收到大于2/3 prevote的block)时获得解锁, 解锁后不会在PoLC round 投票了,因为在该R中已经获得了polka,也就是说已经结束了prevote state。

锁定规则

验证者只能预投票(pre-vote)他们被锁定的区块(因为他在某Round中prevote的block未必和precommit的block是相同的)。这样就阻止验证者在同一个高度,上一轮中预提交(pre-commit)一个区块,之后又预投票了下一轮的另一个区块。

Proof of Safety

假设有-1/3的Byzantine voting power(-1/3指不到1/3), 在R轮时,validator commit一个block B。这就意味着有1/3+的诚实节点lock在了R' > R, 他们直到获得在R`>R 的POLC才能unlock。但是这种unlock的情况不会发生,因为剩余的-2/3个节点能投票给B以外的block,无法形成POLC。(这不是会导致诚实节点一直锁吗?从而网络hang住?)

Proof of Liveness

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容