知乎專欄 | 多維度架構 | | | 微信號 netkiller-ebook | | | QQ群:128659835 請註明“讀者” |
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()) }
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)) }
parms1 := []string{"query","a"} queryArgs := make([][]byte, len(parms1)) for i, arg := range parms1 { queryArgs[i] = []byte(arg) } response := stub.InvokeChaincode("cc_endfinlshed",queryArgs,"roberttestchannel12") if response.Status != shim.OK { errStr := fmt.Sprintf("Failed to query chaincode. Got error: %s", response.Payload) fmt.Printf(errStr) return shim.Error(errStr) } result := string(response.Payload) fmt.Printf(" invoke chaincode %s " ,result) return shim.Success([]byte("success InvokeChaincode and Not opter !!!!!!!! " + result))
import ( "encoding/json" "fmt" "strconv" "github.com/hyperledger/fabric/common/util" "github.com/hyperledger/fabric/core/chaincode/shim" pb "github.com/hyperledger/fabric/protos/peer" ) // Invoke func (am *accountManagement) Invoke(stub shim.ChaincodeStubInterface) peer.Response { actionName, params := stub.GetFunctionAndParameters() if actionName == "callAnotherCC" { chainCodeArgs := util.ToChaincodeArgs("anotherCCFunc", "paramA") response := stub.InvokeChaincode("anotherCCName", chainCodeArgs, "channelName") if response.Status != shim.OK { return shim.Error(response.Message) } return shim.Success(nil) } // NOTE: This is an example, hence assuming only valid call is to call another chaincode return shim.Error(fmt.Sprintf("[ERROR] No <%s> action defined", actionName)) }
func (t *SimpleChaincode) certificate(stub shim.ChaincodeStubInterface, args []string) pb.Response{ creatorByte,_:= stub.GetCreator() certStart := bytes.IndexAny(creatorByte, "-----BEGIN") if certStart == -1 { fmt.Errorf("No certificate found") } certText := creatorByte[certStart:] bl, _ := pem.Decode(certText) if bl == nil { fmt.Errorf("Could not decode the PEM structure") } cert, err := x509.ParseCertificate(bl.Bytes) if err != nil { fmt.Errorf("ParseCertificate failed") } uname:=cert.Subject.CommonName fmt.Println("Name:"+uname) return shim.Success([]byte("Called testCertificate "+uname)) }