鏈碼實戰(一)——Hello World
一、概念
區塊鏈2.0的典型代表就是智能合約,在Fabric中將其稱爲鏈碼,智能合約具體是什麼呢?好多人都有些蒙圈,在我看來智能合約對應到傳統的互聯網就是C/S中的S端部署的程序,因此基於區塊鏈平臺的開發,我可以理解成服務器開發。只不過這個開發是包裹上了區塊鏈這一層技術。
智能合約的開發就是基於區塊鏈的服務端應用開發。主要有以下幾類
系統合約 | 用戶合約 | |
配置系統鏈碼(CSCC) | Peer 端的 Channel 配置 | "由應用程序開發人員根據不同場景需求及成員制定的相關規則,使用 Golang或Java等語言編寫的基於操作區塊鏈分佈式賬本的狀態的業務處理邏輯代碼,運行在鏈碼容器中,通過Fabric 提供的接口與賬本狀態進行交互。下可對賬本數據進行操作,上可以給企業級應用程序提供調用接口 |
生命週期系統鏈碼(LSCC) | 對用戶鏈碼的生命週期進行管理 | |
查詢系統鏈碼(QSCC) | 提供賬本查詢API,如獲取區塊和交易等信息 | |
背書管理系統鏈碼(ESCC) | 負責背書(簽名)過程, 並可以支持對背書策略進行管理 | |
驗證系統鏈碼(VSCC) | 處理交易的驗證,包括檢查背書策略以及多版本併發控制 | |
管理 Chaincode 的五個命令:
- install:將已編寫完成的鏈碼安裝在網絡節點中。
- instantiate:對已安裝的鏈碼進行實例化。
- upgrade:對已有鏈碼進行升級。鏈代碼可以在安裝後根據具體需求的變化進行升級。
- package:對指定的鏈碼進行打包的操作。
- singnpackage:簽名。
鏈碼的使用過程包括:安裝、實例化、查詢、調用。
二、開發模式下測試鏈碼
由於鏈碼的相關操作需要進行大量的命令行操作,具有效率低下的特點,爲了提高開發效率我們將鏈碼的功能逐個測試後,寫成腳本的的形式然後進行執行。可大大提高工作效率,下面主要以Hello World爲例介紹一下鏈碼測試的方法:
1、啓動網絡
命令:
cd fabric-samples/chaincode-docker-devmode/
docker-compose -f docker-compose-simple.yaml up -d
2、構建並啓動鏈碼
1、創建文件
cd ../chaincode
mkdir hello && cd hello
vim hello.go
2、導入鏈碼依賴包
package main
import (
"github.com/hyperledger/fabric/core/chaincode/shim"
"github.com/hyperledger/fabric/protos/peer"
"fmt"
)
3、編寫主函數
func main() {
err := shim.Start(new(HelloChaincode))
if err != nil {
fmt.Printf("Chaincode start err: %v", err)
}
}
4、自定義結構體
type HelloChaincode struct {
}
5、實現 Chaincode 接口
實現 Chaincode 接口必須重寫 Init 與 Invoke 兩個方法。
Init 函數:初始化數據狀態
- 獲取參數並判斷參數長度是否爲2
- 參數: Key, Value
- 調用 PutState 函數將狀態寫入賬本中
- 如果有錯誤, 則返回
- 打印輸出提示信息
- 返回成功
具體實現代碼如下:
// 實例化/升級鏈碼時被自動調用
// -c '{"Args":["Hello","World"]'
func (t *HelloChaincode) Init(stub shim.ChaincodeStubInterface) peer.Response {
fmt.Println("實例化....")
_, args := stub.GetFunctionAndParameters()
// 判斷參數長度是否爲2個
if len(args) != 2 {
return shim.Error("Args Err!")
}
fmt.Println("Save data......")
// 通過調用PutState方法將數據保存在賬本中
err := stub.PutState(args[0], []byte(args[1]))
if err != nil {
return shim.Error("Save data err...")
}
fmt.Println("實例化成功")
return shim.Success(nil)
}
Invoke 函數
- 獲取參數並判斷長度是否爲1
- 利用第1個參數獲取對應狀態 GetState(key)
- 如果有錯誤則返回
- 如果返回值爲空則返回錯誤
- 返回成功狀態
具體實現代碼如下:
// 對賬本數據進行操作時被自動調用(query, invoke)
func (t *HelloChaincode) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
// 獲取調用鏈碼時傳遞的參數內容(包括要調用的函數名及參數)
fun, args := stub.GetFunctionAndParameters()
// cli op
if fun == "query"{
return query(stub, args)
}
return shim.Error("Err op!")
}
實現查詢函數
函數名稱爲 query,具體實現如下:
func query(stub shim.ChaincodeStubInterface, args []string) peer.Response {
// 檢查傳遞的參數個數是否爲1
if len(args) != 1{
return shim.Error("Args err! Args must Key")
}
// 根據指定的Key調用GetState方法查詢數據
result, err := stub.GetState(args[0])
if err != nil {
return shim.Error("根據指定的 " + args[0] + " 查詢數據時發生錯誤")
}
if result == nil {
return shim.Error("根據指定的 " + args[0] + " 沒有查詢到相應的數據")
}
// 返回查詢結果
return shim.Success(result)
}
最後將鏈碼碼彙總即可。
3、構建並啓動鏈碼
1、打開一個新的終端B,進入 chaincode 容器
docker exec -it chaincode bash
2、編譯鏈碼
cd hello
go build
3、啓動鏈碼
CORE_PEER_ADDRESS=peer:7052
CORE_CHAINCODE_ID_NAME=hellocc:0 ./hello
截圖:
4、測試鏈碼
1、打開終端C、進入cli容器
docker exec -it cli bash
2、安裝鏈碼
peer chaincode install -p chaincodedev/chaincode/hello -n hellocc -v 0
3、實例化
peer chaincode instantiate -n hellocc -v 0 -c '{"Args":["init", "Hello","World"]}' -C myc
4、調用鏈碼
peer chaincode query -n hellocc -c '{"Args":["query","Hello"]}' -C myc
根據指定的key查詢對應的狀態數據,結果爲:World。截圖如下:
三、總結
通過學習掌握了鏈碼開發的流程和測試的方法,雖然hello World很簡單,但是卻能很好的學習鏈碼的開發方法,後期的各項後端的工作都將圍繞鏈碼開發展開。