您好,登錄后才能下訂單哦!
這篇文章給大家分享的是有關Hyperledger fabric Chaincode開發的示例分析的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。
shim.ChaincodeStubInterface 接口有三個方法,分別是:Init、Query 和 Invoke
package main
import ( "fmt" "strconv" "github.com/hyperledger/fabric/core/chaincode/shim" pb "github.com/hyperledger/fabric/protos/peer" )
type SimpleChaincode struct { }
負責初始化工作,鏈碼首次部署到區塊鏈網絡時調用,將由部署自己的鏈代碼實例的每個對等節點執行。此方法可用于任何與初始化、引導或設置相關的任務。
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response { }
只要在區塊鏈狀態上執行任何讀取/獲取/查詢操作,就需要調用 Query 方法。如果嘗試在 Query 方法內修改區塊鏈的狀態,將會拋出異常。
此方法主要是做修改操作,但是很多例子中一些用戶也在 Invoke 做查詢。
put, get, del 等操作都在可以在 Invoke 中運行
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { }
參考例子
func (s *SmartContract) Invoke(stub shim.ChaincodeStubInterface) sc.Response { // Retrieve the requested Smart Contract function and arguments function, args := stub.GetFunctionAndParameters() // Route to the appropriate handler function to interact with the ledger appropriately if function == "balanceToken" { return s.balanceToken(stub, args) } else if function == "initLedger" { return s.initLedger(stub) } else if function == "transferToken" { return s.transferToken(stub, args) } return shim.Error("Invalid Smart Contract function name.") }
在 Invoke 函數中,首先使用 stub.GetFunctionAndParameters() 獲取合約函數 function, args := stub.GetFunctionAndParameters() 然后判斷函數名稱,實現對應的邏輯關系。 if function == "balanceToken" { return s.balanceToken(stub, args) } else if function == "initLedger" { return s.initLedger(stub) } else if function == "transferToken" { return s.transferToken(stub, args) }
任何 Go 程序的都需要 main 函數,他是程序的入口,因此該函數被用于引導/啟動鏈代碼。當對peer節點部署chaincode并實例化時,就會執行 main 函數。
func main() { err := shim.Start(new(SimpleChaincode)) if err != nil { fmt.Printf("Error starting Simple chaincode: %s", err) } }
shim.Start(new(SampleChaincode)) 啟動鏈代碼并注冊到peer 節點。
Hyperledger提供基于key/value的數據存儲,其中key是字符串,value則是二進制字節數組,Hyperledger的Go API提供了三個方法用于數據存取:PutState(key, value)用于向Hyperledger中存儲數據, GetState(key)用于從Hyperledger中提取數據,而DelState(key)則從Hyperledger中刪除數據。
寫入數據如果是 struct 結構體,需要序列化,通常使用 json,其他形式的序列化也可以,只要能反序列化即可。
寫入區塊聯系
func (s *SmartContract) initLedger(stub shim.ChaincodeStubInterface) sc.Response { token := &Token{ Owner: "netkiller", TotalSupply: 10000, TokenName: "代幣通正", TokenSymbol: "COIN", BalanceOf: map[string]uint{}} token.initialSupply() tokenAsBytes, _ := json.Marshal(token) stub.PutState("Token", tokenAsBytes) fmt.Println("Added", tokenAsBytes) return shim.Success(nil) }
通過key獲取區塊信息
func (s *SmartContract) balanceToken(stub shim.ChaincodeStubInterface, args []string) sc.Response { if len(args) != 1 { return shim.Error("Incorrect number of arguments. Expecting 1") } tokenAsBytes, _ := stub.GetState(args[0]) token := Token{} json.Unmarshal(tokenAsBytes, &token) amount := token.balance(args[1]) return shim.Success(amount) }
刪除區塊信息
func (s *SmartContract) deleteData(stub shim.ChaincodeStubInterface, args []string) sc.Response { if len(args) != 1 { return shim.Error("Incorrect number of arguments. Expecting 1") } err= stub.DelState(args[0]) if err != nil { return shim.Error("Failed to delete Student from DB, key is: "+key) } return shim.Success(nil) }
State 數據庫并沒有提供修改功能,修改數據可以先讀取,再修改,最后寫入
func (s *SmartContract) transferToken(stub shim.ChaincodeStubInterface, args []string) sc.Response { if len(args) != 3 { return shim.Error("Incorrect number of arguments. Expecting 2") } tokenAsBytes, _ := stub.GetState(args[0]) token := Token{} json.Unmarshal(tokenAsBytes, &token) token.transfer(args[1],args[2],args[3]) tokenAsBytes, _ = json.Marshal(token) stub.PutState(args[0], tokenAsBytes) return shim.Success(nil) }
區塊鏈是一個線性的數據結構,只要知道開始位置,結束位置,就能夠取出中間部分的數據。
func (s *SmartContract) queryAllCars(APIstub shim.ChaincodeStubInterface) sc.Response { startKey := "CAR0" endKey := "CAR999" resultsIterator, err := APIstub.GetStateByRange(startKey, endKey) if err != nil { return shim.Error(err.Error()) } defer resultsIterator.Close() // buffer is a JSON array containing QueryResults var buffer bytes.Buffer buffer.WriteString("[") bArrayMemberAlreadyWritten := false for resultsIterator.HasNext() { queryResponse, err := resultsIterator.Next() if err != nil { return shim.Error(err.Error()) } // Add a comma before array members, suppress it for the first array member if bArrayMemberAlreadyWritten == true { buffer.WriteString(",") } buffer.WriteString("{\"Key\":") buffer.WriteString("\"") buffer.WriteString(queryResponse.Key) buffer.WriteString("\"") buffer.WriteString(", \"Record\":") // Record is a JSON object, so we write as-is buffer.WriteString(string(queryResponse.Value)) buffer.WriteString("}") bArrayMemberAlreadyWritten = true } buffer.WriteString("]") fmt.Printf("- queryAllCars:\n%s\n", buffer.String()) return shim.Success(buffer.Bytes()) }
GetQueryResult 能查詢 json 里面的數據
下面例子是 Name = Neo Chen 的所有數據。
func (t *SimpleChaincode) getQueryResult(stub shim.ChaincodeStubInterface, args []string) pb.Response{ name:="Neo Chen" //需要查詢的名字 queryString := fmt.Sprintf("{\"selector\":{\"Name\":\"%s\"}}", name) resultsIterator,err:= stub.GetQueryResult(queryString)//必須是CouchDB才行 if err!=nil{ return shim.Error("query failed") } person,err:=getListResult(resultsIterator) if err!=nil{ return shim.Error("query failed") } return shim.Success(person) }
通過key獲取歷史數據
func (t *SimpleChaincode) historyQuery(stub shim.ChaincodeStubInterface, args []string) pb.Response{ if len(args) != 1 { return shim.Error("Incorrect number of arguments. Expecting 1") } it,err:= stub.GetHistoryForKey(args[0]) if err!=nil{ return shim.Error(err.Error()) } var result,_= getHistoryListResult(it) return shim.Success(result) }
func getHistoryListResult(resultsIterator shim.HistoryQueryIteratorInterface) ([]byte,error){ defer resultsIterator.Close() // buffer is a JSON array containing QueryRecords var buffer bytes.Buffer buffer.WriteString("[") bArrayMemberAlreadyWritten := false for resultsIterator.HasNext() { queryResponse, err := resultsIterator.Next() if err != nil { return nil, err } // Add a comma before array members, suppress it for the first array member if bArrayMemberAlreadyWritten == true { buffer.WriteString(",") } item,_:= json.Marshal( queryResponse) buffer.Write(item) bArrayMemberAlreadyWritten = true } buffer.WriteString("]") fmt.Printf("queryResult:\n%s\n", buffer.String()) return buffer.Bytes(), nil }
// maintain the index indexName := "color~name" colorNameIndexKey, err := stub.CreateCompositeKey(indexName, []string{marbleJSON.Color, marbleJSON.Name}) if err != nil { return shim.Error(err.Error()) } // Delete index entry to state. err = stub.DelState(colorNameIndexKey) if err != nil { return shim.Error("Failed to delete state:" + err.Error()) }
// get the color and name from color~name composite key objectType, compositeKeyParts, err := stub.SplitCompositeKey(responseRange.Key) if err != nil { return shim.Error(err.Error()) } returnedColor := compositeKeyParts[0] returnedMarbleName := compositeKeyParts[1]
Hyperledger Fabic 事件實現了發布/訂閱消息隊列。您可以自由地在鏈碼中創建和發出自定義事件。例如,區塊鏈的狀態發生改變,就會生成一個事件。通過向區塊鏈上的事件中心注冊一個事件適配器,客戶端應用程序可以訂閱和使用這些事件。
func (t *SimpleChaincode) testEvent(stub shim.ChaincodeStubInterface, args []string) pb.Response{ message := "Event send data is here!" err := stub.SetEvent("evtsender", []byte(message)) if err != nil { return shim.Error(err.Error()) } return shim.Success(nil) } func (t *SimpleChaincode) testEvent(stub shim.ChaincodeStubInterface, args []string) pb.Response{ event := &Token{ Owner: "netkiller", TotalSupply: 10000, TokenName: "代幣通正", TokenSymbol: "COIN", BalanceOf: map[string]uint{}} eventBytes, err ;= json.Marshal(&event) if err != nil { return nil, err } err := stub.SetEvent("evtSender", eventBytes) if err != nil { fmt.Println("Could not set event for loan application creation", err) } }
在當前連碼中調用另一個連碼,調用連碼需要提供連碼名和通道名 stub.InvokeChaincode("連碼名",調用函數,"通道")
func (t *SimpleChaincode) testInvokeChainCode(stub shim.ChaincodeStubInterface, args []string) pb.Response{ trans:=[][]byte{[]byte("invoke"),[]byte("transfer"),[]byte("netkiller"),[]byte("neo"),[]byte("100")} response:= stub.InvokeChaincode("token",trans,"mychannel") fmt.Println(response.Message) return shim.Success([]byte( response.Message)) } 16.9. 案例 16.9.1. 模仿以太坊 ERC20 規范的 Hyperledger Fabric 實現 package main import ( "bytes" "encoding/json" "fmt" "strconv" "github.com/hyperledger/fabric/core/chaincode/shim" sc "github.com/hyperledger/fabric/protos/peer" ) // Define the Smart Contract structure type SmartContract struct { } type Token struct { Owner string `json:"Owner"` TotalSupply uint `json:"TotalSupply"` TokenName string `json:"TokenName"` TokenSymbol string `json:"TokenSymbol"` BalanceOf map[string]uint `json:"BalanceOf"` } func (token *Token) initialSupply(){ token.BalanceOf[token.Owner] = token.TotalSupply; } func (token *Token) transfer (_from string, _to string, _value uint){ if(token.BalanceOf[_from] >= _value){ token.BalanceOf[_from] -= _value; token.BalanceOf[_to] += _value; } } func (token *Token) balance (_from string) uint{ return token.BalanceOf[_from] } func (token *Token) burn(_value uint) { if(token.BalanceOf[token.Owner] >= _value){ token.BalanceOf[token.Owner] -= _value; token.TotalSupply -= _value; } } func (token *Token) burnFrom(_from string, _value uint) { if(token.BalanceOf[_from] >= _value){ token.BalanceOf[_from] -= _value; token.TotalSupply -= _value; } } func (token *Token) mint(_value uint) { token.BalanceOf[token.Owner] += _value; token.TotalSupply += _value; } func (s *SmartContract) Init(stub shim.ChaincodeStubInterface) sc.Response { return shim.Success(nil) } func (s *SmartContract) initLedger(stub shim.ChaincodeStubInterface) sc.Response { token := &Token{ Owner: "netkiller", TotalSupply: 10000, TokenName: "代幣通正", TokenSymbol: "COIN", BalanceOf: map[string]uint{}} token.initialSupply() tokenAsBytes, _ := json.Marshal(token) stub.PutState("Token", tokenAsBytes) fmt.Println("Added", tokenAsBytes) return shim.Success(nil) } func (s *SmartContract) transferToken(stub shim.ChaincodeStubInterface, args []string) sc.Response { if len(args) != 3 { return shim.Error("Incorrect number of arguments. Expecting 2") } tokenAsBytes, _ := stub.GetState(args[0]) token := Token{} json.Unmarshal(tokenAsBytes, &token) token.transfer(args[1],args[2],args[3]) tokenAsBytes, _ = json.Marshal(token) stub.PutState(args[0], tokenAsBytes) return shim.Success(nil) } func (s *SmartContract) balanceToken(stub shim.ChaincodeStubInterface, args []string) sc.Response { if len(args) != 1 { return shim.Error("Incorrect number of arguments. Expecting 1") } tokenAsBytes, _ := stub.GetState(args[0]) token := Token{} json.Unmarshal(tokenAsBytes, &token) amount := token.balance(args[1]) return shim.Success(amount) } func (s *SmartContract) Invoke(stub shim.ChaincodeStubInterface) sc.Response { // Retrieve the requested Smart Contract function and arguments function, args := stub.GetFunctionAndParameters() // Route to the appropriate handler function to interact with the ledger appropriately if function == "balanceToken" { return s.balanceToken(stub, args) } else if function == "initLedger" { return s.initLedger(stub) } else if function == "transferToken" { return s.transferToken(stub, args) } return shim.Error("Invalid Smart Contract function name.") } // The main function is only relevant in unit test mode. Only included here for completeness. func main() { // Create a new Smart Contract err := shim.Start(new(SmartContract)) if err != nil { fmt.Printf("Error creating new Smart Contract: %s", err) } }
感謝各位的閱讀!關于“Hyperledger fabric Chaincode開發的示例分析”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。