Fabric基礎架構原理:鏈碼

想知道更多關於區塊鏈技術知識,請百度【鏈客區塊鏈技術問答社區】
鏈客,有問必答!

圖片描述

智能合約可以部署和運行在區塊鏈環境中,由一段代碼來描述相關的業務邏輯。部署後的智能合約在區塊鏈中沒法修改,智能合約的執行徹底由代碼決定,不受人爲因素的干擾。通常來講,參與方經過智能合約規定各自權利和義務、觸發合約的條件以及結果,一旦該智能合約在區塊鏈環境中運行就能夠得出客觀、準確的結果。
在 Fabric 中,智能合約也稱爲鏈碼(chaincode),分爲用戶鏈碼和系統鏈碼,一般指的是用戶鏈碼。鏈碼是訪問帳本的基本方法,通常是用Go等高級語言編寫的、實現規定接口的代碼。上層應用能夠經過調用鏈碼來初始化和管理帳本的狀態。只要有適當的權限,鏈碼之間也能夠互相調用。git

  1. 鏈碼的背書策略

鏈碼實例化時可指定背書策略,當確認節點接收到交易時,節點獲知相關鏈碼信息,而後檢查該鏈碼的背書策略,判斷交易是否知足背書策略,若知足則標註交易爲合法。
背書策略可分爲主體 principal(P )和閾值 threshold(T) 兩部分,具體以下:
1)principal 指定由哪些成員進行背書。
2)threshold 接受兩個輸入,分別爲閾值t和若干個P的集合n,只要交易中包含了 n 中 t 個成員的背書則認爲交易合法。
例如:
T(1, ‘A’, ‘B’) 則須要 A,B 中任意成員背書。 T(1, ‘A’, T(2, ‘B’, ‘C’)) 則須要 A成員背書或 B,C 成員同時背書。github

  1. 鏈碼開發

鏈碼的在開發過程當中須要實現鏈碼接口,交易的類型決定了哪一個接口函數將會被調用,如 instantiate 和 upgrade 類型會調用鏈碼的Init接口,而 invoke 類型的交易則調用了鏈碼的 Invoke 接口。鏈碼的接口定義以下:(本文來自公衆號:亨利筆記)
type Chaincode interface {
Init(stub ChaincodeStubInterface) pb.Response
Invoke(stub ChaincodeStubInterface) pb.Response
}
下面經過一個例子講解鏈碼的開發流程,示例鏈碼根據交易的類型建立鍵值對並記錄到帳本中,或者根據鍵名到帳本中查找與之相對應的值。
 
請先確保 Go 語言環境已經安裝而且正確設置 GOPATH 環境變量。
(1)建立鏈碼存放目錄
建立keyValueStore目錄以存放鏈碼,同時進入目錄
mkdir $GOPATH/src/keyValueStore
cd $GOPATH/src/keyValueStore
建立並編輯鏈碼文件 keyValueStore.go 。
 
(2)鏈碼源代碼分析
1)導入頭文件。
鏈碼必須依賴 chaincode shim 包和 peer protobuf 包,它們分別用於鏈碼的控制與數據傳輸,其次定義 KeyValueStore 類型,做爲 chaincode shim 的載體。
package main
import (
"fmt"
"github.com/hyperledger/fabric/core/chaincode/shim"
"github.com/hyperledger/fabric/protos/peer"
)
type KeyValueStore struct {
}
2)實現Init方法。
Init 方法經過 shim.ChaincodeStubInterface 接口來獲取實例化鏈碼交易的相關信息,該接口的 GetStringArgs 方法可獲取交易傳給鏈碼的參數。鏈碼實例化時接收key 和 value 兩個參數,所以先對參數個數進行驗證,若驗證經過,則第一個和第二個參數分別做爲 key 和 value 存入到帳本中。
把狀態存入帳本須要藉助 shim.ChaincodeStubInterface 接口 PutState 方法來完成,因爲帳本中的數據都以鍵值對的形式儲存,所以該方法也只接受 key,value兩個參數,其中 value 爲 byte 格式,裏面還包含多個 json 格式的鍵值對。
因爲執行結果須要以消息的形式返回給客戶端,所以還須要把返回消息封裝成 fabric/protos/peer 中 Response 格式。
值得注意的是,鏈碼升級的時候都會調用 Init 方法,編寫升級鏈碼時應注意 Init 方法的實現,以免從新初始化或覆蓋上一版本的帳本狀態。docker

3)實現Invoke方法。
與Init方法相似,Invoke 方法經過 shim.ChaincodeStubInterface 的 GetFunctionAndParameters 方法來獲取 invoke 交易的參數,其中返回的 fn 與 args 分別爲交易調用的具體函數名以及相應參數,此時 Invoke 方法進一步判斷fn的值以進行下一步操做(set或者get),並把操做結果存放在 result 變量中以返回操做結果。json

爲了完成對帳本的讀寫,鏈碼還須要實現如下兩個方法:
set:把輸入的鍵值對記錄在帳本中
get:根據鍵讀取帳本中與之對應的值
4)實現get和put方法。
正如前面所說,invoke 方法根據 fn 的值來執行相應的 get 或 put 函數,這兩個函數也須要 shim.ChaincodeStubInterface 接口來訪問帳本數據。bash

5)實現主函數main():
鏈碼須要在main函數中調用shim.Start()方法用於鏈碼的部署。網絡

(3)測試鏈碼
鏈碼的測試須要經過完整的Fabric網絡,使用官方提供的例子能夠快速構建測試網絡,從而簡化鏈碼的開發流程。這裏介紹搭建測試網絡的步驟:
1)安裝示例代碼庫。
2)進入 fabric-samples 目錄。
$ cd
$GOPATH/src/github.com/hyperledger/fabric-samples
3)把新編寫的鏈碼放入fabric-samples的chaincode目錄下。
$ cp -r
$GOPATH/src/keyValueStore ./chaincode
4)進入chaincode-docker-devmode目錄並啓動網絡,命令中會建立了一個名稱爲myc的通道。
$ cd chaincode-docker-devmode
$ docker-compose -f docker-compose-simple.yaml up -d
5)進入chaincode容器,編譯並運行鏈碼。
$ docker exec -it chaincode
$ cd keyValueStore && go build
$ export CORE_PEER_ADDRESS=peer:7051
$ export CORE_CHAINCODE_ID_NAME=mycc:0
$./keyValueStore
$ exit
6)進入CLI容器並初始化鏈碼,鏈碼ID爲mycc,版本號爲0,部署的通道名稱是myc。
$ docker exec -it cli bash
$ peer chaincode install -p chaincodedev/chaincode/keyValueStore -n mycc -v 0
$ peer chaincode instantiate -n mycc -v 0 -c '{"Args":["a","10"]}' -C myc
7)Invoke和Query鏈碼。
$ peer chaincode query -n mycc -c '{"Args":["query","a"]}' -C myc
$ peer chaincode invoke -n mycc -c '{"Args":["set", "a", "20"]}' -C myc
$ peer chaincode query -n mycc -c '{"Args":["query","a"]}' -C myc
正常狀況下,兩次 query 返回的結果分別爲 10 和 20。
開發鏈碼時能夠經過上述過程進行測試,但需避免使用相同的鏈碼 ID 以避免鏈碼實例化失敗。另外,對於鏈碼升級來講,鏈碼的 ID 應該保持不變,同時新鏈碼的版本號須要比先前實例化的版本高,並經過 upgrade 交易來更新鏈碼在通道中的狀態。
假設對鏈碼 keyValueStore.go 進行了更改,並把最新的鏈碼保存在$GOPATH/src/keyValueStoreNew 下,則升級鏈碼的操做以下:
1)進入fabric-samples目錄並拷貝最新鏈碼到chaincode目錄。
$ cd $GOPATH/src/fabric-samples
$ cp -r $GOPATH/src/keyValueStoreNew ./chaincode
2)進入chaincode容器,編譯並運行更新後的鏈碼。
$ docker exec -it chaincode bash
$ cd keyValueStoreNew && go build
$ export CORE_PEER_ADDRESS=peer:7051
$ export CORE_CHAINCODE_ID_NAME=mycc:1
$ ./keyValueStoreNew
$ exit
3)進入cli容器並升級鏈碼。
$ docker exec -it cli bash
$ peer chaincode install -p chaincodedev/chaincode/keyValueStoreNew -n mycc -v 1
$ peer chaincode upgrade -n mycc -v 1 -c '{"Args":["a","10"]}' -C myc
到此升級鏈碼完畢,能夠對最新的鏈碼mycc進行操做。函數

相關文章
相關標籤/搜索