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。
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容