搭建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"]}'