【转载请标明出处】:https://blog.csdn.net/qq_25870633/article/details/81751101
<https://blog.csdn.net/qq_25870633/article/details/81751101>
之前的文章中我们有讲过了fabric的一些核心的配置文件的选项说明,讲过fabric
的网络启动的步骤,那么,我们会在这篇文章中讲述如何的编写链码,及本地调试链码,及发布链码调用链码等等操作!
【注意】首先,我们在编写链码之前需要下载几个依赖库:
1、github.com/hyperledger/fabric/core/chaincode/shim
2、github.com/hyperledger/fabric/protos/peer
其中,一个最基本的空链码结构为如下所示:
package myChainCode import (
"github.com/hyperledger/fabric/core/chaincode/shim"
"github.com/hyperledger/fabric/protos/peer" "fmt" ) type FirstChainCode struct
{ } /** 实例化/升级链码时调用的方法 */ func (self *FirstChainCode)Init(stub
shim.ChaincodeStubInterface) peer.Response { return peer.Response{} } /**
客户端/cli使用Query或者Invoke的方式调用链码时调用的方法 */ func (self *FirstChainCode)Invoke(stub
shim.ChaincodeStubInterface) peer.Response { return peer.Response{} } func
main() { if err := shim.Start(new(FirstChainCode)); nil != err {
fmt.Printf("实例化链码失败,err := %n", err.Error()) } }
先来讲解下链码文件的结构:
首先,上述是每个链码文件都需要实现 ChainCode 接口
在源码包的 github.com/hyperledger/fabric/core/chaincode/shim/interfaces.go 中的
ChainCode 接口为:
package shim import ( "github.com/golang/protobuf/ptypes/timestamp"
"github.com/hyperledger/fabric/protos/ledger/queryresult" pb
"github.com/hyperledger/fabric/protos/peer" ) // Chaincode interface must be
implemented by all chaincodes. The fabric runs // the transactions by calling
these functions as specified. type Chaincode interface { // Init is called
during Instantiate transaction after the chaincode container // has been
established for the first time, allowing the chaincode to // initialize its
internal data Init(stub ChaincodeStubInterface) pb.Response // Invoke is called
to update or query the ledger in a proposal transaction. // Updated state
variables are not committed to the ledger until the // transaction is
committed. Invoke(stub ChaincodeStubInterface) pb.Response }
其中,
1、当链码收到 实例化 (instantiate) 或者 升级 (upgrade) 类型交易时,Init 方法会被调用;
2、当链码收到 调用 (invoke) 或者 查询 (query)类型交易时, Invoke 方法会被调用;
下面我们在看一个稍微完善点的链码:
package main import ( "github.com/hyperledger/fabric/core/chaincode/shim"
"github.com/hyperledger/fabric/protos/peer" "fmt" ) type SimpleChaincode struct
{ } /** 实例化/升级链码时被自动调用 -c '{"Args":["Hello","World"]' */ func (t
*SimpleChaincode) Init(stub shim.ChaincodeStubInterface) peer.Response { //
获取参数 //args := stub.GetStringArgs() _, args := stub.GetFunctionAndParameters()
// 判断参数长度是否为2个 if len(args) != 2 { return shim.Error("指定了错误的参数个数") } //
通过调用PutState方法将数据保存在账本中 err := stub.PutState(args[0], []byte(args[1])) if err
!= nil { return shim.Error("保存数据时发生错误...") } return shim.Success("链码实例化成功~") }
/** 对账本数据进行操作时被自动调用(query, invoke) peer chaincode query -n hello -C myc -c
'{"Args":["queryData","Hello"]}' */ func (t *SimpleChaincode) Invoke(stub
shim.ChaincodeStubInterface) peer.Response { // 获取调用链码时传递的参数内容(包括要调用的函数名及参数)
fun, args := stub.GetFunctionAndParameters() if fun == "queryData" { return
queryData(stub, args) } return shim.Error("非法操作, 指定功能不能实现") } /** 自定义方法 */ func
queryData(stub shim.ChaincodeStubInterface, args []string) peer.Response { //
检查传递的参数个数是否为1外 if len(args) != 1 { return shim.Error("只能指定相应的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) } func main() { if err :=
shim.Start(new(SimpleChaincode)); nil != err { fmt.Printf("链码启动失败: %v", err) } }
以上就是我们的链码的编写,其中【stub shim.ChaincodeStubInterface 为我们提供了操作
账本的API,具体请参考相关资料】下面我们来查看链码的本地调试及 远端的安装部署
首先,我们要本地调试的话需要具备可以启动简单的本地fabric网络的配置,我这里就直接用了fabric-sample提供的 chaincode
目录来存放本地链码,使用 chaincode-docker-devmode 目录来运行链码,【为什么这么做呢,首先,我们在Hyperledger
fabric的简单入门(一)fabric-samples的下载及自动启动网络脚本演示
<https://blog.csdn.net/qq_25870633/article/details/81113464> 一文中就有说明了 chaincode
和 chaincode-docker-devmode 的作用,且在 chaincode-docker-devmode 中的
docker-compose-simple.yaml 中就能看到,该本地测试环境所引用的链码是 挂载了 chaincode 到容器的】
步骤:
1、先进入 chaincode-docker-devmode 启动本地测试网络 :docker-compose -f
docker-compose-simple.yaml up
2、进入对应的链码所在目录【当然进入到chaincode容器中的对应挂载的目录也是可以的】,如:/fabric-samples/chaincode/sacc
执行go build 把链码编译成go的可执行文件【或者直接把可执行文件拖到这里面来】;
3、在 链码容器 【注意: 一定是去到容器里面启动链码哦】的 对应的链码的可执行文件所在的目录,如:
/opt/gopath/src/chaincode/sacc
这时候我们需要手动启动链码:CORE_PEER_ADDRESS=peer:7052 CORE_CHAINCODE_ID_NAME=mycc:0 ./sacc
【其中,CORE_PEER_ADDRESS 和 docker-compose-simple.yaml 中peer 的CORE_PEER_ADDRESS
端口不一样,为什么是这样,请查看之前的Hyperledger fabric的简单入门(三)fabric主要配置文件细讲
<https://blog.csdn.net/qq_25870633/article/details/81184781> 中的 peer 的配置文件
core.yaml 讲解自明 】
启动链码显示:
链码启动成功!【当然,正式环境链码的启动是有Endorser节点来启动链码容器启动的】
升级链码,在没有关闭本地网络的情况下,升级链码需要,把更改的的执行文件替换(当然不替换也是可以的需要不同名) 且在链码容器中启动链码时,指定
新的版本号【一般是网上叠加的版本号】和指定新的执行文件:
CORE_PEER_ADDRESS=peer:7052 CORE_CHAINCODE_ID_NAME=mycc:2 ./sacc
OK,这时候我们就可以,启动一个客户端来调用对应的链码了,步骤和正常的链码调用一直,如:
安装 -> 实例化 /升级 -> 调用
peer chaincode install -p chaincodedev/chaincode/sacc -n mycc -v 0
peer chaincode instantiate -n mycc -v 0 -c '{"Args":["a","10"]}' -C myc
peer chaincode invoke -n mycc -c '{"Args":["set", "a", "20"]}' -C myc
【注意】本地环境中默认通道为 myc;且本地环境安装及实例化/升级等都不需要一大堆 --tls --msp 等等参数
OK,以上就是我们在本地环境测试链码的方式,正式环境是如何操作链码的,请参考【Hyperledger
fabric的简单入门(二)单机演示fabric网络启动全过程
<https://blog.csdn.net/qq_25870633/article/details/81144847>】最后面操作链码那部分!
热门工具 换一换