【fabric 3】开发你的第一个chaincode

参考:http://hyperledger-fabric.readthedocs.io/en/latest/chaincode4ade.html

1.编码

每一个chaincode都需要实现chaincode interfaceInitInvoke接口
每一个chaincode都应该有一个main函数
代码结构如下所示:

package main

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

type MyFirstCC struct {
}

func (t *MyFirstCC) Init(stub shim.ChaincodeStubInterface) peer.Response {
}

func (t *MyFirstCC) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
}

func main() {
}

main函数,负责在instantiate时启动chaincode

func main() {
    err := shim.Start(new(MyFirstCC))
    if err != nil {
        fmt.Printf("error start MyFirstCC")
    }
}

Init函数,在chaincodeinstantiationupgrade时调用,初始化或者重置数据

func (t *MyFirstCC) Init(stub shim.ChaincodeStubInterface) peer.Response {
    fmt.Println("ex10 Init")
    _, args := stub.GetFunctionAndParameters()

    //set 2 parmas for this chaincode init
    //when instantiation chaincode,should give 2 params
    if len(args) != 2 {
        return shim.Error("Incorrect len of arguments")
    }

    var Aval int
    var A string
    var err error

    A = args[0]
    Aval, err = strconv.Atoi(args[1])
    if err != nil {
        return shim.Error("Expecting integer value for asset holding")
    }
    fmt.Printf("Aval = %d\n", Aval)
    //put the data to ledger
    err = stub.PutState(A, []byte(strconv.Itoa(Aval)))

    if err != nil {
        return shim.Error("failed to Create asset")
    }
    return shim.Success(nil)
}

Invoke函数,在交易时调用。我们可以自定义一些函数,当调用时传递函数名字和参数即可,例如,在本例中我们自定义setget函数。set更新账本数据,get读取账本数据

func (t *MyFirstCC) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
    fmt.Println("ex10 Invoke")

    fn, args := stub.GetFunctionAndParameters()
    var result string
    var err error
    if fn == "set" {
        result, err = set(stub, args)
    } else if fn == "get" {
        result, err = get(stub, args)
    } else {
        return shim.Error("func not found")
    }

    if err != nil {
        return shim.Error(err.Error())
    }

    return shim.Success([]byte(result))
}

func set(stub shim.ChaincodeStubInterface, args []string) (string, error) {
    fmt.Println("ex10 set")
    if len(args) != 2 {
        return "", fmt.Errorf("Incorrect arguments")
    }

    var Aval int
    var A string
    var err error

    A = args[0]
    Aval, err = strconv.Atoi(args[1])
    if err != nil {
        return "", fmt.Errorf("Expecting integer value for asset holding")
    }
    fmt.Printf("Aval = %d\n", Aval)
    //update data in ledger
    err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
    if err != nil {
        return "", fmt.Errorf("failed to PutState:%s", args[0])
    }
    return args[1], nil
}

func get(stub shim.ChaincodeStubInterface, args []string) (string, error) {
    fmt.Println("ex10 get")
    if len(args) != 1 {
        return "", fmt.Errorf("Incorrect arguments")
    }

    var A string
    A = args[0]
    //read data from ledger
    value, err := stub.GetState(A)
    if err != nil {
        return "", fmt.Errorf("failed to get asset: %s with error:%s", args[0], err)
    }
    if value == nil {
        return "", fmt.Errorf("asset not found")
    }
    return string(value), nil
}

2.测试

  • 将上述代码整合到一个.go文件中,在github.com/hyperledger/fabric/examples/chaincode/go下边新建一个文件夹,命名为example10,将go文件放置在本文件夹下,这样可以将我们自己写的chaincode映射到clidocker中
  • 准备环境,可参考【fabric 2】v1.0环境搭建详细过程第1-3步,
    注意:这个步骤执行一次即可满足后续测试需要了
  • 启动docker容器,当你的chaincode有更新时需要执行下面的步骤,以同步到cli中
    docker-compose -f docker-compose-cli.yaml up -d
  • 进入cli容器 docker exec -it cli bash //创建channel需要先进入cli
  • 创建channel
ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
peer channel create -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/channel.tx --tls true --cafile $ORDERER_CA
  • peer加入channel
peer channel join -b mychannel.block
  • install chaincode
peer chaincode install -n mycc -v 0 -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example10  //文件夹的名字是我们放置go文件的位置
  • instantiate chaincode
peer chaincode instantiate -o orderer.example.com:7050 --tls true --cafile $ORDERER_CA -C mychannel -n mycc -v 0 -c '{"Args":["init","a","20"]}' //这里给两个参数"a"和"100"
  • 调用chaincode的get方法
peer chaincode query -C mychannel -n mycc -c '{"Args":["get","a"]}' //查询余额不往账本写数据,不需要背书,用query即可
  • 调用chaincode的set方法
peer chaincode invoke -o orderer.example.com:7050  --tls true --cafile $ORDERER_CA -C mychannel -n mycc -c '{"Args":["set","a","200"]}'    //需要往更新账本,用invoke

再次调用chaincode的get方法

peer chaincode query -C mychannel -n mycc -c '{"Args":["get","a"]}' //我们发现余额已更新为200

【fabric 3】开发你的第一个chaincode_第1张图片

3. 可能遇到的问题

有的时候更改了chaincode代码重启docker发现chaincode没有更新,原因可能是上次创建的chaincode docker image还在,可以通过如下方法解决

docker ps -a

这里写图片描述

docker rm 23bae5e36c07

【fabric 3】开发你的第一个chaincode_第2张图片

docker rmi 05ebb1ebdf07     //参数要改为你的chaincode 对应的image id

至此,问题解决,每次都会更新的

你可能感兴趣的:(fabric)