Chaincode简介
chaincode通常处理由网络成员赞同的业务逻辑,因此它类似于“智能合约”。 可以调用chaincode来更新或查询提案交易中的ledger。
如果有适当的许可,chaincode可以调用另一个chaincode,以访问其状态,无论是在同一个Channel还是在不同的Channel中。 请注意,如果被调用的chaincode与调用chaincode位于不同的通道上,则只允许读取查询。
Chaincode API
每个chaincode程序必须实现Chaincode interface
,其方法被调用以回应收到的交易。
特别是当Chaincode接收实例化或升级transaction时,将调用Init方法,以便Chaincode可以执行任何必要的初始化,包括应用程序状态的初始化。 调用Invoke方法是为了响应接收调用transaction来处理transaction提议。
chaincode “shim”API中的另一个接口是ChaincodeStubInterface
,用于访问和修改ledger,并在chaincode之间进行调用。
在本文中,我们将通过实现一个管理“资产”的简单chaincode应用程序来演示如何使用这些API。
简单的资产Chaincode
我们的应用程序是一个基本样本chaincode,用于在ledger上创建资产(key-value对)。
选择代码的位置
现在,需要为chaincode应用程序创建一个目录作为$GOPATH/src/
的子目录。
为了简单起见,我们使用下面的命令:
mkdir -p $GOPATH/src/sacc && cd $GOPATH/src/sacc
现在,创建将用代码填充的源文件:
touch sacc.go
Housekeeping
首先,我们从一些Housekeeping开始。与每个chaincode一样,它实现了Chaincode接口,即Init
和Invoke
函数。 因此,让我们添加go import语句以获取chaincode的必要依赖关系。 我们将导入chaincode shim包和peer protobuf包。 接下来,让我们添加一个结构SimpleAsset
作为Chaincode shim函数的接收器。
package main
import (
"fmt"
"github.com/hyperledger/fabric/core/chaincode/shim"
"github.com/hyperledger/fabric/protos/peer"
)
// SimpleAsset 实现管理asset的一个简单chaincode
type SimpleAsset struct {
}
Initializing the Chaincode
下面,我们实现 Init
函数.
// chaincode 实例化的时候,调用Init来初始化数据
func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {
}
请注意,chaincode升级也会调用此函数。在编写将升级现有chaincode的代码时,请确保适当地修改Init
函数。 特别是,如果没有“migration”(迁移),或没有任何东西需要作为升级的一部分进行初始化时,请提供一个空的“Init”
方法。
接下来,我们将使用ChaincodeStubInterface.GetStringArgs
函数检索Init
调用的参数,并检查其有效性。 在我们的例子中,我们期待一个key-value对。
func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {
// 从 transaction proposal 获取参数
args := stub.GetStringArgs()
if len(args) != 2 {
return shim.Error("Incorrect arguments. Expecting a key and a value")
}
}
接下来,已经确定该调用是有效的,我们将把初始状态存储在ledger中。 要做到这一点,我们将调用ChaincodeStubInterface.PutState
,并将key和value作为参数传入。 假设一切顺利,会返回一个指示初始化成功的peer.Response
对象。