HyperledgerfabricChaincode开发的示例分析
这篇文章给大家分享的是有关Hyperledger fabric Chaincode开发的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。
创新互联建站一直秉承“诚信做人,踏实做事”的原则,不欺瞒客户,是我们最起码的底线! 以服务为基础,以质量求生存,以技术求发展,成交一个客户多一个朋友!为您提供成都网站设计、成都做网站、成都网页设计、小程序开发、成都网站开发、成都网站制作、成都软件开发、app软件开发公司是成都本地专业的网站建设和网站设计公司,等你一起来见证!
Hyperledger fabric Chaincode 开发
16.7. Chaincode 结构
shim.ChaincodeStubInterface 接口有三个方法,分别是:Init、Query 和 Invoke
16.7.1. 包
package main
16.7.2. 导入库
import ( "fmt" "strconv" "github.com/hyperledger/fabric/core/chaincode/shim" pb "github.com/hyperledger/fabric/protos/peer" )
16.7.3. 定义类
type SimpleChaincode struct { }
16.7.4. Init 方法
负责初始化工作,链码首次部署到区块链网络时调用,将由部署自己的链代码实例的每个对等节点执行。此方法可用于任何与初始化、引导或设置相关的任务。
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response { }
16.7.5. Query
只要在区块链状态上执行任何读取/获取/查询操作,就需要调用 Query 方法。如果尝试在 Query 方法内修改区块链的状态,将会抛出异常。
16.7.6. Invoke
此方法主要是做修改操作,但是很多例子中一些用户也在 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) }
16.7.7. func main()
任何 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 节点。
16.8. shim.ChaincodeStubInterface 接口
Hyperledger提供基于key/value的数据存储,其中key是字符串,value则是二进制字节数组,Hyperledger的Go API提供了三个方法用于数据存取:PutState(key, value)用于向Hyperledger中存储数据, GetState(key)用于从Hyperledger中提取数据,而DelState(key)则从Hyperledger中删除数据。
写入数据如果是 struct 结构体,需要序列化,通常使用 json,其他形式的序列化也可以,只要能反序列化即可。
16.8.1. 曾,删,查 操作
16.8.1.1. PutState(key, value)写入区块
写入区块联系
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) }
16.8.1.2. GetState(key) 读取区块
通过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) }
16.8.1.3. DelState(key) 删除区块
删除区块信息
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) }
16.8.1.4. 修改数据
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) }
16.8.1.5. GetStateByRange(startKey, endKey) 范围查找
区块链是一个线性的数据结构,只要知道开始位置,结束位置,就能够取出中间部分的数据。
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()) }
16.8.1.6. GetQueryResult(query string) CouchDB 查询
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) }
16.8.1.7. stub.GetHistoryForKey
通过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) }
16.8.1.8. shim.HistoryQueryIteratorInterface 接口
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 }
16.8.2. 复合键
16.8.2.1. 创建复合键
// 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()) }
16.8.2.2. 分解复合键
// 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]
16.8.3. stub.SetEvent(key, value) 事件
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) } }
16.8.4. 调用其他链码
在当前连码中调用另一个连码,调用连码需要提供连码名和通道名 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开发的示例分析”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!
新闻名称:HyperledgerfabricChaincode开发的示例分析
网页路径:http://scyanting.com/article/gcggjd.html