本文链码实例为Fabric 官方实例examples/chaincode/go/chaincode_example02,实现简单的转账功能


进入到cli容器里面

$ docker exec -it fabric-cli bash

1. 链码安装

以在org1, peer0 为例

1.1 设置环境变量

export CORE_PEER_LOCALMSPID=Org2MSP
export CORE_PEER_ADDRESS=peer1.org2.example.com:7051
export CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/users/[email protected]/msp
export CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt

1.2 安装链码

# peer chaincode install -n test02 -v 1.0 -p examples/chaincode/go/chaincode_example02

修改相关环境变量和参数,重复步骤1.1 和1.2,在{org1, peer1},{org2, peer0},{org2, peer1}上安装链码

2.链码实例化

以下过程在任意一个节点执行一次就行。


peer chaincode instantiate \
-o orderer.example.com:7050 \
-C "businesschannel"  \
-n test02 \
-v 1.0 \
-c '{"Args":["init","a","100","b","200"]}' \
-P "OR    ('Org1MSP.member','Org2MSP.member')" \
--tls true \
--cafile /etc/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

3.测试链码

3.1 查询初始值


# peer chaincode query -C "businesschannel" -n "exp02" -c '{"Args":["query","a"]}'



# peer chaincode query -C "businesschannel" -n "exp02" -c '{"Args":["query","b"]}'

3.2 转账:从"a" 的账户转账10到"b" 的账户

peer chaincode invoke \
-o orderer.example.com:7050 \
-C "businesschannel" \
-n "test02" \
-c '{"Args":["invoke","a","b","10"]}' \
--tls true \
--cafile /etc/hyperledger/fabric/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

3.3 查询转账结果

# peer chaincode query -C "businesschannel" -n "test02" -c '{"Args":["query","a"]}'

查询另一个节点{org2,peer1} 的账本

export CORE_PEER_LOCALMSPID=Org2MSP
export CORE_PEER_ADDRESS=peer1.org2.example.com:7051
export CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/users/[email protected]/msp
export CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.cr

结果一致。

4.代码解析

4.1 引入必要的包

import (
    "fmt"
    "strconv"

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

  "github.com/hyperledger/fabric/core/chaincode/shim":shim包提供了链码与账本交互的中间层。

4.2 初始化

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

......

//提取参数

    _, args := stub.GetFunctionAndParameters()
    var A, B string    // Entities
    var Aval, Bval int // Asset holdings

......

    // 初始化链码

    A = args[0]
    Aval, err = strconv.Atoi(args[1])

......

 B = args[2]

    Bval, err = strconv.Atoi(args[3])

......

    // 把状态写入账本

    err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
  ......
    err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
......
    return shim.Success(nil)
}

4.3 Inovke方法

获取function值

function, args := stub.GetFunctionAndParameters()

根据function值不同,执行不同的分支处理逻辑。

    if function == "invoke" {
        // Make payment of X units from A to B
        return t.invoke(stub, args)
    } else if function == "delete" {
        // Deletes an entity from its state
        return t.delete(stub, args)
    } else if function == "query" {
        // the old "Query" is now implemtned in invoke
        return t.query(stub, args)
    }

query分支

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

......   

A = args[0]

    // 从账本获得状态值

    Avalbytes, err := stub.GetState(A)

......

}


invoke分支

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

......

//从账本获取"a"的值

Avalbytes, err := stub.GetState(A)

......

//从账本获取"b"的值

Bvalbytes, err := stub.GetState(B)

......

//执行转账

    Aval = Aval - X
    Bval = Bval + X

......

//结果计入账本

   err = stub.PutState(A, []byte(strconv.Itoa(Aval)))

......

err = stub.PutState(B, []byte(strconv.Itoa(Bval)))

......}

delete分支

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

......

//删除一个实体

err := stub.DelState(A)

}


未完待续......