fabric学习(8)——chaincode

  1. chaincode学习

chaincode学习

详情请看代码注释

package main

import (
    "fmt"

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

)

// 必须导入fabric的shim包及peer包,并实现其Init及Invoke方法
// 这两个方法要以一个结构体(可以理解成对象)为载体,可以是空的结构体
type ChaincodeStudy struct {
}

// main方法也是合约必备的方法,是启动整个合约的入口
func main() {
    if err := shim.Start(new(ChaincodeStudy)); err != nil {
        fmt.Println("chaincode start error ", err)
    }

}

// Init 方法会在执行peer chaincode instantiate命令的时候调用
func (t *ChaincodeStudy) Init(stub shim.ChaincodeStubInterface) pb.Response {
    /*
        stub.GetFunctionAndParameters()方法可以获得传入的方法名及参数
        例如使用下列初始化命令:
            peer chaincode instantiate -o  orderer.caohuan.com:7050
            -C caohuanchannel -n caohuanTestcc -v 1.0 -c '{"Args":["init","a","100","b","500"]}'
            -P " OR    ('Org1MSP.member','Org2MSP.member')"
        funcName打印出来就是"init"  args就是["a","100","b","500"]
        所以此处命令行的init可以换成任意方法名,只要在合约的Init()方法中指定该方法即可
    */
    funcName, args := stub.GetFunctionAndParameters()
    fmt.Printf("funcname: %v ,args: %v", funcName, args)

    // return shim.Success代表执行成功
    //如果有错误,可以return shim.Error("something is wrong")
    return shim.Success(nil)

}

/*
    peer chaincode invoke 和 peer chaincode query 都是进入到Invoke方法
    两者区别在于:
        invoke要适应合约的背书规则,去相应的背书节点获取签名从而把交易发送给order节点进行打包
        query不会提交交易,不会发往背书节点,更不会上链
    所以使用query进行查询,而调用交易一定要使用invoke命令
*/
func (t *ChaincodeStudy) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
    // 同样的,通过stub.GetFunctionAndParameters()获取函数名及参数
    // 这样是为了避免把所有的实现都写在同一个方法内,根据不同的funcName再去调用不同的函数
    funcName, args := stub.GetFunctionAndParameters()
    if funcName == "invoke" {
        return t.invokeCC(stub, args)
    } else if funcName == "query" {
        return t.queryCC(stub, args)
    }

    return shim.Success(nil)

}

func (t *ChaincodeStudy) invokeCC(stub shim.ChaincodeStubInterface, args []string) pb.Response {
    return shim.Success(nil)
}

func (t *ChaincodeStudy) queryCC(stub shim.ChaincodeStubInterface, args []string) pb.Response {
    // return的是一个[]byte
    result := []byte("value")
    return shim.Success(result)
}

// 总结一下合约内常用的API
func (t *ChaincodeStudy) ApiList(stub shim.ChaincodeStubInterface) {
    // 获取调用方法及参数
    funcName, args := stub.GetFunctionAndParameters()
    fmt.Println(funcName, args)

    // 存值
    err := stub.PutState("key", []byte("value"))
    fmt.Println(err)
    
    // 取值
    res, err := stub.GetState("key")
    fmt.Println(res, err)
    
    // 删除
    err = stub.DelState("key")
    
    /*
        用于同一channel中对于不同的org的权限控制,用的较少。
        需要在instantiate chaincode的时候就指定好策略:
            {
                "name":"collecionPrivate",
                "policy":"OR('Org1MSP.member')",
                "requiredPeerCount":0,
                "maxPeerCount":3,
                "blockTOLive":3,
                "menberOnlyRead":true
            }
    
        peer chaincode  instantiate --collections-config 实例化的时候指定文件路径
    */
    err = stub.PutPrivateData("collecionPrivate", "key", []byte("value"))
    res, err = stub.GetPrivateData("collecionPrivate", "key")
    err = stub.DelPrivateData("collecionPrivate", "key")
    
    // 取值时根据范围取,返回的是一个迭代,只有key有序的情况下才有用
    iterator, err := stub.GetStateByRange("startKey", "endKey")
    if iterator.HasNext() {
        fmt.Println(iterator.Next())
    }
    
    // couchDB的复查询功能,可以不仅根据key来查,还可以根据value来查,没有索引的情况下比较慢
    // 例如查询所有 age = 20 的人
    iterator, err = stub.GetQueryResult(fmt.Sprintf("{\"selector\":{\"age\":\"%v\"}}", 20))
    
    // 根据取值范围查询,并分页,bookmark类似于mysql中的offset
    iterator, bookmark, err := stub.GetStateByRangeWithPagination("startKey", "endKey", 10, "")
    fmt.Println(bookmark)
    
    // 根据复查询分页
    iterator, bookmark, err = stub.GetQueryResultWithPagination("sql", 10, "")
    
    //获取某个key所有的历史记录
    hisIterator, err := stub.GetHistoryForKey("key")
    if hisIterator.HasNext() {
        fmt.Println(hisIterator.Next())
    }
    
    // 设置event,可以发布/订阅消息队列
    var as []byte
    for _, a := range args {
        as = append(as, []byte(a)...)
    }
    stub.SetEvent("InitEvent", as)
    
    //调用其他合约
    stub.InvokeChaincode("合约名", [][]byte{[]byte("invoke"), []byte("transfer"), []byte("a")}, "通道")
    
    //设置日志级别
    //将"debug"字符串转换成LoggingLevel类型
    //"CRITICAL"      0
    //"ERROR"         1
    //"WARNING"       2
    //"NOTICE"        3
    //"INFO"          4
    //"DEBUG"         5
    logLevel, _ := shim.LogLevel("DEBUG")
    shim.SetLoggingLevel(logLevel)

}


转载请注明来源

×

喜欢就点赞,疼爱就打赏