深度学习
链码是通过SDK和背书节点通信的,就是说链码的SDK只需要实现接口的定义就能和背书节点交互。理论上,链码是可以 支持多种语言的。目前的版本(1.0.0)支持的语言只有Golang,其他语言(比如Java)还不够完善,正式发布的时候是禁用的。Car支持利用 fabric-chaintool打包的代码,目前也只支持Golang。下面详细地介绍Golang语言的链码提供的接口,讨论如何开发和测试链码。加 入 会 员 微 信 dedao555
10.3.1 链码需要实现的接口
链码必须要实现的接口如下:
type Chaincode interface {
// 初始化工作,一般情况下仅调用一次
Init(stub ChaincodeStubInterface) pb.Response
// 查询或更新状态数据,可多次调用
Invoke(stub ChaincodeStubInterface) pb.Response
}
其中,查询和调用都是在同一个接口Invoke里实现的,不再实现单独的Query接口。
一个链码的样例模版如下,更多的样例可以参考fabric源码或者fabric-samples下的例子:
package main
import (
"fmt"
"github.com/hyperledger/fabric/core/chaincode/shim"
)
type SimpleChaincode struct {
}
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string,
args []string) ([]byte, error) {
fmt.Printf("SimpleChaincode Init: finished\n")
return shim.Success(nil)
}
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function
string, args []string) ([]byte, error) {
var err error
func, args := stub.GetFunctionAndParameters()
fmt.Printf("SimpleChaincode Invoke: func=%v, args = %v\n", func, args)
return shim.Success(nil)
}
func main() {
err := shim.Start(new(SimpleChaincode))
if err != nil {
fmt.Printf("Error starting Simple chaincode: %s", err)
}
}
应用程序发起的调用是如何调用这两个接口的呢?
10.3.2 链码的SDK提供给链码的接口
链码的SDK是shim,提供给链码的接口包括如下几种类型:
·与链码调用参数解析相关;
·与交易信息解析相关;
·与状态数据操作相关;
·与链码调用相关;
·与事件处理相关;
·与辅助操作相关。
下面逐一介绍每种类型具体的接口定义及其功能,这在实际的链码编写过程中都会用到。
1.与链码调用参数解析相关的接口
shim提供了多种获取链码调用参数的接口,可以根据不同的场景使用,如表10-10所示。
表10-10 与链码调用参数解析相关的接口
其中,接口GetArgsSlice返回的字符数组中间没有分隔符,没有办法还原成原始的函数名称和参数信息,实际链码编写过程中基本不会使用这个接口。
2.与交易信息解析相关的接口
与提交的交易信息解析相关的接口如表10-11所示。
表10-11 与交易信息解析相关的接口
需要特别说明的是GetBinding接口,binding是和交易相关的一些指纹信息,计算方法如下:
binding = HASH(Nonce, Creator, Epoch)
其中,Epoch代表的是时间窗口,背书节点在验证Proposal或者记账节点验证交易时会确认:
·交易里的Epoch和当前Epoch的一致性;
·同一个Epoch里没有出现相同交易号的交易。
目前Epoch的管理并没有实现,强制设置为0。其他接口的说明参考前面LSCC里的内容。
3.与状态数据操作相关的接口
与状态数据操作相关的接口又分为3类:
·基于单一键操作的接口;
·基于键范围查询的接口;
·基于值内容查询的接口。
链码基于单一键操作的接口如表10-12所示。
表10-12 链码基于单一键操作的接口
链码基于键范围查询的接口如表10-13所示。
表10-13 链码基于键范围查询的接口
部分组合键查询实际按键的前缀查询,例如,某个链码的组合键格式为K1-K2-K3,支持按K1或K1-K2前缀查询,底层转化为区间查询实现。更多组合键查询的内容参考5.6节。
链码基于值内容查询的接口如表10-14所示。
表10-14 链码基于内容查询的接口
基于值的查询需要状态数据库的支持,目前只有CouchDB才能支持。
4.与链码调用相关的接口
与链码调用相关的接口如表10-15所示。
表10-15 与链码相互调用的接口
链码是可以调用其他链码的接口的,目前实现的原则如下。
·如果被调用的链码和调用的链码在相同的链上,会继承交易模拟器,被调用链码生成的读写集添加到交易中,读写集是以链码编号(chaincodeId)作为命名空间的。就是说相同链的链码调用的读写都是有效的,会影响到被调用链码的状态数据库。
·如果被调用的链码和调用的链码不在相同的链上,会生成一个新的交易模拟器,返回调用执行的Response给链码,不会添加读写集到交易中。就是说,不同链的链码调用只能查询状态数据,不能写入。
5.与事件处理相关的接口
与事件处理相关的接口如表10-16所示。
表10-16 与链码事件处理相关的接口
6.与辅助操作相关的接口
与辅助操作相关的接口如表10-17所示。
表10-17 与链码辅助操作相关的接口
日志操作相关的接口:Debug、Info、Notice、Warning、Error、Critical和Debugf、Infof、Noticef、Warningf、Errorf、Criticalf等,其中带'f'的版本是有格式化字符串的。
链码的SDK也会有日志,名称是shim,日志级别由环境变量CORE_CHAINCODE_LOGGING_SHIM控制,是启动链码的时候传递给链码容器的。
10.3.3 链码开发的注意事项
目前链码的设计并没有考虑区块链外部数据源的问题,在链码开发过程中需要注意以下的事项。
·不能使用不确定性的变量作为计算的输入:比如不能采用随机数或者获取系统当前时间等。链码会在不同的节点上多次运行,但是运行的时间并不严格一致,环境的查询导致不同节点上执行的结果不一致,最终无法达成共识。
·避免调用外部数据接口导致重复计算:比如多个节点多次调用外部写数据的接口,可能会导致区块链外部重复计算。这种情况多个链码的执行结果可能是一致的,不会导致共识失败,但会影响外部的一致性,这是一种逻辑错误。
10.3.4 链码的调试
自动部署的链码都是运行在容器中的,开发调试过程比较复杂,需要经历如下的步骤,如图10-9所示。
图10-9 生产环境下链码的调试流程图
其实,Fabric本身提供了开发模式启动节点:
peer node start --peer-chaincodedev=true
省略中间的创建通道的过程,编译和启动链码的过程如下:
cd examples/chaincode/go/chaincode_example02
go build
CORE_CHAINCODE_LOGLEVEL=debug CORE_PEER_ADDRESS=127.0.0.1:7051 CORE_CHAINCODE_ID_NAME=mycc:0 ./chaincode_example02
后面是正常的安装和实例化的操作,步骤如图10-10所示。
图10-10 调试环境下链码的调试流程图
在这个模式下,链码直接以可执行的程序运行,开发调试不再需要创建链码镜像,能够快速调试链码程序。
本章先介绍了基于超级账本的应用开发模型,从应用开发的角度看,主要有两个部分,一个部分是基于不同语言的SDK开发 和区块链网络交互的应用程序,另外一个部分是实现超级账本的智能合约。目前SDK提供了4种语言的版本,本章主要以Golang版本为基础介绍了SDK的 各个模块及其主要的功能,然后介绍了几种主要应用场景的调用时序图,方便了解应用程序、SDK和超级账本节点之间的交互关系。
最后介绍了超级账本的智能合约,链码的基本框架,链码的主要接口及其功能,如何编写链码和调试。
了解了以上的内容,就能够动手搭建符合自身业务场景的区块链网络,利用区块链技术实现具有智能合约、不可篡改等特性的应用。
来源:我是码农,转载请保留出处和链接!
本文链接:http://www.54manong.com/?id=1051
微信号:qq444848023 QQ号:444848023
加入【我是码农】QQ群:864689844(加群验证:我是码农)
全站首页 | 数据结构 | 区块链| 大数据 | 机器学习 | 物联网和云计算 | 面试笔试
var cnzz_protocol = (("https:" == document.location.protocol) ? "https://" : "http://");document.write(unescape("%3Cspan id='cnzz_stat_icon_1276413723'%3E%3C/span%3E%3Cscript src='" + cnzz_protocol + "s23.cnzz.com/z_stat.php%3Fid%3D1276413723%26show%3Dpic1' type='text/javascript'%3E%3C/script%3E"));本站资源大部分来自互联网,版权归原作者所有!
评论专区