Hyperledger-Fabric · 2017年11月2日 2

Hyperledger-Fabric安装开发部署(二)测试运行

简介

  • Hyperledger Fabric是分布式账本解决方案的平台,以模块化架构为基础,提供高度的机密性,弹性,灵活性和可扩展性。它旨在支持不同组件的可插拔实现,并适应经济生态系统中存在的复杂性性。
  • Hyperledger Fabric提供独
    特的弹性和可扩展架构,区别于其他区块链解决方案。在未来的规划中,对于企业区块链将完全建立在审核且开源架构之上; Hyperledger Fabric是你最好的起点。

官方英文版教程:
http://hyperledger-fabric.readthedocs.io/en/latest/index.html


1. 运行e2e_cli初始化脚本

上一篇中我们已经下载整个Fabric项目,其中包含了这里需要用到的e2e_cli:
/opt/gopath/src/github.com/hyperledger/fabric/examples/e2e_cli

在这里我们需要执行的文件是network_setup.sh

$ ./network_setup.sh up

在执行之前我,让我们先看一下所执行的方法:

....
....
function networkUp () {
    if [ -f "./crypto-config" ]; then
      echo "crypto-config directory already exists."
    else
      #Generate all the artifacts that includes org certs, orderer genesis block,
      # channel configuration transaction
      source generateArtifacts.sh $CH_NAME
    fi

    if [ "${IF_COUCHDB}" == "couchdb" ]; then
      CHANNEL_NAME=$CH_NAME TIMEOUT=$CLI_TIMEOUT docker-compose -f $COMPOSE_FILE -f $COMPOSE_FILE_COUCH up -d 2>&1
    else
      CHANNEL_NAME=$CH_NAME TIMEOUT=$CLI_TIMEOUT docker-compose -f $COMPOSE_FILE up -d 2>&1
    fi
    if [ $? -ne 0 ]; then
    echo "ERROR !!!! Unable to pull the images "
    exit 1
    fi
    docker logs -f cli
}
...
...
#Create the network using docker compose
if [ "${UP_DOWN}" == "up" ]; then
    networkUp
elif [ "${UP_DOWN}" == "down" ]; then ## Clear the network
    networkDown
elif [ "${UP_DOWN}" == "restart" ]; then ## Restart the network
    networkDown
    networkUp
else
    printHelp
    exit 1
fi

可以看到这个文件共有3种功能,创建、清理、重启网络;
创建Fabric网络主要包含了如下动作:

  • 1 编译生成Fabric公私钥、证书的程序,程序在目录:/opt/gopath/src/github.com/hyperledger/fabric/release/linux-amd64/bin
  • 2 基于configtx.yaml生成创世区块和通道相关信息,并保存在channel-artifacts文件夹。
  • 3 基于crypto-config.yaml生成公私钥和证书信息,并保存在crypto-config文件夹中。
  • 4 基于docker-compose-cli.yaml启动1Orderer+2org*2Peer+1CLI的Fabric容器。
  • 5 在CLI启动的时候,会运行scripts/script.sh文件,这个脚本文件包含了创建Channel,加入Channel,安装Example02,运行Example02等功能。
$ ./network_setup.sh up

如果不出意外将会看到如下内容,可以开始下一步测试。

此处在阿里云Centos中创建Channel失败,腾讯云中并无问题,原因尚未调查清楚。

2. 测试运行

接下来让我们尝试着调用一些定义好的方法看看Fabric能实现怎样的效果。
在e2e这个例子中,channel名字是mychannel,chaincode的名字是mycc。我们首先进入CLI,我们重新打开一个命令行窗口,输入:

$ docker exec -it cli bash

运行以下命令可以查询a账户的余额:

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

mychannel与mycc都是提前在配置中定义好的channel与chaincode实例名;'{"Args":["query","a"]}'这里的query最终指向的是/opt/gopath/src/github.com/hyperledger/fabric/examples/e2e_cli/examples/chaincode/go/chaincode_example02/chaincode_example02.go这个Go源码中的query方法;mycc可以理解为这个文件的实例名;
Go是编译语言,所以这个路径只是他的源码,如果想要自己定义则需要重新安装、实例化、添加peer(之后的文章会讲到如何安装、更新、操作chaincode,还有chaincode的版本控制等等)。

接着来看一下chaincode_example02.go有什么内容:

.......
//这个方法并不是上边我们调用Query时触发的;
//它是再我们实例化chaincode时触发的,接下来会说它的调用地方
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
    fmt.Println("ex02 Init")
    _, args := stub.GetFunctionAndParameters()
    var A, B string    // Entities
    var Aval, Bval int // Asset holdings
    var err error
    if len(args) != 4 {
        return shim.Error("Incorrect number of arguments. Expecting 4")
    }

    // Initialize the chaincode
    A = args[0]
    Aval, err = strconv.Atoi(args[1])
    if err != nil {
        return shim.Error("Expecting integer value for asset holding")
    }
    B = args[2]
    Bval, err = strconv.Atoi(args[3])
    if err != nil {
        return shim.Error("Expecting integer value for asset holding")
    }
    fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)

    // Write the state to the ledger
    err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
    if err != nil {
        return shim.Error(err.Error())
    }

    err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
    if err != nil {
        return shim.Error(err.Error())
    }

    return shim.Success(nil)
}
.......
//这个就是刚才我们查询所调用到的方法
//内容非常简单,接收一个参数,然后GetState()返回对应的值
// 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)
}
.......

这段代码我们看到了刚才query所调用的具体方法以及具体内容,但是有个问题,我们并没有执行任何插入的操作,怎么会查询到值?
/opt/gopath/src/github.com/hyperledger/fabric/examples/e2e_cli/scripts/script.sh这个脚本是再我们初始化的时候出发执行的,其种有一段代码:

instantiateChaincode () {
    PEER=$1
    setGlobals $PEER
    # while 'peer chaincode' command can get the orderer endpoint from the peer (if join was successful),
    # lets supply it directly as we know it using the "-o" option
    if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then
        peer chaincode instantiate -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "OR    ('Org1MSP.member','Org2MSP.member')" >&log.txt
    else
        peer chaincode instantiate -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "OR  ('Org1MSP.member','Org2MSP.member')" >&log.txt
    fi
    res=$?
    cat log.txt
    verifyResult $res "Chaincode instantiation on PEER$PEER on channel '$CHANNEL_NAME' failed"
    echo "===================== Chaincode Instantiation on PEER$PEER on channel '$CHANNEL_NAME' is successful ===================== "
    echo
}

看这方法名字就知道它是要实例化的我们的chaincode;
这里需要注意的是开启tls与不开启调用的方式是不一样的;
peer chaincode instantiate -o orderer.example.com:7050 -C $CHANNEL_NAME -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "OR ('Org1MSP.member','Org2MSP.member')" >&log.txt
可以看到这里定义了实例名mycc;并且调用的上边chaincode_example02.go中的初始化方法,还传入了4个值;对比上边chaincode_example02.go中,这4个值即代表了插入key=a,value=100;key=b,value=200这两组数据,这就是我们刚刚查询值的由来。

chaincode_example02.go中还有一个invoke方法,可以用以下方式调用:

$ peer chaincode invoke -o orderer.example.com:7050  --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/examples/e2e_cli/crypto-config/ordererOrganizations/example.com/msp/tlscacerts/tlsca.example.com-cert.pem  -C mychannel -n mycc -c '{"Args":["invoke","a","b","30"]}'

参照chaincode_example02.go中的源码很易容理解这里指的是a向b转账30。还有其他的方法,有兴趣可以依次尝试调用。

由于我的Fabric换了一套多节点实例没有e2e的环境,所以不能贴出具体执行结果,大家可以自己尝试。

到此基本上一切正常,运行exit命令退出cli容器。
关闭此Fabric网络的方法在开启时有过介绍。

这里只是简单的配置一个Fabric网络并调用已经安装好的chaincode,在实际场景中还需要更多的知识储备。需要了解可能诸如nodejs-SDK,用nodejs来触发Fabric网络种的各种方法,实现各自的业务场景;其次还需要学习Golang,主要是为了编写chaincode,满足我们的各种需求。


下一篇将介绍如何使用Nodejs调用chaincode,以及Nodejs-SDK

.
.
.
.
.
.
.
【本文章出自NM1024.com,转载请注明作者出处。】






>>转载请注明原文链接地址:Hyperledger-Fabric安装开发部署(二)测试运行