5-ChainCode生命周期、分类及安装、实例化命令解析

5-ChainCode生命周期、分类及安装、实例化命令解析

在HyperLedger-Fabric区块链网络中,ChainCode是一个重要的部分。它运行在与外界隔离的容器中,承担着更新账本的重要功能。可以说,Fabric区块链网络所维护的公共账本,正是因为有了ChainCode,才有了“代码即法律”一说。接下来,这篇文章将来将简单介绍一下ChainCode。全文按照如下结构来展开:

全文结构

1、ChainCode与智能合约

首先,来说一下智能合约。

智能合约,是一个抽象的概念。那么,智能合约有什么样的特性呢?

智能合约的历史可以追溯到 1990s 年代。它是由尼克萨博(Nick Szabo)提出的理念,几乎与互联网同龄。他在发表在自己的网站的几篇文章中提到了智能合约的理念。他的定义如下:

“一个智能合约是一套以数字形式定义的承诺(promises) ,包括合约参与方可以在上面执行这些承诺的协议。”

这样高度抽象的定义,只有建立在一定的知识储备量,才能够理解。这里,我们不去强行解释清楚什么是智能合约,而是抓住智能合约的几个重要的属性,来慢慢的理解智能合约。

简单来讲智能合约就是用程序实现合约的内容,并且这个程序是事件驱动、有状态的。下图是智能合约的模型。

智能合约模型

智能合约程序不只是一个可以自动执行的计算机程序:它自己就是一个系统参与者。它对接收到的信息进行回应,它可以接收和储存价值,也可以向外发送信息和价值。

这个程序就像一个可以被信任的人,可以临时保管资产,总是按照事先的规则执行操作

智能合约模型:它是运行在可复制、共享的账本上的计算机程序,可以处理信息,接收、储存和发送价值。

从合同的角度来说,智能合约(Smart contract )是一种旨在以信息化方式传播、验证或执行合同的计算机程序。


那么,什么是ChainCode?

ChainCode(链码)是智能合约在Fabric区块链网络的实现形式。

链码被部署在Fabric网络节点上,运行在隔离沙盒(目前为Docker容器)中,并通过gRPC协议与相应的Peer节点进行交互,以操作分布式账本中的数据。

启动Fabric网络后,可以通过命令行或SDK进行链码操作,验证网络运行是否正常。

它扮演的角色如下图所示:

应用程序通过向区块链网络发送交易来调用智能合约,从而操作账本中的状态。


2、ChainCode的运行方式

在Fabric中交易的处理过程,客户端将提案首先发送到背书节点,背书节点检提案的合法性。如果合法的话,背书节点将通过交易所属的链码临时执行一个交易,并执行背书节点在本地持有的状态副本。

Chaincode应该仅仅被安装于chaincode所有者的背书节点上,链码运行在节点上的沙盒(Docker容器)中,并通过gRPC协议与相应的Peer节点进行交互,以使该chaincode逻辑对整个网络的其他成员保密。

请务必在一条channel上每一个要运行你chaincode的背书节点上安装你的chaincode

其他没有chaincode的成员将无权成为chaincode影响下的交易的认证节点(endorser)。也就是说,他们不能执行chaincode。不过,他们仍可以验证交易并提交到账本上。

ChainCode要在区块链网络中运行,需要经过链码安装链码实例化两个步骤。

[多次安装,一次实例化]
在一个区块链子链中,该网络是由“1账本+1通道+N个peer节点”组成。
如果我们要手动来搭建Fabric网络的话,即通过命令行的形式来进行ChainCode的安装与实例化。我们需要多次install,一次instance。

也就是说,对于整个Fabric网络来说,假设有X个背书节点,那么,我们需要给每个背书节点安装ChainCode,但是在整个网络搭建过程中只需要instance ChainCode一次。
因为install 针对的是背书节点,instance 针对的是通道。

install 链码的对象是背书节点,主要目的是方便背书节点对运行链码,对交易进行模拟。
instance 链码的对象是channel,主要目的是为了将安装过的链码在指定通道上进行实例化调用,在节点上创建容器启动,并执行初始化操作。实例化的过程中,需要指定背书策略,来确定通道上哪些节点执行的交易才能添加到账本中。

安装的过程其实就是对指定的代码进行编译打包,并把打包好的文件发送到Peer,等待接下来的实例化。其实,这就是我们接下来要讲解的链码的生命周期这一部分。

实例化链上代码主要是在Peer所在的机器上对前面安装好的链上代码进行包装,生成对应Channel的Docker镜像和Docker容器。并且在实例化时我们可以指定背书策略

1. Chaincode运行在一个受保护的Docker容器当中,与背书节点的运行互相隔离。
2. Chaincode可通过应用提交的交易对账本状态初始化并进行管理。

3、ChainCode的生命周期

对于区块链网络的操作者来说,他们也许并不想涉足chaincode应用的开发,不过却需要肩负管理区块链网络的责任,并运用Hyperledger Fabric API来安装、实例化与升级chaincode。

Hyperledger Fabric API提供了四个管理chaincode生命周期的命令:package, install, instantiate,upgrade。在未来的版本中,正考虑添加stopstart交易的指令,以便能方便地停止与重启chaincode,而不用非要真正卸载它才行在一个区块链网络中,将打包、安装、实例化和升级chaincode的过程作为一种可操作的chaincode生命周期函数进行调用。

在这里,我们简单讨论package,signpackageinstall, instantiate,upgrade,stop&start这几个生命周期。具体如下图所示:

链码的生命周期


1.Packaging | 打包

在区块链中,将链码安装到Peer节点,与我们安装普通程序不一样。

Fabric对链码的安装有严格的验证和安全机制。

安装好的链码,谁有资格实例化?

又该使用什么样的背书策略来调用ChainCode呢?

这一切,都需要在安装之前,将它们规定好。我们把这些附加信息+ChainCode源码统称为ChainCode包。

一般而言,ChainCode包由以下三个部分组成:

  • chaincode本身,其由ChaincodeDeploymentSpec(Chaincode部署规范)来定义。ChaincodeDeploymentSpec,以下简称CDS。CDS是根据代码及一些其他属性(名称,版本等)来定义chaincode。
  • 一个可选的实例化策略,该策略可被 背书策略 描述。
  • 一组表示chaincode所有权的签名

打包的过程,就是将这三部分信息打包成一个整体。一般来说,打包chaincode有两种方式:

第一种是当你想要让chaincode有多个所有者的时候,此时就需要让chaincode包被多个所有者签名。这种情况下需要我们创建一个被签名的chaincode包(SignedCDS),这个包依次被每个所有者签名。

另一种就比较简单了,让chaincode有一个所有者的时候,此时只要被一个人签名即可。

要创建一个签名过的chaincode包,请用下面的指令:

peer chaincode package -n mycc -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02 -v 0 -s -S -i "AND('OrgA.admin')" ccpack.out

选项说明:

  • -s:选项创建了一个可被多个所有者签名的包,而非简单地创建一个CDS。如果使用-s,那么当其他所有者要签名的时候,-S也必须同时使用。否则,该过程将创建一个仅包含实例化策略的签名chaincode包(SignedCDS)。
  • -S选项可以使在core.yaml文件中被localMspid相关属性值定义好的MSP对包进行签名。该选项是可选的。不过,如果我们创建了一个没有签名的包,那么它就不能被任何其他所有者用signpackage指令进行签名。
  • -i选项也是可选的,它允许我们为chaincode指定实例化策略。实例化策略与背书策略格式相同,它指明谁可以实例化chaincode。


2.signpackage | 签名并打包

一个在创建时就被签名的chaincode包可以交给其他所有者进行检查与签名。具体的工作流程支持通道外对chaincode包签名。

ChaincodeDeploymentSpec 可以选择被全部所有者签名并创建一个 SignedChaincodeDeploymentSpec(SignedCDS),SignedCDS包含三个部分:

  • CDS包含chaincode的源码、名称与版本
  • 一个chaincode实例化策略,其表示为背书策略
  • chaincode所有者的列表,由Endorsement定义

一个chaincode所有者可以对一个之前创建好的带签名的包进行签名,具体使用如下指令:

peer chaincode signpackage ccpack.out signedccpack.out

指令说明:

  • 指令中的ccpack.outsignedccpack.out分别是输入与输出包。
  • signedccpack.out则包含一个用本地MSP对包进行的附加签名。


3. install | 安装

install的过程会将chaincode的源码以一种被称ChaincodeDeploymentSpec(CDS)的规定格式打包,并把它安装在一个将要运行该chaincode的peer节点上。

在Fabric网络中,我们需要在一个channel上每一个要运行你chaincode的背书节点上安装你的chaincode。

Chaincode应该仅仅被安装于chaincode所有者的背书节点上,以使该chaincode逻辑对整个网络的其他成员保密。其他没有chaincode的成员将无权成为chaincode影响下的交易的认证节点(endorser)。对于认证节点来说,他们不能执行chaincode。不过,他们仍可以验证交易并提交到账本上。

下面安装chaincode:

使用CLI安装一个存放在sacc目录下的chaincode时,命令如下

peer chaincode install -n asset_mgmt -v 1.0 -p sacc

选项说明:

  • -n:name 对链码进行命令
  • -v: version 指定chaincode的版本
  • -p: path 指明chainCode的路径

在CLI内部会为sacc创建SignedChaincodeDeploymentSpec,并将其发送到本地peer节点。这些节点会调用LSCC上的Install方法。


4. instantiate | 实例化chaincode

实例化ChainCode过程会调用 生命周期系统chaincode (LSCC)来在一个channel上创建并初始化一段chaincode。实例化过程,会生成对应Channel的Docker镜像和Docker容器。并且在实例化时我们可以指定背书策略。

当然,一个实例化交易的创建者必须符合在SignedCDS中chaincode的实例化策略,且必须充当channel的写入器(这会成为channel创建配置的一部分),这对于channel的安全至关重要。

使用CLI去实例化 名为mycc 的chaincode,指令具体如下:

peer chaincode instantiate -n mycc -v 1.0 -c '{"Args":["john","0"]}' -P "OR ('Org1.member','Org2.member')"

选项说明:

  • -n 实例化链码的名称
  • -c --ctor,链码的具体执行参数,为json格式
  • -P --Policy 指定实例化策略

5.upgrade | 升级chaincode

一段chaincode可以通过更改它的版本(SignedCDS的一部分)来随时进行更新。至于SignedCDS的其他部分,比如所有者及实例化策略,都是可选的。不过,chaincode的名称必须一致,否则它会被当做完全不同的另一段chaincode。

在升级之前,chaincode的新版本必须安装在需要它的背书节点上。升级是一个类似于实例化交易的交易,它会将新版本的chaincode与channel绑定。其他与旧版本绑定的channel则仍旧运行旧版本的chaincode。换句话说,升级交易只会一次影响一个提交它的channel。


6.stop&star | 停止与启动

注意,停止与启动生命周期交易的功能还没实现。不过,你可以通过移除chaincode容器以及从每个背书节点删除SignedCDS包来停止chaincode。具体而言,就是删除所有主机或虚拟机上peer节点运行于其中的chaincode的容器,随后从每个背书节点删除SignedCDS。


7.chainCode的状态总结

在上述的过程中,ChainCode的状态有以下几种。这里做一个小总结:

  • CDS -ChainCodeSpec 包含链码源码,名称,版本等信息
  • SignedCDS-SignedChaincodeDeploymentSpec ,包含 CDS、一个chaincode实例化策略,其表示为背书策略、chaincode所有者的列表,由Endorsement定义。
Spec “规范”

4.ChainCode的种类

在Fabric中,链码可以分为两种,系统chaincode用户chaincode

1.系统ChainCode

系统链码则负责Fabric节点自身的处理逻辑,包括系统配置、背书、校验等工作。这些处理过程最初通过硬编码(Hard-Coded)的方式固化在系统中。Fabric通过系统链码的形式来实现,运行在Peer主进程内,兼顾了逻辑实现和管理的灵活性,以及通信的性能。

例如:一个系统chaincode只能通过peer节点的二进制文件升级。同时,系统chaincode只能以一组编译好的特定的参数进行注册,且不具有背书策略相关功能。

以下是系统chaincode的表格:

Fabric五大类型系统链码

系统链码目前仅支持Go语言,在Peer节点启动时会自动完成注册和部署,以进程内逻辑形式跟主进程进行交互。


2.用户chaincode

用户链码对应用开发者来说十分重要,它提供了基于区块链分布式账本的状态处理逻辑,基于它可以开发出多种复杂的应用。在超级账本Fabric项目中,用户可以使用Go语言来开发链码,未来还将支持包括Java、JavaScript在内的多种高级语言。

用户链码相关的代码都在core/chaincode路径下。其中core/chaincode/shim包中的代码主要是供链码容器侧调用使用,其他代码主要是Peer侧使用。


3.两者的比较

相同点

  • 系统chaincode用户chaincode两种的编程模型相同,

不同点

  • 系统chaincode运行于peer节点内而用户chaincode运行在一个隔离的容器中。因此,系统chaincode在节点内构建且不遵循上文描述的chaincode生命周期。
  • 安装实例化升级这三项操作不适用于系统chaincode。

5.总结

上面三部分,我们简单介绍了ChainCode的基本特性,了解了ChainCode在区块链网络中以怎样的形式存在,也清楚了ChainCode的生命周期以及ChainCode的分类。这一部分,对后续ChainCode的开发,是必须要掌握的知识。


参考文献:

HyperLedger-Fabric 中文文档-智能合约操作手册

HyperLedger-Fabric-中文文档-CLI

《区块链原理、设计与应用》-杨保华-9.5链码的概念与使用

《区块链原理、设计与应用》-杨保华-12.5用户链码

《区块链原理、设计与应用》-杨保华-12.6系统链码

编辑于 2018-12-20 17:20