Fabric1.4:鏈碼管理與測試

1 鏈碼介紹

智能合約在 Hyperledger Fabric 中稱爲鏈碼(chaincode),是提供分佈式帳本的狀態處理邏輯。鏈碼被部署在fabric 的網絡節點中,可以獨立運行在具備安全特性的受保護的 Docker 容器中,以 gRPC 協議與相應的 peer 節點進行通訊,以操做分佈式帳本中的數據。git

通常鏈碼分爲兩種:系統鏈碼用戶鏈碼github

1.1 系統鏈碼

負責 Fabric 節點自身的處理邏輯,包括系統配置、背書、校驗等工做,在 Peer 節點啓動時會自動完成註冊和部署。系統鏈碼分爲如下五種:docker

  • 配置系統鏈碼(Configuration System Chaincode,CSCC):負責處理 Peer 端的 Channel 配置;shell

  • 生命週期系統鏈碼(Lifecycle System Chaincode,LSCC):負責對用戶鏈碼的生命週期進行管理;緩存

  • 查詢系統鏈碼(Query System Chaincode,QSCC): 提供帳本查詢 API。如獲取區塊和交易等信息;安全

  • 背書管理系統鏈碼(Endorsement System Chaincode,ESCC):負責背書(簽名)過程, 並能夠支持對背書策略進行管理;bash

  • 驗證系統鏈碼(Validation System Chaincode,VSCC):處理交易的驗證,包括檢查背書策略以及多版本併發控制。網絡

<br>併發

1.2 用戶鏈碼

用戶鏈碼不一樣於系統鏈碼,系統鏈碼是 fabric 的內置鏈碼,而用戶鏈碼是由應用程序開發人員根據不一樣場景需求編寫的基於分佈式帳本的狀態的業務處理邏輯代碼,運行在鏈碼容器中,經過 Fabric 提供的接口與帳本狀態進行交互。分佈式

用戶鏈碼向下可對帳本數據進行操做,向上能夠給企業級應用程序提供調用接口。

<br>

1.3 鏈碼生命週期

管理 Chaincode 的生命週期共有五個命令:

  • **install:**將已編寫完成的鏈碼安裝在網絡節點中;

  • **instantiate:**對已安裝的鏈碼進行實例化;

  • **upgrade:**對已有鏈碼進行升級,鏈代碼能夠在安裝後根據具體需求的變化進行升級;

  • **package:**對指定的鏈碼進行打包的操做。

  • **singnpackage:**對已打包的文件進行簽名。

<div align=center><img src="https://pic1.zhimg.com/v2-9b5be494f045aff54c0af53344e88644_r.jpg" width=80%></div> <br>

2 鏈碼的使用

咱們使用 fabric v1.4.3 版本的 fabric-samples 提供的 first-network 網絡進行說明,修改 first-network/scripts/script.sh 腳本中的下列代碼:

# 將判斷語句中的 true 改成 false,first-network 網絡就不會進行鏈碼的安裝、實例化等操做
if [ "${NO_CHAINCODE}" != "false" ]; then
	## Install chaincode on peer0.org1 and peer0.org2
	echo "Installing chaincode on peer0.org1..."
	installChaincode 0 1       
	echo "Install chaincode on peer0.org2..."
	installChaincode 0 2       
	#...
	#...
fi

啓動 first-network 網絡:

$ ./byfn.sh up

進入 CLI 客戶端容器,CLI 客戶端默認以 Admin.org1 身份鏈接 peer0.org1 節點:

$ docker exec -it cli bash

檢查當前節點(peer0.org1.example.com)以加入哪些通道:

# peer channel list

執行結果返回:

Channels peers has joined: 
mychannel

說明當前節點已經加入通道 mychannel。

2.1 安裝鏈碼

使用 install 命令安裝鏈碼:

# peer chaincode install -n mycc -v 1.0 -p github.com/chaincode/chaincode_example02/go/
  • -n: 指定要安裝的鏈碼的名稱
  • -v: 指定鏈碼的版本
  • -p: 指定要安裝的鏈碼源代碼的所在路徑

執行結果返回:

[chaincodeCmd] install -> INFO 04c Installed remotely response:<status:200 payload:"OK" >

說明鏈碼成功安裝至 peer 節點中。

注意:鏈碼須要根據指定的背書策略安裝在須要背書的全部 peer 節點中。未安裝鏈碼的節點不能執行鏈碼邏輯,但仍能夠驗證交易並提交到帳本中。

<br>

2.2 實例化鏈碼

設置通道名稱的環境變量:

# export CHANNEL_NAME=mychannel
# echo $CHANNEL_NAME

設置 orderer 節點的證書路徑的環境變量:

# export ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
# echo $ORDERER_CA

使用 instantiate 命令進行鏈碼的實例化:

# peer chaincode instantiate -o orderer.example.com:7050 --tls --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -v 1.0 -c '{"Args":["init","a", "100", "b","200"]}' -P "OR ('Org1MSP.peer','Org2MSP.peer')"
  • -o: 指定 Oderer 服務節點地址
  • --tls: 開啓 TLS 驗證
  • --cafile: 指定了 Orderer 的根證書路徑,用於驗證 TLS 握手
  • -n: 指定要實例化的鏈碼名稱,必須與安裝時指定的鏈碼名稱相同
  • -v: 指定要實例化的鏈碼的版本號,必須與安裝時指定的鏈碼版本號相同
  • -C: 指定通道名稱
  • -c: 實例化鏈碼時指定的參數
  • -P: 指定背書策略

背書策略的背書實體通常表示爲:MSP.ROLE,其中 MSP 是 MSP ID,ROLE 支持 client、peer、admin 和 member 四種角色。 例如: Org1MSP.admin 表示 Org1 這個 MSP 下的任意管理員; Org1MSP.member 表示 Org1 這個 MSP 下的任意成員。

背書策略語法結構以下:

// 基礎表達式形式,EXPR 能夠是 AND、OR 和 OutOf 邏輯符,E 是實體或者嵌套的表達式
EXPR(E[, E...])
// 須要三個組織 org一、org2 和 org3 的 member 共同背書籤名
AND('Org1MSP.member', 'Org2MSP.member', 'Org3MSP.member')
// 須要 org1 和 org2 其中一個組織的 member 背書籤名
OR('Org1MSP.member', 'Org2MSP.member')
// 須要 Org1 的 admin 背書,或者 Org2 和 Org3 下的 member 共同背書籤名
OR('Org1MSP.admin', AND('Org2MSP.member', 'Org3MSP.member'))
// 須要 org一、org二、org3 的 member 的至少兩個背書籤名
OutOf(2, 'Org1MSP.member', 'Org2MSP.member', 'Org3MSP.member')

**注意:**鏈碼須要安裝在多個背書的 Peer 節點中,但實例化只需執行一次。

<br>

2.3 查詢鏈碼

鏈碼部署成功以後,能夠經過特定的命令調用鏈碼,從而發起交易或查詢請求,對帳本數據進行操做。

使用 query 命令查詢鏈碼:

# peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
  • -n: 指定要調用的鏈碼名稱
  • -C: 指定通道名稱
  • -c 指定調用鏈碼時所須要的參數

執行成功後,返回輸出結果 100。

<br>

2.4 調用鏈碼

客戶端發起交易,對帳本數據進行更改,須要將背書以後的交易發送給排序節點上鍊。所以,須要開啓 TLS 驗證並指定對應的 orderer 證書路徑。

須要注意,鏈碼執行查詢操做和執行事務(改變帳本數據)操做的流程是不一樣的:

  • 鏈碼查詢操做:客戶端接收到背書節點的交易提案響應後不會將交易請求提交給 Orderer 節點,即查詢操做不須要上鍊,任選一個背書節點進行鏈碼查詢操做便可;
  • 鏈碼事務操做:客戶端先須要根據指定背書策略收集到足夠的交易提案的背書籤名,再將背書後的交易提交給 Orderer 節點,即事務操做的交易須要成塊上鍊。

使用 invoke 命令調用鏈碼:

# peer chaincode invoke -o orderer.example.com:7050 --tls --cafile $ORDERER_CA  -C $CHANNEL_NAME -n mycc -c '{"Args":["invoke","a","b","10"]}'
  • -o: 指定orderer節點地址
  • --tls: 開啓TLS驗證
  • --cafile: 指定了 Orderer 的根證書路徑,用於驗證 TLS 握手
  • -n: 指定鏈碼名稱
  • -C: 指定通道名稱
  • -c: 指定調用鏈碼的所需參數

執行返回如下結果,說明交易執行成功:

[chaincodeCmd] chaincodeInvokeOrQuery -> INFO 04c Chaincode invoke successful. result: status:200

再次查詢 a 帳戶的餘額,若是執行結果返回 90,說明交易被正確執行了:

# peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'

**注意:**若是交易須要多個背書節點的背書,可使用 --peerAddresses 標誌指定節點。例如:交易須要 peer0.org1 和 peer0.org2 的共同背書:

# peer chaincode invoke -o orderer.example.com:7050 --tls --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["invoke","a","b","10"]}'

<br>

2.5 鏈碼的打包與簽名

鏈碼部署除了正常的安裝、實例化操做步驟以外,還有一種部署方式,即先將鏈碼進行打包,而後對已打包的文件進行簽名,最後再進行安裝與實例的操做。

使用以下的命令進行打包操做:

# peer chaincode package -n exacc -v 1.0 -p github.com/chaincode/chaincode_example02/go/  -s -S -i "AND('Org1MSP.admin')" ccpack.out

參數說明:

  • -s: 建立一個能夠被多個全部者簽名的包
  • -S: 可選參數,使用 core.yaml 文件中被 localMspId 相關屬性值定義的 MSP 對包進行簽名
  • -i: 指定鏈碼的實例化策略(指定誰能夠實例化鏈碼)

打包後的文件能夠直接使用 install 命令安裝,如:peer chaincode install ccpack.out,可是通常對打包後的文件簽名再進一步安裝。

使用以下的命令對打包文件進行簽名操做(添加當前 MSP 簽名到簽名列表中):

# peer chaincode signpackage ccpack.out signedccpack.out

signedccpack.out 包含一個用本地 MSP 對包進行的附加簽名。

安裝已簽名的打包文件:

# peer chaincode install signedccpack.out

對已安裝的鏈碼進行實例化操做,指定背書策略:

# peer chaincode instantiate -o orderer.example.com:7050 --tls --cafile $ORDERER_CA -C $CHANNEL_NAME -n exacc -v 1.0 -c '{"Args":["init","a", "100", "b","200"]}' -P "OR ('Org1MSP.peer','Org2MSP.peer')"

測試:

使用以下命令查詢鏈碼,輸出結果爲 100:

# peer chaincode query -C $CHANNEL_NAME -n exacc -c '{"Args":["query","a"]}'

使用以下命令調用鏈碼進行轉帳操做:

# peer chaincode invoke -o orderer.example.com:7050  --tls --cafile $ORDERER_CA  -C $CHANNEL_NAME -n exacc -c '{"Args":["invoke","a","b","10"]}'

使用以下命令再次查詢鏈碼,輸出結果爲 90:

# peer chaincode query -C $CHANNEL_NAME -n exacc -c '{"Args":["query","a"]}'

<br>

2.6 升級鏈碼

首先,先對修改以後的鏈碼進行安裝:

# peer chaincode install -n mycc -v 2.0 -p github.com/chaincode/chaincode_example02/go/

而後,使用以下命令對已安裝的鏈碼進行升級:

# peer chaincode upgrade -o orderer.example.com:7050 --tls --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -v 2.0 -c '{"Args":["init","a", "100", "b","200"]}' -P "OR ('Org1MSP.peer','Org2MSP.peer')"

測試:

使用以下命令查詢鏈碼,輸出結果爲 100:

# peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'

使用以下命令調用鏈碼進行轉帳操做:

# peer chaincode invoke -o orderer.example.com:7050  --tls --cafile $ORDERER_CA  -C $CHANNEL_NAME -n mycc -c '{"Args":["invoke","a","b","10"]}'

使用以下命令再次查詢鏈碼,輸出結果爲 90:

# peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'

須要注意的是,升級過程當中,chaincode 的 Init 函數會被調用以執行數據相關的操做,或者從新初始化數據;因此須要多加當心,以免在升級 chaincode 時重設狀態信息。

<br>

2.7 查看鏈碼日誌

使用 docker ps 命令能夠查看到當前網絡中有如下三個鏈碼容器啓動:

  • dev-peer0.org1.example.com-mycc-1.0

  • dev-peer0.org1.example.com-mycc-2.0

  • dev-peer0.org1.example.com-exacc-1.0

使用 docker logs 命令能夠查看鏈碼日誌:

$ docker logs dev-peer0.org1.example.com-mycc-1.0
ex02 Init
Aval = 100, Bval = 200
ex02 Invoke
Query Response:{"Name":"a","Amount":"100"}
ex02 Invoke
Aval = 90, Bval = 210
ex02 Invoke
Query Response:{"Name":"a","Amount":"90"}
$ docker logs dev-peer0.org1.example.com-mycc-2.0
ex02 Init
Aval = 100, Bval = 200
ex02 Invoke
Query Response:{"Name":"a","Amount":"100"}
ex02 Invoke
Aval = 90, Bval = 210
ex02 Invoke
Query Response:{"Name":"a","Amount":"90"}
$ docker logs dev-peer0.org1.example.com-exacc-1.0
ex02 Init
Aval = 100, Bval = 200
ex02 Invoke
Query Response:{"Name":"a","Amount":"100"}
ex02 Invoke
Aval = 90, Bval = 210
ex02 Invoke
Query Response:{"Name":"a","Amount":"90"}

<br>

3 dev 模式下的鏈碼測試

3.1 啓動測試網絡

上述過程是在 first-network 網絡下的鏈碼測試,可是該網絡下的鏈碼測試過於複雜,須要指定不少參數,若是隻是想測試所編寫的鏈碼的正確性,可使用 dev 開發模式。

進入 chaincode-docker-devmode 目錄:

$ cd ./fabric-samples/chaincode-docker-devmode/

該目錄下存在以下五個文件:

  • **docker-compose-simple.yaml:**網絡啓動依賴的配置文件,該配置文件中指定了四個容器,分別爲:orderer、peer、cli、chaincode
  • **msp:**網絡環境的 MSP,包含一系列的證書及私鑰
  • **script.sh:**cli 運行的建立並加入通道的腳本
  • **myc.tx:**通道交易配置文件
  • orderer.block: 排序服務初始區塊配置文件

使用以下命令啓動網絡:

$ docker-compose -f docker-compose-simple.yaml up -d
Creating network "chaincodedockerdevmode_default" with the default driver
Creating orderer ... 
Creating orderer ... done
Creating peer ... 
Creating peer ... done
Creating cli ... 
Creating chaincode ... 
Creating cli
Creating cli ... done

以開發模式開啓 peer,還啓動了兩個容器:chaincode 容器,用於鏈碼環境;CLI 容器,用於與鏈碼進行交互,其中建立和鏈接通道的命令已經被嵌入 CLI 容器中了,因此能夠直接進行鏈碼調用。

**注意:**啓動該網絡前,應先刪除其餘網絡活躍的容器,要不能運行過程可能會出現問題。使用下列兩個命令刪除活躍的容器和清理網絡緩存:

$ docker rm -f $(docker ps -aq)
$ docker network prune

<br>

3.2 構建並啓動鏈碼

使用以下命令進入 chaincode 容器 :

$ docker exec -it chaincode bash

出現以下結果,則運行成功:

root@d32997378218:/opt/gopath/src/chaincode#

查看該 chaincode 容器的定義:

chaincode:
    container_name: chaincode
    image: hyperledger/fabric-ccenv
    tty: true
    environment:
      - GOPATH=/opt/gopath
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      - FABRIC_LOGGING_SPEC=DEBUG
      - CORE_PEER_ID=example02
      - CORE_PEER_ADDRESS=peer:7051
      - CORE_PEER_LOCALMSPID=DEFAULT
      - CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/msp
    working_dir: /opt/gopath/src/chaincode
    command: /bin/sh -c 'sleep 6000000'
    volumes:
        - /var/run/:/host/var/run/
        - ./msp:/etc/hyperledger/msp
        - ./../chaincode:/opt/gopath/src/chaincode
    depends_on:
      - orderer
      - peer

該容器的當前目錄 /opt/gopath/src/chaincode 對應本地系統中的 ./../chaincode,咱們使用該目錄下的 chaincode_example02 鏈碼進行測試。進入 chaincode_example02/go/ 目錄編譯鏈碼:

# cd chaincode_example02/go/
# go build

使用以下命令啓動並運行鏈碼:

# CORE_PEER_ADDRESS=peer:7052 CORE_CHAINCODE_ID_NAME=mycc:0 ./go

命令含義:

  • **CORE_PEER_ADDRESS:**用於指定 peer,其中 7052 端口是鏈碼的專用監聽端口(7051 是 peer 節點監聽的網絡端口)

  • **CORE_CHAINCODE_ID_NAME:**用於註冊到 peer 的鏈碼

    • mycc: 指定鏈碼名稱
    • 0: 指定鏈碼初始版本號
    • ./go: 指定鏈碼文件

開啓一個新的終端,使用以下命令進行 CLI 容器:

$ docker exec -it cli bash

進入 CLI 容器後,使用以下命令安裝鏈碼:

# peer chaincode install -p chaincodedev/chaincode/chaincode_example02/go -n mycc -v 0

使用以下命令實例化鏈碼:

# peer chaincode instantiate -n mycc -v 0 -c '{"Args":["init","a", "100", "b","200"]}' -C myc

測試:

使用以下命令查詢鏈碼,輸出結果爲 100:

# peer chaincode query -n mycc -c '{"Args":["query","a"]}' -C myc

使用以下命令調用鏈碼進行轉帳操做:

# peer chaincode invoke -n mycc -c '{"Args":["invoke","a","b","10"]}' -C myc

使用以下命令再次查詢鏈碼,輸出結果爲 90:

# peer chaincode query -n mycc -c '{"Args":["query","a"]}' -C myc

日誌:

chaincode 容器在測試過程會打印鏈碼執行輸出的日誌:

ex02 Init
Aval = 100, Bval = 200
ex02 Invoke
Query Response:{"Name":"a","Amount":"100"}
ex02 Invoke
Aval = 90, Bval = 210
ex02 Invoke
Query Response:{"Name":"a","Amount":"90"}

<br>

3.3 關閉測試網絡

使用以下命令關閉測試網絡:

$ docker-compose -f docker-compose-simple.yaml down

<br>

參考

  1. 《Hyperledger Fabric 菜鳥進階攻略》
相關文章
相關標籤/搜索