搭建hyperledger fabric 网络(数据库 使用CouchDB )参考上一篇随笔:快速搭建hyperledger fabric 1.3 网络
当CouchDB查询返回大型结果集时,可以使用一系列API,这些API可以通过调用链代码来对结果列表进行分页。 分页提供了一种机制,通过指定页面大小和起始点来划分结果集——一个指示结果集开始位置的书签。 客户端应用程序迭代地调用执行查询的链代码,直到不再返回结果。
main.go
package main import ( "fmt" "github.com/hyperledger/fabric/core/chaincode/shim" ) type ChainCode struct { } type Msg struct { Status bool `json:"Status"` Code int `json:"Code"` Result string `json:"Result"` } func main() { err := shim.Start(new(ChainCode)) if err != nil { fmt.Printf("Error starting chaincode: %s", err) } }
router.go
package main import ( "fmt" "github.com/hyperledger/fabric/core/chaincode/shim" pb "github.com/hyperledger/fabric/protos/peer" ) func (cc *ChainCode) Init(stub shim.ChaincodeStubInterface) pb.Response { return shim.Success(nil) } func (cc *ChainCode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { function, args := stub.GetFunctionAndParameters() switch function { case "addServiceRecord": //新增记录 return cc.addServiceRecord(stub, args) case "getServiceRecord": //查询 return cc.getServiceRecord(stub, args) default: //error fmt.Println("invoke did not find func: " + function) return shim.Error("Received unknown function invocation") } }
emr.go

package main import ( "bytes" "encoding/json" "fmt" "strconv" "github.com/hyperledger/fabric/core/chaincode/shim" pb "github.com/hyperledger/fabric/protos/peer" ) type ServiceRecord struct { Frcode string `json:"frcode"` //县区代码 Service_Code string `json:"service_code"` //卫生服务活动代码 Service_Name string `json:"service_name"` //卫生服务活动 Service_Time string `json:"service_time"` //活动时间 Institution_Code string `json:"institution_code"` //医疗机构编号 Institution_Name string `json:"institution_name"` //医疗机构名称 OperatorId string `json:"operatorid"` //操作人编号 Operator_Name string `json:"operator_name"` //操作人名称 Operate_Time string `json:"operate_time"` //操作时间,年月日+时分秒 PersonId string `json:"personid"` //服务对象编号 Person_Name string `json:"person_name"` //服务对象名称 ServiceId string `json:"serviceid"` //记录编号 Area_Code string `json:"area_code"` //人员所属区域编码 } func (cc *ChainCode) addServiceRecord(stub shim.ChaincodeStubInterface, args []string) pb.Response { jsonStr := args[0] var serviceRecord ServiceRecord err := json.Unmarshal([]byte(jsonStr), &serviceRecord) if err != nil { message := "数据处理失败! 参数错误!" msg := &Msg{Status: false, Code: 0, Result: message} rev, _ := json.Marshal(msg) return shim.Success(rev) } key := serviceRecord.ServiceId esixtAsBytes, err := stub.GetState(key) if string(esixtAsBytes) != "" || err != nil { message := "数据处理失败! 重复的记录编号!" msg := &Msg{Status: false, Code: 0, Result: message} rev, _ := json.Marshal(msg) return shim.Success(rev) } serviceRecordAsBytes, _ := json.Marshal(serviceRecord) err = stub.PutState(key, serviceRecordAsBytes) if err != nil { message := "数据处理失败! 存储错误!" msg := &Msg{Status: false, Code: 0, Result: message} rev, _ := json.Marshal(msg) return shim.Success(rev) } message := "数据处理成功!" msg := &Msg{Status: true, Code: 0, Result: message} rev, _ := json.Marshal(msg) return shim.Success(rev) } func (cc *ChainCode) getServiceRecord(stub shim.ChaincodeStubInterface, args []string) pb.Response { queryString := args[0] pageSize, err := strconv.ParseInt(args[1], 10, 32) if err != nil { message := "数据处理失败! 参数错误!" msg := &Msg{Status: false, Code: 0, Result: message} rev, _ := json.Marshal(msg) return shim.Success(rev) } bookmark := args[2] queryResults, err := getQueryResultForQueryStringWithPagination(stub, queryString, int32(pageSize), bookmark) if err != nil { message := "查询失败! " + err.Error() msg := &Msg{Status: false, Code: 0, Result: message} rev, _ := json.Marshal(msg) return shim.Success(rev) } msg := &Msg{Status: true, Code: 0, Result: string(queryResults)} rev, _ := json.Marshal(msg) return shim.Success(rev) } func getQueryResultForQueryStringWithPagination(stub shim.ChaincodeStubInterface, queryString string, pageSize int32, bookmark string) ([]byte, error) { fmt.Printf("- getQueryResultForQueryString queryString:\n%s\n", queryString) resultsIterator, responseMetadata, err := stub.GetQueryResultWithPagination(queryString, pageSize, bookmark) if err != nil { return nil, err } defer resultsIterator.Close() buffer, err := constructQueryResponseFromIterator(resultsIterator) if err != nil { return nil, err } bufferWithPaginationInfo := addPaginationMetadataToQueryResults(buffer, responseMetadata) fmt.Printf("- getQueryResultForQueryString queryResult:\n%s\n", bufferWithPaginationInfo.String()) return buffer.Bytes(), nil } func constructQueryResponseFromIterator(resultsIterator shim.StateQueryIteratorInterface) (*bytes.Buffer, error) { // 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 nil, err } // 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("]") return &buffer, nil } func addPaginationMetadataToQueryResults(buffer *bytes.Buffer, responseMetadata *pb.QueryResponseMetadata) *bytes.Buffer { buffer.WriteString("[{\"ResponseMetadata\":{\"RecordsCount\":") buffer.WriteString("\"") buffer.WriteString(fmt.Sprintf("%v", responseMetadata.FetchedRecordsCount)) buffer.WriteString("\"") buffer.WriteString(", \"Bookmark\":") buffer.WriteString("\"") buffer.WriteString(responseMetadata.Bookmark) buffer.WriteString("\"}}]") return buffer }
安装合约
peer chaincode install -n emr -v 1.0 -l golang -p github.com/chaincode/EMR/go/
实例化合约
peer chaincode instantiate -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID mychannel -n emr -l golang -v 1.0 -c '{"Args":["init",""]}' -P 'OR ('\''Org1MSP.peer'\'','\''Org2MSP.peer'\'')'
插入数据1
peer chaincode invoke -C mychannel -n emr -c '{"Args":["addServiceRecord","{\"Frcode\":\"xxxx002\",\"Service_Code\":\"xxxx\",\"Service_Name\":\"1\",\"Service_Time\":\"xxxx\",\"Institution_Code\":\"xxxx\",\"Institution_Name\":\"198544455454\",\"OperatorId\":\"xxxxx\",\"Operator_Name\":\"0\",\"Operate_Time\":\"xxxxx\",\"PersonId\":\"xxxxx\",\"Person_Name\":\"xxxxx\",\"ServiceId\":\"xxxxx001\",\"Area_Code\":\"xxxxx\"}"]}' --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
插入数据2
peer chaincode invoke -C mychannel -n emr -c '{"Args":["addServiceRecord","{\"Frcode\":\"xxxx002\",\"Service_Code\":\"xxxx\",\"Service_Name\":\"1\",\"Service_Time\":\"xxxx\",\"Institution_Code\":\"xxxx\",\"Institution_Name\":\"198544455454\",\"OperatorId\":\"xxxxx\",\"Operator_Name\":\"0\",\"Operate_Time\":\"xxxxx\",\"PersonId\":\"xxxxx\",\"Person_Name\":\"xxxxx\",\"ServiceId\":\"xxxxx002\",\"Area_Code\":\"xxxxx\"}"]}' --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
插入数据3
peer chaincode invoke -C mychannel -n emr -c '{"Args":["addServiceRecord","{\"Frcode\":\"xxxx002\",\"Service_Code\":\"xxxx\",\"Service_Name\":\"1\",\"Service_Time\":\"xxxx\",\"Institution_Code\":\"xxxx\",\"Institution_Name\":\"198544455454\",\"OperatorId\":\"xxxxx\",\"Operator_Name\":\"0\",\"Operate_Time\":\"xxxxx\",\"PersonId\":\"xxxxx\",\"Person_Name\":\"xxxxx\",\"ServiceId\":\"xxxxx003\",\"Area_Code\":\"xxxxx\"}"]}' --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
插入数据4
peer chaincode invoke -C mychannel -n emr -c '{"Args":["addServiceRecord","{\"Frcode\":\"xxxx002\",\"Service_Code\":\"xxxx\",\"Service_Name\":\"1\",\"Service_Time\":\"xxxx\",\"Institution_Code\":\"xxxx\",\"Institution_Name\":\"198544455454\",\"OperatorId\":\"xxxxx\",\"Operator_Name\":\"0\",\"Operate_Time\":\"xxxxx\",\"PersonId\":\"xxxxx\",\"Person_Name\":\"xxxxx\",\"ServiceId\":\"xxxxx004\",\"Area_Code\":\"xxxxx\"}"]}' --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
插入数据5
peer chaincode invoke -C mychannel -n emr -c '{"Args":["addServiceRecord","{\"Frcode\":\"xxxx002\",\"Service_Code\":\"xxxx\",\"Service_Name\":\"1\",\"Service_Time\":\"xxxx\",\"Institution_Code\":\"xxxx\",\"Institution_Name\":\"198544455454\",\"OperatorId\":\"xxxxx\",\"Operator_Name\":\"0\",\"Operate_Time\":\"xxxxx\",\"PersonId\":\"xxxxx\",\"Person_Name\":\"xxxxx\",\"ServiceId\":\"xxxxx005\",\"Area_Code\":\"xxxxx\"}"]}' --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
分页查询1(如果未指定书签,则查询以“第一”记录页开头。)
peer chaincode query -C mychannel -n emr -c '{"Args":["getServiceRecord","{\"selector\":{\"$and\": [{\"frcode\":\"xxxx002\"},{\"service_code\":\"xxxx\"}]}}","3",""]}'
分页查询2
peer chaincode query -C mychannel -n emr -c '{"Args":["getServiceRecord","{\"selector\":{\"$and\": [{\"frcode\":\"xxxx002\"},{\"service_code\":\"xxxx\"}]}}","3","g1AAAABAeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYpzVICAgYExSJ4DJo8ikwUAQs8Smw"]}'
分页查询3
peer chaincode query -C mychannel -n emr -c '{"Args":["getServiceRecord","{\"selector\":{\"$and\": [{\"frcode\":\"xxxx002\"},{\"service_code\":\"xxxx\"}]}}","3","g1AAAABAeJzLYWBgYMpgSmHgKy5JLCrJTq2MT8lPzkzJBYpzVICAgYEpSJ4DJo8ikwUAQwsSnw"]}'