链码的编写需要自定义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()则所有操作都成功,否则所有操作都失败。
/*
args := stub.GetArgs()
- args 所有参数的[]byte形式
*/
GetArgs() [][]byte
/*
args := stub.GetStringArgs()
- args 所有参数的[]string形式
*/
GetStringArgs() []string
/*
functionName, args := stub.GetFunctionAndParameters()
- functionName 方法名
- args 方法名后面的所有参数
*/
GetFunctionAndParameters() (functionName string,args []string)
/*
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)
GetStateByPartialCompositeKeyWithPagination(objectType string, keys []string, pageSize int32, bookmark string) (StateQueryIteratorInterface, *pb.QueryResponseMetadata, error)
/*
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)
/*
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)
GetTxID() string
GetChannelID() string
GetTxTimestamp() (*timestamp.Timestamp, error)
GetCreator() ([]byte, error)
GetTransient() (map[string][]byte, error)
/*
err := stub.SetEvent(key, value)
注:sdk监听链码时,会根据正则表达式对key值进行筛选,value值将会传给链码的监听对象;
*/
SetEvent(name string, payload []byte) error
/*
resp := stub.InvokeChaincode(chaincodeName, args, channel)
*/
InvokeChaincode(chaincodeName string, args [][]byte, channel string) pb.Response
HasNext() bool
Close() error
Next() (*queryresult.KV, error)
HasNext() bool
Close() error
Next() (*queryresult.KeyModification, error)