參考:http://hyperledger-fabric.readthedocs.io/en/latest/chaincode4ade.html
1.編碼
每一個chaincode都需要實作
chaincode interface
的
Init
和
Invoke
接口
每一個chaincode都應該有一個main函數
代碼結構如下所示:
package main
import (
"fmt"
"strconv"
"github.com/hyperledger/fabric/core/chaincode/shim"
peer "github.com/hyperledger/fabric/protos/peer"
)
type MyFirstCC struct {
}
func (t *MyFirstCC) Init(stub shim.ChaincodeStubInterface) peer.Response {
}
func (t *MyFirstCC) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
}
func main() {
}
main
函數,負責在
instantiate
時啟動chaincode
func main() {
err := shim.Start(new(MyFirstCC))
if err != nil {
fmt.Printf("error start MyFirstCC")
}
}
Init
函數,在chaincode
instantiation
或
upgrade
時調用,初始化或者重置資料
func (t *MyFirstCC) Init(stub shim.ChaincodeStubInterface) peer.Response {
fmt.Println("ex10 Init")
_, args := stub.GetFunctionAndParameters()
//set 2 parmas for this chaincode init
//when instantiation chaincode,should give 2 params
if len(args) != {
return shim.Error("Incorrect len of arguments")
}
var Aval int
var A string
var err error
A = args]
Aval, err = strconv.Atoi(args])
if err != nil {
return shim.Error("Expecting integer value for asset holding")
}
fmt.Printf("Aval = %d\n", Aval)
//put the data to ledger
err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
if err != nil {
return shim.Error("failed to Create asset")
}
return shim.Success(nil)
}
Invoke
函數,在交易時調用。我們可以自定義一些函數,當調用時傳遞函數名字和參數即可,例如,在本例中我們自定義
set
和
get
函數。
set
更新賬本資料,
get
讀取賬本資料
func (t *MyFirstCC) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
fmt.Println("ex10 Invoke")
fn, args := stub.GetFunctionAndParameters()
var result string
var err error
if fn == "set" {
result, err = set(stub, args)
} else if fn == "get" {
result, err = get(stub, args)
} else {
return shim.Error("func not found")
}
if err != nil {
return shim.Error(err.Error())
}
return shim.Success([]byte(result))
}
func set(stub shim.ChaincodeStubInterface, args []string) (string, error) {
fmt.Println("ex10 set")
if len(args) != {
return "", fmt.Errorf("Incorrect arguments")
}
var Aval int
var A string
var err error
A = args]
Aval, err = strconv.Atoi(args])
if err != nil {
return "", fmt.Errorf("Expecting integer value for asset holding")
}
fmt.Printf("Aval = %d\n", Aval)
//update data in ledger
err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
if err != nil {
return "", fmt.Errorf("failed to PutState:%s", args])
}
return args], nil
}
func get(stub shim.ChaincodeStubInterface, args []string) (string, error) {
fmt.Println("ex10 get")
if len(args) != {
return "", fmt.Errorf("Incorrect arguments")
}
var A string
A = args]
//read data from ledger
value, err := stub.GetState(A)
if err != nil {
return "", fmt.Errorf("failed to get asset: %s with error:%s", args], err)
}
if value == nil {
return "", fmt.Errorf("asset not found")
}
return string(value), nil
}
2.測試
- 将上述代碼整合到一個.go檔案中,在
下邊建立一個檔案夾,命名為github.com/hyperledger/fabric/examples/chaincode/go
,将go檔案放置在本檔案夾下,這樣可以将我們自己寫的chaincode映射到clidocker中example10
-
準備環境,可參考【fabric 2】v1.0環境搭建詳細過程第1-3步,
注意:這個步驟執行一次即可滿足後續測試需要了
- 啟動docker容器,當你的chaincode有更新時需要執行下面的步驟,以同步到cli中
docker-compose -f docker-compose-cli.yaml up -d
- 進入cli容器
docker exec -it cli bash //建立channel需要先進入cli
- 建立channel
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
peer channel create -o orderer.example.com: -c mychannel -f ./channel-artifacts/channel.tx --tls true --cafile $ORDERER_CA
- peer加入channel
- install chaincode
- instantiate chaincode
- 調用chaincode的
方法get
peer chaincode query -C mychannel -n mycc -c '{"Args":["get","a"]}' //查詢餘額不往賬本寫資料,不需要背書,用query即可
- 調用chaincode的
方法set
再次調用chaincode的
get
方法
3. 可能遇到的問題
有的時候更改了chaincode代碼重新開機docker發現chaincode沒有更新,原因可能是上次建立的chaincode docker image還在,可以通過如下方法解決
docker rm 23bae5e36c07
至此,問題解決,每次都會更新的