trainingDiary_7

2019-12-20-链码的概念与原理

写在前面

环境基本搭建完毕,但还是有一点小问题,但已经不影响开发了,所以可以开始学习fabric提供的接口编写代码了。

链码的概念:

Chaincode:链上代码,简称链码,一般是指由开发人员使用Go语言(也支持Java等语言)编写的应用程序代码,提供分布式账本的状态处理逻辑。链码被部署在Fabric的网络节点中,能够独立运行在具有安全特性的受保护的 Docker 容器中,以 gRPC 协议与相应的 peer 节点进行通信,以操作(初始化或管理)分布式账本中的数据。可以根据不同的需求开发出不同的复杂的应用。

链码分类

在 Hyperledger Fabric 中,链码一般分为:

系统链码
用户链码

负责 Fabric 节点自身的处理逻辑, 包括系统配置、背书、校验等工作

系统链码仅支持 Go 语言, 在 Peer 节点启动时会自动完成注册和部署

系统链码共有五种类型:

配置系统链码(CSCC)

CSCC:Configuration System Chaincode,负责处理 Peer 端的 Channel 配置。

生命周期系统链码(LSCC)

LSCC:Lifecycle System Chaincode,负责对用户链码的生命周期进行管理。

查询系统链码(QSCC)

QSCC:Query System Chaincode,提供账本查询 API。如获取区块和交易等信息。

背书管理系统链码(ESCC)

ESCC:Endorsement System Chaincode,负责背书(签名)过程, 并可以支持对背书策略进行管理(对提交的交易提案的模拟运行结果进行签名,,之后创建响应消息返回给客户端)

验证系统链码(VSCC)

VSCC:Validation System Chaincode,处理交易的验证,包括检查背书策略以及多版本并发控制

用户链码

由应用程序开发人员根据不同场景需求及成员制定的相关规则,使用 Golang(或Java等)语言编写的基于操作区块链分布式账本的状态的业务处理逻辑代码,运行在链码容器中,通过 Fabric 提供的接口与账本状态进行交互。

用户链码在整个应用程序中处于重要地位。因为它下可对账本数据进行操作,上可以给企业级应用程序提供调用接口。所以一个没有链码的企业级应用程序,不能称之为是基于区块链的企业级应用程序。

链码的生命周期管理

链码开发编写完成后,并不能立刻使用,而是必须经过一系列的操作之后才能应用在 Hyperledger Fabric 网络中进而处理客户端提交的交易。这一系列的操作是由链码的生命周期来负责管理。

管理 Chaincode 的生命周期共有五个命令:

install:将已编写完成的链码安装在网络节点中。

instantiate:对已安装的链码进行实例化。

upgrade:对已有链码进行升级。链代码可以在安装后根据具体需求的变化进行升级。

package:对指定的链码进行打包的操作。

singnpackage:签名。

状态其实指的就是账本中的数据。
一个链码对应一个账本,所以一般情况下链码是不可以访问其它账本中的数据的。

链码接口

链码启动必须通过调用 shim 包中的 Start 函数,而 Start 函数被调用时需要传递一个类型为 Chaincode 的参数,这个参数 Chaincode 是一个接口类型,该接口中有两个重要的函数 Init 与 Invoke 。
chaincode接口的定义:

1
2
3
4
type Chaincode interface{
Init(stub ChaincodeStubInterface) peer.Response
Invoke(stub ChaincodeStubInterface) peer.Response
}

Init 与 Invoke 方法

编写链码,关键是实现 Init 与 Invoke 两个方法,必须由所有链码实现。Fabric 通过调用指定的函数来运行事务。

Init:在链码实例化或升级时被调用, 完成初始化数据的工作。
invoke:更新或查询提案事务中的分类帐本数据状态时,Invoke 方法被调用, 因此响应调用或查询的业务实现逻辑都需要在此方法中编写实现。

必要结构

依赖包

shim 包为链码提供了 API 用来访问/操作数据状态、事务上下文和调用其他链代码;peer 包提供了链码执行后的响应信息。所以开发链码需要引入如下依赖包:

1
2
3
4
5
"github.com/hyperledger/fabric/core/chaincode/shim"
shim 包提供了链码与账本交互的中间层。
链码通过 shim.ChaincodeStub 提供的方法来读取和修改账本的状态。
"github.com/hyperledger/fabric/protos/peer"
peer.Response:封装的响应信息

也就是说一个开发的链码源文件的必要结构要像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package main

// 引入必要的包
import(
"fmt"

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

// 声明一个结构体
type SimpleChaincode struct {

}

// 为结构体添加Init方法
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) peer.Response{
// 在该方法中实现链码初始化或升级时的处理逻辑
// 编写时可灵活使用stub中的API
}

// 为结构体添加Invoke方法
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) peer.Response{
// 在该方法中实现链码运行中被调用或查询时的处理逻辑
// 编写时可灵活使用stub中的API
}

// 主函数,需要调用shim.Start( )方法
func main() {
err := shim.Start(new(SimpleChaincode))
if err != nil {
fmt.Printf("Error starting Simple chaincode: %s", err)
}
}