當前位置:編程學習大全網 - 源碼下載 - Tendermint ***識算法

Tendermint ***識算法

分布式壹致性算法壹般可以分為兩類:拜占庭容錯和非拜占庭容錯。

非拜占庭容錯算法如 Paxos, Raft 等在當前的分布式系統中已經廣泛使用,而拜占庭容錯算法的實際應用範圍相對來說小很多(特別是在區塊鏈問世之前)。

Tendermint 屬於拜占庭容錯算法,它針對傳統的 PBFT 算法做了優化,只需要有兩輪投票即可達成***識,目前 Tendermint 算法主要應用在區塊鏈系統中,這篇文章就從原理上來介紹 Tendermint 的***識機制。

關於 Tendermint 算法的完整描述在 這裏 。

這裏先介紹壹下算法的流程,理解了算法流程之後,再來闡述該算法的安全性證明 (Proof of Safty) 和活性證明 (Proof of Liveness)。

下面這張圖是 tendermint 狀態轉換圖

算法主要有 NewHeigh -> Propose -> Prevote -> Precommit -> Commit 壹*** 5 個狀態(階段)。

上述每個狀態都被稱為壹個 Step,首尾的 NewHeigh 和 Commit 這兩個 Steps 被稱為特殊的 Step,而中間加粗體的三個 Steps 則被稱為壹個 Round,是***識階段,也是也是算法的核心原理所在。

需要註意的是,壹個塊的最終提交(Commit)可能需要多個 Round 過程,這是因為有許多原因可能會導致當前 Round 不成功(比如出塊節點 Offline,提出的塊是無效塊,收到的 Prevote 或者 Precommit 票數不夠 +2/3 等等),出現這些情況的話,解決方案就是移步到下壹輪,或者增加 timeout 時間)。

這裏,還要介紹壹個重要概念:PoLC,全稱為 Proof of Lock Change,表示在某個特定的高度和輪數(height, round),對某個塊或 nil (空塊)超過總結點 2/3 的 Prevote 投票集合,簡單來說 PoLC 就是 Prevote 的投票集。

Tendermint 中有兩種類型的節點,Validator 節點和 Non-Validator 節點,顧名思義,只有 Validator 節點會參與***識投票,而普通節點作為 Non-Validator 節點,不參與***識投票,只協助傳遞狀態或向 Validator 節點發送交易請求。

初始狀態下(創世塊),高度為 0, 此時,系統會基於 Round Robin 原則來選出壹個 Validator(每個 Validator 都有壹定的 Voting Power),由這個 Validator 打包壹個新的 Block, 並向所有節點發出 Proposal,剩余的 Validator 節點對該 Proposal 進行投票,最終達成***識。

以下,分階段來闡述各個階段:

當上壹輪 Commit 結束,就會出現新高度,這是就需要進入下壹輪***識了,也就是說,這就是新壹輪***識過程的開始,這時候需要選出壹個 Proposer。選擇算法是 Round Robin,基於他們的 Voting Power(上壹輪的選中的 Validator 節點會把其 Voting Power 值減去 Total Voting Power,也就是說上壹輪的 Validator 在這壹輪,其 Voting Power 會變成負數)。

在 Propose 節點開始的時候,該輪指定的 proposer 需要通過 gossip 廣播壹條 proposal 到所有的 peers。如果此時這個 proposer 被鎖在上壹輪的某個 block 上,那麽它就直接 propose 那個 block,同時包含壹條 proof of lock 的信息。

Validator 節點收到 propose 信息之後就進入 Prevote 投票階段。投票時,如果 Validator 被鎖在之前壹個 block 上,那麽還是給之前那個 block 投 prevote 票,否則就投當前的 block。同時,它會繼續收集對這個 block 的 prevote 投票,等輪到他 propose 的時候打包進 PoLC。

註意:

如果自己有 Lock-Block,這時又收到壹個新的針對另外壹個塊的 PoLC,並且滿足LastLockRound < PoLC-Round < 當前 Round,則解鎖 Lock-Block。

如果 timeout 期間沒收到 proposal,或者收到的 proposal 是無效的,那麽就投 nil 票。

在 Prevote 階段不會鎖住任何 block。

Prevote 超時或者收到的 Prevote 的 nil 票超過 2/3 時,就進入 Precommit 階段。

如果此時收到了 +2/3 的 prevote 投票,就廣播壹條 precommit 投票,同時, 把自己鎖在當前的 block 上(把之前的都釋放掉) 。壹個節點壹次只能鎖在壹個塊上。

如果收到 +2/3 的 nil 投票,那麽就釋放鎖。

當壹個節點鎖在壹個 block 上的時候(有 PoLC) ,它會將 LastLockRound 置為當前 Round,並對這個塊投 Precommit 票。

如果有針對 nil 票的 PoLC,則解鎖並且對 nil 投 Precommit 票;否則的話保持 Lock-Block 不變,並投 nil 。

如果在 timeout 期間內,沒有收到對某個塊的足夠的 +2/3 投票(prevote 或者 nil 都行),那麽就什麽也不幹。

最終,如果壹個節點收到了 +2/3 的 precommit 投票,就進入 Commit 階段。否則,繼續進入下壹輪的 Propose 階段。

Commit 階段是壹個特殊階段,有兩個並行的條件必須滿足:

At any time during the consensus process if a node receives more than 2/3 of commits for a particular block, it immediately enters the Commit step if it hadn’t already. Thus there are two ways to enter the Commit step. A commit-vote for a block at round R counts as prevotes and precommits for all rounds R0 where R < R0 . Commit-votes are gossipped to neighboring peers in the background re-gardless of the current round or step。

At any time during the consensus process if a node is locked on a block from round R but receives a proof-of-lock for a round R0 where R < R0 , the node unlocks.

Tendermint 的安全性就是說,在對高度為 H 的塊達成***識之後,不可能會出現新的高度為 H 的塊,也就是說 Tendermint 保證不會分叉,保證不會分叉的主要角色就是 Lock-Block。

先看下wiki對於安全性證明的描述:

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 投票。

下面給出較為詳細的證明過程,假設高度為 H 的塊 b 在第 R 輪達成***識。給出如下條件:

需要證明, 當 x 個節點 commit 之後,剩余(也就是 y + z)的沒有 Commit 塊 b 的節點不會對另外壹個塊達成***識。

也就是說需要證明:y + z - z0 < 2/3,假設所有的拜占庭節點都對 b 投了 Precommit,則滿足:x + y + z0 > 2/3。

簡而言之,要從 x + y + z0 > 2/3 證明 y + z - z0 < 2/3。

我們通過反證法來證明:

假設 y + z - z0 > 2/3,也就是在第 r 輪之後有可能造成分叉,則:

x + y + z - z0 > 2/3 + x => 1 - z0 > 2/3 + x => x + z0 < 1/3。

而上面我們提到了,因為x節點已經 Commit 塊 b,則 x + y + z0 > 2/3,且 y < 1/3,則說明 x + z0 必須大於1/3。由此證明,y + z - z0 < 1/3 成立,在第 R 輪之後無法對另壹個塊達成***識,也就不可能出現分叉。

活性證明相對來說就要簡單壹些,假設多於 1/3 的節點分別 Lock 在不同的塊上,則在 Prevote 階段的條件保證最終 round 較小的會 unlock,而且 proposal 的超時時間會隨著輪數的提高而提高。

在證明安全性的過程中提到,有可能會有部分節點由於沒有收到足夠的 Precommit 投票導致無法 commit,這個時候可以通過同步來使各個節點的狀態盡量保持壹致,在wiki中提到壹個 JSet 和 VSet 的概念,當節點已經 commit 時,就可以廣播壹條消息攜帶 VSet 給其他節點,其他節點驗證對於塊的 commit 是否有效。這壹點其實和 bft-raft (另外壹個拜占庭容錯算法,Raft 算法的變種)的做法類似。

  • 上一篇:svn忽略文件中,括號內有recursively與沒有,有什麽區別?(如下圖)
  • 下一篇:詩歌名字大全
  • copyright 2024編程學習大全網