本文介绍了什么是智能合约,以及如何在Fabric下编写一个简单的智能合约Demo。
什么是智能合约?
智能合约是一种旨在以信息化方式传播、验证或执行合同的计算机协议。智能合约允许在没有第三方的情况下进行可信交易。这些交易可追踪且不可逆转,Fabric为智能合约提供了一个可信的执行环境。
Fabric下的智能合约
Chaincode是Fabric下智能合约的代码实现,是一段在区块链上验证,存储和执行的代码,只有通过Chaincode才能与Fabric网络进行交互。
在Fabric下又分为系统Chaincode和普通Chaincode。
- 系统Chaincode运行于peer节点内而非一个隔离的容器中,没有生命周期的概念,用于实现一些系统行为。
- 普通Chaincode运行在一个单独的容器中,对外提供操作Fabric网络的接口,有打包、安装、实例化和升级四个生命周期并且有相应的函数提供调用,操作更加的灵活也是我们通常所指Chaincode。
Chaincode的运行过程
- Channel负责连接不同的Peer,同步连接到的Peer对Chaincode的执行结果,相当于将一些节点划分为一个子集同时同步Chaincode的执行结果。
- Endorser负责执行Chaincode。
- Orderer负责对Chaincode的执行结果进行共识,目前支持solo/kafka/sBFT三种共识方式。
- Committer负责将Chaincode经过共识后的结果写入Ledger。
编写Chaincode
Chaincode必须实现两个接口。
type Chaincode interface {
// 初始化⼯作,⼀般情况下仅被调⽤⼀次,升级时也会调用该函数
Init(stub ChaincodeStubInterface) pb.Response
// 查询或更新world state,可多次被调⽤
Invoke(stub ChaincodeStubInterface) pb.Response
}
下面是一个最小智能合约所需要的结构。
package main
import (
"fmt"
"github.com/hyperledger/fabric/core/chaincode/shim"
)
type SimpleAsset struct {}
func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {}
func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response {}
func main() {
if err := shim.Start(new(SimpleAsset)); err != nil {
fmt.Printf("Error starting SimpleAsset chaincode: %s", err)
}
}
具体的业务逻辑都在Invoke这个函数里面进行编写。
首先,我们完善一下Init函数
func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {
args := stub.GetStringArgs()
if len(args) != 2 {
return shim.Error("Incorrect arguments. Expecting a key and a value")
}
// 实例化的时候初始化一下状态
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(nil)
}
接着在Invoke里编写业务逻辑
func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
fn, args := stub.GetFunctionAndParameters()
var result string
var err error
if fn == "set" {
result, err = set(stub, args)
} else {
result, err = get(stub, args)
}
if err != nil {
return shim.Error(err.Error())
}
return shim.Success([]byte(result))
}
Invoke根据不同的参数决定调用查询或者是设置状态。
编写set和get函数
func set(stub shim.ChaincodeStubInterface, args []string) (string, error) {
if len(args) != 2 {
return "", fmt.Errorf("Incorrect arguments. Expecting a key and a value")
}
err := stub.PutState(args[0], []byte(args[1]))
if err != nil {
return "", fmt.Errorf("Failed to set asset: %s", args[0])
}
return args[1], nil
}
func get(stub shim.ChaincodeStubInterface, args []string) (string, error) {
if len(args) != 1 {
return "", fmt.Errorf("Incorrect arguments. Expecting a key")
}
value, err := stub.GetState(args[0])
if err != nil {
return "", fmt.Errorf("Failed to get asset: %s with error: %s", args[0], err)
}
if value == nil {
return "", fmt.Errorf("Asset not found: %s", args[0])
}
return string(value), nil
}
github上有完整代码,代码非常简单就是根据命令查询或者设置世界状态。
执行效果如下图:

这样就在Fabric上实现了一个简单的智能合约。
https://zhuanlan.zhihu.com/p/33750599