本文是在閱讀《區(qū)塊鏈開發(fā)實戰(zhàn)-Hyperledger Fabric關(guān)鍵技術(shù)與案例分析》一書的同時,在實踐中記錄的一些實踐步驟與經(jīng)驗分享。
Hyperledger Fabric開發(fā)實戰(zhàn)-05證書服務(wù)器
在上一節(jié)Hyperledger Fabric開發(fā)實戰(zhàn)-03智能合約中,演示了一個簡單的Chaincode示例,可以看到,Chaincode中主要是Init和Invoke方法的實現(xiàn)。兩個方法的原型如下:
func (t *mychaincode) Init(stub shim.ChaincodeStubInterface) pb.Response{
}
func (t *mychaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response{
}
可以看到,主要是對shim.ChaincodeStubInterface的使用。
shim接口
shim.ChaincodeStubInterface
// 獲取傳入的參數(shù),args是一個數(shù)組
function,args = stub.GetFunctionAndParameters()
// 將數(shù)據(jù)保存到fabric中
PutState(key string, value []byte) error
// 將數(shù)據(jù)保存到fabric中
GetState(key string) ([]byte,error)
// 獲取區(qū)間內(nèi)的key
GetStateByRange(startKey,endKey string) (StateQueryInterface,error)
// 獲取key的歷史
GetHistoryForKey(key string) (HistoryQueryIteratorInterface,error)
// 刪除key
DelState(key string) error
// 創(chuàng)建一個組合對象,類似hash對象
CreateCompositeKey(objectType string,attributes [] string) (string,error)
// 獲取hash對象的屬性內(nèi)容
GetStateByPartialCompositeKey(objectType string,keys []string) (StateQueryInterface,error)
// 拆分復(fù)合對象的key
SplitCompositeKey(compositeKey string) (string,[]string,error)
pb.Response
shim提供了一組方法,用來包裝返回的信息
返回成功
// 原型
func Success(payload []byte) pb.Response
// 使用
shim.Success([]byte("success"))
返回失敗
// 原型
func Error(msg string) pb.Response
// 使用
shim.Error("success"))
Chaincode存取數(shù)據(jù)
通過上面的shim接口,我們可以看到如何將數(shù)據(jù)存放到賬本中,如何從賬本取出,下面編寫一個例子來演示,對上一節(jié)的代碼進行改動。
Init方法中,接收兩個名字和金額,如["init","Alice","100","Bob","200"]
func (t *mychaincode) Init(stub shim.ChaincodeStubInterface) pb.Response{
var args []string
fmt.Println(" << ====[Init] success init it is view in docker ======")
_,args = stub.GetFunctionAndParameters()
var a ,b string
var aAmt,bAmt int
var err error
a = args[0]
aAmt,err = strconv.Atoi(args[1])
b = args[2]
bAmt,err = strconv.Atoi(args[3])
fmt.Println("aAmt is ",aAmt)
fmt.Println("bAmt is ",bAmt)
stub.PutState(a,[]byte(args[1]))
stub.PutState(b,[]byte(args[3]))
if err != nil{
fmt.Println("error")
}
return shim.Success([]byte("success init"))
}
Invoke方法中,接受A到B的轉(zhuǎn)賬,如["invoke","Alice","Bob","10"]
func (t *mychaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response{
var args []string
var aAmtBytes,bAmtBytes []byte
fmt.Println(" << ====[Invoke] success init it is view in docker ======")
_,args = stub.GetFunctionAndParameters()
var a ,b string
var aAmt,bAmt int
var transAmt int
//var err error
a = args[0]
b = args[1]
transAmt,_ = strconv.Atoi(args[2])
aAmtBytes,_ = stub.GetState(a)
bAmtBytes,_ = stub.GetState(b)
aAmt, _ = strconv.Atoi(string(aAmtBytes))
bAmt, _ = strconv.Atoi(string(bAmtBytes))
fmt.Println("aAmt form fabric is ",aAmt)
fmt.Println("bAmt form fabric is ",bAmt)
aAmt = aAmt - transAmt
bAmt = bAmt + transAmt
stub.PutState(a, []byte(strconv.Itoa(aAmt)))
stub.PutState(b, []byte(strconv.Itoa(bAmt)))
return shim.Success([]byte("success init"))
}
編寫完成后,還需要編寫main方法
func main(){
err := shim.Start(new(mychaincode))
if err != nil{
fmt.Println("Error starting Simple chaincode : %s",err)
}
}
之后,使用go build構(gòu)建,再按照上一節(jié)的方法,安裝,實例化,調(diào)用測試,使用docker logs查詢?nèi)罩?/p>
<< ====[Init] success init it is view in docker ======
aAmt is 100
bAmt is 200
<< ====[Invoke] success init it is view in docker ======
aAmt form fabric is 100
bAmt form fabric is 200
<< ====[Invoke] success init it is view in docker ======
aAmt form fabric is 90
bAmt form fabric is 210
<< ====[Invoke] success init it is view in docker ======
aAmt form fabric is 80
bAmt form fabric is 220
編寫完成Chaincode后,可以執(zhí)行
go build查看是否編譯成功,如果安裝和實例化之后更改了Chaincode程序,需要重新build,然后使用peer chaincode upgrade命令,設(shè)置最新的版本號,更新chaincode