1. 程式人生 > 實用技巧 >istanbul演算法詳解

istanbul演算法詳解

文章以及資料(開源):github地址

目錄

Terminology:

  • Validator:塊的驗證者
  • Proposer:塊驗證者中被選擇用來出塊的
  • Round: 共識的輪數。一輪中 Proposer 開始提出一個一個出塊建議,然後以提交區塊結束。
  • Proposal:新的塊生成提議
  • Sequence:提議的序號。當前序列號大於先前的;塊高就是此提議的序列號。
  • Backlog:儲存未來的共識訊息
  • Round state
    : 特定sequence和輪次的共識訊息,包括 pre-prepare 訊息, prepare 訊息, and commit 訊息.
  • Consensus proof:用來證明塊已經通過共識處理的塊簽名
  • Snapshot:上一個時期的驗證者投票狀態

Consensus

Proposer 必須在每個 round中連續不斷的為consensus 生成 block prorosal。

istanbul BFT 包括 3 個階段的共識:PRE-PREPARE,PREPARE,COMMIT。

容錯機制: N = 3F +1 ;N表示驗證節點,F表示錯誤節點。

在每輪之前將會以迴圈的方式選擇一個 validator 作為 proposer. 接著 proposer將會提出一個新的 block proposal 並且廣播通過 pre-prepare 訊息。一旦接受到 pre-prepare訊息 ,validators將會進入到 pre-prepared 階段並且廣播 prepare 訊息。這個步驟是為了確保 validators 執行在相同的 sequence 和相同的 round 中。當接收到2F+1 的Prepare訊息時,validators 進入到 prepared並且廣播 commit 訊息。此步驟是通知其它節點接受建議的塊並將塊插入鏈。 最後,validator等待2F + 1 COMMIT訊息進入COMMITTED狀態,然後將塊插入鏈。

注意:Istanbul中 的塊是最終的,沒有分叉,任何有效的塊必須位於主鏈的某個位置。

為了防止故障節點從主鏈生成完全不同的鏈,每個驗證器將2F + 1個接收到的COMMIT簽名附加到標頭中的extraData欄位,然後將其插入鏈中, 因此,塊是可自我驗證的,並且也可以支援輕客戶端。但是,動態extraData會導致塊雜湊計算出現問題。由於來自不同驗證器的相同塊可以具有不同的COMMIT簽名集,因此同一塊也可以具有不同的塊雜湊。 為了解決這個問題,我們通過排除COMMIT簽名部分來計算塊雜湊。 因此,我們仍然可以保持塊/塊雜湊一致性,並將共識證明放在塊頭中。

Consensus states

Istanbul BFT是一種狀態機複製演算法。 每個驗證器都維護一個狀態機副本,以達到塊一致性。

States:

  • NEW ROUND: Proposer傳送新的 block proposal。 Validator等待PRE-PREPARE訊息。
  • PRE-PREPARED:驗證器已收到PRE-PREPARE訊息並廣播PREPARE訊息。 然後它等待2F + 1 個PREFARE或COMMIT訊息。
  • PREPARED: 驗證器已收到2F + 1個PREPARE訊息並廣播COMMIT訊息。 然後它等待2F + 1 COMMIT訊息。
  • COMMITTED:驗證器已收到2F + 1個COMMIT訊息,並能夠將建議的塊插入區塊鏈。
  • FINAL COMMITTED:新塊已成功插入區塊鏈,validator 已準備好進入下一輪。
  • ROUND CHANGE:驗證器正在等待同一個建議的輪數上的2F + 1個ROUND CHANGE訊息。

State transitions

  • NEW ROUND -> PRE-PREPARED:
    • Proposer 從txpool 中收集交易
    • Proposer生成塊提議並將其廣播給驗證者。 然後它進入PRE-PREPARED狀態。
    • 每個validator在收到具有以下條件的PRE-PREPARE訊息後進入PRE-PREPARED:
      • 塊提案來自有效的提案人。
      • 塊頭有效
      • 塊提議的sequence和round匹配validator的狀態
    • Validator廣播PREPARE訊息給其他validators
  • PRE-PREPARED -> PREPARED:
    • Validator接收2F + 1個有效的PREPARE訊息以進入PREPARED狀態。 有效訊息符合以下條件:
      • 匹配 sequence 和 round
      • 匹配block hash
      • 訊息來自於已知 validators
  • COMMITTED -> FINAL COMMITTED:
    • validator 將 2F+1 個提交的簽名放到 extraData中並且嘗試將區塊上鍊
    • 插入成功後,Validator進入FINAL COMMITTED狀態。
  • FINAL COMMITTED -> NEW ROUND:
    • 驗證器選擇一個新的提議器並啟動一個新的round timer 。

Round change flow

  • 3 個條件將會觸發 ROUND CHANGE
    • Round change timer 過期
    • 無效 PREPREPARE 訊息
    • 塊插入失敗
  • 當驗證器注意到上述條件之一適用時,它會廣播ROUND CHANGE訊息以及建議的 round number,並等待來自其他驗證器的ROUND CHANGE訊息。 建議的round number 根據以下條件選擇:
    • 如果驗證器已從其peers接收到ROUND CHANGE訊息,則它將選擇具有F + 1個ROUND CHANGE訊息的最大 round number。
    • 否則,它會選擇1 +當前的round number作為建議的輪數。
  • 每當驗證器在同一個建議的輪數上收到F + 1個ROUND CHANGE訊息時,它就會將收到的訊息與它自己的一個進行比較。 如果接收的數量較大,驗證器將再次使用收到的號碼廣播ROUND CHANGE訊息。
  • 在相同的建議round number上接收到2F + 1個ROUND CHANGE訊息後,驗證器退出round change loop,計算新的提議者,然後進入NEW ROUND狀態。
  • 驗證器跳出round change loop的另一個條件是它通過對等同步接收驗證的塊。

Proposer selection

目前我們支援兩種策略:round robinsticky proposer.。

  • Round robin:在迴圈設定中,提議者將在每個塊和round change中進行更改
  • Sticky proposer: 在 sticky proposer中, proposal只有在發生一輪變更時才會改變。

Validator list voting

我們使用與Clique類似的驗證器投票機制,並複製Clique EIP的大部分內容。 每個epoch交易都會重置驗證器投票,這意味著如果授權或取消授權投票仍在進行中,則投票過程將被終止。

對於所有交易塊:

  • Proposer可以投一票來建議更改驗證人名單。
  • 每個目標受益人的最新提案僅保留一個驗證人。
  • 隨著鏈條的進展,投票將被實時統計(允許同時提議)。
  • 達到多數共識的proposals ,VALIDATOR_LIMIT立即生效。
  • 無效的提案不會因客戶端實現簡單而受到懲罰。
  • 一項生效的提案需要放棄該提案的所有未決投票(贊成和反對),並以 clean state 開始

Future message and backlog

在非同步網路環境中,可以接收將來無法在當前狀態下處理的訊息。 例如,驗證器可以在NEW ROUND上接收COMMIT訊息。 我們將此類訊息稱為“未來訊息”。 當驗證程式收到將來的訊息時,它會將訊息放入其待辦事項中,並儘可能在稍後嘗試處理。

Optimization

為了加速共識過程,在接收PREFARE訊息的2F + 1之前接收到2F + 1 COMMIT訊息的驗證器將跳轉到COMMITTED狀態,這樣就不必等待進一步的PREPARE訊息。

Constants

我們定義以下常量:

  • EPOCH_LENGTH:檢查點和重置待處理投票之後的塊數。
    • 建議30000使testnet保持類似於主要網路ethash時代。
  • REQUEST_TIMEOUT: 在以毫秒為單位進行輪次更改之前,每個達成一致的超時。
  • BLOCK_PERIOD: 兩個連續塊之間的最小時間戳差異(秒)。
  • PROPOSER_POLICY:提議者選擇策略,預設為round robin.。
  • ISTANBUL_DIGEST:固定的 magic number, 0x63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365用於Istanbul塊識別的塊頭中的mixDigest。
  • DEFAULT_DIFFICULTY: 預設塊難度,設定為0x0000000000000001。
  • EXTRA_VANITY: 固定數量的額外資料字首位元組預留給提議者。
    • 建議保留當前額外資料容量和/或使用的32個位元組。
  • NONCE_AUTH: magic nonce number 0xffffffffffffffff投票新增驗證器。
  • NONCE_DROP:magic nonce number 0x0000000000000000 投票移除驗證器
  • UNCLE_HASH:總是Keccak256(RLP([]))作為叔叔在PoW之外沒有意義。
  • PREPREPARE_MSG_CODE: 固定編號0. PREPREPARE訊息的訊息程式碼。
  • COMMIT_MSG_CODE: 固定編號1. COMMIT訊息的訊息程式碼。
  • ROUND_CHANGE_MSG_CODE:固定號碼2. ROUND CHANGE訊息的訊息程式碼。

我們還定義了以下每塊常量:

  • BLOCK_NUMBER: 鏈中的塊高度,其中生成塊的高度為0。
  • N: 授權驗證人數。
  • F:允許的錯誤驗證器數量。
  • VALIDATOR_INDEX:當前授權驗證器的排序列表中的塊驗證器的索引。
  • VALIDATOR_LIMIT: 傳遞授權或取消授權提議的驗證者數量。
    • 必須是最低限額(N / 2)+ 1才能對鏈條達成多數共識。

Block header

我們沒有為伊斯坦布林BFT發明新的塊頭。 相反,我們跟隨Clique重新調整ethash標頭欄位,如下所示:

  • beneficiary: 建議修改驗證器列表的地址。

    • 應該通常用零填充,僅在投票時修改。
    • 儘管如此,允許使用任意值(即使是無意義的值,例如投票給非驗證者),以避免投票機制實施中的額外複雜性。
  • nonce:關於受益人領域定義的帳戶的提議者提案。

    • 應該是NONCE_DROP建議取消授權受益人作為現有驗證人。
    • 應該是NONCE_AUTH建議授權受益人作為新的驗證人。
    • 必須填充零,NONCE_DROP或NONCE_AUTH
  • mixHash: 固定 magic number 0x63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365 用於伊斯坦布林區塊識別

  • ommersHash:必須是UNCLE_HASH,因為在PoW之外,叔叔沒有意義。

  • timestamp:必須至少是父時間戳+ BLOCK_PERIOD

  • difficulty:必須填寫0x0000000000000001。

  • extraData: 簽名者和RLP編碼的伊斯坦布林額外資料的組合欄位,其中伊斯坦布林額外資料包含驗證器列表,proposer seal和 commit seal。 伊斯坦布林的額外資料定義如下:

     type IstanbulExtra struct {
     	Validators    []common.Address 	//Validator addresses
     	Seal          []byte			//Proposer seal 65 bytes
     	CommittedSeal [][]byte			//Committed seal, 65 * len(Validators) bytes
     }
    

    因此extraData將採用EXTRA_VANITY |的形式 ISTANBUL_EXTRA其中| 表示用於分隔vanity和伊斯坦布林額外資料的固定索引(不是分隔符的實際字元)。

    • 第一個EXTRA_VANITY位元組(固定)可以包含任意提議者vanity資料。
    • ISTANBUL_EXTRA位元組是從RLP(IstanbulExtra)計算的RLP編碼的伊斯坦布林額外資料,其中RLP()是RLP編碼功能,而IstanbulExtra是伊斯坦布林額外資料。
      • Validators: 驗證器列表,必須按升序排序。
      • Seal: 提議者的header seal 簽名。
      • CommittedSeal:提交的簽名列表作為共識證明

Block hash, proposer seal, and committed seals

由於以下原因,Istanbul塊雜湊計算與ethash塊雜湊計算不同:

  1. 提議者需要將提議者密封在extraData中以證明該塊由所選提議者簽名。
  2. 驗證者需要將2F + 1個已提交的密封作為extraData中的共識證明,以證明該塊已經達成共識。

計算仍然類似於ethash塊雜湊計算,但我們需要處理extraData。 我們按如下方式計算欄位:

Proposer seal calculation

在提議者密封計算時,committed的密封仍然是未知的,因此我們計算密封與那些未知的密封空。 計算如下:

  • Proposer seal: SignECDSA(Keccak256(RLP(Header)), PrivateKey)
  • PrivateKey: Proposer's的私鑰
  • Header: 和ethash 的header一樣,只不過extradata不一樣
  • extraData: vanity | RLP(IstanbulExtra), 在IstanbulExtra, CommittedSealand Seal` 是空陣列.
Block hash calculation

在計算塊雜湊時,我們需要排除已提交的密封,因為該資料在不同的驗證器之間是動態的。 因此,我們在計算雜湊時使CommittedSeal為空陣列。 計算如下:

  • Header: 和ethash 的header一樣,只不過extradata不一樣
  • extraData: vanity | RLP(IstanbulExtra), 在IstanbulExtra, CommittedSealand Seal` 是空陣列.
Consensus proof

在將塊插入區塊鏈之前,每個驗證器需要從其他驗證器收集2F + 1個已提交的密封以構成共識證明。 一旦它收到足夠的提交密封,它將填充IstanbulExtra中的CommittedSeal,重新計算extraData,然後將塊插入區塊鏈。 請注意,由於已提交的密封可能因不同的來源而不同,因此我們會在計算塊雜湊時排除該部分,如上一節所述。

Committed seal calculation:

committed seal由每個簽名雜湊的驗證器以及其私鑰的COMMIT_MSG_CODE訊息程式碼計算。 計算如下:

  • Committed seal: SignECDSA(Keccak256(CONCAT(Hash, COMMIT_MSG_CODE)), PrivateKey).
  • CONCAT(Hash, COMMIT_MSG_CODE): 連線 block hash and COMMIT_MSG_CODE bytes.
  • PrivateKey: 簽署驗證者的私鑰。

Block locking mechanism

引入鎖定機制以解決安全問題。 通常,當提議者用塊B鎖定在某個高度H時,它只能為高度H提出B.另一方面,當驗證器被鎖定時,它只能在B上投票選擇高度H.

Lock

鎖定鎖(B,H)包含一個塊及其高度,這意味著它的所有驗證器當前被鎖定在某個塊B和高度H.在下面,我們還使用+表示多於和 - 表示小於。 例如,+ 2/3驗證器表示超過三分之二的驗證器,而-1/3驗證器表示不到三分之一的驗證器。

Lock and unlock

  • Lock:驗證器在高度為“H”的塊“B”上接收到“2F + 1”“PREPARE”訊息時被鎖定。
  • Unlock: 驗證器在高度“H”處解鎖,並在未能將塊“B”插入塊鏈時阻止“B”。

Protocol (+2/3 validators are locked with Lock(B,H))

  • PRE-PREPARE:

    • Proposer:

      • 情況1,提議者被鎖定:在B上廣播PRE-PREPARE,並進入PREPARED狀態。

      • 情況2,提議者未被鎖定:在塊B'上廣播PRE-PREPARE。

    • Validator:

      • 情況1,在現有塊上接收PRE-PREPARE:忽略。
        • 注意:它最終會導致輪次更改,並且提議者將通過同步獲得舊塊。
      • 情況2,驗證器被鎖定:
        • 案例2.1,在B上收到PRE-PREPARE:在B上廣播PREPARE
        • 案例2.2,在B'上接收PRE-PREPARE:廣播ROUND CHANGE。
      • 情況3,驗證器未鎖定:
        • 情況3.1,在B上接收PRE-PREPARE:在B上廣播PREPARE
        • 案例3.2,在B'上接收PRE-PREPARE:在B'上廣播PREPARE。
          • 注意:由於+2/3被鎖定在B並且這將導致全面更改,因此此共識輪將最終進行全面更改。
  • PREPARE:

    • 案例1,驗證器被鎖定:
      • 情況1.1,在B上接收PREPARE:在B上廣播COMMIT,並進入PREPARED狀態。
        • 注意:這不應該發生,它應該跳過這一步並在PRE-PREPARE階段輸入PREPARED。
      • 案例1.2,在B'上收到PREPARE:忽略。
        • 注意:B'上不應該有+1/3 PREPARE,因為+2/3被鎖定在B.因此B'上的共識輪將導致輪次更改。 驗證器不能直接在此廣播ROUND CHANGE,因為此PREPARE訊息可能來自故障節點。
    • 情況2,驗證器未鎖定:
      • 情況2.1,在B上收到PREPARE:在B上等待2F + 1 PREPARE訊息
        • 注意:在接收2F + 1 PREPARE訊息之前,它很可能會收到2F + 1 COMMIT訊息,因為有+2/3驗證器被鎖定在B.在這種情況下,它將直接跳轉到COMMITTED狀態。
      • 情況2.2,在B'上收到PREPARE:在B'上等待2F + 1 PREPARE訊息。
        • Note: This consensus will eventually get into round change since +2/3 validators are locked on B and which would lead to round change.
  • COMMIT:

    • 驗證者必須被鎖定:
      • 情況1,在B上收到COMMIT:等待2F + 1 COMMIT訊息。
      • 案例2,B'收到COMMIT:不應該發生。

Locking cases

  • Round change:
    • Case 1, +2/3 are locked:
      • 如果提議者被鎖定,則建議B.
      • 否則它會提出B',但這將導致另一輪變革。
      • 結論:最終B將由誠實的驗證者承諾。
    • Case 2, +1/3 ~ 2/3 are locked:
      • 如果提議者被鎖定,則建議B.
      • 否則它會提出B'。 但是,由於+1 / 3被鎖定在B,因此沒有驗證器可以在B'上接收2F + 1 PREPARE,這意味著沒有驗證器可以鎖定在B'。 此外,那些+1 / 3鎖定驗證器將不會響應B'並最終導致全面更改。
      • 結論:最終B將由誠實的驗證者承諾。
    • Case 3, -1/3 are locked:
      • 如果提議被鎖定,則建議B.
      • 否則它會提出B'。 如果+2/3在B'上達成共識,那些鎖定的-1/3將通過同步獲得B'並移動到下一個高度。 否則,將會有另一輪變更。
      • 結論:它可以是B或其他塊B'最終提交。
  • 插入失敗導致的round change:
    • 它將屬於上述一輪變更案例之一。
      • 如果塊實際上是壞的(不能插入區塊鏈),最終+2/3驗證器將在H處解鎖塊B並嘗試建議新的塊B'。
      • 如果塊是好的(可以插入區塊鏈),那麼它仍然是上述圓形更改案例之一。
  • -1/3驗證器成功插入塊,但其他驗證器成功觸發迴圈更改,這意味著+1 / 3仍鎖定在鎖定(B,H)
    • 案例1,提議者已插入B:提議者將在H'提出B',但+1 / 3被鎖定在B,因此B'將不會通過共識,這最終將導致輪次更改。 其他驗證器將對B執行共識或通過同步獲得B.
    • 案例2,提議者未插入B:
      • 案例2.1,提議者被鎖定:提議者提出B.
      • 案例2.2,提議者未被鎖定:提議者將在H處提出B'。其餘與上述案例1相同。
  • +1/3驗證器成功插入塊,-2 / 3試圖在H處觸發圓形更改
    • 案例1,提議者已插入B:提議者將在H'提出B',但在+1/3通過同步獲得B之前不會通過共識。
    • 案例2,提議者未插入B:
      • 案例2.1,提議者被鎖定:提議者提出B.
      • 案例2.2,提議者未被鎖定:提議者在H處提出B'。其餘與上述案例1相同。
  • +2/3驗證器成功插入塊,-1 / 3試圖在H處觸發圓形更改
    • 案例1,提議者已插入B:提議者將在H'提出B',這可能會導致成功的共識。 然後那些-1/3需要通過同步獲得B.
    • 案例2,提議者未插入B:
      • 案例2.1,提議者被鎖定:提議者提出B.
      • 案例2.2,提議者沒有被鎖定:提議者在H處建議B'。因為+2/3已經在H處有B,所以這一輪將導致輪次改變。

Gossip network

傳統上,驗證者需要緊密連線才能達到穩定的共識結果,這意味著所有驗證者需要彼此直接連線; 但是,在實際的網路環境中,很難實現穩定和恆定的p2p連線。 為了解決這個問題,伊斯坦布林BFT實施了八卦網路來克服這種限制。 在八卦網路環境中,所有驗證器只需要弱連線,這意味著當它們直接連線或者它們之間連線有一個或多個驗證器時,任何兩個驗證器都會被連線。 共識訊息將在驗證器之間中繼。