前言
本系列文章代码均为Go语言。
- Hyperledger Fabric 开发——初步认识智能合约(链码)
- Hyperledger Fabric 开发——开发用户链码
- Hyperledger Fabric 开发——测试用户链码 (待更新)
链码文件 Chaincode.go 的基本结构
首先,我们来看一个示例代码。所有的链码都含有此基本结构
package main
import (
"fmt"
"github.com/hyperledger/fabric/core/chaincode/shim"
pb "github.com/hyperledger/fabric/protos/peer"
)
type SimpleChaincode struct {
}
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
return shim.Success(nil)
}
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
return shim.Success(nil)
}
func main() {
err := shim.Start(new(SimpleChaincode))
if err != nil {
fmt.Printf("Error starting Simple chaincode: %s", err)
}
}
下面通过 fabric-samples 中的 chaincode 案例 sacc.go 来学习一下 chaincode 的各个部分以及编写。
- 导入资源包与定义结构体
首先导入fmt、shim、protos包。
Chaincode 接口定义了 Init 和 Invoke 函数,Shim 包定义了 Success、Error 等常用方法,shim 包的ChaincodeStubInterface 接口提供了一组方法,通过该组方法可以非常方便的操作账本数据。
详细说明请参照官方文档:
- https://pkg.go.dev/github.com/hyperledger/fabric/core/chaincode/shim?tab=doc#ChaincodeStubInterface
- https://pkg.go.dev/github.com/hyperledger/fabric/protos/peer?tab=doc
接下来定义一个属性为空的结构体 SimpleAsset
作为链码方法的接收参数。
package main
import (
"fmt"
"github.com/hyperledger/fabric/core/chaincode/shim"
"github.com/hyperledger/fabric/protos/peer"
)
// SimpleAsset implements a simple chaincode to manage an asset
type SimpleAsset struct {
}
- Init 函数
Init 函数用于初始化链码。在链码实例化和升级的时候都会调用 Init方法。
链码初始化的时候,调用了 ChaincodeStubInterface.GetStringArgs 函数来获取初始化时输入的参数。这个例子中,我们期望传入两个参数,作为一个key/value对。接下来,将key/value作为 ChaincodeStubInterface.PutState 的参数,如果 shim 向客户端返回正确消息则表明初始化成功。
// Init is called during chaincode instantiation to initialize any
// data. Note that chaincode upgrade also calls this function to reset
// or to migrate data.
func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {
// Get the args from the transaction proposal
args := stub.GetStringArgs()
if len(args) != 2 {
return shim.Error("Incorrect arguments. Expecting a key and a value")
}
// Set up any variables or assets here by calling stub.PutState()
// We store the key and the value on the ledger
err := stub.PutState(args[0], []byte(args[1]))
if err != nil {
return shim.Error(fmt.Sprintf("Failed to create asset: %s", args[0]))
}
return shim.Success