比較各種共識算法的Finality和Liveness
BFTF技术社区联盟
2018-10-19 03:13
本文约4814字,阅读全文需要约19分钟
不要浪費時間為純異步網絡設計共識算法。

原作者:靈魂機器

由於FLP Imposibility 原理,

No completely asynchronous consensus protocol can tolerate even a single unannounced process death


因此不要浪費時間為純異步網絡設計共識算法。解決辦法就是,要么加強對網絡的要求,要求網絡是Synchronous或者Partially Synchronous的(從異步到同步或者半同步,網絡狀態變好了),或者放鬆對finality的要求,不要求Deterministic finality,只要求Probabilistic finality 即可。兩者同時進行也可以。


表1 各種共識算法比較


下面詳細講解一下上面表格中的內容。


Finality

Finality看起來和Safety, Consistency 很相似,又似乎有所不同,非常容易讓人困惑。

簡單的理解,你可以認為Finality, Safety, Consistency是同義詞,即Finality=Safety=Consistency。

更深入理解,我認為Finality是一個綜合體,Finality>Safety>Consistency 。 Consistency適用於所有分佈式系統的,包括可信環境例如Hadoop和不可信環境例如Bitcoin; Safety適用於拜占庭環境下;Finality 是在區塊鏈這個場景下的術語,區塊鍊是拜占庭場景下的一個子集(拜占庭問題除了區塊鏈還有非區塊鏈的解決方案)。 Consistency 是CAP理論中的C,更加general, 要求沒有Finality那麼多。 Finality包含的含義比Consistency更多更強。 Finality包含了下面所有含義:

  • 所有節點的數據應是一致的。客戶端發出一個讀操作到任意一個節點,得到的結果應該是一樣的。這個就是CAP裡所說的Consistency. 這個術語是適用於所有的分佈式系統的,包括可信環境例如Hadoop和不可信環境例如Bitcoin。

  • 所有節點要確保不進入互相衝突,分裂的狀態,即safety。這個術語是適用於Byzantine fault tolerance這個領域的,在拜占庭這種開放環境裡,有惡意節點會廣播兩個互相衝突的消息(例如雙花交易),導致全網所有節點陷入分裂狀態,達不成一直,這就破壞了Safety這個性質。所有拜占庭下的共識算法,都需要處理好惡意節點的問題,保證全網的safety。

  • 交易一旦進入區塊,應該不可撤銷,即Immutability。在區塊鏈場景下,要保證Safety,不僅需要處理好惡意節點發出雙花交易這種問題,而且還要防止惡意節點撤銷已經打包進區塊的交易。因為區塊鍊是一個單鍊錶,是一個線性結構,惡意節點理論上可以從舊的一個區塊出發,分叉處一個更長的新鏈,把自己已經發出去的交易全部撤銷掉,把自己的錢再花一遍(是另一種形式的雙花)


綜上,Finality=Consistency + Safety + Immutability。

Liveness

Liveness可以認為與CAP中的Availability等價。當網絡出現partition時,比如海底光纜斷裂,將全球互聯網分割成兩個部分,整個區塊鏈系統是否能正常寫入新的交易?喜歡Finality的共識算法,這時候會選擇無限等待,新的transaction無法寫入,直到海底光纜修復,兩邊的互聯網互通;喜歡Availabilty的共識算法,這時候兩邊網絡會獨立運作,數據分家了,兩邊的全節點中的數據變得不一致。

比如Tendermint就是這類,犧牲Liveness追求Deterministic Finality。假設海底光纜斷裂將網絡分為兩邊,那麼每一邊都有一半的validator, 於是在vote和commit階段,每一邊的所有validator, 100%全部投票贊成某個proposal block,最多只能收到50%的投票,達不到2/3,於是整個區塊鍊網絡會無限等待,直到收集到2/3投票為止。在這個等待期間,無法出下一個塊,新的交易也無法寫入,整個網絡陷入癱瘓。


比特幣在碰到這種網絡分割的時候,兩部分的比特幣系統會繼續向前走,依舊可以寫入新的transaction, 產生新的區塊,當海底光纜修復後,兩邊互聯網連通後,再選擇合併。

在海底光纜沒斷之前,全球所有全節點的狀態是一致的,如下圖:

當海底光纜斷裂後,全球網絡被分割為兩部分,兩個部分都會獨立出塊,這時候兩邊已經不一致了,但是兩邊各自是感知不到的,以為自己依舊是一條線性的區塊鏈,如下圖:

左邊和右邊,雖然依舊每10分鐘挖出一個新塊,但是左邊的block07和右邊的block07,block hash 是不相等的。這時候比特幣網絡還是available的,只是Finality破壞了。

當海底光纜修復後,這時候,兩邊互相同步block,會意識到出現了分叉,如下圖:

現在全球所有全節點的狀態,變成上圖,有分叉了,由於兩邊的高度都是8,無法決定哪個分叉是正確的,這時候,就看礦工支持哪邊了,哪邊的算力高,哪邊先出了新塊,那麼哪邊就勝出了,短的那條鏈會被拋棄,比如假設右邊搶先新出了一個塊,那麼右邊勝出,左邊分叉被拋棄,所有全節點中的數據又變成一條線性區塊鏈,達成一致了,如下圖:

其實即使海底光纜不斷,網絡沒有partition, 也會經常發生兩個miner各自同時挖出一個新塊的情況,這時候就比拼誰運氣好,下一個新塊繼承哪一個分叉哪一個就勝出。也就說比特幣理論上永遠沒有一個確定性的一致性狀態,分叉隨時會在任意高度上出現,因此比特幣犧牲了一點Finality, 換取更強的Liveness。


Network Assumption

所有分佈式共識算法都對網絡有一個隱含的假設前提。
先說一下網絡的分類:

同步:消息一定會在某個的時間T內被送達,這個上限(upper bound)的值T,是已知的常量,所有節點都是知道的。如果消息在T時間內沒有送達,就不對這個消息作指望了,節點認為該消息已經丟失,不會繼續等它。所有節點都有條不紊的,每經過一個時間T,就往前進一步,非常整齊。

半同步:消息一定會在某個的時間T內被送達,但這個T的值,不是固定的值,而是動態變化的,例如是根據網絡狀況動態計算出來的。所有節點

異步:消息會在任意時間到達,可能很快,也可能很慢,總之沒有一個明確的上限(upper bound)甚至無限期延遲,無論多晚到達,節點都要接受並處理這個消息,不能簡單的因為超時就丟棄消息

比特幣對網絡的假設就是網絡是同步的,時間上限是10分鐘左右,一個Miner 挖出一個block後,向全網廣播,這時候整個比特幣系統,期望就是這個block 在10分鐘內會被所有在線的全節點full node收到,意思就是說每隔10分鐘,所有全節點都會整整齊齊地往前走一步,即往自己的區塊鏈尾部追加一個block。即使網速很快,例如3分鐘不到,這個新block已經被所有全節點收到了,比特幣還是會每隔10分鐘往前走一步(出一個新塊)。以太坊類似,不過時間上限是15秒。

Tendermint 在propose階段假設網絡是半同步的,因為在這一步會有一個超時時間,如果超過時間還沒收到一個proposal新塊,那麼其他validator就會認為proposer節點已經掛了,於是出一個空塊,直到round-robin到下一個proposer。 Tendermint在prevote和precommit都需要收集超過2/3的投票,是無限等待的,也就是在這兩個階段是假設網絡是異步的。最終,Tendermint對網絡的要求是半同步的。

pBFT在pre-prepare, prepare, commit三個階段全部是異步的,既然是異步的,沒有超時機制,那怎麼往前進展呢?收集到了超過2/3就能繼續往前進。不過所有節點在收到一個客戶端的請求,都會啟動一個定時器,如果在某個時間內該請求還沒有執行完畢,就會觸發View Change。 View Change 這個部分是半同步的。

在這裡可以體會到Tendermint相比pBFT的簡化之處了。 Tendermint 把超時機制挪動到了propose階段(相當於pBFT的pre-prepare階段),如果proposer在規定時間內,廣播出了一個proposal block,那麼就前進到下一步,如果超時了,也前進到下一步,不過這個是proposal block是一個空塊(空塊時也會完整走一遍pre-vote和pre-commit流程,不過block height不會自增1,相當於網絡在空轉,一直到round-robin到下一個新的proposer節點,重新廣播新的proposal block)。也就是無論如何,propose階段都會往前進入到下一步。但是Tendermint的pre-prepare是異步的,有可能永遠卡主。 pBFT把超時機制挪動到了View Change 這一部分,因此pBFT就多出來一個View Change 步驟,比Tendermint複雜了一些。 Tendermint通過提交空塊和round-robin更換proposer 節點, 而pBFT則是通過View Change 來更換primary節點。 Tendermint消除了複雜的View Change這一步驟。

除了消除View Change這一點,Tendermint還在另一個地方有所簡化,Tendermint的所有信息都存儲在blockchain裡。而pBFT是1999年提出來的,那時候還沒有blockchain這個東西,因此pBFT的所有節點雖有有一致的數據,但數據是分散存放的。 pBFT的每個節點的數據包括:

The state of each replica includes the state of the service, a message log containing messages the replica has accepted, and an integer denoting the replica’s current view.

Blockchain就是一個分佈式數據庫,好比在MySQL這類DBMS數據庫沒出現之前,人們都是把數據寫入文件然後存在硬盤上,發明出各種奇怪的文件格式和組織方式。有了MySQL後,管理數據就方便多了。同理,Tendermint 把數據全部存入blockchain, pBFT沒有blockchain這樣一個分佈式數據庫,所有節點需要自己在硬盤上管理數據,比如為了壓縮消息日誌,丟棄老的消息,節省硬盤空間,引入了checkpoint的概念。

Tendermint和pBFT關係類似於Raft和Paxos的關係,Tendermint是pBFT的簡化版,是針對blockchain這個場景下的簡化版pBFT

下圖是Tendermint的算法流程圖:

參考資料


參考資料

參考資料

  1. 1999.Castro.  Practical Byzantine Fault Tolerance

  2. Tendermint: Byzantine Fault Tolerance in the Age of Blockchains

  3. Consensus Compare: Casper vs. Tendermint

  4. A Proof of Stake overview

  5. Compared with traditional PBFT, what advantage does Tendermint algorithm has?

  6. Synchronous, partially synchronous and asynchronous consensus algorithms

  7. GRANDPA Block Finality in Polkadot: An Introduction (Part 1)

  8. Finality in Blockchain Consensus


BFTF技术社区联盟
作者文库