Hyperledger/fabric - first-network解析(二)

查看chaincode

閱讀scripts/script.shscripts/util.sh可以發現,對于這個fabric網絡來說,執行chaincode的方式是,在cli容器中,執行peer命令。
比如,查詢a的值:

$ docker exec cli peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'
90

查看peer的help可見:

Available Commands:
  chaincode   Operate a chaincode: install|instantiate|invoke|package|query|signpackage|upgrade|list.
  channel     Operate a channel: create|fetch|join|list|update|signconfigtx|getinfo.
  help        Help about any command
  logging     Log levels: getlevel|setlevel|revertlevels.
  node        Operate a peer node: start|status.
  version     Print fabric peer version.

peer工具可以執行對chaincode的各種操作。(還可以操作channel/node/logging level)

可以看下當前installed的chaincode:

$ docker exec cli peer chaincode list --installed
Get installed chaincodes on peer:
Name: mycc, Version: 1.0, Path: github.com/chaincode/chaincode_example02/go/, Id: 333a19b11063d0ade7be691f9f22c04ad369baba15660f7ae9511fd1a6488209

這里我們知道,之前執行的chaincode mycc到底是什么了。

查看這個文件(只留下query函數):

package main

import (
    "fmt"
    "strconv"
    "github.com/hyperledger/fabric/core/chaincode/shim"
    pb "github.com/hyperledger/fabric/protos/peer"
)

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

func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
    ......
}

func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
    fmt.Println("ex02 Invoke")
    function, args := stub.GetFunctionAndParameters()
    if function == "query" {
        // the old "Query" is now implemtned in invoke
        return t.query(stub, args)
    }

    return shim.Error("Invalid invoke function name. Expecting \"invoke\" \"delete\" \"query\"")
}

// query callback representing the query of a chaincode
func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
    var A string // Entities
    var err error

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

    A = args[0]

    // Get the state from the ledger
    Avalbytes, err := stub.GetState(A)
    if err != nil {
        jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}"
        return shim.Error(jsonResp)
    }

    if Avalbytes == nil {
        jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}"
        return shim.Error(jsonResp)
    }

    jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}"
    fmt.Printf("Query Response:%s\n", jsonResp)
    return shim.Success(Avalbytes)
}

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

從整體來看,一個chaincode的寫法就是:

  1. type A struct {}
  2. 實現func (a *A) Init(stub shim.ChaincodeStubInterface) pb.Response方法。
  3. 實現func (a *A) Invoke(stub shim.ChaincodeStubInterface) pb.Response方法。內部分發工作到其他功能函數。
  4. 實現功能函數。形式為func (a *A) fn(stub shim.ChaincodeStubInterface, args []string) pb.Response
  5. shim.Start(new(SimpleChaincode))

其中github.com/hyperledger/fabric/core/chaincode/shim是一個重要的輔助包,貫穿chaincode編寫的各方面。

再看query函數,實際上就是做了一件事:stub.GetState(args[0]),即獲取"a"的state。

同文件中的invoke方法,則是令A-X,B+X,可以認為是A賬戶到B賬戶轉移X值。

這個chaincode的nodejs版本在這里。因為語言特性,寫起來更簡單一些。

現在,我們可以修改這個chaincode,再重新啟動整個網絡,查看不同的結果了。

動態增加chaincode

同樣閱讀scripts/script.shscripts/util.sh可以發現,注冊chaincode的方法是:
peer chaincode install -n mycc -v ${VERSION} -l ${LANGUAGE} -p ${CC_SRC_PATH}
需要注意的是,由于chaincode實質上是一個類,所以調用其方法前,需要先用peer instantiate實例化它。

開發fabric項目的通用方法

從之前的分析我們了解到,開發一個fabric項目,最主要的是兩個步驟:

  1. 構造一個合理的fabric network。
  2. 根據業務編寫chaincode,并應用于network。
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容