<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    hello world

    隨筆 - 2, 文章 - 63, 評論 - 0, 引用 - 0
    數(shù)據(jù)加載中……

    fabric CouchDB使用-marbles鏈碼碼翻譯

    源碼

    關(guān)鍵代碼梳理
    1. 創(chuàng)建索引
      //  ==== 創(chuàng)建顏色的索引 ====
          
      //  索引是一個狀態(tài)數(shù)據(jù)庫中的正常鍵值對
          
      //  該鍵是一個復(fù)合鍵,其中首先列出了要進(jìn)行范圍查詢的元素。(本例中是顏色,需要把顏色放在首位,結(jié)構(gòu)是:indexName~color~name)
          
      //  這將使基于匹配indexName~.~*的復(fù)合鍵的非常有效的狀態(tài)范圍查詢成為可能。
          
      //  該處代碼是創(chuàng)建的地方,使用的地方詳見: transferMarblesBasedOnColor  方法
          indexName := "color~name"
          colorNameIndexKey, err := stub.CreateCompositeKey(indexName, []string{marble.Color, marble.Name})
          if err != nil {
              return shim.Error(err.Error())
          }

          // 將索引項保存到狀態(tài)。只需要索引的key,不需要存儲大理石的marble
          
      // 注意-傳遞“nil”值將有效地從state中刪除密鑰,因此我們將空字符作為值傳遞
          value := []byte{0x00}
          stub.PutState(colorNameIndexKey, value)
    2. 刪除索引
      // maintain the index
          indexName := "color~name"
          colorNameIndexKey, err := stub.CreateCompositeKey(indexName, []string{marbleJSON.Color, marbleJSON.Name})
          if err != nil {
              return shim.Error(err.Error())
          }

          //  在狀態(tài)中刪除索引的記錄項
          err = stub.DelState(colorNameIndexKey)
          if err != nil {
              return shim.Error("Failed to delete state:" + err.Error())
          }
    3. 索引查詢
      Note that we don't get the value (2nd return variable), we'll just get the marble name from the composite key
      GetStateByPartialCompositeKey不會返回對象的全部數(shù)據(jù),只會返回索引key和
      // Query the color~name index by color
          
      // This will execute a key range query on all keys starting with 'color'
          coloredMarbleResultsIterator, err := stub.GetStateByPartialCompositeKey("color~name", []string{color})
          if err != nil {
              return shim.Error(err.Error())
          }
          defer coloredMarbleResultsIterator.Close()


    翻譯后的源碼
    /*
     SPDX-License-Identifier: Apache-2.0
    */

    // ====CHAINCODE EXECUTION SAMPLES (CLI) ==================

    // ==== Invoke marbles ====
    // peer chaincode invoke -C myc1 -n marbles -c '{"Args":["initMarble","marble1","blue","35","tom"]}'
    // peer chaincode invoke -C myc1 -n marbles -c '{"Args":["initMarble","marble2","red","50","tom"]}'
    // peer chaincode invoke -C myc1 -n marbles -c '{"Args":["initMarble","marble3","blue","70","tom"]}'
    // peer chaincode invoke -C myc1 -n marbles -c '{"Args":["transferMarble","marble2","jerry"]}'
    // peer chaincode invoke -C myc1 -n marbles -c '{"Args":["transferMarblesBasedOnColor","blue","jerry"]}'
    // peer chaincode invoke -C myc1 -n marbles -c '{"Args":["delete","marble1"]}'

    // ==== Query marbles ====
    // peer chaincode query -C myc1 -n marbles -c '{"Args":["readMarble","marble1"]}'
    // peer chaincode query -C myc1 -n marbles -c '{"Args":["getMarblesByRange","marble1","marble3"]}'
    // peer chaincode query -C myc1 -n marbles -c '{"Args":["getHistoryForMarble","marble1"]}'

    // 富查詢 (需要 CouchDB 狀態(tài)數(shù)據(jù)庫):
    // peer chaincode query -C myc1 -n marbles -c '{"Args":["queryMarblesByOwner","tom"]}'
    // peer chaincode query -C myc1 -n marbles -c '{"Args":["queryMarbles","{\"selector\":{\"owner\":\"tom\"}}"]}'

    // 具有分頁的富查詢 (需要 CouchDB 狀態(tài)數(shù)據(jù)庫):
    // peer chaincode query -C myc1 -n marbles -c '{"Args":["queryMarblesWithPagination","{\"selector\":{\"owner\":\"tom\"}}","3",""]}'

    // 支持富查詢的索引
    //
    // 為了使JSON查詢高效,CouchDB中需要索引,在進(jìn)行具有排序的JSON查詢時也是需要索引的。
    // 對于Hyperledger Fabric 1.1,索引可以放在: META-INF/statedb/couchdb/index目錄中。
    // 每個索引必須以自己的方式定義, 擴(kuò)展名為*.json的文本文件,索引定義格式為JSON,如下所示
    // CouchDB索引JSON語法,如下所示:
    // http://docs.couchdb.org/en/2.1.1/api/database/find.html#db-index
    //
    // marbles02 例子展示了索引的使用
    // 索引文件定義在 META-INF/statedb/couchdb/indexes/indexOwner.json.
    // 對于部署在生產(chǎn)環(huán)境上的鏈碼,建議在將索引的定義和鏈碼放在一起,這樣安裝鏈碼以及在通道上初始化時就能
    // 作為一個整體自動建立索引。
    // 有關(guān)更多詳細(xì)信息,請參閱Hyperledger Fabric文檔。
    //
    // 通過CouchDB Fauxton接口(CouchDB Fauxton interface)或者curl命令行工具(a command line curl utility)可以創(chuàng)建或者修改索引。
    // 這樣就可以在生產(chǎn)環(huán)境中有訪問權(quán)限的CouchDB節(jié)點上,不斷嘗試修改各種索引以支持鏈碼的查詢操作。
    // 通過這樣更新的方式,也會更新到META-INF/statedb/couchdb/indexes中,支持整體打包和部署。
    //
    // 在下面的示例中,您可以找到支持marbles02鏈碼查詢的索引定義,以及可以在開發(fā)環(huán)境中用于在CouchDB Fauxton接口或
    // curl命令行實用程序中創(chuàng)建索引的語法。

    // 例子中 hostname:port 的值在具體執(zhí)行時需要替換一下,根據(jù)所處環(huán)境可能有如下兩種情況:
    // 1、從另外一個docker容器或者其他獨立環(huán)境訪問CouchDB docker容器時:
    // http://couchdb:5984/
    //
    // 2、從同一個CouchDB docker容器訪問時:
    // http://127.0.0.1:5984/

    // 索引 docType, owner.
    //
    // 定義索引
    // curl -i -X POST -H "Content-Type: application/json" -d "{\"index\":{\"fields\":[\"docType\",\"owner\"]},\"name\":\"indexOwner\",\"ddoc\":\"indexOwnerDoc\",\"type\":\"json\"}" http://hostname:port/myc1_marbles/_index
    //

    // 索引 docType, owner, size (descending order).
    //
    // 定義索引
    // curl -i -X POST -H "Content-Type: application/json" -d "{\"index\":{\"fields\":[{\"size\":\"desc\"},{\"docType\":\"desc\"},{\"owner\":\"desc\"}]},\"ddoc\":\"indexSizeSortDoc\", \"name\":\"indexSizeSortDesc\",\"type\":\"json\"}" http://hostname:port/myc1_marbles/_index

    // 指定了索引文檔名和索引名的 富查詢:
    //   peer chaincode query -C myc1 -n marbles -c '{"Args":["queryMarbles","{\"selector\":{\"docType\":\"marble\",\"owner\":\"tom\"}, \"use_index\":[\"_design/indexOwnerDoc\", \"indexOwner\"]}"]}'

    // 只指定索引文檔名 富查詢::
    //   peer chaincode query -C myc1 -n marbles -c '{"Args":["queryMarbles","{\"selector\":{\"docType\":{\"$eq\":\"marble\"},\"owner\":{\"$eq\":\"tom\"},\"size\":{\"$gt\":0}},\"fields\":[\"docType\",\"owner\",\"size\"],\"sort\":[{\"size\":\"desc\"}],\"use_index\":\"_design/indexSizeSortDoc\"}"]}'

    package main

    import (
        "bytes"
        "encoding/json"
        "fmt"
        "strconv"
        "strings"
        "time"

        "github.com/hyperledger/fabric/core/chaincode/shim"
        pb "github.com/hyperledger/fabric/protos/peer"
    )

    // SimpleChaincode example simple Chaincode implementation
    type SimpleChaincode struct {
    }

    type marble struct {
        ObjectType string `json:"docType"` // docType用于區(qū)分狀態(tài)數(shù)據(jù)庫中的各種對象類型
        Name       string `json:"name"`    //the fieldtags are needed to keep case from bouncing around
        Color      string `json:"color"`
        Size       int    `json:"size"`
        Owner      string `json:"owner"`
    }

    // ===================================================================================
    // Main
    // ===================================================================================
    func main() {
        err := shim.Start(new(SimpleChaincode))
        if err != nil {
            fmt.Printf("Error starting Simple chaincode: %s", err)
        }
    }

    // Init初始化鏈碼
    // ===========================
    func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
        return shim.Success(nil)
    }

    // Invoke - 調(diào)用的入口點
    // ========================================
    func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
        function, args := stub.GetFunctionAndParameters()
        fmt.Println("invoke is running " + function)

        // Handle different functions
        if function == "initMarble" { // 創(chuàng)建一個新的 marble
            return t.initMarble(stub, args)
        } else if function == "transferMarble" { // 改變一個 marble 的 owner
            return t.transferMarble(stub, args)
        } else if function == "transferMarblesBasedOnColor" { //轉(zhuǎn)移所有某種顏色的 marble
            return t.transferMarblesBasedOnColor(stub, args)
        } else if function == "delete" { //刪除一個 marble
            return t.delete(stub, args)
        } else if function == "readMarble" { //讀取一個 marble
            return t.readMarble(stub, args)
        } else if function == "queryMarblesByOwner" { // 通過 owner 查詢 marbles (富查詢)
            return t.queryMarblesByOwner(stub, args)
        } else if function == "queryMarbles" { //查詢 marbles (參數(shù)是 couchdb的語句)
            return t.queryMarbles(stub, args)
        } else if function == "getHistoryForMarble" { //獲取一個 marble 的歷史紀(jì)錄
            return t.getHistoryForMarble(stub, args)
        } else if function == "getMarblesByRange" { //范圍查詢 marbles
            return t.getMarblesByRange(stub, args)
        } else if function == "getMarblesByRangeWithPagination" { // 分頁范圍查詢
            return t.getMarblesByRangeWithPagination(stub, args)
        } else if function == "queryMarblesWithPagination" { // 分頁查詢
            return t.queryMarblesWithPagination(stub, args)
        }

        fmt.Println("invoke did not find func: " + function) //error
        return shim.Error("Received unknown function invocation")
    }

    // ============================================================
    // initMarble - 創(chuàng)建一個新的 marble, 保存到鏈碼的世界狀態(tài)中
    // ============================================================
    func (t *SimpleChaincode) initMarble(stub shim.ChaincodeStubInterface, args []string) pb.Response {
        var err error

        //   0       1       2     3
        
    // "asdf", "blue", "35", "bob"
        if len(args) != 4 {
            return shim.Error("Incorrect number of arguments. Expecting 4")
        }

        // ==== Input sanitation ====
        fmt.Println("- start init marble")
        if len(args[0]) <= 0 {
            return shim.Error("1st argument must be a non-empty string")
        }
        if len(args[1]) <= 0 {
            return shim.Error("2nd argument must be a non-empty string")
        }
        if len(args[2]) <= 0 {
            return shim.Error("3rd argument must be a non-empty string")
        }
        if len(args[3]) <= 0 {
            return shim.Error("4th argument must be a non-empty string")
        }
        marbleName := args[0]
        color := strings.ToLower(args[1])
        owner := strings.ToLower(args[3])
        size, err := strconv.Atoi(args[2])
        if err != nil {
            return shim.Error("3rd argument must be a numeric string")
        }

        // ==== 檢查 marble 是否已存在 ====
        marbleAsBytes, err := stub.GetState(marbleName)
        if err != nil {
            return shim.Error("Failed to get marble: " + err.Error())
        } else if marbleAsBytes != nil {
            fmt.Println("This marble already exists: " + marbleName)
            return shim.Error("This marble already exists: " + marbleName)
        }

        // ==== 創(chuàng)建 marble 對象并序列化 JSON 格式====
        objectType := "marble"
        marble := &marble{objectType, marbleName, color, size, owner}
        marbleJSONasBytes, err := json.Marshal(marble)
        if err != nil {
            return shim.Error(err.Error())
        }
        // 如果不想使用結(jié)構(gòu)體的json序列化,也可以手動構(gòu)造json字符串
        
    //marbleJSONasString := `{"docType":"Marble",  "name": "` + marbleName + `", "color": "` + color + `", "size": ` + strconv.Itoa(size) + `, "owner": "` + owner + `"}`
        
    //marbleJSONasBytes := []byte(str)

        
    // === 保存 marble 到世界狀態(tài)中 ===
        err = stub.PutState(marbleName, marbleJSONasBytes)
        if err != nil {
            return shim.Error(err.Error())
        }

        //  ==== 創(chuàng)建顏色的索引 ====
        
    //  索引是一個狀態(tài)數(shù)據(jù)庫中的正常鍵值對
        
    //  該鍵是一個復(fù)合鍵,其中首先列出了要進(jìn)行范圍查詢的元素。(本例中是顏色,需要把顏色放在首位,結(jié)構(gòu)是:indexName~color~name)
        
    //  這將使基于匹配indexName~.~*的復(fù)合鍵的非常有效的狀態(tài)范圍查詢成為可能。
        
    //  該處代碼是創(chuàng)建的地方,使用的地方詳見: transferMarblesBasedOnColor  方法
        indexName := "color~name"
        colorNameIndexKey, err := stub.CreateCompositeKey(indexName, []string{marble.Color, marble.Name})
        if err != nil {
            return shim.Error(err.Error())
        }

        // 將索引項保存到狀態(tài)。只需要索引的key,不需要存儲大理石的marble
        
    // 注意-傳遞“nil”值將有效地從state中刪除密鑰,因此我們將空字符作為值傳遞
        value := []byte{0x00}
        stub.PutState(colorNameIndexKey, value)

        // ==== Marble saved and indexed. Return success ====
        fmt.Println("- end init marble")
        return shim.Success(nil)
    }

    // ===============================================
    // readMarble - read a marble from chaincode state
    // ===============================================
    func (t *SimpleChaincode) readMarble(stub shim.ChaincodeStubInterface, args []string) pb.Response {
        var name, jsonResp string
        var err error

        if len(args) != 1 {
            return shim.Error("Incorrect number of arguments. Expecting name of the marble to query")
        }

        name = args[0]
        valAsbytes, err := stub.GetState(name) //get the marble from chaincode state
        if err != nil {
            jsonResp = "{\"Error\":\"Failed to get state for " + name + "\"}"
            return shim.Error(jsonResp)
        } else if valAsbytes == nil {
            jsonResp = "{\"Error\":\"Marble does not exist: " + name + "\"}"
            return shim.Error(jsonResp)
        }

        return shim.Success(valAsbytes)
    }

    // ==================================================
    // delete - remove a marble key/value pair from state
    // ==================================================
    func (t *SimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response {
        var jsonResp string
        var marbleJSON marble
        if len(args) != 1 {
            return shim.Error("Incorrect number of arguments. Expecting 1")
        }
        marbleName := args[0]

        // to maintain the color~name index, we need to read the marble first and get its color
        valAsbytes, err := stub.GetState(marbleName) //get the marble from chaincode state
        if err != nil {
            jsonResp = "{\"Error\":\"Failed to get state for " + marbleName + "\"}"
            return shim.Error(jsonResp)
        } else if valAsbytes == nil {
            jsonResp = "{\"Error\":\"Marble does not exist: " + marbleName + "\"}"
            return shim.Error(jsonResp)
        }

        err = json.Unmarshal([]byte(valAsbytes), &marbleJSON)
        if err != nil {
            jsonResp = "{\"Error\":\"Failed to decode JSON of: " + marbleName + "\"}"
            return shim.Error(jsonResp)
        }

        err = stub.DelState(marbleName) //remove the marble from chaincode state
        if err != nil {
            return shim.Error("Failed to delete state:" + err.Error())
        }

        // maintain the index
        indexName := "color~name"
        colorNameIndexKey, err := stub.CreateCompositeKey(indexName, []string{marbleJSON.Color, marbleJSON.Name})
        if err != nil {
            return shim.Error(err.Error())
        }

        //  在狀態(tài)中刪除索引的記錄項
        err = stub.DelState(colorNameIndexKey)
        if err != nil {
            return shim.Error("Failed to delete state:" + err.Error())
        }
        return shim.Success(nil)
    }

    // ===========================================================
    // transfer a marble by setting a new owner name on the marble
    // ===========================================================
    func (t *SimpleChaincode) transferMarble(stub shim.ChaincodeStubInterface, args []string) pb.Response {

        //   0       1
        
    // "name", "bob"
        if len(args) < 2 {
            return shim.Error("Incorrect number of arguments. Expecting 2")
        }

        marbleName := args[0]
        newOwner := strings.ToLower(args[1])
        fmt.Println("- start transferMarble ", marbleName, newOwner)

        marbleAsBytes, err := stub.GetState(marbleName)
        if err != nil {
            return shim.Error("Failed to get marble:" + err.Error())
        } else if marbleAsBytes == nil {
            return shim.Error("Marble does not exist")
        }

        marbleToTransfer := marble{}
        err = json.Unmarshal(marbleAsBytes, &marbleToTransfer) //unmarshal it aka JSON.parse()
        if err != nil {
            return shim.Error(err.Error())
        }
        marbleToTransfer.Owner = newOwner //change the owner

        marbleJSONasBytes, _ := json.Marshal(marbleToTransfer)
        err = stub.PutState(marbleName, marbleJSONasBytes) //rewrite the marble
        if err != nil {
            return shim.Error(err.Error())
        }

        fmt.Println("- end transferMarble (success)")
        return shim.Success(nil)
    }

    // ===========================================================================================
    // 從一個給定的查詢結(jié)果的迭代器構(gòu)建一個JSON數(shù)組
    // ===========================================================================================
    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
    }

    // ===========================================================================================
    // addPaginationMetadataToQueryResults adds QueryResponseMetadata, which contains pagination
    // info, to the constructed query results
    // ===========================================================================================
    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
    }

    // ===========================================================================================
    // 使用開始鍵和結(jié)束鍵進(jìn)行范圍查詢

    // 只讀方法的結(jié)果通常不會提交給 ordering. 如果為只讀結(jié)果提交給排序,
    // 或者如果查詢用于更新事務(wù)并且提交給 ordering, 然后提交對等點將重新執(zhí)行,以保證結(jié)果集在認(rèn)可時間和提交時間之間是穩(wěn)定的。
    // 如果結(jié)果集在背書之間發(fā)生了更改,交易會無效
    // 因此,范圍查詢是根據(jù)查詢結(jié)果執(zhí)行更新事務(wù)的安全選項。!!!!  區(qū)別于 GetQueryResult

    // ===========================================================================================
    func (t *SimpleChaincode) getMarblesByRange(stub shim.ChaincodeStubInterface, args []string) pb.Response {

        if len(args) < 2 {
            return shim.Error("Incorrect number of arguments. Expecting 2")
        }

        startKey := args[0]
        endKey := args[1]

        resultsIterator, err := stub.GetStateByRange(startKey, endKey)
        if err != nil {
            return shim.Error(err.Error())
        }
        defer resultsIterator.Close()

        buffer, err := constructQueryResponseFromIterator(resultsIterator)
        if err != nil {
            return shim.Error(err.Error())
        }

        fmt.Printf("- getMarblesByRange queryResult:\n%s\n", buffer.String())

        return shim.Success(buffer.Bytes())
    }

    // ==== Example: GetStateByPartialCompositeKey/RangeQuery =========================================
    // transferMarblesBasedOnColor will transfer marbles of a given color to a certain new owner.
    // 根據(jù)局部的復(fù)合鍵(前綴)返回所有匹配的鍵值 使用 color~name 'index'.
    // 會重新驗證,所以安全
    // ===========================================================================================
    func (t *SimpleChaincode) transferMarblesBasedOnColor(stub shim.ChaincodeStubInterface, args []string) pb.Response {

        //   0       1
        
    // "color", "bob"
        if len(args) < 2 {
            return shim.Error("Incorrect number of arguments. Expecting 2")
        }

        color := args[0]
        newOwner := strings.ToLower(args[1])
        fmt.Println("- start transferMarblesBasedOnColor ", color, newOwner)

        // Query the color~name index by color
        
    // This will execute a key range query on all keys starting with 'color'
        coloredMarbleResultsIterator, err := stub.GetStateByPartialCompositeKey("color~name", []string{color})
        if err != nil {
            return shim.Error(err.Error())
        }
        defer coloredMarbleResultsIterator.Close()

        // Iterate through result set and for each marble found, transfer to newOwner
        var i int
        for i = 0; coloredMarbleResultsIterator.HasNext(); i++ {
            // Note that we don't get the value (2nd return variable), we'll just get the marble name from the composite key
            responseRange, err := coloredMarbleResultsIterator.Next()
            if err != nil {
                return shim.Error(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]
            fmt.Printf("- found a marble from index:%s color:%s name:%s\n", objectType, returnedColor, returnedMarbleName)

            // Now call the transfer function for the found marble.
            
    // Re-use the same function that is used to transfer individual marbles
            response := t.transferMarble(stub, []string{returnedMarbleName, newOwner})
            // if the transfer failed break out of loop and return error
            if response.Status != shim.OK {
                return shim.Error("Transfer failed: " + response.Message)
            }
        }

        responsePayload := fmt.Sprintf("Transferred %d %s marbles to %s", i, color, newOwner)
        fmt.Println("- end transferMarblesBasedOnColor: " + responsePayload)
        return shim.Success([]byte(responsePayload))
    }

    // =======Rich queries =========================================================================
    // Two examples of rich queries are provided below (parameterized query and ad hoc query).
    // Rich queries pass a query string to the state database.
    // Rich queries are only supported by state database implementations
    //  that support rich query (e.g. CouchDB).
    // The query string is in the syntax of the underlying state database.
    // With rich queries there is no guarantee that the result set hasn't changed between
    //  endorsement time and commit time, aka 'phantom reads'.
    // Therefore, rich queries should not be used in update transactions, unless the
    // application handles the possibility of result set changes between endorsement and commit time.
    // Rich queries can be used for point-in-time queries against a peer.
    // ============================================================================================

    // ===== Example: Parameterized rich query =================================================
    // queryMarblesByOwner queries for marbles based on a passed in owner.
    // This is an example of a parameterized query where the query logic is baked into the chaincode,
    // and accepting a single query parameter (owner).
    // Only available on state databases that support rich query (e.g. CouchDB)
    // =========================================================================================
    func (t *SimpleChaincode) queryMarblesByOwner(stub shim.ChaincodeStubInterface, args []string) pb.Response {

        //   0
        
    // "bob"
        if len(args) < 1 {
            return shim.Error("Incorrect number of arguments. Expecting 1")
        }

        owner := strings.ToLower(args[0])

        queryString := fmt.Sprintf("{\"selector\":{\"docType\":\"marble\",\"owner\":\"%s\"}}", owner)

        queryResults, err := getQueryResultForQueryString(stub, queryString)
        if err != nil {
            return shim.Error(err.Error())
        }
        return shim.Success(queryResults)
    }

    // ===== Example: Ad hoc rich query ========================================================
    // queryMarbles uses a query string to perform a query for marbles.
    // Query string matching state database syntax is passed in and executed as is.
    // Supports ad hoc queries that can be defined at runtime by the client.
    // If this is not desired, follow the queryMarblesForOwner example for parameterized queries.
    // Only available on state databases that support rich query (e.g. CouchDB)
    // =========================================================================================
    func (t *SimpleChaincode) queryMarbles(stub shim.ChaincodeStubInterface, args []string) pb.Response {

        //   0
        
    // "queryString"
        if len(args) < 1 {
            return shim.Error("Incorrect number of arguments. Expecting 1")
        }

        queryString := args[0]

        queryResults, err := getQueryResultForQueryString(stub, queryString)
        if err != nil {
            return shim.Error(err.Error())
        }
        return shim.Success(queryResults)
    }

    // =========================================================================================
    // getQueryResultForQueryString executes the passed in query string.
    // Result set is built and returned as a byte array containing the JSON results.
    // =========================================================================================
    func getQueryResultForQueryString(stub shim.ChaincodeStubInterface, queryString string) ([]byte, error) {

        fmt.Printf("- getQueryResultForQueryString queryString:\n%s\n", queryString)

        resultsIterator, err := stub.GetQueryResult(queryString)
        if err != nil {
            return nil, err
        }
        defer resultsIterator.Close()

        buffer, err := constructQueryResponseFromIterator(resultsIterator)
        if err != nil {
            return nil, err
        }

        fmt.Printf("- getQueryResultForQueryString queryResult:\n%s\n", buffer.String())

        return buffer.Bytes(), nil
    }

    // ====== 分頁查詢 =========================================================================
    // 分頁提供了一種方法來檢索具有定義的頁面大小和起點(書簽)。空字符串書簽定義查詢的第一個“頁面”結(jié)果。
    // 分頁查詢返回可用于檢索下一頁結(jié)果的下一個查詢。分頁查詢擴(kuò)展包含頁面大小和書簽的豐富查詢和范圍查詢。
    // 本例中提供了兩個示例。
    // 第一個是getMarblesByRangeWithPagination它執(zhí)行分頁范圍查詢。
    // 第二個例子是富查詢的分頁查詢。
    // =========================================================================================

    // ====== 分頁范圍查詢 ===============================================
    // getMarblesByRangeWithPagination根據(jù)開始和結(jié)束鍵、頁面大小和書簽執(zhí)行范圍查詢。
    // 獲取的記錄數(shù)將等于或小于頁面大小。分頁范圍查詢僅對只讀事務(wù)有效。
    // ===========================================================================================
    func (t *SimpleChaincode) getMarblesByRangeWithPagination(stub shim.ChaincodeStubInterface, args []string) pb.Response {

        if len(args) < 4 {
            return shim.Error("Incorrect number of arguments. Expecting 4")
        }

        startKey := args[0]
        endKey := args[1]
        //return type of ParseInt is int64
        pageSize, err := strconv.ParseInt(args[2], 10, 32)
        if err != nil {
            return shim.Error(err.Error())
        }
        bookmark := args[3]

        resultsIterator, responseMetadata, err := stub.GetStateByRangeWithPagination(startKey, endKey, int32(pageSize), bookmark)
        if err != nil {
            return shim.Error(err.Error())
        }
        defer resultsIterator.Close()

        buffer, err := constructQueryResponseFromIterator(resultsIterator)
        if err != nil {
            return shim.Error(err.Error())
        }

        bufferWithPaginationInfo := addPaginationMetadataToQueryResults(buffer, responseMetadata)

        fmt.Printf("- getMarblesByRange queryResult:\n%s\n", bufferWithPaginationInfo.String())

        return shim.Success(buffer.Bytes())
    }

    // ===== 分頁富查詢 ========================================================
    // queryMarblesWithPagination使用查詢字符串、頁面大小和書簽來執(zhí)行marble查詢。
    // 查詢字符串匹配狀態(tài)數(shù)據(jù)庫語法按原樣傳入和執(zhí)行。獲取的記錄數(shù)將等于或小于指定的頁大小。
    // 支持可由客戶端在運行時定義的特殊查詢。
    // 如果不需要,請按照queryMarblesForOwner示例進(jìn)行參數(shù)化查詢。
    // 僅在支持富查詢(例如CouchDB)分頁查詢的狀態(tài)數(shù)據(jù)庫上可用,僅對只讀事務(wù)有效。
    // =========================================================================================
    func (t *SimpleChaincode) queryMarblesWithPagination(stub shim.ChaincodeStubInterface, args []string) pb.Response {

        //   0
        
    // "queryString"
        if len(args) < 3 {
            return shim.Error("Incorrect number of arguments. Expecting 3")
        }

        queryString := args[0]
        //return type of ParseInt is int64
        pageSize, err := strconv.ParseInt(args[1], 10, 32)
        if err != nil {
            return shim.Error(err.Error())
        }
        bookmark := args[2]

        queryResults, err := getQueryResultForQueryStringWithPagination(stub, queryString, int32(pageSize), bookmark)
        if err != nil {
            return shim.Error(err.Error())
        }
        return shim.Success(queryResults)
    }

    // =========================================================================================
    // getQueryResultForQueryStringWithPagination executes the passed in query string with
    // pagination info. Result set is built and returned as a byte array containing the JSON results.
    // =========================================================================================
    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 (t *SimpleChaincode) getHistoryForMarble(stub shim.ChaincodeStubInterface, args []string) pb.Response {

        if len(args) < 1 {
            return shim.Error("Incorrect number of arguments. Expecting 1")
        }

        marbleName := args[0]

        fmt.Printf("- start getHistoryForMarble: %s\n", marbleName)

        resultsIterator, err := stub.GetHistoryForKey(marbleName)
        if err != nil {
            return shim.Error(err.Error())
        }
        defer resultsIterator.Close()

        // buffer is a JSON array containing historic values for the marble
        var buffer bytes.Buffer
        buffer.WriteString("[")

        bArrayMemberAlreadyWritten := false
        for resultsIterator.HasNext() {
            response, 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("{\"TxId\":")
            buffer.WriteString("\"")
            buffer.WriteString(response.TxId)
            buffer.WriteString("\"")

            buffer.WriteString(", \"Value\":")
            // if it was a delete operation on given key, then we need to set the
            
    //corresponding value null. Else, we will write the response.Value
            
    //as-is (as the Value itself a JSON marble)
            if response.IsDelete {
                buffer.WriteString("null")
            } else {
                buffer.WriteString(string(response.Value))
            }

            buffer.WriteString(", \"Timestamp\":")
            buffer.WriteString("\"")
            buffer.WriteString(time.Unix(response.Timestamp.Seconds, int64(response.Timestamp.Nanos)).String())
            buffer.WriteString("\"")

            buffer.WriteString(", \"IsDelete\":")
            buffer.WriteString("\"")
            buffer.WriteString(strconv.FormatBool(response.IsDelete))
            buffer.WriteString("\"")

            buffer.WriteString("}")
            bArrayMemberAlreadyWritten = true
        }
        buffer.WriteString("]")

        fmt.Printf("- getHistoryForMarble returning:\n%s\n", buffer.String())

        return shim.Success(buffer.Bytes())
    }

    posted on 2019-12-27 17:18 聽風(fēng) 閱讀(642) 評論(0)  編輯  收藏 所屬分類: 區(qū)塊鏈


    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 亚洲午夜无码久久久久| 国产福利免费视频 | 久久久久亚洲av无码专区喷水| 亚洲理论片在线中文字幕| 久久久国产精品无码免费专区| 亚洲AV无码资源在线观看| 亚洲精品视频专区| 亚洲精品无码不卡在线播放HE| 免费观看的a级毛片的网站| 91人人区免费区人人| 黄床大片免费30分钟国产精品| 亚洲AV色无码乱码在线观看| 亚洲另类自拍丝袜第1页| 亚洲avav天堂av在线不卡| 国产AV无码专区亚洲AV手机麻豆| 国产小视频在线免费| 最近中文字幕免费mv视频8| 黄在线观看www免费看| 99热这里只有精品6免费| 少妇性饥渴无码A区免费| 男女拍拍拍免费视频网站| 成人嫩草影院免费观看| 老司机午夜在线视频免费| 亚洲JLZZJLZZ少妇| 亚洲国产aⅴ成人精品无吗| 久久亚洲国产成人影院| 亚洲人成电影在线观看青青| 亚洲系列国产精品制服丝袜第| 亚洲av日韩av高潮潮喷无码| 久久亚洲精品成人777大小说| 久久精品国产亚洲沈樵| 亚洲熟妇丰满多毛XXXX| 亚洲午夜久久久影院| 亚洲日本乱码在线观看| 亚洲人成77777在线播放网站| 亚洲乱码中文字幕综合| 亚洲精品无码av人在线观看 | 色老头综合免费视频| 免费精品久久久久久中文字幕 | 国产成人aaa在线视频免费观看| 日本免费网站观看|