Hyperledger fabric共識與交易
Fabric 的共識過程包括 3 個階段:背書、排序和校驗。
背書
在背書( endorsement )階段中,背書節點對客戶端發來的交易預案進行合法性檢驗,然後模擬執行鏈碼得到交易結果,最後根據設定的背書邏輯判斷是否支援該交易預案。如果背書邏輯決定支援交易預案,它將把預案簽名後發回給客戶端。
客戶端通常需要根據鏈碼的背書策略,向一個或者多個成員的背書節點發出背書請求。背書策略會定義需要哪些節點背書交易才有效,例如需要5個成員的背書節點中至少3個同意;或者某個特殊身份的成員支援等。客戶端只有在收集滿足背書策略的支援之後,廣播出去的交易才能被視為有效。
排序
排序( ordering )階段就是由排序服務對交易進行排序,確定交易之間的時序關係。排序服務把一段時間內收到的交易進行排序,然後把排序後的交易打包成資料塊(區塊),再把區塊廣播給通道中的成員。採用這種方式,各個成員收到的是一組發生順序相同的交易,從而保證了所有節點的資料一致性。
Fabric 1.0 中的排序服務支援可插拔的架構,除了提供的 SOLO 和 Kafka 模式外,使用者可以新增第三方的排序服務。SOLO 是單機確認模式,僅適合開發測試中使用。Kafka 模式是基於 Kafka 開源的分散式資料流平臺,具有高擴充套件性和容錯能力,適合用在生產系統。需要注意的是,Kafka 只提供了 CFT 型別的容錯能力,即僅可對節點的一般故障失效容錯,缺乏對節點故意作惡的行為進行容錯的能力。
排序服務是共識機制中重要的一環,所有交易都要通過排序服務的排序才可以達成全網共識,因此排序服務要避免成為網路上的效能瓶頸。
校驗
校驗( validation )階段是確認節點對排序後的交易進行一系列的檢驗,包括交易資料的完整性檢查、是否重複交易、背書籤名是否符合背書策略的要求、交易的讀寫集是否符合多版本併發控制 MVCC ( Multiversion Concurrency Control )的校驗等等。當交易通過了所有校驗之後,將被標註為合法並寫入賬本中。因為所有的確認節點都按照相同的順序檢驗交易,並且把合法的交易依次寫入賬本中,因此它們的狀態能夠始終保持一致。
基於上面的共識機制,應用端首先構建交易的預案,預案的作用是呼叫通道中的鏈碼來讀取或者寫入賬本的資料。應用端使用 Fabric 的 SDK 打包交易預案,並使用使用者的私鑰對預案進行簽名。
應用打包完交易預案後,接著把預案提交給通道中的背書節點。通道的背書策略定義了哪些節點背書後交易才能有效,應用端根據背書策略選擇相應的背書節點,並向它們提交交易預案。
2)背書節點收到交易預案後,首先校驗交易的簽名是否合法,然後根據簽名者的身份,確認其是否具有許可權進行相關交易。此外,背書節點還需要檢查交易預案的格式是否正確以及是否之前提交過(防止重放攻擊)。
在所有合法性校驗通過後,背書節點按照交易預案,呼叫鏈碼。鏈碼執行時,讀取的資料(鍵值對)是節點中本地的狀態資料庫。需要指出的是,鏈碼在背書節點中是模擬執行,即對資料庫的寫操作並不會對賬本作改變,所有的寫操作將歸總到一個寫入的集合( Write Set )中記錄下來。
在鏈碼執行完成之後,將返回鏈碼讀取過的資料集( Read Set )和鏈碼寫入的資料集( Write Set )。讀集和寫集將在確認節點中用於確定交易是否最終寫入賬本。
3)背書節點把鏈碼模擬執行後得到的讀寫集( Read-Write Set )等資訊簽名後發回給預案提交方(應用端)。
4)應用端在收到背書響應之後,檢查背書節點的簽名和比較不同節點背書的結果是否一致。如果預案是查詢賬本的請求,則應用端無需提交交易給排序節點。如果是更新賬本的請求,應用端在收集到滿足背書策略的背書響應數量之後,把背書預案中得到的讀寫集、所有背書節點的簽名和通道號發給排序節點。
5)排序節點在收到各個節點發來的交易後,並不檢查交易的全部內容,而是按照交易中的通道號對交易分類排序,然後把相同通道的交易打包成資料塊( blob )。
6)排序節點把打包好的資料塊廣播給通道中所有的成員。資料塊的廣播有兩種觸發條件,一種是當通道的交易數量達到某個預設的閾值,另一種是在交易數量沒有超過閾值但距離上次廣播的時間超過某個特定閾值,也可觸發廣播資料塊。兩種方式相結合,使得排序過的交易可以及時廣播出去。
7)確認節點收到排序節點發來的交易資料塊後,逐筆檢查區塊中的交易。先檢查交易的合法性以及該交易是否曾經出現過。然後呼叫 VSCC( Validation System Chaincode )的系統鏈碼檢驗交易的背書籤名是否合法,以及背書的數量是否滿足背書策略的要求。
接下來進行多版本併發控制 MVCC 的檢查,即校驗交易的讀集(Read Set)是否和當前賬本中的版本一致(即沒有變化)。如果沒有改變,說明交易寫集(Write Set)中對資料的修改有效,把該交易標註為有效,交易的寫集更新到狀態資料庫中。
如果當前賬本的資料和讀集版本不一致,則該交易被標註為無效,不更新狀態資料庫。資料塊中的交易資料在標註成“有效”或“無效”後封裝成區塊(block)寫入賬本的區塊鏈中。
上述的交易流程中,採用了 MVCC 的樂觀鎖( optimistic locking )模型,提高了系統的併發能力。需要注意的是,MVCC 也帶來了一些侷限性。例如,在同一個區塊中若有兩個交易先後對某個資料項做更新,順序在後的交易將失敗,因為它的讀集版本和當前資料項版本已經不一致(因為之前的交易更新了資料)。