Hyperledger Fabric Transaction Proposal過程


客戶端將交易預提案(Transaction Proposal)通過 gRPC 發送給支持 Endorser 角色的 Peer 進行背書。

這些交易提案可能包括鏈碼的安裝、實例化、升級、調用、查詢;以及 Peer 節點加入和列出通道操作。

Peer 接收到請求后,會調用 core/endorser/endorser.go 中 Endorser 結構體 的ProcessProposal(ctx context.Context, signedProp *pb.SignedProposal) (*pb.ProposalResponse, error) 方法,進行具體的背書處理。

背書過程主要完成如下操作:

  • 檢查提案消息的合法性,以及相關的權限;
  • 模擬執行提案:啟動鏈碼容器,對世界狀態的最新版本進行臨時快照,基於它執行鏈碼,將結果記錄在讀寫集中;
  • 對提案內容和讀寫集合進行簽名,並返回提案響應消息。

整體過程

主要過程如下圖所示。

Endorser ProcessProposal 過程

  • 檢查提案合法性;
    • 調用 ValidateProposalMessage() 方法對簽名的提案進行格式檢查,主要包括:
      • Channel 頭部格式:是否合法頭部類型,由 validateChannelHeader() 完成;
      • 簽名頭格式:是否包括了 nonce 和creators 數據,由 validateSignatureHeader() 完成;
      • 簽名域:creator 證書 MSP 檢查是否合法,簽名是否正確,由 checkSignatureFromCreator() 完成。
    • 如果是系統鏈碼調用(SCC),檢查是否是允許從外部調用的三種 SCC 之一:cscc、lscc、qscc 或 rscc;
    • 如果 chainID 不為空,獲取對應 chain 的賬本結構,並檢查 TxID 唯一性,確保同一交易未曾提交到賬本結構中;
    • 對於用戶鏈碼調用,需要檢查 ACL:資源為 PROPOSE,默認策略是簽名提案者在通道上擁有寫權限(CHANNELWRITERS)。
  • 模擬執行提案
    • 如果 chainID 不為空,獲取對應賬本的交易模擬器(TxSimulator)和歷史查詢器(HistoryQueryExecutor),這兩個結構將在后續執行鏈碼時被使用。
    • 如果 chainID 不為空,調用 simulateProposal() 方法獲取模擬執行的結果,檢查返回的響應 response 的狀態,若不小於錯誤 500 則創建並返回一個失敗的 ProposalResponse。
  • 對提案內容和讀寫集合進行簽名
    • chainID 非空情況下,調用 endorseProposal() 方法利用 ESCC,對之前得到的模擬執行的結果進行背書。返回 ProposalResponse,檢查 simulateProposal 返回的response 的狀態,若不小於錯誤閾值 400(被背書節點反對),返回 ProposalResponse 及鏈碼錯誤 chaincodeError(endorseProposal 里有檢查鏈碼執行結果的狀態,而 simulateProposal 沒有檢查)。
    • 將 response.Payload 賦給 ProposalResponse.Response.Payload(因為 simulateProposal 返回的 response 里面包含鏈碼調用的結果)。
    • 返回響應消息 ProposalResponse。

simulateProposal 方法

simulateProposal 方法會通過執行鏈碼邏輯來獲取對狀態的修改結果,並存放到讀寫集合中,主要過程如下:

  • 從提案結構的載荷中提取 ChaincodeInvocationSpec 結構,其中包含了所調用鏈碼(包括系統鏈碼和用戶鏈碼)的路徑、名稱和版本,以及調用時傳入的參數列表;
  • 檢查 ESCC 和 VSCC(尚未實現);
  • 對用戶鏈碼,檢查提案中的實例化策略跟賬本上記錄的該鏈碼的實例化策略(安裝鏈碼時指定)是否一致。防止有人修改權限在其它通道非法實例化。
  • 調用 callChaincode() 方法執行 Proposal,返回 Response 和 ChaincodeEvent。
    • 調用 core.endorser 包中 SupportImpl.Execute() 方法,該方法主要調用 core.chaincode 包中的 ExecuteChaincode() 方法,進一步調用包內的 Execute() 方法。調用過程中會把交易模擬器和歷史查詢器通過上下文結構體傳入后續子方法。
    • Execute() 方法會調用 ChaincodeSupport.Launch() 方法創建並啟動鏈碼容器。啟動成功后創建鏈碼 gRPC 消息,通過 ChaincodeSupport.Execute() 方法發送消息給 CC 容器,執行相關的合約,並返回執行響應(ChaincodeMessage 結構)。此過程中會將讀寫集記錄到交易模擬器結構體中。
  • 對於非空 chainID(大部分跟賬本相關的操作),執行 GetTxSimulationResults() 拿到執行結果 TxSimulationResults結構,從中可以解析出讀寫集數據。
  • 最終返回鏈碼標准數據結構 ChaincodeDefinition、響應消息 ChaincodeMessage、交易讀寫集 PubSimulationResults、鏈碼事件 ChaincodeEvent。

endorseProposal 方法

主要過程如下:

  • 獲取被調用的鏈碼指定的背書鏈碼的名字。
  • 通過 callChaincode() 實現對背書鏈碼的調用,返回響應 response(對 ESCC 的調用同樣也會產生 simulation results,但 ESCC 不能背書自己產生的simulation results,需要背書最初被調用的鏈碼產生的 simulation results)。
  • 檢查 response.Status,是否大於等於 400(錯誤閾值),若是則把 response 賦給 proposalResponse.Response 並返回 proposalResponse。
  • 將 response.Payload解碼后(ProposalResponse類型)返回。

callChaincode 方法

主要過程如下:

  • 判斷交易模擬器,不為空則把它加入到Context的K-V存儲中。
  • 判斷被call的cc是不是系統鏈碼,創建CCContext(包含通道名、鏈碼名、版本號、交易ID、是否 SCC、簽名 Prop、Prop)
  • 調用 core/chaincode/chaincodeexec.go 下的 ExecuteChaincode(),返回響應 response 和 事件ccevent。
  • 返回 response和ccevent。

來源:https://github.com/yeasy/hyperledger_code_fabric/blob/master/process/chaincode_start.md


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM