How to fetch asset modification history in hyperle

2019-05-30 06:26发布

I am using IBM bluemix blockchain service to tryout some smart contract logic for my asset sharing demo.

Is there anyway to query the asset modified history in hyperledger fabric network.

I have checked with documentations for both fabric 0.6 and 1.0 versions, but I can find only the stub.pushState(key,value_json) and stub.getState(key) to interact width the ledger.
But using stub.getState(key), I can fetch only the latest entry of the key, but how can I fetch and display the series of changes/modification written for the same key. I have iterated through the block using {peeraddress}/Block/getBlock/{Block}, but I am getting the encrypted transaction payloads only since its security is on. I am not getting the idea to display the history of asset modifications for the same key.


Please suggest me the correct way to do this.

Thanks in advance

3条回答
够拽才男人
2楼-- · 2019-05-30 07:04

You can use GetHistoryForKey() API as following:

    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 to the interface with API description:

// 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)

In case you'd like to inspect history of changes not in context of chaincode you can use QSCC (Query System Chaincode), which provide following capabilities:

// These are function names from Invoke first parameter
const (
    GetChainInfo       string = "GetChainInfo"
    GetBlockByNumber   string = "GetBlockByNumber"
    GetBlockByHash     string = "GetBlockByHash"
    GetTransactionByID string = "GetTransactionByID"
    GetBlockByTxID     string = "GetBlockByTxID"
)
查看更多
来,给爷笑一个
3楼-- · 2019-05-30 07:10

IF you need. Java SDk and go chaincode combination. Here is the example

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;
}

and you go chancode implemetation is as follows

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())

}

There you go. Have fun.

查看更多
唯我独甜
4楼-- · 2019-05-30 07:12

From the Fabric FAQ, A. The chaincode API GetHistoryForKey() will return history of values for a key.

查看更多
登录 后发表回答