ChainMaker 添加查询历史数据功能

从官方童靴得知,后期会加上历史查询功能,目前如有需要请自行实现

直接从链上查询某个Key的历史功能还是非常有必要的,对于溯源类应用还是很方便的。数据存储解析

总体需要改三个地方,go sdk ,protocol,chainmaker-go

生成protocol

添加grpc 数据位于chainmaker-sdk-go/pb/proto/store/query_result.proto

message KVHistory {
  string contract_name = 1;
  string key = 2;
  string value = 3;
  string tx_id = 4;
}
// 返回数据
message KVHistoryArray {
  repeated KVHistory kv_arrays = 1;
}
// 参数
message KVHistortParams {
  string chain_id = 1;
  string key = 2;
  string contract_name = 3;
}

添加grpc方法位于chainmaker-sdk-go/pb/proto/api/rpc_node.proto

...
import "store/query_result.proto";
service RpcNode {
    //  这个是新增方法
    rpc QueryHistory(store.KVHistortParams) returns (store.KVHistoryArray) {};
    ...
}

生成go文件

cd chainmaker-sdk-go/pb/proto
protoc --gogo_out=plugins=grpc:./ ./api/rpc_node.proto
protoc --gogo_out=plugins=grpc:./ ./store/query_result.proto 

将生成的go文件rpc_node.pb.goquery_result.pb.go 分别替换掉go sdk
chainmaker-go里对应的文件,chainmaker-go需要替换2个地方分别是tools/sdk/pb//pb/
注(go-sdk 在替换时需要修改一下rpc_node.pb.go的包名)

package api
import (
    common "chainmaker.org/chainmaker-sdk-go/pb/protogo/common"
    config "chainmaker.org/chainmaker-sdk-go/pb/protogo/config"
    store "chainmaker.org/chainmaker-sdk-go/pb/protogo/store"
    ...
)
...

此时 go sdk和chainmaker-go 具有相同的protocol了

修改chainmaker-sdk-go

添加方法在chainmaker-sdk-go/sdk_client.go

func (cc *ChainClient) SendQueryHistoryRequest(ContractName,Key,ChainId string,timeout int64) (*store.KVHistoryArray, error) {
    kvHistortParams:= &store.KVHistortParams{}
    kvHistortParams.ContractName=ContractName
    kvHistortParams.Key=Key
    kvHistortParams.ChainId=ChainId
    if timeout < 0 {
            timeout = GetTxTimeout
    }

    ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
    defer cancel()

    ignoreAddrs := make(map[string]struct{})
    for {
        client, err := cc.pool.getClientWithIgnoreAddrs(ignoreAddrs)
        if err != nil {
            return nil, err
        }

        if len(ignoreAddrs) > 0 {
            cc.logger.Debugf("[SDK] begin try to connect node [%s]", client.ID)
        }
// 查询历史数据
        resp, err := client.rpcNode.QueryHistory(ctx, kvHistortParams)
        if err!=nil{
            return nil,err
        }

        cc.logger.Debugf("[SDK] sendQueryHistoryRequest resp: %+v", resp)
        return resp, nil
    }
}

自己封装了一下

// 查询历史数据
func (mg *Manager) QueryHistory(ContractName,Key,ChainId string) (*store.KVHistoryArray, error) {
    resp, err := mg.client.SendQueryHistoryRequest(ContractName,Key,ChainId , -1)
    if err != nil {
        return nil, errors.Wrap(err, fmt.Sprintf("[%s]合约[%s]链查询失败", ContractName, ChainId))
    }
    fmt.Println(resp)
    return resp, nil
}

调用方法

_agree_manager.QueryHistory(contract_name,"fact_json#name","c1628498288425")

注意 这里的key 如果是组合的需要用#连接
我合约里的key是这么定义的if r:=ctx.PutState("fact_json","name", jsonStr);r==1{

修改go-sdk

在服务端修改位置如下module/rpcserver/api_service.go

// 查询历史数据
func (s *ApiService) QueryHistory(ctx context.Context, req *storePb.KVHistortParams) (*storePb.KVHistoryArray, error) {
    kvHistoryArray:=&storePb.KVHistoryArray{}
    _arrays:=make([]*storePb.KVHistory,0)
    // 获取数据库
    if store, err := s.chainMakerServer.GetStore(req.ChainId); err != nil {
        s.log.Error(err)
        return nil,err
    }else {
        // 查询数据
        if datas,err:= store.GetHistoryForKey(req.ContractName,[]byte(req.Key));err!=nil{
            s.log.Error(err)
            return nil,err
        }else {
     // 迭代器 循环读取
            for datas.Next(){
                history_value,err:=datas.Value()
                if err!=nil{
                    s.log.Error(err)
                    return nil,err
                }
                kv:=&storePb.KVHistory{}
                kv.Key=req.Key
                kv.ContractName=req.ContractName
                kv.TxId=history_value.TxId
                kv.Value=string(history_value.Value)
                //  history_value还有isdelete 和时间戳  
                _arrays=append(_arrays,kv)
            }
        }
    }
    kvHistoryArray.KvArrays=_arrays
    return kvHistoryArray, nil
}

这样就针对某个Key的历史交易记录查询就基本完成了
服务端图如下


DDE34348-3FD2-4AF3-ADCD-D1E385163CC8.png

仅供参考

你可能感兴趣的:(ChainMaker 添加查询历史数据功能)