『壹』 Quorum介紹(二):Quorum共識
我們知道,公共區塊鏈是一個開放的社區,任何人都能夠成為一個節點加入網路,在網路中計算,提交交易到鏈上等,因此公鏈是沒有信任基礎的,所以公鏈的共識第一要義就是證明交易的合法性和真實性,防止惡意成員的搗亂,效率不是第一要義。
與公鏈的環境不同,有準入門檻的企業鏈或者聯盟鏈鏈上的所有成員在加入時實際上是已經獲得了某些認可和許可的,因此企業鏈/聯盟鏈上的成員是有一定信任基礎的。在企業級鏈上我們沒有必要使用POW或者POS這種浪費算力或者低效的交易共識。
Quorum提供了多種共識供用戶採用:
在講Raft前,有必要提一下Paxos演算法,Paxos演算法是Leslie Lamport於1990年提出的基於消息傳遞的一致性演算法。然而,由於演算法難以理解,剛開始並沒有得到很多人的重視。其後,作者在八年後,也就是1998年在ACM上正式發表,然而由於演算法難以理解還是沒有得到重視。而作者之後用更容易接受的方法重新發表了一篇論文《Paxos Made Simple》。
可見,Paxos演算法是有多難理解,即便現在放到很多高校,依然很多學生、教授都反饋Paxos演算法難以理解。同時,Paxos演算法在實際應用實現的時候也是比較困難的。這也是為什麼會有後來Raft演算法的提出。
Raft是實現分布式共識的一種演算法,主要用來管理日誌復制的一致性。它和Paxos的功能是一樣,但是相比於Paxos,Raft演算法更容易理解、也更容易應用到實際的系統當中。而Raft演算法也是聯盟鏈採用比較多的共識演算法。
Raft一共有三種角色狀態:
每個節點上都有一個倒計時器 (Election Timeout),時間隨機在 150ms 到 300ms 之間。有幾種情況會重設 Timeout:
在分布式系統中,「時間同步」是一個很大的難題,因為每個機器可能由於所處的地理位置、機器環境等因素會不同程度造成時鍾不一致,但是為了識別「過期信息」,時間信息必不可少。
Raft演算法中就採用任期(Term)的概念,將時間切分為一個個的Term(同時每個節點自身也會本地維護currentTerm),可以認為是邏輯上的時間,如下圖。
每一任期的開始都是一次領導人選舉,一個或多個候選人(Candidate)會嘗試成為領導(Leader)。如果一個人贏得選舉,就會在該任期(Term)內剩餘的時間擔任領導人。在某些情況下,選票可能會被評分,有可能沒有選出領導人(如t3),那麼,將會開始另一任期,並且立刻開始下一次選舉。Raft 演算法保證在給定的一個任期最少要有一個領導人。
特殊情況的處理
在以太坊中節點本身並沒有角色,因此在使用Raft共識時,我們稱leader節點為挖礦節點:
Raft共識機制本身保證了同一時間點最多隻有一個leader,因此用在以太坊模型下也只會有一個出塊者,避免了同時出塊或者算力浪費的情況。
在單筆交易(transaction)層級Quorum依然沿用了Ethereum的p2p傳輸機制,只有在塊(block)層級才會使用Raft的傳輸機制。
其中需要注意到一點,在以太坊中一個節點收到塊以後就會立刻記賬,而在Quorum模型中,一個塊的記錄必須遵從Raft協議,每個節點從leader處收到塊以後必須報告給leader確認收到以後,再由leader通知各個節點進行數據提交(記錄)
在Quorum模型中新塊的信息是很有可能和已有塊的header信息不符的,最容易發生這種情況的就是選舉人更替(挖礦節點更替),具體描述如下:
假設有兩個節點,node1和node2,node1是現有的leader,現有鏈的最新區塊是0xbeda,它的父區塊是0xacaa
對塊「Extends」或者「No-op」的標記是在更上層完成的,並不由raft本身log記錄機制實現。因為在raft內部,信息並不分為有效或無效,只有在區塊鏈層面才會有有效區塊和無效區塊的含義。
需要注意的是,Quorum的這種記賬機制和本身Ethereum的LVC(最長鏈機制)是完全不一樣的
Quorum的出塊頻率默認是50ms一個塊,可以通過 --raftblocktime 參數進行設置
投機性出塊並不是以太坊Raft共識嚴格必須的核心機制之一,但是是提高出塊效率的有效方式。
一個塊從產生到實際被記錄賬本,走完整個raft流程實際上是需要耗費一定時間的。如果我們在上一個塊被計入賬本之後才開始產生下一個塊,那麼一筆交易想要成功被記錄需要耗費較多的時間。
而在投機性(speculative minting)出塊中,我們允許一個新塊在它的父塊被記錄之前就產生。依次類推,在一段時間內,實際上會產生「投機鏈(speculative chain)」,在祖先塊沒有被記錄進賬本之前,一個一個新塊已經依據先後關系組成了一條臨時鏈片段,等待被記錄。
對於已經被記錄進投機塊的交易,我們會在交易池中標記為「proposed transaction」
在之前我們說過,raft機制中是存在兩個挖礦節點比賽出塊和記賬的可能的,因此,一條 speculative chain 中間的某一個塊很有可能不會被記錄到賬本中。在這種情況下我們也會把交易池中的交易狀態修改回來。( InvalidRaftOrdering event)
目前,Quorum並沒有對speculative chain的長度做限制,但在它的未來規劃中有講這一點作為一個性能優化項加入開發進程,最後能夠讓一個挖礦節點即使在raft共識層沒有連接上,它也可以離線一直出塊,產生自己的speculative chain。
一條speculative chain有以下幾個部分構成:
在塊傳輸上我們使用etcd Raft默認的http傳輸,當然使用Ethereum的p2p傳輸也是可以的,但是Quorum團隊在測試階段發現,高負載的狀態下,ETH p2p的性能沒有raft p2p性能好。
Quorum使用50400埠作為Raft 傳輸層的默認監聽埠,也可以通過 --raftport 參數自行設置。
一個集群默認的最大節點個數是25,可以通過 --maxpeers N 來設置,N是你的最大節點個數。
Quorum的IBFT其實就是PBFT,只不過摩根大通把它自己實現的PBFT叫做IBFT,所以IBFT的基本原理與PBFT是一樣的,所不同的是,IBFT中把出塊和共識的三階段結合在了一起。
Istanbul BFT修改自PBFT演算法,包括三個階段: PRE-PREPARE 、 PREPARE 以及 COMMIT 。在 N 個節點的網路中,這個演算法可以最多容忍 F 個出錯節點,其中 N=3F+1 。
Istanbul BFT演算法中的區塊是確定的,意味著鏈沒有分叉並且合法的區塊一定是在鏈中。為了防止一個惡意節點生成不同的鏈,在把區塊插入進鏈 之前 ,每一個validator必須把 2F + 1 個 COMMIT 簽名放進區塊頭的 extraData 欄位。因此,區塊是可以自我驗證的(因為有簽名)並且輕客戶端也支持。
然而動態的 extraData 也會造成區塊的hash計算問題。因為一個區塊可以被不同的validator驗證,所以會有不同的簽名,所以同一個區塊會有不同的hash。解決的方案是,計算區塊hash的時候把 COMMIT 簽名排除在外。因此我們任然可以在保證block hash一致性的同時進行共識驗證。
由於Ethereum POA共識在網上已經有大量介紹,筆者這里就不多做詳細介紹,只對重要特點和POA的工作流程做大致梳理和介紹