Fabric 智能合約具體代碼模板分析
Fabric的智能合約稱爲鏈碼(chaincode),分爲系統鏈碼和用戶鏈碼。系統鏈碼用來實現系統層面的功能,用戶鏈碼實現用戶的應用功能。鏈碼被編譯成一個獨立的應用程序,運行於隔離的Docker容器中。
和以太坊相比,Fabric鏈碼和底層賬本是分開的,升級鏈碼時並不需要遷移賬本數據到新鏈碼當中,真正實現了邏輯與數據的分離,同時,鏈碼採用Go、Java、Nodejs語言編寫。
Fabric鏈碼通過gprc與peer節點交互,
(1)當peer節點收到客戶端請求的輸入(propsal)後,會通過發送一個鏈碼消息對象(帶輸入信息,調用者信息)給對應的鏈碼。
(2)鏈碼調用ChaincodeBase裏面的invoke方法,通過發送獲取數據(getState)和寫入數據(putState)消息,向peer節點獲取賬本狀態信息和發送預提交狀態。
(3)鏈碼發送最終輸出結果給peer節點,節點對輸入(propsal)和 輸出(propsalreponse)進行背書籤名,完成第一段簽名提交。
(4)之後客戶端收集所有peer節點的第一段提交信息,組裝事務(transaction)並簽名,發送事務到orderer節點排隊,最終orderer產生區塊,併發送到各個peer節點,把輸入和輸出落到賬本上,完成第二段提交過程。
Fabric 智能合約鏈碼開發的基礎,一句話總結起來就是:一個基類,兩個查詢,一個寫入。
▲一個基類
Java中ChaincodeBase是自定義鏈碼的合約基類,裏面的run(ChaincodeStub stub, String function, String[] args)方法是peer調用鏈碼的入口函數,其中必須自定義一個init方法,用於合約初始化及升級初始化動作。代碼如下圖:
GO由於其動態接口的特性,不需要特別聲明實現合約接口。但是必須實現兩個接口方法:
▪ Init(stubshim.ChaincodeStubInterface) :init用於合約初始化及升級初始化動作;
▪ Invoke(stubshim.ChaincodeStubInterface):Invoke是peer調用鏈碼的入口函數;代碼如下圖:
ChaincodeStub裏面包含豐富的賬本操作,常用的有getCallerCertificate(),getState(k), putState(k,v), invokeChaincode(…), rangeQueryState(k1,k2),getTxId()等。
▲兩個查詢
因爲fabric默認的狀態數據庫是個k-v庫,常用到的方法就以下兩個查詢。
1. getState(k)獲取單獨的key對應的value值。
2. rangeQueryState(k1,k2),獲取k1開始,k2結束的所有k-v對象, 返回的是個Map<String,String>對象, 其中k1,k2按字典序排序。
▲一個寫入
putState(k,v), 寫入數據,此處要注意下,putState數據並不會馬上落到賬本上, 要等到第二段交易提交共識達成後,數據纔會落地。代碼如下圖:
我師弟在我指導下寫的,暫時這樣,後續還要改改。