1、接口说明

func:GetChannelID() string

channelName := getChannelID()
返回 mychannel

func:GetCreator() ([]byte, error)

creator, err := stub.GetCreator()
string(creator) 是一个 CERTIFICATE 字符串格式

func:GetHistoryForKey(key string) (HistoryQueryIteratorInterface, error)

方法返回指定状态键的值历史记录
该方法需要通过peer节点配置中的如下选项开启:core.ledger.history.enableHistoryDatabase = true

func:GetQueryResult(query string) (StateQueryIteratorInterface, error)

方法在状态数据库上执行一个rich查询。该方法 仅在支持rich查询的状态数据库上有效
query:查询语句,字符串

func:GetQueryResultWithPagination(query string, pageSize int32, bookmark string) (StateQueryIteratorInterface, *pb.QueryResponseMetadata, error)

返回一个迭代器

func:GetSignedProposal() (*pb.SignedProposal, error)

返回签名交易提议的解码对象,类型为SignedProposal

func:GetStateByRange(startKey, endKey string) (StateQueryIteratorInterface, error)

方法返回一个账本状态键的迭代器,可用来 遍历在起始键和结束键之间的所有状态键,返回结果按词典顺序排列。
如果起始键和结束键之间的数量大于节点配置文件core.yaml中定义的totalQueryLimit, 那么返回结果数量将受限于totalQueryLimit的约定。
调用返回的StateQueryIterator迭代器对象的close()方法关闭迭代器。
startKey:起始键,字符串
endKey:结束键,字符串

func:GetStateByRangeWithPagination(startKey, endKey string, pageSize int32, bookmark string) (StateQueryIteratorInterface, *pb.QueryResponseMetadata, error)

startKey:起始键,字符串
endKey:结束键,字符串
pageSize:页大小,整数
bookmark:书签,字符串

func:GetStateValidationParameter(key string) ([]byte, error)

方法返回指定状态键的背书策略

func:GetTxID() string

当前链码调用请求的交易ID。交易ID可以在通道范围 内唯一标识一个交易

func:GetTxTimestamp() (*timestamp.Timestamp, error)

返回交易创建时的时间戳,值取自交易的ChannelHeader部分, 因此它表示的是客户端的时间戳,并且在所有的背书服务节点上有相同的值。

2、富查询

CouchDB富查询

使用CouchDB作为fabric的状态存储可以很方便的实现富查询的功能而不需要我们自己做额外的工作。

CouchDB通过对Value的内容进行查询来实现富查询的需求。使用 MangoDB API Layer 来实现Query语法,需要传入一个queryString查询字符串,其语法可以在Github查看。

定义一个数据结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
 
type Car struct {
ID string `json:"ID"` // key
Color string `json:"Color"`
Price string `json:"Price"`
LaunchDate string `json:"LaunchDate"`
}
```

富查询代码如下:
```golang

func (t *CarchainCode) queryByColor(stub shim.ChaincodeStubInterface, args []string) Car.Response {
if len(args) != 1 {
return shim.Error("Incorrect number of arguments. Expecting 1")
}

color := args[0]
queryString := fmt.Sprintf(`{"selector":{"Color":"%s"}}`, color) //Mongo Query string 语法见上文链接
resultsIterator, err := stub.GetQueryResult(queryString) // 富查询的返回结果可能为多条 所以这里返回的是一个迭代器 需要我们进一步的处理来获取需要的结果

if err != nil {
return shim.Error("Rich query failed")
}
defer resultsIterator.Close() //释放迭代器

var buffer bytes.Buffer
bArrayMemberAlreadyWritten := false
buffer.WriteString(`{"result":[`)

for resultsIterator.HasNext() {
queryResponse, err := resultsIterator.Next() //获取迭代器中的每一个值
if err != nil {
return shim.Error("Fail")
}
if bArrayMemberAlreadyWritten == true {
buffer.WriteString(",")
}
buffer.WriteString(string(queryResponse.Value)) //将查询结果放入Buffer中
bArrayMemberAlreadyWritten = true
}
buffer.WriteString(`]}`)
fmt.Print("Query result: %s", buffer.String())

return shim.Success(buffer.Bytes())
}

3、区间查询

在chaincode中可以使用stub接口实现区间查询。

1
2
3
4
5
6
7
8
9
10
// GetStateByRange returns a range iterator over a set of keys in the
// ledger. The iterator can be used to iterate over all keys
// between the startKey (inclusive) and endKey (exclusive).
// The keys are returned by the iterator in lexical order. Note
// that startKey and endKey can be empty string, which implies unbounded range
// query on start or end.
// Call Close() on the returned StateQueryIteratorInterface object when done.
// The query is re-executed during validation phase to ensure result set
// has not changed since transaction endorsement (phantom reads detected).
GetStateByRange(startKey, endKey string) (StateQueryIteratorInterface, error)

根据需要查询区间的开始键与结束键(开始键与结束键按字典顺序排序)获得区间查询的结果(结果包含开始键、不包括结束键的半闭半开区间)。
例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
func (t *SimpleChaincode) rangeQuery(stub shim.ChaincodeStubInterface, args []string) pb.Response {

resultsIterator, err := stub.GetStateByRange("Car:001", "Car:003")
//这里应为传入参数,开始键与结束键按字典顺序排序

if err != nil {
return shim.Error("Query by Range failed")
}
defer resultsIterator.Close() //释放迭代器

var buffer bytes.Buffer
bArrayMemberAlreadyWritten := false
buffer.WriteString(`{"result":[`)

for resultsIterator.HasNext() {
queryResponse, err := resultsIterator.Next() //获取迭代器中的每一个值
if err != nil {
return shim.Error("Fail")
}
if bArrayMemberAlreadyWritten == true {
buffer.WriteString(",")
}
buffer.WriteString(string(queryResponse.Value)) //将查询结果放入Buffer中
bArrayMemberAlreadyWritten = true
}
buffer.WriteString(`]}`)
fmt.Print("Query result: %s", buffer.String())

return shim.Success(buffer.Bytes())
}