如何在 hyperledger fabric 中获取资产修改历史
How to fetch asset modification history in hyperledger fabric
我正在使用 IBM bluemix blockchain service 为我的资产共享演示试用一些智能合约逻辑。
在hyperledger fabric network中是否有查询资产修改历史的方法。
我已经检查了 fabric 0.6 和 1.0 版本的文档,但我只能找到 stub.pushState(key,value_json) 和 stub.getState(key) 在账本上进行交互。
但是使用 stub.getState(key), 我只能获取 key 的最新条目,但是如何获取并显示为同一键编写的 changes/modification 系列。
我已经使用 {peeraddress}/Block/getBlock/{Block}
遍历了该块,但是我只是因为它的安全性开启才获得加密的交易有效负载。我不明白要显示同一密钥的资产修改历史记录。
请告诉我正确的方法。
提前致谢
来自 Fabric FAQ,A. 链代码 API GetHistoryForKey() 将 return 键值的历史记录。
您可以使用 GetHistoryForKey()
API 如下:
historyIter, err := stub.GetHistoryForKey(key)
if err != nil {
errMsg := fmt.Sprintf("[ERROR] cannot retrieve history for key <%s>, due to %s", key, err)
fmt.Println(errMsg)
return shim.Error(errMsg)
}
for historyIter.HasNext() {
modification, err := historyIer.Next()
if err != nil {
errMsg := fmt.Sprintf("[ERROR] cannot read record modification for key %s, id <%s>, due to %s", key, err)
fmt.Println(errMsg)
return shim.Error(errMsg)
}
fmt.Println("Returning information about", string(modification.Value))
}
Here is the link 到接口 API 描述:
// GetHistoryForKey returns a history of key values across time.
// For each historic key update, the historic value and associated
// transaction id and timestamp are returned. The timestamp is the
// timestamp provided by the client in the proposal header.
// GetHistoryForKey requires peer configuration
// core.ledger.history.enableHistoryDatabase to be true.
// The query is NOT re-executed during validation phase, phantom reads are
// not detected. That is, other committed transactions may have updated
// the key concurrently, impacting the result set, and this would not be
// detected at validation/commit time. Applications susceptible to this
// should therefore not use GetHistoryForKey as part of transactions that
// update ledger, and should limit use to read-only chaincode operations.
GetHistoryForKey(key string) (HistoryQueryIteratorInterface, error)
如果您想检查不在链代码上下文中的更改历史记录,您可以使用 QSCC(查询系统链代码),它提供以下功能:
// These are function names from Invoke first parameter
const (
GetChainInfo string = "GetChainInfo"
GetBlockByNumber string = "GetBlockByNumber"
GetBlockByHash string = "GetBlockByHash"
GetTransactionByID string = "GetTransactionByID"
GetBlockByTxID string = "GetBlockByTxID"
)
如果你需要的话。 Java SDK 和 go chaincode 组合。这是示例
Java code
public List<HistoryDao> getUFOHistory(String key) throws Exception {
String[] args = { key };
Logger.getLogger(QueryChaincode.class.getName()).log(Level.INFO, "UFO communication history - " + args[0]);
Collection<ProposalResponse> responses1Query = ucc.getChannelClient().queryByChainCode("skynetchaincode", "getHistoryForUFO", args);
String stringResponse = null;
ArrayList<HistoryDao> newArrayList = new ArrayList<>();
for (ProposalResponse pres : responses1Query) {
stringResponse = new String(pres.getChaincodeActionResponsePayload());
Logger.getLogger(QueryChaincode.class.getName()).log(Level.INFO, stringResponse);
newArrayList = gson.fromJson(stringResponse, new TypeToken<ArrayList<HistoryDao>>() {
}.getType());
}
if (null == stringResponse)
stringResponse = "Not able to find any ufo communication history";
return newArrayList;
}
你去chancode实现如下
Go code
func (t *SmartContract) getHistoryForUFO(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
if len(args) < 1 {
return shim.Error("Incorrect number of arguments. Expecting 1")
}
ufoId := args[0]
resultsIterator, err := APIstub.GetHistoryForKey(ufoId)
if err != nil {
return shim.Error(err.Error())
}
defer resultsIterator.Close()
var buffer bytes.Buffer
buffer.WriteString("[")
bArrayMemberAlreadyWritten := false
for resultsIterator.HasNext() {
response, err := resultsIterator.Next()
if err != nil {
return shim.Error(err.Error())
}
// Add a comma before array members, suppress it for the first array member
if bArrayMemberAlreadyWritten == true {
buffer.WriteString(",")
}
buffer.WriteString("{\"TxId\":")
buffer.WriteString("\"")
buffer.WriteString(response.TxId)
buffer.WriteString("\"")
buffer.WriteString(", \"Value\":")
// if it was a delete operation on given key, then we need to set the
//corresponding value null. Else, we will write the response.Value
//as-is (as the Value itself a JSON)
if response.IsDelete {
buffer.WriteString("null")
} else {
buffer.WriteString(string(response.Value))
}
buffer.WriteString(", \"Timestamp\":")
buffer.WriteString("\"")
buffer.WriteString(time.Unix(response.Timestamp.Seconds, int64(response.Timestamp.Nanos)).String())
buffer.WriteString("\"")
buffer.WriteString(", \"IsDelete\":")
buffer.WriteString("\"")
buffer.WriteString(strconv.FormatBool(response.IsDelete))
buffer.WriteString("\"")
buffer.WriteString("}")
bArrayMemberAlreadyWritten = true
}
buffer.WriteString("]")
fmt.Printf("- History returning:\n%s\n", buffer.String())
return shim.Success(buffer.Bytes())
}
给你。玩得开心。
对于 NodeJS SDK:
您可以使用 'GetHistoryForKey'。
它 returns 跨时间键值的历史记录。对于每个历史密钥更新,都会返回历史值以及关联的事务 ID 和时间戳。
您可以在这里找到它(文档 link):
https://fabric-shim.github.io/release-1.3/fabric-shim.ChaincodeStub.html#getHistoryForKey__anchor
我正在使用 IBM bluemix blockchain service 为我的资产共享演示试用一些智能合约逻辑。
在hyperledger fabric network中是否有查询资产修改历史的方法。
我已经检查了 fabric 0.6 和 1.0 版本的文档,但我只能找到 stub.pushState(key,value_json) 和 stub.getState(key) 在账本上进行交互。
但是使用 stub.getState(key), 我只能获取 key 的最新条目,但是如何获取并显示为同一键编写的 changes/modification 系列。
我已经使用 {peeraddress}/Block/getBlock/{Block}
遍历了该块,但是我只是因为它的安全性开启才获得加密的交易有效负载。我不明白要显示同一密钥的资产修改历史记录。
请告诉我正确的方法。
提前致谢
来自 Fabric FAQ,A. 链代码 API GetHistoryForKey() 将 return 键值的历史记录。
您可以使用 GetHistoryForKey()
API 如下:
historyIter, err := stub.GetHistoryForKey(key)
if err != nil {
errMsg := fmt.Sprintf("[ERROR] cannot retrieve history for key <%s>, due to %s", key, err)
fmt.Println(errMsg)
return shim.Error(errMsg)
}
for historyIter.HasNext() {
modification, err := historyIer.Next()
if err != nil {
errMsg := fmt.Sprintf("[ERROR] cannot read record modification for key %s, id <%s>, due to %s", key, err)
fmt.Println(errMsg)
return shim.Error(errMsg)
}
fmt.Println("Returning information about", string(modification.Value))
}
Here is the link 到接口 API 描述:
// GetHistoryForKey returns a history of key values across time.
// For each historic key update, the historic value and associated
// transaction id and timestamp are returned. The timestamp is the
// timestamp provided by the client in the proposal header.
// GetHistoryForKey requires peer configuration
// core.ledger.history.enableHistoryDatabase to be true.
// The query is NOT re-executed during validation phase, phantom reads are
// not detected. That is, other committed transactions may have updated
// the key concurrently, impacting the result set, and this would not be
// detected at validation/commit time. Applications susceptible to this
// should therefore not use GetHistoryForKey as part of transactions that
// update ledger, and should limit use to read-only chaincode operations.
GetHistoryForKey(key string) (HistoryQueryIteratorInterface, error)
如果您想检查不在链代码上下文中的更改历史记录,您可以使用 QSCC(查询系统链代码),它提供以下功能:
// These are function names from Invoke first parameter
const (
GetChainInfo string = "GetChainInfo"
GetBlockByNumber string = "GetBlockByNumber"
GetBlockByHash string = "GetBlockByHash"
GetTransactionByID string = "GetTransactionByID"
GetBlockByTxID string = "GetBlockByTxID"
)
如果你需要的话。 Java SDK 和 go chaincode 组合。这是示例
Java code
public List<HistoryDao> getUFOHistory(String key) throws Exception {
String[] args = { key };
Logger.getLogger(QueryChaincode.class.getName()).log(Level.INFO, "UFO communication history - " + args[0]);
Collection<ProposalResponse> responses1Query = ucc.getChannelClient().queryByChainCode("skynetchaincode", "getHistoryForUFO", args);
String stringResponse = null;
ArrayList<HistoryDao> newArrayList = new ArrayList<>();
for (ProposalResponse pres : responses1Query) {
stringResponse = new String(pres.getChaincodeActionResponsePayload());
Logger.getLogger(QueryChaincode.class.getName()).log(Level.INFO, stringResponse);
newArrayList = gson.fromJson(stringResponse, new TypeToken<ArrayList<HistoryDao>>() {
}.getType());
}
if (null == stringResponse)
stringResponse = "Not able to find any ufo communication history";
return newArrayList;
}
你去chancode实现如下
Go code
func (t *SmartContract) getHistoryForUFO(APIstub shim.ChaincodeStubInterface, args []string) sc.Response {
if len(args) < 1 {
return shim.Error("Incorrect number of arguments. Expecting 1")
}
ufoId := args[0]
resultsIterator, err := APIstub.GetHistoryForKey(ufoId)
if err != nil {
return shim.Error(err.Error())
}
defer resultsIterator.Close()
var buffer bytes.Buffer
buffer.WriteString("[")
bArrayMemberAlreadyWritten := false
for resultsIterator.HasNext() {
response, err := resultsIterator.Next()
if err != nil {
return shim.Error(err.Error())
}
// Add a comma before array members, suppress it for the first array member
if bArrayMemberAlreadyWritten == true {
buffer.WriteString(",")
}
buffer.WriteString("{\"TxId\":")
buffer.WriteString("\"")
buffer.WriteString(response.TxId)
buffer.WriteString("\"")
buffer.WriteString(", \"Value\":")
// if it was a delete operation on given key, then we need to set the
//corresponding value null. Else, we will write the response.Value
//as-is (as the Value itself a JSON)
if response.IsDelete {
buffer.WriteString("null")
} else {
buffer.WriteString(string(response.Value))
}
buffer.WriteString(", \"Timestamp\":")
buffer.WriteString("\"")
buffer.WriteString(time.Unix(response.Timestamp.Seconds, int64(response.Timestamp.Nanos)).String())
buffer.WriteString("\"")
buffer.WriteString(", \"IsDelete\":")
buffer.WriteString("\"")
buffer.WriteString(strconv.FormatBool(response.IsDelete))
buffer.WriteString("\"")
buffer.WriteString("}")
bArrayMemberAlreadyWritten = true
}
buffer.WriteString("]")
fmt.Printf("- History returning:\n%s\n", buffer.String())
return shim.Success(buffer.Bytes())
}
给你。玩得开心。
对于 NodeJS SDK:
您可以使用 'GetHistoryForKey'。 它 returns 跨时间键值的历史记录。对于每个历史密钥更新,都会返回历史值以及关联的事务 ID 和时间戳。
您可以在这里找到它(文档 link):
https://fabric-shim.github.io/release-1.3/fabric-shim.ChaincodeStub.html#getHistoryForKey__anchor