智能合约(链码)
1、概述
链码的编写需要自定义struct,实现shim包Chaincode接口的两个方法:
type Chaincode interface {
Init(stub ChaincodeStubInterface) pb.Response
Invoke(stub ChaincodeStubInterface) pb.Response
}
链码的生命周期包括链码安装、实例化、升级等。其中链码的实例化和升级都会调用Init()方法,链码的invoke、query调用方式都只会调用Invoke()方法。
在shim包中,fabric给我们提供了ChaincodeStubInterface接口,在该接口中,我们可以使用接口中的方法实现具体的链码业务。
特别说明一句,如果链码方法最后返回的pb.Response是shim.Error(),那么所有的操作,包括数据插入、数据删除、创建复合键、发送事件、调用其他链码等都是无效的,即一次链码的调用具有事务性,如果返回shim.Success()则所有操作都成功,否则所有操作都失败。
2、接口描述
1)参数解析
- 直接获取所有参数
- 字节数组[]byte形式
/*
args := stub.GetArgs()
- args 所有参数的[]byte形式
*/
GetArgs() [][]byte
- 字符串string形式
/*
args := stub.GetStringArgs()
- args 所有参数的[]string形式
*/
GetStringArgs() []string
- 获取方法名和调用参数(string格式)
/*
functionName, args := stub.GetFunctionAndParameters()
- functionName 方法名
- args 方法名后面的所有参数
*/
GetFunctionAndParameters() (functionName string,args []string)
2)复合键操作
- 创建复合键
/*
compositeKey, err := stub.CreateCompositeKey(objectType, attributes)
- objectType用于分类,放在compositeKey中的最前面,无实际含义
- attributes是一个slice,会拼接成string类型,接在objectType后面
*/
CreateCompositeKey(objectType string, attributes []string) (string, error)
- 分割复合键
/*
key, compositeKeys, err := stub.SplitCompositeKey(iterator.Next().Key)
- iterator为查询复合键的迭代器,Next()方法返回下一个复合键对象,Key标识该
对象的复合键;
- compositeKeys,[]string类型,得到即为创建复合键时的attributes值
*/
SplitCompositeKey(compositeKey string) (string, []string, error)
- 查询复合键
- 查询所有结果
/*
iterator, err := stub.GetStateByPartialCompositeKey(objectType, keys)
- keys用于筛选
* 当keys为空时,返回该objectType下的所有复合键;
* 当keys不为空时,需要按照顺序,依次填入字段,即按照最左匹配原则,筛选出符
合条件的复合键;
*/
GetStateByPartialCompositeKey(objectType string, keys []string) (StateQueryIteratorInterface, error)
- 分页展示结果(仅couchDB支持)
GetStateByPartialCompositeKeyWithPagination(objectType string, keys []string, pageSize int32, bookmark string) (StateQueryIteratorInterface, *pb.QueryResponseMetadata, error)
3)账本数据处理
- 查询数据
- 查询单个数据
/*
data, err := stub.GetState(key)
*/
GetState(key string) ([]byte, error)
- 查询范围内的数据
- 查询所有结果
/*
iterator, err :=stub.GetStateByRange(startKey, endKey)
- startKey, endKey为查询的范围边界,注意是左闭右开, [startKey, endKey),即查询的结果是不包括endKey的值;
*/
GetStateByRange(startKey, endKey string) (StateQueryIteratorInterface, error)
* 分页展示结果(仅couchDB支持)
GetStateByRangeWithPagination(startKey, endKey string, pageSize int32, bookmark string) (StateQueryIteratorInterface, *pb.QueryResponseMetadata, error)
- 条件查询(仅couchDB支持)
- 查询所有结果(仅couchDB支持)
/*
iterator, err := stub.GetQueryResult(query)
- query为富查询语句
*/
GetQueryResult(query string) (StateQueryIteratorInterface, error)
* 分页展示结果(仅couchDB支持)
/*
iterator, metadata, err := stub.GetQueryResultWithPagination(query, pageSize, bookmark)
*/
GetQueryResultWithPagination(query string, pageSize int32, bookmark string) (StateQueryIteratorInterface, *pb.QueryResponseMetadata, error)
- 插入数据
/*
err := stub.PutState(key, value)
*/
PutState(key string, value []byte) error
- 删除数据
/*
err := stub.DelState(key)
*/
DelState(key string) error
- 查询数据修改的历史记录
/*
iterator, err := stub.GetHistoryForKey(key)
*/
GetHistoryForKey(key string) (HistoryQueryIteratorInterface, error)
4)交易信息
- 获取交易ID
GetTxID() string
- 获取ChannelID
GetChannelID() string
- 获取交易创建的时间戳
GetTxTimestamp() (*timestamp.Timestamp, error)
- 获取交易提交者的身份信息
GetCreator() ([]byte, error)
- 获取交易的临时信息
GetTransient() (map[string][]byte, error)
5) 发送事件
/*
err := stub.SetEvent(key, value)
注:sdk监听链码时,会根据正则表达式对key值进行筛选,value值将会传给链码的监听对象;
*/
SetEvent(name string, payload []byte) error
6)私有数据处理 (略)
7)调用其他链码
/*
resp := stub.InvokeChaincode(chaincodeName, args, channel)
*/
InvokeChaincode(chaincodeName string, args [][]byte, channel string) pb.Response
3、其他接口补充
1)数据状态查询结果迭代器接口(StateQueryIteratorInterface)
- 判断是否还有元素
HasNext() bool
- 关闭迭代器
Close() error
- 获取下一个元素
Next() (*queryresult.KV, error)
2)历史记录查询结果迭代器接口(HistoryQueryIteratorInterface)
- 判断是否还有元素
HasNext() bool
- 关闭迭代器
Close() error
- 获取下一个元素
Next() (*queryresult.KeyModification, error)
4、图解
来源:oschina
链接:https://my.oschina.net/u/4389064/blog/4367436