智能合约是Fabric区块链网络的心脏,在可执行代码中定义不同组织之间的规则。智能合约打包成chaincode,部署chaincode后即可通过chaincode生成交易记录到账本上。
二、智能合约与账本的交互开发者需要开发的模块包括Application和SmartContract,Application可以通过ledger的API直接访问区块链,也可以通过智能合约访问区块链和世界状态,智能合约和账本都可以发出event,如下图所示:
智能合约访问World state的接口:
chaincode支持Java、Node.js、Go等语言,下面给出Go的样例:
import (
"fmt"
"github.com/hyperledger/fabric/core/chaincode/shim"
"github.com/hyperledger/fabric/protos/peer"
)
// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}
// Init is called during chaincode instantiation to initialize any data.
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
// Initialize the chaincode
A = args[0]
Aval, err = strconv.Atoi(args[1])
B = args[2]
Bval, err = strconv.Atoi(args[3])
fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)
// Write the state to the ledger
err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
return shim.Success(nil)
}
// Invoke is called per transaction on the chaincode. Each transaction is
// either a 'get' or a 'set' on the asset created by Init function. The Set
// method may create a new asset by specifying a new key-value pair.
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
function, args := stub.GetFunctionAndParameters()
if function == "invoke" {
// Make payment of X units from A to B
return t.invoke(stub, args)
} else if function == "delete" {
// Deletes an entity from its state
return t.delete(stub, args)
} else if function == "query" {
// the old "Query" is now implemtned in invoke
return t.query(stub, args)
}
return shim.Error("Invalid invoke function name. Expecting \"invoke\" \"delete\" \"query\"")
}
Init方法用于初始化chaincode,在chaincode实例化的时候会被调用,上面例子中初始化了A的value和B的value,然后调用PutState接口将数据写入账本中。
Invoke方法在运行交易的时候会被调用,可以通过function参数实现不同的交易逻辑,上面例子中实现了invoke、delete以及query三种交易。
四、chaincode生命周期
chaincode的生命周期包括打包(Package)、安装(Install)、实例化(Instantiate)、运行(Running)以及升级(Upgrade)。
4.1 打包(Package)打包时会生成一个ChaincodeDeploymentSpec (CDS),里面包含了chaincode的源码、名称、版本号;还可以指定实例化策略,指定由谁来进行实例化操作,表达式与背书策略相同;chaincode的拥有者还需要对package进行签名。
打包的操作示例如下所示,指定了名称为mycc、源码路径、版本为1.0、实例化策略为只有组织OrgA的admin角色才能进行实例化,打包的目的文件为 ccpack.out。
peer chaincode package -n mycc -p github.com/hyperledger/fabric-samples/chaincode/abstore/go -v 1.0 -s -S -i "AND('OrgA.admin')" ccpack.out
打包完成后就可以对package进行签名,目的文件为signedccpack.out,示例如下所示:
peer chaincode signpackage ccpack.out signedccpack.out
4.2 安装(Install)
打包完成后就可以进行安装了,一个Peer可以安装多个chaincode,需要注意的是channel上每个Endorsing peer上都必须安装该chaincode。安装ccpack.out的示例如下所示:
peer chaincode install ccpack.out
4.3 实例化(Instantiate)
实例化的时候需要设置背书策略,下面示例中通过-c参数指定了初始化数据,通过-P参数指定了背书策略需要组织Org1和Org2的成员一起背书:
peer chaincode instantiate -C mychannel -n mycc -v 1.0 -c '{"Args":[“a”, “100”, “b”, “200”]}' -P "AND ('Org1.member','Org2.member')"
4.4 运行(Running)
实例化完成后client就可以提交交易请求了,由chaincode处理交易并更新账本,然后返回响应,client也会接收到响应,下面为查询和转账的示例:
peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}’
peer chaincode invoke -o order-url -C mychannel -n mycc -c '{"Args":["invoke","a","b","10"]}'
4.5 升级(Upgrade)
有新的业务需求需要对chaincode进行更新,更新时需要改变版本号;升级之前,新版本的chaincode必须已经在所有要求的背书节点上安装完成;升级过程类似于实例化操作,一次升级只会影响一个channel,示例如下所示:
peer chaincode upgrade -C mychannel -n mycc -v 1.0 -c '{"Args":["a","100","b","200"]}'
五、System Chaincode
System Chaincode在Peer进程中运行,而不是像普通chaincode一样在隔离的容器中运行;System Chaincode实现了一些系统行为,下面列举其中一些System Chaincode:
LSCC(Lifecycle system chaincodeC):处理应用的chaincode生命周期管理请求,包括上面章节中的打包、安装、实例化、升级等; CSCC(Configuration system chaincode):处理Peer端的channel配置,比如某个peer加入channel等; QSCC(Query system chaincode):提供账本查询API,比如获取区块和交易记录。