Hyperledger Fabric学习笔记——将智能合约部署到通道

Fabric V2.0将fabcar链码java版部署到test-network的流程。

1、启动网络

cd fabric-samples/test-network
./network.sh down
./network.sh up createChannel

首先删除旧的docker容器或以前生成的组件,然后启动网络,创建一个mychannel通道,这个通道由两个成员Org1和Org2,并将属于组织的对等节点加入通道。创建成功截图(部分)如下:

2、设置Logspout(可选)

logspout工具用来查看一组Docker容器的聚合输出,可以帮助管理员在安装智能合约时调试问题或者开发人员在调用智能合约时调试问题。通过运行monitordocker.sh脚本来启动Logspout:

cd fabric-samples/test-network
cp ../commercial-paper/organization/digibank/configuration/cli/monitordocker.sh .
./monitordocker.sh net_test

成功后如下图:

3、打包智能合约(java版本)

在打包链码之前,我们需要安装链码依赖,示例使用Gradle安装链码依赖。

cd fabric-samples/chaincode/fabcar/java
./gradlew installDist

这一步我遇到了一点小问题,我电脑上的jdk是最新的13版本,使用上面命令后报错如下:

于是安装了jdk8并设置了一下jdk切换,切换到jdk8后就成功了(官网用的应该是jdk11,由于疫情期间网络问题,所以我暂且用了之前有存的jdk8)。

vi ~/.zprofile
#在.zprofile文件中进行如下修改,设置默认jdk为8,并可以切换
export JAVA_8_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_151.jdk/Contents/Home
export JAVA_13_HOME=/Library/Java/JavaVirtualMachines/jdk-13.0.2.jdk/Contents/Home
export JAVA_HOME=$JAVA_8_HOME
alias jdk8="export JAVA_HOME=$JAVA_8_HOME"
alias jdk13="export JAVA_HOME=$JAVA_13_HOME"

成功后如下图所示:

成功之后,build目录下就会有构建好的智能合约。至此,就完成了依赖的安装和智能合约的构建,接下来可以创建链码包了。回到test-network目录,这样才能将链码和其他网络组件一起打包,可以使用peer CLI来创建一个需要形式的链码包。peer的二进制文件在fabric-samples目录下的bin目录中,首先要把这些二进制文件加入CLI路径中,然后需要设置FABRIC_CFG_PATH指向core.yaml文件。还需要确认二进制文件的版本,必须是2.0.0或更新才可以正确地运行本案例。

cd ../../../test-network
export PATH=${PWD}/../bin:${PWD}:$PATH
export FABRIC_CFG_PATH=$PWD/../config/
peer version

还需要设置CORE_PEER_MSPCONFIGPATH指向一个管理员或者客户端用户的MSP目录,作为使用的身份。然后就可以使用peer lifecycle chaincode package命令创建链码包。

export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/[email protected]/msp
peer lifecycle chaincode package fabcar.tar.gz --path ../chaincode/fabcar/java/build/install/fabcar --lang java --label fabcar_1

上面第二条命令在当前目录创建了一个名为fabcar.tar.gz的链码包,--lang标明使用的语言,--path提供智能合约代码的位置,--label用来设定标识安装好的链码的身份,包括链码名称和版本。

4、安装链码包

首先将链码安装在Org1的peer上。设置环境变量,使得以Org1管理员身份操作peer CLI,CORE_PEER_ADDRESS将被设置指向Org1peer,peer0.org1.example.com。

export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=localhost:7051

在该peer上安装链码:

peer lifecycle chaincode install fabcar.tar.gz

成功后如下图所示:

同样,设置环境变量并将链码安装到org2的peer上(因为transaction需要org1和org2同时认可)。

CORE_PEER_LOCALMSPID="Org2MSP"
CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=localhost:9051

peer lifecycle chaincode install fabcar.tar.gz

5、批准链码定义

在安装链码包之后,需要批准链码定义。链码定义包括了链码管理重要的参数,比如名称、版本和链码认可策略等。在链码部署到通道之前,批准链码的通道成员的集合由Application/Channel/lifecycleEndorsement policy管理。默认的,这个策略需要通道中绝大多数的成员(组织层面)批准链码,因为例子中只有两个组织,因此需要作为Org1和Org2批准Fabcar链码定义。

如果一个组织在它的peer上安装了链码,那么它需要将package ID包括在由其批准的链码定义中,这样组织才能使用链码去认可transactions。可以通过peer lifecycle chaincode queryinstalled命令查询节点上的package ID。package ID是链码标签和链码二进制哈希的组合,

下面代码将查询package ID并保存在环境变量CC_PACKAGE_ID中(注:不同的人运行可能得到不同的ID,要将自己命令行中输出的ID保存在环境变量中)。

接下来将使用package ID来批准链码。链码定义批准是组织层面的,所以只需要把一个peer作为目标,批准会通过gossip传播到组织中的其他peers,之前我们将环境变量设置成作为Org2管理员操作peer CLI。使用下面命令来批准一个链码定义:

peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 1.0 --init-required --package-id $CC_PACKAGE_ID --sequence 1 --tls true --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

--package-id用来将package ID包括在链码定义中,--sequence参数保存链码定义或者更新的次数,--init-required表示会先调用初始化函数初始化链码。还可以提供--signature-policy或者--channel-config-policy在参数在approveformyorg命令后来指定链码认可策略。本例子采用默认的认可策略,即通道中绝大多数成员认可(组织层面)。需要以一个管理员的身份批准链码定义,即CORE_PEER_MSPCONFIGPATH变量需要指向一个包括管理员身份的目录。批准需要提交到排序服务,验证管理员签名然后分配到peers上。同样,需要作为Org1管理员批准链码定义:

CORE_PEER_LOCALMSPID="Org1MSP"
CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/[email protected]/msp
CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
CORE_PEER_ADDRESS=localhost:7051

peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 1.0 --init-required --package-id $CC_PACKAGE_ID --sequence 1 --tls true --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

尽管只需要大多数组织批准链码定义(使用默认策略),但是所有的组织只有批准了链码定义才能启动组织下peers上的链码,即组织批准链码定义相当于是逻辑上在组织层面定义了链码,只需要在一个组织的一个peer上批准链码定义,这个批准会通过gossip传递到组织中其他peers。因此,如果在一个通道成员还没有批准链码定义时提交了链码定义transaction,那么这个成员就无法认可该向通道部署链码的transaction。因此,建议所有的通道成员批准链码后再发起提交链码定义到通道的transaction。

总的来说,链码需要先部署到每个组织的节点上,然后在一个节点上批准链码定义,完成在组织层面的逻辑定义,然后再发起部署到通道transaction,完成逻辑上部署到通道。

6、将链码定义提交到通道

在足够数量的组织批准链码定义后,一个组织可以将链码定义提交到通道。如果通道的大多数成员批准了定义,提交transaction就会成功,链码定义中认可的参数就会在通道上实现。

可以使用peer lifecycle chaincode checkcommitreadiness命令来检查通道成员是否批准了相同的链码定义。该命令的标识符和为组织批准链码定义时一样,但是不需要包括--package-id。

peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name fabcar --version 1.0 --init-required --sequence 1 --tls true --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --output json

上面的命令会产生一个JSON映射,显示通道成员是否批准了checkcommitreadiness命令中指定的参数。如下图所示:

通道中两个组织都批准链同样的参数,链码就做好了提交到通道的准备。使用peer lifecycle chaincode commit命令提交链码定义到通道。提交命令也需要由组织管理员提交:

peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --channelID mychannel --name fabcar --version 1.0 --sequence 1 --init-required --tls true --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt

上面的transaction使用--peerAddresses标识来定位Org1和Org2中的节点peer0.org1.example.com和peer0.org2.example.com。提交transaction被提交到通道中的节点上查询被响应组织批准的链码定义。命令需要定位来自足够多的组织的peers以满足部署链码的策略。在一个组织内的peers会通过gossip来进行传播。

通道成员返回的链码定义认可将会提交到排序服务打包成块再分配到通道中,通道中的peers验证是否有足够多的组织批准了链码定义。peer lifecycle chaincode commit命令将会等待peer完成验证后返回响应。

可以使用如下命令来确认链码定义已经被提交到通道中:

peer lifecycle chaincode querycommitted --channelID mychannel --name fabcar --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

如果链码成功的提交到通道,上面命令会返回如下有关链码定义的信息:

7、调用链码

使用下面的命令在账本中创建一个初始的汽车集合,注意,调用命令需要定位足够多的peers来满足链码认可策略。

peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls true --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n fabcar --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --isInit -c '{"function":"InitLedger","Args":[]}'

这里我遇到了一个问题,上述命令返回如下:

应该是在使用gradlew构建项目的时候或者其java版本智能合约代码出现了问题,具体是什么原因暂时没搞清楚,等后面学习了智能合约开发相关内容后再回来研究,本主题将智能合约部署到通道的其他过程均没有问题,因为用go语言版智能合约进行部署后调用成功如下图所示:

因为在链码定义中包括了--init-required标识,所以第一个transaction需要通过传递--isInit标识给调用命令初始化链码。因为Fabcar智能合约使用了Fabric contract API,所以第一个transaction可以定位任意一个链码中的函数,如果使用Fabric Chaincode Shim API提供的低级APIs,这个transaction只能定位初始化函数。第一次调用链码,无论是初始化还是其他函数,都要符合链码认可策略。

可以使用查询函数来读取链码初始化创建的汽车集合:

peer chaincode query -C mychannel -n fabcar -c '{"Args":["queryAllCars"]}'

成功结果如下图:

发布了38 篇原创文章 · 获赞 0 · 访问量 2006

猜你喜欢

转载自blog.csdn.net/Nemoosi/article/details/104835169