这是Hyperledger Fabric V1.0 官方文档里的Chaincode for Developers章节。
第一次翻译,不妥之处还请网友指出,我们一起学习一起进步。
原文地址(http://hyperledger-fabric.readthedocs.io/en/latest/chaincode4ade.html)
链码是什么
Chaincode是一个用Go编写的程序,最终在其他编程语言(如Java)中实现了一个规定的界面。 链码运行在与背书节点相隔离的安全的Docker容器中。Chaincode通过由应用程序提交的交易来初始化和管理账本状态。
链码通常用来处理网络成员所同意的业务逻辑,因此可被视为“智能合约”。 由链码创建的状态仅限于该链码,不能被另一个链码直接访问。 然而,在同一个网络中,给定适当的权限,一个链码可以调用另一个链码来访问其状态。
在下面的章节中,我们将通过一个应用程序开发人员的眼睛探索chaincode。 我们将介绍一个简单的链码示例应用程序,并介绍 Shim API中的每个方法。
链码 API
每个链码程序必须实现链码接口(Chaincode interface),其方法在响应接收到的交易时被调用。 特别地,当链码接收到实例化或更新交易时,调用初始化Init方法,使得链码可以执行任何必需的初始化,包括应用程序状态的初始化。 Invoke方法在响应接收到一个用来处理交易提议的invoke交易时被调用。
链码“shim”API中的另一个接口是ChaincodeStubInterface,用于访问和修改账本,并在链码之间进行调用。
在本教程中,我们将通过实现一个用来管理简单资产的链码应用程序来演示这些API的使用。
简单资产链码
我们的应用程序是用来在账本上创建资产(键值对)的一个基本示例链码。
选择源代码的存放位置
如果你没有go语言的环境,请先确认正确安装和配置go语言。
现在你要在$*GOPATH*/src/下面为你的链码应用程序建立一个子目录。
为了让事情简单点,我们执行下面的命令:
mkdir -p $GOPATH/src/sacc && cd $GOPATH/src/sacc
现在让我们创建源文件并编写代码:
touch sacc.go
Housekeeping 准备工作
首先,让我们先进行一些准备工作。与每个链码一样,链码就是实现了链码接口Chaincode interface
https://github.com/hyperledger/fabric/blob/master/core/chaincode/shim/interfaces.go#L28
特别是 init和invoke函数。
所以我们要为链码导入必须的依赖包。
我们将导入链码的shim包和peer protobuf 包。
package main
import (
"fmt"
"github.com/hyperledger/fabric/core/chaincode/shim"
"github.com/hyperledger/fabric/protos/peer"
)
初始化链码
接下来我们要实现一个初始化函数。
// Init is called during chaincode instantiation to initialize any data.
func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {
}
请注意链码升级也会调用这个函数。当升级一个现有的链码时,请确保修改相应的初始化 Init 函数。特别是 如果没有进行迁移或者作为升级的一部分没有什么需要初始化时提供了一个空的初始化方法是更应当注意。
接下来,我们将使用ChaincodeStubInterface.GetStringArgs函数取出Init调用的参数,并检查其有效性。 在我们的例子中,我们期望获得一个键值对。
// Init is called during chaincode instantiation to initialize any
// data. Note that chaincode upgrade also calls this function to reset
// or to migrate data, so be careful to avoid a scenario where you
// inadvertently clobber your ledger's 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")
}
}
接下来,现在我们将要建立起一个有效的函数调用,我们将把初始状态存储在账本中。 为此,我们将键和值作为参数传递给ChaincodeStubInterface.PutState方法。 假设一切顺利,将返回一个表示初始化已经成功的peer.Response对象。
// Init is called during chaincode instantiation to initialize any
// data. Note that chaincode upgrade also calls this function to reset
// or to migrate data, so be careful to avoid a scenario where you
// inadvertently clobber your ledger's 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")
}