Tendermint共识算法

Tendermint共识算法

  • 1 Abstract
  • 2 Introduction
  • 3 Algorithm Details
    • 3.1 NewHeight
    • 3.2 Propose
    • 3.3 Prevote
    • 3.4 Precommit
    • 3.5 Commit
  • 4 Algorithm Analysis
    • 4.1 Safety
    • 4.2 Liveness
  • 5 Summary
  • 6 Reference

1 Abstract

区块链作为一个去中心化的分布式记账本,最近几年取得了飞速发展。究其原因,去中心化让其更加可靠,去信任化让其更加安全。从根本而言,区块链是个大型的分布式数据库系统,在这个分布式系统中有着众多的参与节点,我们现在探究的就是如何让众多参与节点达成一个一致性结果。
共识算法可以分为两类,一类是Byzantine Fault Tolerance,也就是我们俗称的拜占庭容错算法,比较有代表性的有PBFT,PoW,PoS等。另一类是Fail-Stop Failure,也就是非拜占庭容错的共识算法,比较有代表性的有Paxos,Raft等。
今天我们着重介绍的是基于拜占庭容错的一个十分经典的共识算法----Tendermint[^1]

2 Introduction

Tendermint共识算法_第1张图片
算法分为共识阶段(加粗)和非共识阶段(非加粗)

NewHeigth->Propose->Prevote->Precommit->Commit

算法规定三个共识阶段是一个Round,一个块的提交可能要经过多个Round,从图中我们也可以看出,其分为多个阶段。

参与节点分为Validator节点Non-Validator节点Validator节点是负责参与共识的节点。

作为一种拜占庭容错算法,算法才用了2/3这个条件去限制整个过程,这种方式与PBFT类似。

A set of +2/3 of prevotes for a particular block or at (H,R) is called a proof-of-lock-change or PoLC for short.

from:https://github.com/tendermint/tendermint/wiki/Byzantine-Consensus-Algorithm

PoLC(Proof of Lock Change)表示的是在某个高度轮数(height,Round),对某个块的Prevote投票集合超过2/3,也就是Prevote的投票集。正是有了它的存在让Validator节点永远不可能在同一高度提交冲突块。详细的解释将会在第三部分中的Prevote阶段介绍。

3 Algorithm Details

首先,创世区块高度(Height=0),通过Round Robin[^2]随机选取一个Validator节点作为Proposal一个Block的节点,然后剩下的Validator节点对其进行投票。
下面分NewHeigth->Propose->Prevote->Precommit->Commit阶段阐述整个共识过程。

这里谈一下我自己的一点儿理解
Prevote和Precommit都是broadcast过程,但是Prevote是节点内部,Precommit是节点间。本质上都是vote过程,在Wiki中,其过程都被称为Prevote Vote和Precommit Vote。(我不知道这里能否说清楚这个过程

Tendermint共识算法_第2张图片

3.1 NewHeight

表示要开始新一轮的Proposal,开始新一轮的Proposal的原因有2,1:之前Proposal解锁(与PoLC有关,Prevote阶段会提到)2:通过所有阶段共识阶段(>2/3)

需要注意的是,为了避免选出重复的Proposer(Proposal的提议者),系统内设置了Total Voting Power,当Proposer成功将自己的Proposal Commit完成之后,会用Voting Power-Total Voting Power,让其成为负值。原理就是让上一轮参与Proposal过程的Validator节点不会参与到下一轮的Proposal过程。

3.2 Propose

  • Upon entering Propose:
    1.The designated proposer proposes a block at (H,R).
  • The Propose step ends:
    1.After timeoutProposeR after entering Propose. --> goto Prevote(H,R)
    2.After receiving proposal block and all prevotes at PoLC-Round. --> goto Prevote(H,R)
    3.After common exit conditions

from:https://github.com/tendermint/tendermint/wiki/Byzantine-Consensus-Algorithm

Proposal包含了block和可供选择的最近的PoLC-Round,包含PoLC-Round的原因是保证某些锁定的节点可以让其释放掉,以保证系统的liveness,因为在Proposer成功propose一个block之前,可能存在从上一个PoLC到这一个PoLC的过程,在这个过程中可能伴随着vote失败,那么这个时候就需要将vote到错误block被锁的节点进行释放,以保证系统的活跃度。(提一嘴Istanbul-BFT,它没有这一步过程,所以很容易造成liveness无法保证的情况,下一篇博文会对其分析)

Proposer通过Gossip协议发送Proposal到剩余的每个Validator节点,如果该Proposer被Lock到上一轮的block中,那么该Proposer会直接propose那个block,同时含有证明的Proof of Lock(证明该Proposer被Lock在之前Round中的事实)。
对于如何解锁(这里是不太严谨的说法)将在下面说到。

3.3 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.
    3.Else, if the proposed block from Propose(H,R) is good, it prevotes that.
    4.Else, if the proposal is invalid or wasn’t received on time, it prevotes .
  • The Prevote step ends:
    1.After +2/3 prevotes for a particular block or . --> goto Precommit(H,R)
    2.After timeoutPrevote after receiving any +2/3 prevotes. --> goto Precommit(H,R)
    3.After common exit conditions

from:https://github.com/tendermint/tendermint/wiki/Byzantine-Consensus-Algorithm

Validator节点收到Propose的block之后,会判断自身节点是否被锁在之前的block中,如果锁在之前的block中,会继续为之前的block投票,否则就投当前的block。(这个投票过程类似于PBFT中的Prepare的全网广播,目的是让其它节点同意区块的存在)

为了保证活跃度,假设自身是个Lock-Block,这个时候如果收到一个针对新block的PoLC(投票完成的标志),LatestLockRound

3.4 Precommit

Precommit是真实Lock的地方

  • 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 , it unlocks and precommits .
    3.Else, it keeps the lock unchanged and precommits .
    A precommit for means “I didn’t see a PoLC for this round, but I did get +2/3 prevotes and waited a bit”.key words
  • The Precommit step ends:
    1.After +2/3 precommits for . --> goto Propose(H,R+1)
    2.After timeoutPrecommit after receiving any +2/3 precommits. --> goto Propose(H,R+1)
    3.After common exit conditions
    4.common exit conditions
    4.1After +2/3 precommits for a particular block. --> goto Commit(H)
    4.2After any +2/3 prevotes received at (H,R+x). --> goto Prevote(H,R+x)
    4.3After any +2/3 precommits received at (H,R+x). --> goto Precommit(H,R+x)

Prevote超时或者收到Prevote(or nil)+2/3的时候,进入Precommit阶段,如果此时节点收到+2/3的Prevote的投票,广播一条Precommit投票,同时将自己锁在这个block上(将之前的block释放掉)。一个节点依次只能锁在一个块上。

当一个节点锁在一个block上的时候(有PoLC),它将LastLockRound设置为当前Round,并且对这个投Precommit票。

如果有针对 nil 票的 PoLC,则解锁并且对 nil 投 Precommit 票;否则的话保持 Lock-Block 不变,并投 nil 。

如果在 timeout 期间内,没有收到对某个块的足够的 +2/3 投票(prevote 或者 nil 都行),那么就什么也不干。

最终,如果一个节点收到了 +2/3 的 precommit 投票,就进入 Commit 阶段。否则,继续进入下一轮的 Propose 阶段。

3.5 Commit

  • Set CommitTime = now()
  • Wait until block is received. --> goto NewHeight(H+1)

要想真正commit,必须要满足两个条件:

  1. 节点收到这个block
  2. 等待收到+2/3节点的commit信息

4 Algorithm Analysis

4.1 Safety

  • Assume that at most -1/3 of the voting power of validators is byzantine. If a validator commits block B at round R, it’s because it saw +2/3 of precommits at round R. This implies that 1/3+ of honest nodes are still locked at round R’ > R. These locked validators will remain locked until they see a PoLC at R’ > R, but this won’t happen because 1/3+ are locked and honest, so at most -2/3 are available to vote for anything other than B.

假定有最多小于总结点 1/3 的拜占庭节点。如果一个节点在第 R 轮提交一个块,则表明此节点在第 R 轮收到大于 2/3 的针对此块的 Precommit 投票。这也就意味有大于1/3 的诚实节点在第 R’ (R’ > R)轮仍然锁定在这个块上(因为大于 2/3 的 Precommit 投票必定包含大于 1/3 诚实节点的 Precommit 投票)。只有当遇到针对另一个块的 PoLC 时才会解锁,但是在 R’ 轮是不可能有针对某个块的 PoLC,因为已经有大于 1/3 的诚实节点已经锁定在这个块上,所以就不可能有对另外一个块大于 2/3的 Prevote 投票。

4.2 Liveness

  • If 1/3+ honest validators are locked on two different blocks from different rounds, a proposers’ PoLC-Round will eventually cause nodes locked from the earlier round to unlock. Eventually, the designated proposer will be one that is aware of a PoLC at the later round. Also, timeoutProposalR increments with round R, while the size of a proposal are capped, so eventually the network is able to “fully gossip” the whole proposal (e.g. the block & PoLC).

假设多于 1/3 的节点分别 Lock 在不同的块上,则在 Prevote 阶段的条件保证最终Round 较小的会 unlock,而且 Proposal 的超时时间会随着轮数的提高而提高。

5 Summary

Tendermint共识算法作为一种拜占庭容错的类PBFT的共识算法,结合了锁(Lock)的概念,并且创新性的提出了PoLC的概念,让Liveness得到了充分的保障。下篇博客中将针对另外一种类PBFT的共识算法Istanbul-BFT进行解析,并且对其Liveness进行分析,发现其问题(reference4中)。最后感谢前人blog,为我的文章提供了参考,希望大家有问题能多多交流。

6 Reference

[1]: https://github.com/tendermint/tendermint/wiki/Byzantine-Consensus-Algorithm a
[2]:https://baike.baidu.com/item/Round Robin/1980131?fr=aladdin
[3]: https://www.jianshu.com/p/ac82ec874be0
[4]:https://github.com/jpmorganchase/quorum/issues/305

你可能感兴趣的:(区块链学习,共识算法,区块链共识算法,Tendermint,Istanbul-BFT,拜占庭容错)