Hyperledger Fabric 交易過程中讀寫集語義
https://hyperledger-fabric.readthedocs.io/zh_CN/latest/readwrite.html
交易模擬和讀寫集
背書節點
在模擬交易期間,會爲交易準備一個讀寫集。讀集
包含了模擬期間交易讀取的鍵和鍵的版本的列表。寫集
包含了交易寫入鍵(可以與讀取集中的鍵重疊)的新值。如果交易是刪除一個鍵,該鍵就會被增加一個刪除標識(在新值的位置)。
如果交易多次向同一個鍵寫入數據,只有最後寫入的數據會記錄下來。同樣,如果交易讀取一個鍵的值,就會返回這個鍵的已提交狀態的值,即使讀取之前在同一個交易中更新了鍵值。換句話說,不支持“讀你所寫”的語義。
就像前面所說的,鍵的版本只記錄在讀集中;寫集只包含鍵和交易設置的鍵的最新值。
版本的實現有很多種。版本設計的基本需求是,鍵不能有重複的版本號。例如單調遞增的數字。**在目前的實現中,我們使用交易所在的區塊高度來作爲交易中所有修改的鍵的版本號。**這樣區塊中交易的高度通過一個元組來表示(txNumber 是區塊中交易的高度)。這種方式比遞增的數字有更多好處,主要有,它可以讓其他組件比如狀態數據庫、交易模擬和驗證有更多的設計選擇。
下邊是爲模擬一個交易所準備的讀寫集示例。爲了簡化說明,我們使用了一個遞增的數字來表示版本。
<TxReadWriteSet>
<NsReadWriteSet name="chaincode1">
<read-set>
<read key="K1", version="1">
<read key="K2", version="1">
</read-set>
<write-set>
<write key="K1", value="V1">
<write key="K3", value="V2">
<write key="K4", isDelete="true">
</write-set>
</NsReadWriteSet>
<TxReadWriteSet>
另外,如果交易在模擬中執行的是一個範圍查詢,範圍查詢和它的結果都會被記錄在讀寫集的 查詢信息(query-info)
中。
交易驗證和使用讀寫集更新世界狀態
提交節點
使用讀寫集中的讀集來驗證交易,使用寫集來更新受影響的鍵的版本和值。
在驗證階段,如果讀集中鍵的版本和世界狀態中鍵的版本一致就認爲該交易是 有效的
,這裏我們假設所有之前 有效
的交易(同一個區塊中該交易之前的交易)都會被提交(提交狀態)。當讀寫集中包含一個或多個查詢信息(query-info)時,需要執行額外的驗證。
這種額外的驗證需要確保在根據查詢信息獲得的結果的超集(多個範圍的合併)中沒有插入、刪除或者更新鍵。 換句話說,如果我們在模擬執行交易期間重新執行任何一個範圍,我們應該得到相同的結果。這個檢查保證瞭如果交易在提交期間出了虛項,該交易就會被標記爲無效的。這種檢查只存在於範圍查詢中(例如鏈碼中的 GetStateByRange 方法)其他查詢中沒有實現(例如鏈碼中的 GetQueryResult 方法)。其他查詢仍會存在出現虛項的風險,我們應該只在不向排序服務提交的只讀交易中使用查詢,除非應用程序能保證模擬的結果和驗證/提交時的結果一致。
如果交易通過了有效性驗證,提交節點就會根據寫集更新世界狀態。在更新階段,會根據寫集更新世界狀態中對應的鍵的值。然後,世界狀態中鍵的版本會更新到最新的版本。
模擬和驗證示例
本章節通過示例場景幫助你理解讀寫集語義。在本例中,k
表示鍵,在世界狀態中表示一個元組 (k,ver,val)
, ver
是鍵 k
的版本, val
是值。
現在假設有五個交易 T1,T2,T3,T4 和 T5
,所有的交易模擬都基於同一個世界狀態的快照。下邊的步驟展示了世界狀態和模擬這些交易時的讀寫活動。
World state: (k1,1,v1), (k2,1,v2), (k3,1,v3), (k4,1,v4), (k5,1,v5)
T1 -> Write(k1, v1'), Write(k2, v2')
T2 -> Read(k1), Write(k3, v3')
T3 -> Write(k2, v2'')
T4 -> Write(k2, v2'''), read(k2)
T5 -> Write(k6, v6'), read(k5)
現在,假設這些交易的順序是從 T1 到 T5(他們可以在同一個區塊,也可以在不同區塊)
-
T1
通過了驗證,因爲它沒有執行任何讀操作。然後世界狀態中的鍵k1
和k2
被更新爲(k1,2,v1'), (k2,2,v2')
-
T2
沒有通過驗證,因爲它讀了鍵k1
,但是交易T1
改變了k1
-
T3
通過了驗證,因爲它沒有執行任何讀操作。然後世界狀態中的鍵k2
被更新爲(k2,3,v2'')
-
T4
沒有通過驗證,因爲它讀了鍵k2
,但是交易T1
改變了k2
-
T5
通過了驗證,因爲它讀了鍵k5
,但是k5
沒有被其他任何交易改變
注意:不支持有多個讀寫集的交易。