1. 提交交易預案
1)應用端首先構建交易的預案,預案的作用是調用通道中的鏈碼來讀取或者寫入賬本的數據。應用端使用 Fabric 的 SDK 打包交易預案,並使用用戶的私鑰對預案進行簽名。
應用打包完交易預案后,接着把預案提交給通道中的背書節點。通道的背書策略定義了哪些節點背書后交易才能有效,應用端根據背書策略選擇相應的背書節點,並向它們提交交易預案。
2. 背書節點處理
2)背書節點收到交易預案后,首先校驗交易的簽名是否合法,然后根據簽名者的身份,確認其是否具有權限進行相關交易。此外,背書節點還需要檢查交易預案的格式是否正確以及是否之前提交過(防止重放攻擊)。
在所有合法性校驗通過后,背書節點按照交易預案,調用鏈碼。鏈碼執行時,讀取的數據(鍵值對)是節點中本地的狀態數據庫。需要指出的是,鏈碼在背書節點中是模擬執行,即對數據庫的寫操作並不會對賬本作改變,所有的寫操作將歸總到一個寫入的集合( Write Set )中記錄下來。
在鏈碼執行完成之后,將返回鏈碼讀取過的數據集( Read Set )和鏈碼寫入的數據集( Write Set )。讀集和寫集將在確認節點中用於確定交易是否最終寫入賬本。
3. 返回響應結果
3)背書節點把鏈碼模擬執行后得到的讀寫集( Read-Write Set )等信息簽名后發回給預案提交方(應用端)。
4.發送排序節點
4)應用端在收到背書響應之后,檢查背書節點的簽名和比較不同節點背書的結果是否一致。如果預案是查詢賬本的請求,則應用端無需提交交易給排序節點。如果是更新賬本的請求,應用端在收集到滿足背書策略的背書響應數量之后,把背書預案中得到的讀寫集、所有背書節點的簽名和通道號發給排序節點。
5.排序節點處理
5)排序節點在收到各個節點發來的交易后,並不檢查交易的全部內容,而是按照交易中的通道號對交易分類排序,然后把相同通道的交易打包成數據塊( blob )。
6.發送交易區塊
6)排序節點把打包好的數據塊廣播給通道中所有的成員。數據塊的廣播有兩種觸發條件,一種是當通道的交易數量達到某個預設的閾值,另一種是在交易數量沒有超過閾值但距離上次廣播的時間超過某個特定閾值,也可觸發廣播數據塊。兩種方式相結合,使得排序過的交易可以及時廣播出去。
7.檢驗區塊交易
7)確認節點收到排序節點發來的交易數據塊后,逐筆檢查區塊中的交易。先檢查交易的合法性以及該交易是否曾經出現過。然后調用 VSCC( Validation System Chaincode )的系統鏈碼檢驗交易的背書簽名是否合法,以及背書的數量是否滿足背書策略的要求。接下來進行多版本並發控制 MVCC 的檢查,即校驗交易的讀集(Read Set)是否和當前賬本中的版本一致(即沒有變化)。如果沒有改變,說明交易寫集(Write Set)中對數據的修改有效,把該交易標注為有效,交易的寫集更新到狀態數據庫中。
如果當前賬本的數據和讀集版本不一致,則該交易被標注為無效,不更新狀態數據庫。數據塊中的交易數據在標注成“有效”或“無效”后封裝成區塊(block)寫入賬本的區塊鏈中。
上述的交易流程中,采用了 MVCC 的樂觀鎖( optimistic locking )模型,提高了系統的並發能力。需要注意的是,MVCC 也帶來了一些局限性。例如,在同一個區塊中若有兩個交易先后對某個數據項做更新,順序在后的交易將失敗,因為它的讀集版本和當前數據項版本已經不一致(因為之前的交易更新了數據)。