# Chaincode的开发部署及使用

By [leaf](https://paragraph.com/@leaf-6) · 2022-12-06

---

超级账本的开发，首先来了解一下Chaincode的概念，然后介绍如何开发Chaincode，如何将Chaincode部署到Fabric中，以及如何使用Chaincode。

Chaincode，中文一般称为链码，是超级账本中的智能合约，本质上就是一段计算机语言实现的程序。Chaincode是超级账本的重要组成部分，一般用Go语言编写，也支持用Java、JavaScript等计算机语言来进行编写。本书中的Chaincode使用Go语言编写。

那Chaincode是如何运行的呢？Chaincode编写完成后需要进行编译并部署到超级账本上。部署完成后，Chaincode运行在一个受保护的Docker容器当中，与背书结点的运行互相隔离。超级账本通过Chaincode实现对账本数据的读取和修改操作，同时也会把操作的日志保存到超级账本的数据库中。由一个Chaincode创建的状态仅限于该Chaincode有权限访问，不能由另一个Chaincode直接访问。然而，在同一个超级账本中，给定适当的权限，一个Chaincode可以调用另一个Chaincode来访问其创建的状态。

Chaincode的生命周期包括打包、安装、实例化和升级这四个阶段，具体过程会在下面实例中讲解。

开发Chaincode就是实现特定的接口，这个接口包括两个方法——Init（）方法和Invoke（）方法。这两个方法的作用如下：当Chaincode接收instantiate或upgrade事务时，会调用Init（）方法，以便Chaincode可以执行任何必要的初始化，包括应用程序状态的初始化；Invoke（）方法是为了响应接收调用事务来处理事务提案。

下面实现一个最简单的Chaincode，这个例子中的作用就是展示如何开发Chaincode以及Chaincode的执行流程。在这个Chaincode中不对数据进行处理，调用方法后直接返回就可以了，所以在编写Init（）方法和Invoke（）方法的主体功能时返回空值就可以了。代码如下：

![](https://storage.googleapis.com/papyrus_images/4625604a85d9e8d65cc3c16b6ce911be6708f8885190dff9db797d80dd78a88c.png)

其中main函数是Go程序执行的入口函数，当在结点部署Chaincode时，就会执行main函数里面的内容。main函数中第1句Err：=shim.Start（new（SampleChaincode））会启动示例的Chaincode，如发生错误会输出启动失败的信息，否则就会输出成功运行的信息。

在上面的示例中实现了Chaincode的3个方法，依次为Init、Query和Invoke。下面依次来了解下这3个方法的作用

●Init（）方法。Init（）方法会在Chaincode首次部署实现到区块链时由各个结点调用，此方法可用于实现任何与初始化、引导或设置相关的任务。

●Query（）方法。只要在区块链上执行任何查询操作，就会调用Query（）方法。Query（）方法不会修改区块链的状态，因此它不会在交易上下文内运行。如果尝试在Query（）方法内修改区块链的状态，将出现一个错误。另外，因为此方法仅用于读取区块链的状态，所以对它的调用不会记录在区块链上。

●Invoke（）方法。只要修改区块链的状态，就会调用Invoke（）方法，所以所有对区块链进行的更新或删除操作都应封装在Invoke方法内。因为此方法将修改区块链的状态，所以超级账本会自动创建一个交易上下文，以便此方法在其中执行。对此方法的所有调用都会在区块链上记录为交易，这些交易最终被写入区块中。

实现了上述的代码后就可以操作这个Chaincode。Fabric提供了4个命令管理Chaincode，分别是打包（package）、安装（install）、实例化（instantiate）、升级（upgrade）。首先通过package命令打包Chaincode，然后用install命令安装Chaincode，再通过instantiate实例化Chaincode。如果需要升级Chaincode，则需要先安装新版本的Chaincode，再通过upgrade命令对其进行升级。

在未来的版本中，官方也正在考虑添加stop和start命令禁用和重新启用Chaincode，而不必卸载它。在成功安装并实例化了一个Chaincode之后，Chaincode就处于活跃中（正在运行）。在安装完毕后，也可以在任何时间都对Chaincode进行升级，如图

![](https://storage.googleapis.com/papyrus_images/4551c895f6a92416448aad5ecda78d808662fae9611d614e731dceebec083779.png)

Chaincode有两种安装方式，一是直接安装源代码，二是通过package命令打包并签名生成打包文件，然后再通过install命令进行安装生成的打包文件。

以上就是Chaincode的开发和使用过程，最后再花一小节补充说明一下Chaincode的打包过程。

为了方便对Chaincode进行管理和签名认证，通常需要对Chaincode进行打包操作。所以本节专门对Chaincode的打包过程进行详解。

Chaincode包由3部分组成，包括Chaincode代码本身、一个可选的实例化策略和拥有Chaincode实体的一组签名。其中区块链上Chaincode被实例化进行交易的时候，可被Chaincode对应的实例化策略验证。

签名有以下作用。

●建立Chaincode的所有权

●对包的内容进行验证。

●检测包是否篡改。

打包Chaincode有两种方式。第1种方式是当Chaincode有多个所有者的时候，需要让Chaincode包被多个所有者签名。这种情况下需要创建一个需要签名的Chaincode包，这个包依次被每个所有者签名。第2种就比较简单了，在已签名的结点上用install命令进行打包操作即可。

**以上就是关于Chaincode的内容，下面开始进入超级账本的实际开发。**

第1个实例是构建一个本地的Fabric网络，通过本案例可以学习如何基于超级账本构建一个简单的区块链网络，并与这个网络进行基本的交互操作，例如查询和更新超级账本的区块链数据。

超级账本的本地环境安装一节中已经下载了Fabric Samples的代码，在这些示例代码中一个名为“first-network”的文件夹，整个文件夹是一个完整的Fabric项目示例，实现了一个Fabric网络，这个Fabric网络中包含多个结点，以及一个命令行工具。下面使用这个示例构建第1个Fabric网络。

进入fabric-network的子目录first-network中，可以看到该目录下有一个名为byfn.sh的脚本文件。这个脚本文件中有着很完备的注释说明，执行“./byfn.sh­h”可以看到这个脚本文件的使用说明，包括如何启动和停止等操作Fabric网络的命令，如图

![](https://storage.googleapis.com/papyrus_images/fda79948f63fd3464a122494e7e1b2df24ae7ee13f05232ae6ba79f07ccc2dd1.png)

下面开始构建这个简单的Fabric网络。使用命令“./byfn.sh -m generate”来生成网络所需的证书和创世区块，命令执行的过程中需要进行一些配置，这里使用默认配置，在命令行工具中输入“Y”确认既可，如图

![](https://storage.googleapis.com/papyrus_images/4de27ad95af7f3be6d2be9e7e659ae5740a4f00bef89a477e5b3c5a3d25e9cba.png)

可以看到在这个过程中，先是用cryptogen工具生成各种网络实体的证书和密钥（cryptogen是Fabric项目中提供的用来生成需要的证书的工具），这些证书是身份的代表，它们允许在网络中进行交流和交易时进行签名/验证身份；然后生成一个genesis block（创世区块），用于引导orderer结点进行排序服务；最后生成Channel所需要的交易配置信息并保存到文件中。

![启动“first network”网络](https://storage.googleapis.com/papyrus_images/c02daaef8ce747d669714a6c200d6d47a93ec2c2ba805753354e3a87cfaea5c9.png)

启动“first network”网络

![  启动网络成功](https://storage.googleapis.com/papyrus_images/bdca9d386cdf90471f53e784a9eeea1a4d9c61822c89ebe215c2b7823b24dd45.png)

启动网络成功

若要关闭这个网络可以使用./byfn.sh -m down命令进行操作，如图所示。

在启动这个Fabric网络后，我们就可以与这个网络的交互。交互的内容包括对网络中管道（channel，是指在Fabric网络中的通道，用来连接网络中的结点和隔离其他非相关的结点）的管理和对Chaincode的操作，从而更深入地认识Fabric网络。与Fabric网络交互的方式是可以通过命令行工具（CLI）调用Fabric API实现。

使用CLI需要先进入CLI容器（一个包含命令行工具CLI的docker容器，可以理解为一个可运行CLI的独立环境），进入容器的命令是“docker exec-it cli bash”，如图

![  关闭网络](https://storage.googleapis.com/papyrus_images/80309476cc3b8c4e7bc71a677f00039ccd6cc51b8141547f1237f63f954037d9.png)

关闭网络

![进入CLI容器](https://storage.googleapis.com/papyrus_images/39037c31ed96163a659a0e420a4300b8d9bcdbc9f59c8677529fcb6ba7988634.png)

进入CLI容器

进入CLI容器后可以看到容器中的内容并对Fabric网络进行查询和更新操作。在CLI中使用的命令主要分为两种，一种是和channel有关的命令，另外一种是和Chaincode有关的命令。

（1）和channel有关的命令

和channel有关的命令如下。

●创建channel。

进入CLI容器，可以通过如下命令来创建通道：

peer channel create -o orderer.example.com：7050 -c mychannel -f./channel-artifacts/channel.tx --tls true --cafile/opt/gopath/src/github.com/hyperledger/ fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer. example.com/msp/tlscacerts/tlsca.example.com-cert.pem

其中的参数含义如下。

●-o orderer.example.com：7050：指定了orderer的服务定义，用作排序服务。

●-c mychannel：要创建通道的名字。

●-f./channel-artifacts/channel.tx：指定由configtxgen等工具生成的配置交易文件，用于提交给orderer结点。

●--tls true：与orderer通信是否启动TLS。

\--cafile/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem：指定orderer结点的TLS证书，该证书为PEM格式。

●加入channel。

加入channel的命令是peer channel join -b mychannel.block，其中-b是区块路径，这里指向包含创世区块的文件路径。

●列举所有channel。

列举所有channel的命令是peer channel list。

●更新channel。

更新channel的命令是peer channel update -o orderer.example.com：7050 -c mychannel -f./channel-artifacts/Org1MSPanchors.tx --tls true --cafile /opt/ gopath/src/github.com/ hyperl-edger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlsc-acerts/tlsca.example.com-cert.pem，参数与创建channel的类似。

（2）和Chaincode有关的命令

和Chaincode有关的命令如下。

●安装Chaincode：peer chaincode install\[flags\]。

●实例化Chaincode：peer chaincode instantiate\[flags\]。

●调用Chaincode：peer chaincode invoke。

●打包Chaincode：peer chaincode package。

●查询Chaincode：peer chaincode query。

●对Chaincode进行签名：peer chaincode signpackage。

●更新Chaincode：peer chaincode upgrade。

其中主要可以使用的参数如下。

●-C：channel ID。

●-c：JSON字串的链代码构造函数消息（默认“{}”）。

●-h：帮助。

●-l：编写Chaincode的语言，默认“golang”。

●-n：Chaincode名称。

●-p：Chaincode路径。

●-v：Chaincode版本。

●-o：orderer结点。

下面通过Chaincode命令查询和更新超级账本。

查询和更新超级账本
=========

在CLI容器中，先使用query对a和b的余额进行查询操作（其中a和b是在使用byfn.sh-m up命令启动网络时自动创建的两个账户），可以看到a有90，而b有210，如图

![](https://storage.googleapis.com/papyrus_images/3be2d6df5ebfc1ea82fbfb632cd9ea337d316db57df54ac4bf96ebbfab19e3ee.png)

然后从b账户转80到a账户。这个交易将创建一个新的区块并更新区块链。操作命令如图

![b账户转80到a账户](https://storage.googleapis.com/papyrus_images/c54a5fe499c321d4e1484ea412323313c2683590c21722790f394dfb592df897.png)

b账户转80到a账户

由上图可以看到操作成功，此时在查询a账户和b账户，应该可以看到a账户有170，b账户有130，如图

![查询更新后a和b余额](https://storage.googleapis.com/papyrus_images/316ceb72befd5ab70c6b649086655e11428999889c2eae898128b464d00cf4ce.png)

查询更新后a和b余额

以上就是通过Chaincode查询和更新超级账本的方法。

---

*Originally published on [leaf](https://paragraph.com/@leaf-6/chaincode)*
