天天看點

CITA 共識

共識

CITA 的共識子產品主要是保證多個節點對于交易的順序和 Block 的内容達成一緻。在衆多的分布式算法中, 我們選擇實作了非拜占庭容錯的 Raft 算法和拜占庭容錯的的 CITA-BFT 算法。

共識的架構

共識主要有 MQ(消息隊列)通訊子產品、交易池、定時子產品、WAL(write ahead log)、算法邏輯子產品。

+-------------+       +-------------+       +-----+
   | MQ通訊子產品   |<----->| 算法邏輯子產品 |<----> | WAL |
   +-------------+       +-------------+       +-----+
          ^                ^    ^
          |                |    |
          |----------------+    |
          |                     |
     +--------+           +-----------+
     | 交易池  |           | 定時子產品  |
     +--------+           +-----------+
           

MQ 通訊子產品: CITA 的消息通過 MQ 進行周轉,MQ 通訊子產品負責訂閱、釋出基于 MQ 的消息。

交易池: 交易池訂閱和存儲交易資訊,并提供交易的打包、生成 Block。還進行交易的持久化,實作快速确認的功能。

定時子產品: 提供算法定時服務。使用者向定時子產品發送定時請求,定時子產品在時間到達後,發送确認資訊。

WAL: WAL 提供預寫日志(write ahead log)的服務,持久化各個節點的投票。用來進行節點崩潰後恢複。

算法邏輯子產品: 分布式算法邏輯的實作子產品,接受共識其它子產品發送過來的資訊,根據自身的算法要求,進行算法邏輯相應的處理。 例如對于 CITA-BFT 就需要進行一系列的狀态轉換。

基本前提

  • 每個共識節點知道其它共識節點的公鑰
  • 每個共識節點發送的投票資訊,都必須有自己的簽名
  • 共識節點根據公鑰和簽名可以驗證消息的真實性
  • 共識節點數量需要滿足算法要求的基本數量

基本步驟

雖然分布式算法多種多樣,具體落實在 CITA 中,基本上需要進行如下的步驟:

  • 共識子產品從消息隊列中訂閱交易資訊,放入交易池。如果應用有快速确認的需求,交易池可以對交易進行持久化。
  • 共識算法根據配置和算法要求,選擇一個出塊的節點。該出塊節點把塊的哈希值(Block.Hash)作為共識的主要資訊通過 MQ 通訊子產品向其它的節點進行廣播。
  • 當出塊節點進過一輪或者多輪投票,收到算法要求的法定多數的投票傳回時,向 Chain 子產品确認出塊,否則進入重新選擇出塊節點的計算,由下一個出塊節點繼續出塊。
  • 接收 Chain 傳回的狀态資訊,作為出塊成功的标志。
  • 出塊成功後,從交易池删除已經達成共識的交易。

Raft 算法

Raft 作為非拜占庭容錯的算法,主要是主節點出塊。主節點有故障時,從節點會啟動重新選主的流程,是以 Raft 的機制主要分為兩部分:選主流程和 主節點同步資訊流程。

選主流程:

  1. 每個節點發送提升請求給其他節點。
  2. 收到 1/2+的投票的節點,升為主節點。
  3. 如果有沖突,采用随機退避的方式,再次投票。

主節點同步資訊:

  1. 主節點打包交易,出塊,把塊發送給從節點。
  2. 從節點收到後發送确認資訊傳回。
  3. 主節點收到 1/2+确認後,發送确認資訊給從節點。
  4. 主節點持久化和發送 Block 到 Chain 進行計算。

CITA-BFT 算法

CITA-BFT 狀态轉換

NewHeight -> (Propose -> Prevote -> Precommit)+ -> Commit -> NewHeight -> ...


                            +-------------------------------------+
                            v                                     |(Wait til `CommmitTime+timeoutCommit`)
                      +-----------+                         +-----+-----+
         +----------> |  Propose  +--------------+          | NewHeight |
         |            +-----------+              |          +-----------+
         |                                       |                ^
         |(Else, after timeoutPrecommit)         v                |
   +-----+-----+                           +-----------+          |
   | Precommit |  <------------------------+  Prevote  |          |
   +-----+-----+                           +-----------+          |
         |(When +2/3 Precommits for block found)                  |
         v                                                        |
   +--------------------------------------------------------------------+
   |  Commit                                                            |
   |                                                                    |
   |  * Set CommitTime = now;                                           |
   |  * Wait for block, then stage/save/commit block;                   |
   +--------------------------------------------------------------------+
           
  1. proposal 階段:proposal 節點打包交易池中的交易,WAL 記錄後,通過 MQ 通訊子產品,發送 proposal 消息給共識的其它節點,然後進入 prevote 階段。而非 proposal 節點在進行一段時間的逾時後,進入 prevote 投票階段。
  2. prevote 階段:每個共識節點根據收到的 proposal 資訊,進行 prevote 投票。校驗成功則 prevote block.hash,校驗失敗或者沒有收到 proposal 資訊則 prevote 空票。
  3. prevote 等待階段:等待節點收到 2/3 節點以上的 prevote 投票,在必要的逾時後,進入 precommit 階段。
  4. precommit 階段:節點根據 prevote 階段收到的投票進行判斷,如果收到相同 block.hash 的 prevote 投票,超過 2/3,則 precommit block.hash,否則 precommit 空值
  5. precommit 等待階段:等待收到的 precommit 投票數超過節點數的 2/3。如果收到 precommit 相同 block.hash 投票超過 2/3 時,進入 commit 階段。否則進入新一輪的 proposal 的階段。
  6. commit 階段:共識子產品把共識完成的 block 發送給 chain 子產品後,等待 chain 子產品的計算完成後發送的狀态資訊,然後進入下一個高度 NewHeight。

CITA-BFT 交易池操作流程

  1. 交易池啟動時,嘗試從 KV 資料庫恢複資料
  2. 交易池訂閱 MQ 的交易資訊
  3. 交易池收到交易後,持久化到 KV 資料庫
  4. 交易池收到打包請求,檢查交易的有效性,輸出有效交易清單
  5. 交易池根據出塊的交易清單,删除已經上鍊的交易

CITA-BFT 故障重新開機流程

  1. 從 WAL 子產品中,恢複某個塊高度的投票資訊
  2. 根據恢複後的狀态資訊,重複投票資訊
  3. 程序根據目前狀态,繼續運作