导语
智能合约是区块链中一个非常重要的概念和组成部分。在Fabric中内成为Chaincode,中文翻译为链码。涉及到链码地方都是 Chaincode.
7.1 Chaincode 初探
Fabric中的Chaincode包含了一个Chaincode代码和Chaincode管理命令这两部分。
- Chaincode 代码是业务的承载体,负责具体的业务逻辑
- Chaincode 管理命令负责 Chaincode的部署,安装,维护等工作
1.Chaincode代码
Fabric的Chaincode是一段运行在容器中的程序。Chaincode是客户端程序和Fabric之间的桥梁。
通过Chaincode客户端程序可以发起交易,查询交易。
Chaincode是运行在Dokcer容器中,因此相对来说安全。
目前支持 java,node,go,go是最稳定的。其他还在完善。
2.Chaincode的管理命令
Chaincode管理命令主要用来对Chaincode进行安装,实例化,调用,打包,签名操作。
Chaincode命令包含在Peer模块中,是peer模块中一个子命令, 该子命令的名称 是chaincode.该子命令是 peer chaincode
7.2 快速编写和运行一个Chaincode
1.创建一个Chaincode代码的目录
首先创建一个目录存放Chaincode的代码。建议放在$GOPATH指定的路径中。
2.创建 Chaincode源代码文件并且编写源代码
在创建域代码文件的命令如下:
- 第一步 部署
- 第二步 实例化
- 第三步 调用
如果 没有出现错误,那我们就完完成了一个最简单的chaincode的代码编写部署,发布,调用的过程。
7.3 Golang版本的Chaincode的代码结构
真的勇士敢于直面惨淡的人生,敢于正视淋漓的鲜血
7.3.1 Chaincode源代码的基本结构
1.包名
- 一个chaincode通常是一个 Goalng源文件,包名必须是main
- package main
2.引入包
Chaincode需要引入一个写Fabric提供的一些系统包,这些系统提供了Chaincode和Fabric进行通信的接口。
在引入包中, shim提供了Fabric系统提供的上下文环境,包含了Chaincode和Fabic交互的接口。在Chaincode中,执行赋值,查询,等功能都是需要通过shim.
3.定义结构体并实现
每个chaincode必须需要定义一个结构体,结构体的名称可以是任意符合Golang命名规范的字符串。
chaincode结构体是chaincode的主体结构。chaincode结构体需要实现Fabric提供的接口 peer,其中必须实现的两个方法是:
4.Chaincode的init方法
Init方法是系统初始化方法,当执行命令 peer chaincode instantiate实例化chaincode的时候回调用该方法,同时命令中-c选项后面内容会作为参数传入Init方法中。实例化chaincode实例化命令:
上面命令传入4个参数。注意命令中Args后面一共5个参数,其中一个参数init是固定值,后面 的才是参数。
参数是没有限制的。 可以采用json格式传递
获取传入参数:
4.Invoke方法
Invoke 方法的主要作用是写人数据 ,比如发起交易等。
在执行命令peer chaincode invoke 的时候系统会调用该方法, 同时会把命令中-c中参数传入方法中。
传入三个参数, 注意Args后面数据中的第一个值 invoke 是默认的固定参数。
7.3.2 shim 包的核心方法
shim 主要负责和客户端进行通信。
1.Success
Success 方法负责将正确的消息返回给调用Chaincode的客户端。
2.Error
Error方法将错误的信息返回给调用Chaincode的客户端。
3.LogLevel
LogLevel方法负责修改Chaincode中运行日志的级别。
7.3.3 ChaincodeStublnte face 接口中的核心方法
在shim包中有个一个接口ChaincodeStublnte 。在Invoke方法和Query方法中该接口作为参数传入方法中。
ChaincodeStublnte 提供了一组方法。
- 系统管理
- 存储管理
- 交易管理
- 调用外部chaincode
1. ChaincodeStublnterface 接口的系统相关方法
- GetFunctionAndParameters:该方法负责接收调用Chaincode的客户端传递过来的参数。
一个命令来测试GetFunctionAndParameters方法是怎样接收客户端传递过来的参数。
2.ChaincodeStubinterface) 接口的存储管理相关方法
-
- PutState :负责把客户端传递过来的数据保存到 Fabric中。
- PutState :负责把客户端传递过来的数据保存到 Fabric中。
-
- GetState:负责从Fabric中取出数据。然后把这些数据交给Chaincode处理。
- GetState:负责从Fabric中取出数据。然后把这些数据交给Chaincode处理。
-
- GetStateByRange: 根据Key的范围来查询相关的数据。
- GetStateByRange: 根据Key的范围来查询相关的数据。
-
- GetHistoryForKey:负责查询某个键的历史记录。
-
- DelState: 用来删除一个Key。
- DelState: 用来删除一个Key。
-
- CreateCompositeKey:负责创建一个组合键。
- CreateCompositeKey:负责创建一个组合键。
-
- GetState rPartialCompositeKey:用来查询复合键的值。
-
- SplitCompositeKey:用来拆分复合键的属性。
- SplitCompositeKey:用来拆分复合键的属性。
3. ChaincodeStublnterface 接口中交易管理相关方法
-
- GetTxTimestamp :负责获取当前客户端发送的交易时间戳。
4. 调用其他Chaincode的方法
-
- InvokeChaincode:这个接口可以调用其他Chaincode。
7.4 Chaincode的相关操作命令和选项
Chaincode是通过peer模块的Chaincode子命令来完成相关部署的工作。执行命令 peer chain-help:
-
Chaincode命令的公用选项
- cafile:PEM格式证书的位置
- o,orderer:orderer服务器的访问地址
- tls:使用orderer的TLS证书的位置
- transient :JSON参数的编码映射
-
- Chaincode 命令的子命令 :数可以是配置文件也可以是环境变量,所以采用环境变量
- c,------ctor------JSON格式的构造参数,默认是{}
- l,------lang------编写的语言,默认是golang
- n, ------name--------Chaincode的名字
- p, ------path -------Chaincode源代码的路径
- v,------version--------当前的操作Chaincode的版本。
instal命令成功后,会在peer模块的数据文件中生成一个-n参数和一个-v参数组成的文件。
在该路径下面会发现一个名为:qlkszzncc.1.1的类似的文件。这个文件就是 Chaincode打包之后的文件。
-
- instantiate:可以对已经执行过得instanll命令的Chaincode进行实例化。
命名执行完成之后会启动Chain运行的Docker镜像,同时还会对Chaincode进行初始化。
- C -----channelID-----当前命命令运行的通道。默认是 testchainid
- c -----ctor-----JSON格式的构造参数。默认值是{}
- E -----escc -----应用于当前Chaincode的系统背书Chaincode的名字
- l -----lang-----编写Chaincode的变成语言,默认值是Golang
- n-----name-----Chaincode的名称
- P-----policy-----当前的Chaincode的背书策略
- v-----version-----当前操作的Chaincode的版本,
- V-----vscc-----当前Chaincode调用的验证系统Chaincode的名字
-
- invoke: invoke命令用来调用chaincode
- C-----channelID------当前命令运行的通道 默认是testchainid
- c------ctor-----JSON格式的构造参数, 默认值是{}
- n-----name-----Chaincode的名字
-
- list:查询已经安装好的Chaincode.
- C-----channelID-----当前命令运行的通道。默认值是 testchainid
- installed------获取当前Peer节点可以被install的chaincode
- instantiated-----获取当前Channel中已经被instantiated的chaincode
-
- package :将 Chaincode打包
- s-----cc-package:对打包后的Chaincode 进行签名
- c ------ctor------JSON格式的构造参数,默认值是{}
- i------instantiate-policy ------Chaincode的权限
- l------ lang------编写的Chaincode的变成语言,默认值是golang
- n------name------Chaincode的名称
- p------path------Chaincode源代码的路径
- S------sign-----对打包的文件用本地MSP配置文件中localmspId指定的值进行签名
- v------version ------当前操作的 Chaincode的版本。
-
- query:执行Chaincode代码中的query方法。
- C------channelID,当前命令运行的通道,默认值是 testchainid
- c------ctor------JSON格式的构造参数,默认值是{}
- x-----hex------是否对输出的内容进行编码处理
- n------name------Chaincode的名字
- r------raw------是否输入二进制内容
- t------tid------ 指定当前查询的编号
-
- signpackage:对已经打好包的 Chaincode进行签字
- signpackage:对已经打好包的 Chaincode进行签字
-
- upgrade:更新已经存在的Chaincode
- C------channelID------当前命令运行的通道,默认值是testchainid
- c-----ctor JSON格式的构造参数,默认值是{}
- E-----escc------应用于当前Chaincode的系统背书Chaincode的名字
- l------lang------编写Chaincode的编程语言。 默认值是 golang
- n------name----- Chaincode的名字
- p------path------Chaincode源代码的路径
- P-----policy------当前Chaincode的背书策略
- v-----version------当前的操作Chaincode的版本
- V------vscc------当前 Chaincode调用的验证系统Chaincode名称
7.4 如何通过 Chaincode进行交易的endorse
区块链最重要的一个特点是:去中心化。所有参与者集体维护公共账本。
Fabaric 中对数据参与方对数据的确认是真实通过Chaincode来进行的。
在Fabric中有一个非常重要的概念成为Endorsement中文名为背书。
什么是背书呢?
背书就是仪表交易被确认的过程。大概意思就是交易你必须背会一本书才能操作。
背书策略被用来指示对相关的参与方如何对交易进行确认。当一个节点接收到一个交易请求的时候,会调用vscc系统(系统Chaincode,专门负责处理背书相关的操作)与交易的Chaincode共同来验证交易的合法性。在vscc和交易的 Chaincode共同对交易的确认中,通常会做一下的校验。
- 所有的背书是否有效
- 参与背书的数量是否满足要求
- 所有背书参与方是否满足要求
背书策略是第二和第三的一种方式。
背书策略的设置是通过Chaincode部署时instantiate命令中的-p参数来设置的。
上面的命令是对Chaincode进行实例化的操作。我们提取-p后面的参数:
这个参数包说明是当前Chaincode发起的交易,需要组织编号为 Org1MSP的组织编号为Org2MSP的组织中的任何一个用户共同参与交易的确认并且同意。这样交易才能生效并且记录到 区块链中。
通过上述背书策略的示例我们可以知道背书策略是通过一定的关键字和系统的属性组成的。
背书拆解:
-
and 参与背书者之间的关系,and表示所有参与方的任何一方参与背书即可完成交易的确认。还可以使用OR,如果使用OR表示参与方的任何一方参与背书即可完成交易的确认。
-
OrglMSP.m mber 这是表示参与背书的组织和组织中参与背书的用户。Org1MSP表示组织的编号。这个值是怎么来的呢
在cryptoge模块中,给模块根据配置文件生成系统的配置和账号信息。在cryptogen的配置文件有一个节点 Organizations-ID,该节点的值就是该组织的编号。也是在配置背书策略时需要使用到的组织的额编号。member泛指组织内的任何一个用户,淡然也可以是组织某个具体的用户
背书的而编写规则
- 背书规则示例一
-
按照背书规则一进行背书交易,必须经过组织中的用户共同验证交易才能生效
按照背书规则而进行背书交易,只需要经过一个组织中的任何一个成员验证 就可以生效
- 背书规则三
按照第三种规则进行别墅交易的方法有两个让交易生效。
- 组织1 中的某个用户交易进行验证
- 组织2和组织3 中的成员共同对交易进行验证
还有一点需要注意,就是背书规则只是针对Chain中写入数据的操作进行校验,对于查询类的操作不需要背书。
Fabric中的背书发生在客户端。需要进行相关的代码的编写才能完成整个背书的操作。