概述
伊斯坦布爾拜占庭容錯 (IBFT) 共識的靈感來自 Castro-Liskov 99 論文。
IBFT繼承了最初的PBFT,採用了三階段共識,PRE-PREPARE、PREPARE和COMMIT。 在 N 個驗證器網絡中,系統最多可以容忍 F 個故障節點,其中 N = 3F + 1。 執行
術語
驗證者:區塊驗證參與者。
提議者:被選中在共識回合中提議區塊的區塊驗證參與者。
回合:共識回合。 一輪開始於提議者創建區塊提案,結束於區塊承諾或輪次變更。
提案:正在進行共識處理的新區塊生成提案。
序號:提案的序號。 一個序列號應該大於所有先前的序列號。 目前,每個提議的區塊高度都是其關聯的序列號。
備份 Backlog:保存未來共識消息的存儲。
回合狀態:特定序列和回合的共識消息,包括預準備消息、準備消息和提交消息。
共識證明:一個區塊的承諾簽名,可以證明該區塊已經通過了共識過程。
快照:上個紀元的驗證者投票狀態。
共識
伊斯坦布爾 BFT 共識協議從第 0 輪開始,驗證者以循環方式從他們自己中選出一個提議者。 然後,提議者將提出一個新的區塊提議,並將其與 PRE-PREPARE 消息一起廣播。 在收到來自提議者的 PRE-PREPARE 消息後,其他驗證者驗證傳入的提議並進入 PRE-PREPARED 狀態並廣播 PREPARE 消息。 此步驟是為了確保所有驗證器都在同一序列和同一輪上工作。 當驗證器從其他驗證器收到 ceil(2N/3) 個 PREPARE 消息時,驗證器切換到 PREPARED 狀態並廣播 COMMIT 消息。 這一步是為了通知其他驗證者它接受了提議的區塊並將將該區塊插入鏈中。 最後,驗證者等待 ceil(2N/3) 條 COMMIT 消息進入 COMMITTED 狀態,然後將區塊附加到鏈中。
伊斯坦布爾 BFT 協議中的塊是最終的,這意味著沒有分叉,任何有效的塊必須位於主鏈中的某個位置。 為了防止故障節點生成與主鏈完全不同的鏈,每個驗證器在將其插入鏈之前將接收到的 COMMIT 簽名的 ceil(2N/3) 附加到標頭中的 extraData 字段。 因此,所有塊都是可自我驗證的。 但是,動態的 extraData 會導致區塊哈希計算出現問題。 由於來自不同驗證者的同一個塊可以有不同的 COMMIT 簽名集,所以同一個塊也可以有不同的塊哈希值。 為了解決這個問題,我們通過排除 COMMIT 簽名部分來計算塊哈希。 因此,我們仍然可以保持區塊/區塊哈希的一致性,將共識證明放在區塊頭中。
共識狀態
伊斯坦布爾 BFT 是一種狀態機複製算法。 每個驗證器維護一個狀態機副本以達成區塊共識。 IBFT共識中的各種狀態是,
新一輪:提議者發送新的區塊提議。 驗證者等待 PRE-PREPARE 消息。
PRE-PREPARED:驗證者已收到 PRE-PREPARE 消息並廣播 PREPARE 消息。 然後它等待 ceil(2N/3) 個 PREPARE 或 COMMIT 消息。
PREPARED:驗證者已收到 ceil(2N/3) 個 PREPARE 消息並廣播 COMMIT 消息。 然後它等待 ceil(2N/3) 個 COMMIT 消息。
COMMITTED:驗證者收到 ceil(2N/3) 個 COMMIT 消息,並能夠將提議的區塊插入區塊鏈。
FINAL COMMITTED:新區塊成功插入區塊鏈,驗證器準備好進行下一輪。
ROUND CHANGE:驗證者正在等待 ceil(2N/3) 輪更改消息中相同的提議輪數。
狀態轉換
狀態轉換
新回合 -> 預先準備好的: 提議者從 txpool 收集交易。 提議者生成一個區塊提議並將其廣播給驗證者。 然後它進入 PRE-PREPARED 狀態。 每個驗證者在收到具有以下條件的 PRE-PREPARE 消息後進入 PRE-PREPARED: 區塊提議來自有效的提議者。 塊頭有效。 區塊提議的順序和輪次與驗證者的狀態相匹配。 驗證者向其他驗證者廣播 PREPARE 消息。
預先準備 -> 準備: Validator 收到 ceil(2N/3) 個有效 PREPARE 消息進入 PREPARED 狀態。 有效消息符合以下條件: 匹配的順序和回合。 匹配的塊哈希。 消息來自已知的驗證器。 驗證器在進入 PREPARED 狀態時廣播 COMMIT 消息。
準備 -> 承諾: Validator 收到 ceil(2N/3) 個有效的 COMMIT 消息以進入 COMMITTED 狀態。 有效消息符合以下條件: 匹配的順序和回合。 匹配的塊哈希。 消息來自已知的驗證器。
已提交 -> 最終提交: 驗證器將 ceil(2N/3) 承諾簽名附加到 extraData 並嘗試將塊插入區塊鏈。 驗證器在插入成功時進入 FINAL COMMITTED 狀態。
最終提交 -> 新一輪: 驗證者選擇一個新的提議者並開始新一輪的計時器。
回合變化流程
三個條件可以觸發 ROUND CHANGE:
回合更改計時器到期。
無效的 PREPREPARE 消息。
塊插入失敗。
當驗證者註意到上述條件之一適用時,它會廣播 ROUND CHANGE 消息以及建議的輪數,並等待來自其他驗證者的 ROUND CHANGE 消息。 提議的輪數是根據以下條件選擇的:
如果驗證器收到來自其對等方的 ROUND CHANGE 消息,它會選擇具有 F + 1 個 ROUND CHANGE 消息的最大輪數。
否則,它選擇 1 + 當前輪數作為建議的輪數。
每當驗證者收到 F + 1 條關於相同提議輪數的 ROUND CHANGE 消息時,它會將收到的消息與自己的消息進行比較。 如果接收到的更大,驗證器將使用接收到的數字再次廣播 ROUND CHANGE 消息。
在收到相同提議輪數的 ROUND CHANGE 消息的 ceil(2N/3) 後,驗證器退出輪更改循環,計算新提議者,然後進入 NEW ROUND 狀態。
驗證者跳出循環變化循環的另一個條件是當它通過對等同步接收到已驗證的塊時。
提議者選擇
目前我們支持兩種策略:round robin 和 sticky proposer。
循環法:循環法是默認的提議者選擇策略。 在此設置中,提議者將在每個區塊和輪次更改中更改。
Sticky proposer:在sticky proposer設置中,proposer只會在輪換發生時改變。
驗證者列表投票
伊斯坦布爾 BFT 使用與 Clique 類似的驗證者投票機制,並從 Clique EIP 複製大部分內容。 每個紀元交易都會重置驗證器投票,這意味著任何用於添加/刪除驗證器的未決投票都會被重置。
對於所有交易塊:
提議者可以投一票來提議更改驗證者列表。
僅每個目標受益人的最新提案來自單個驗證者。
隨著鏈的進展(允許並發提案),實時計票。
達成多數共識的提案 VALIDATOR_LIMIT 立即生效。
無效的提議不會因為客戶端實現的簡單性而受到懲罰。
一項生效的提案需要放棄對該提案的所有未決投票(支持和反對)。
未來的消息和積壓
在異步網絡環境中,人們可能會收到無法在當前狀態下處理的未來消息。 例如,驗證者可以在 NEW ROUND 上接收 COMMIT 消息。 我們稱這種信息為“未來信息”。 當驗證器收到一條未來的消息時,它會將消息放入其待辦事項列表中,並在可能的情況下嘗試稍後處理。
區塊哈希、提議者印章和承諾印章
由於以下原因,伊斯坦布爾區塊哈希計算不同於 ethash 區塊哈希計算:
提議者需要在extraData中蓋上提議者的印章,以證明該區塊是由被選中的提議者簽署的。
驗證者需要將 ceil(2N/3) of committed seals 作為共識證明放在 extraData 中,以證明該塊已通過共識。
計算仍然類似於ethash塊哈希計算,不同之處在於我們需要處理extraData。 我們計算字段如下:
提案人印章計算
到 proposer seal 計算時,committed seals 仍然是未知的,所以我們計算那些未知數為空的 seal。 計算如下:
提議者印章:SignECDSA(Keccak256(RLP(Header)), PrivateKey)
PrivateKey:提議者的私鑰。
標頭:與 ethash 標頭相同,只是具有不同的 extraData。
額外數據:虛榮| RLP(IstanbulExtra),其中在IstanbulExtra中,CommittedSeal和Seal為空數組。
區塊哈希計算
在計算塊哈希時,我們需要排除已提交的印章,因為該數據在不同驗證器之間是動態的。 因此,我們在計算哈希時將 CommittedSeal 設為空數組。 計算是:
標頭:與 ethash 標頭相同,只是具有不同的 extraData。
額外數據:虛榮| RLP(IstanbulExtra),其中在 IstanbulExtra 中,CommittedSeal 是一個空數組。
共識證明
貝弗在將一個區塊插入區塊鏈時,每個驗證者需要從其他驗證者那裡收集 ceil(2N/3) 個承諾印章來組成一個共識證明。 一旦它收到足夠多的承諾印章,它將填充 IstanbulExtra 中的 CommittedSeal,重新計算 extraData,然後將塊插入區塊鏈。 請注意,由於提交的印章可能因不同來源而異,因此我們在計算塊哈希時排除了該部分,如上一節所述。
承諾印章計算:
Committed seal 由每個簽署散列的驗證器及其私鑰的 COMMIT_MSG_CODE 消息代碼計算得出。 計算如下:
承諾印章:SignECDSA(Keccak256(CONCAT(Hash, COMMIT_MSG_CODE)), PrivateKey)。
CONCAT(Hash, COMMIT_MSG_CODE):連接塊散列和 COMMIT_MSG_CODE 字節。
PrivateKey:簽名驗證者的私鑰。
Last updated