区块链2.0的典型代表就是智能合约,在Fabric中将其称为链码,智能合约具体是什么呢?好多人都有些蒙圈,在我看来智能合约对应到传统的互联网就是C/S中的S端部署的程序,因此基于区块链平台的开发,我可以理解成服务器开发。只不过这个开发是包裹上了区块链这一层技术。
智能合约的开发就是基于区块链的服务端应用开发。主要有以下几类
系统合约 | 用户合约 | |
配置系统链码(CSCC) | Peer 端的 Channel 配置 | "由应用程序开发人员根据不同场景需求及成员制定的相关规则,使用 Golang或Java等语言编写的基于操作区块链分布式账本的状态的业务处理逻辑代码,运行在链码容器中,通过Fabric 提供的接口与账本状态进行交互。下可对账本数据进行操作,上可以给企业级应用程序提供调用接口 |
生命周期系统链码(LSCC) | 对用户链码的生命周期进行管理 | |
查询系统链码(QSCC) | 提供账本查询API,如获取区块和交易等信息 | |
背书管理系统链码(ESCC) | 负责背书(签名)过程, 并可以支持对背书策略进行管理 | |
验证系统链码(VSCC) | 处理交易的验证,包括检查背书策略以及多版本并发控制 | |
管理 Chaincode 的五个命令:
install:将已编写完成的链码安装在网络节点中。 instantiate:对已安装的链码进行实例化。 upgrade:对已有链码进行升级。链代码可以在安装后根据具体需求的变化进行升级。 package:对指定的链码进行打包的操作。 singnpackage:签名。链码的使用过程包括:安装、实例化、查询、调用。
二、开发模式下测试链码由于链码的相关操作需要进行大量的命令行操作,具有效率低下的特点,为了提高开发效率我们将链码的功能逐个测试后,写成脚本的的形式然后进行执行。可大大提高工作效率,下面主要以Hello World为例介绍一下链码测试的方法:
1、启动网络
命令:
cd fabric-samples/chaincode-docker-devmode/
docker-compose -f docker-compose-simple.yaml up -d
2、构建并启动链码
1、创建文件
cd ../chaincode
mkdir hello && cd hello
vim hello.go
2、导入链码依赖包
package main
import (
"github.com/hyperledger/fabric/core/chaincode/shim"
"github.com/hyperledger/fabric/protos/peer"
"fmt"
)
3、编写主函数
func main() {
err := shim.Start(new(HelloChaincode))
if err != nil {
fmt.Printf("Chaincode start err: %v", err)
}
}
4、自定义结构体
type HelloChaincode struct {
}
5、实现 Chaincode 接口
实现 Chaincode 接口必须重写 Init 与 Invoke 两个方法。
Init 函数:初始化数据状态
具体实现代码如下:
// 实例化/升级链码时被自动调用
// -c '{"Args":["Hello","World"]'
func (t *HelloChaincode) Init(stub shim.ChaincodeStubInterface) peer.Response {
fmt.Println("实例化....")
_, args := stub.GetFunctionAndParameters()
// 判断参数长度是否为2个
if len(args) != 2 {
return shim.Error("Args Err!")
}
fmt.Println("Save data......")
// 通过调用PutState方法将数据保存在账本中
err := stub.PutState(args[0], []byte(args[1]))
if err != nil {
return shim.Error("Save data err...")
}
fmt.Println("实例化成功")
return shim.Success(nil)
}
Invoke 函数
获取参数并判断长度是否为1 利用第1个参数获取对应状态 GetState(key) 如果有错误则返回 如果返回值为空则返回错误 返回成功状态具体实现代码如下:
// 对账本数据进行操作时被自动调用(query, invoke)
func (t *HelloChaincode) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
// 获取调用链码时传递的参数内容(包括要调用的函数名及参数)
fun, args := stub.GetFunctionAndParameters()
// cli op
if fun == "query"{
return query(stub, args)
}
return shim.Error("Err op!")
}
实现查询函数
函数名称为 query,具体实现如下:
func query(stub shim.ChaincodeStubInterface, args []string) peer.Response {
// 检查传递的参数个数是否为1
if len(args) != 1{
return shim.Error("Args err! Args must Key")
}
// 根据指定的Key调用GetState方法查询数据
result, err := stub.GetState(args[0])
if err != nil {
return shim.Error("根据指定的 " + args[0] + " 查询数据时发生错误")
}
if result == nil {
return shim.Error("根据指定的 " + args[0] + " 没有查询到相应的数据")
}
// 返回查询结果
return shim.Success(result)
}
最后将链码码汇总即可。
3、构建并启动链码1、打开一个新的终端B,进入 chaincode 容器
docker exec -it chaincode bash
2、编译链码
cd hello
go build
3、启动链码
CORE_PEER_ADDRESS=peer:7052
CORE_CHAINCODE_ID_NAME=hellocc:0 ./hello
截图:
1、打开终端C、进入cli容器
docker exec -it cli bash
2、安装链码
peer chaincode install -p chaincodedev/chaincode/hello -n hellocc -v 0
3、实例化
peer chaincode instantiate -n hellocc -v 0 -c '{"Args":["init", "Hello","World"]}' -C myc
4、调用链码
peer chaincode query -n hellocc -c '{"Args":["query","Hello"]}' -C myc
根据指定的key查询对应的状态数据,结果为:World。截图如下:
通过学习掌握了链码开发的流程和测试的方法,虽然hello World很简单,但是却能很好的学习链码的开发方法,后期的各项后端的工作都将围绕链码开发展开。