From 44e78500ac5f66cf8de51603d8a98450afb3082b Mon Sep 17 00:00:00 2001 From: denyeart Date: Sun, 29 Jan 2017 11:07:33 -0500 Subject: [PATCH] [FAB-1917] Fix chaincode query API Address review comments from: https://gerrit.hyperledger.org/r/#/c/4767/ Updates to logging and comments per Murali's feedback. Rename ExecuteQuery() to GetQueryResult() per Binh's feedback. The rename is only made at the top level chaincode function The name change will be propagated to all the underlying helper functions and messages as part of a larger refactor that Murali has planned for post-alpha. Fix handler.go result type (KV should be QueryRecord). Tested that chaincode calls to GetQueryResult() work end-to-end. Change-Id: I9cda95bab237e03880243be0b15110d119f033e8 Signed-off-by: denyeart --- core/chaincode/handler.go | 36 +++++++++++++++---------------- core/chaincode/shim/chaincode.go | 7 +++++- core/chaincode/shim/handler.go | 14 ++++++------ core/chaincode/shim/interfaces.go | 29 ++++++++++++++----------- core/chaincode/shim/mockstub.go | 10 ++++++++- examples/chaincode/go/map/map.go | 2 +- 6 files changed, 58 insertions(+), 40 deletions(-) diff --git a/core/chaincode/handler.go b/core/chaincode/handler.go index 9c732997676..b1b7103b22f 100644 --- a/core/chaincode/handler.go +++ b/core/chaincode/handler.go @@ -714,7 +714,7 @@ func (handler *Handler) handleRangeQueryState(msg *pb.ChaincodeMessage) { }() } -// afterRangeQueryState handles a RANGE_QUERY_STATE_NEXT request from the chaincode. +// afterQueryStateNext handles a QUERY_STATE_NEXT request from the chaincode. func (handler *Handler) afterQueryStateNext(e *fsm.Event, state string) { msg, ok := e.Args[0].(*pb.ChaincodeMessage) if !ok { @@ -725,10 +725,10 @@ func (handler *Handler) afterQueryStateNext(e *fsm.Event, state string) { // Query ledger for state handler.handleQueryStateNext(msg) - chaincodeLogger.Debug("Exiting RANGE_QUERY_STATE_NEXT") + chaincodeLogger.Debug("Exiting QUERY_STATE_NEXT") } -// Handles query to ledger to rage query state next +// Handles query to ledger for query state next func (handler *Handler) handleQueryStateNext(msg *pb.ChaincodeMessage) { // The defer followed by triggering a go routine dance is needed to ensure that the previous state transition // is completed before the next one is triggered. The previous state transition is deemed complete only when @@ -754,17 +754,17 @@ func (handler *Handler) handleQueryStateNext(msg *pb.ChaincodeMessage) { unmarshalErr := proto.Unmarshal(msg.Payload, queryStateNext) if unmarshalErr != nil { payload := []byte(unmarshalErr.Error()) - chaincodeLogger.Errorf("Failed to unmarshall state range next query request. Sending %s", pb.ChaincodeMessage_ERROR) + chaincodeLogger.Errorf("Failed to unmarshall state next query request. Sending %s", pb.ChaincodeMessage_ERROR) serialSendMsg = &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_ERROR, Payload: payload, Txid: msg.Txid} return } txContext := handler.getTxContext(msg.Txid) - rangeIter := handler.getQueryIterator(txContext, queryStateNext.ID) + queryIter := handler.getQueryIterator(txContext, queryStateNext.ID) - if rangeIter == nil { - payload := []byte("Range query iterator not found") - chaincodeLogger.Errorf("Range query iterator not found. Sending %s", pb.ChaincodeMessage_ERROR) + if queryIter == nil { + payload := []byte("query iterator not found") + chaincodeLogger.Errorf("query iterator not found. Sending %s", pb.ChaincodeMessage_ERROR) serialSendMsg = &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_ERROR, Payload: payload, Txid: msg.Txid} return } @@ -775,7 +775,7 @@ func (handler *Handler) handleQueryStateNext(msg *pb.ChaincodeMessage) { var qresult ledger.QueryResult var err error for ; i < maxRangeQueryStateLimit; i++ { - qresult, err = rangeIter.Next() + qresult, err = queryIter.Next() if err != nil { chaincodeLogger.Errorf("Failed to get query result from iterator. Sending %s", pb.ChaincodeMessage_ERROR) return @@ -789,14 +789,14 @@ func (handler *Handler) handleQueryStateNext(msg *pb.ChaincodeMessage) { } if qresult != nil { - rangeIter.Close() + queryIter.Close() handler.deleteQueryIterator(txContext, queryStateNext.ID) } payload := &pb.QueryStateResponse{KeysAndValues: keysAndValues, HasMore: qresult != nil, ID: queryStateNext.ID} payloadBytes, err := proto.Marshal(payload) if err != nil { - rangeIter.Close() + queryIter.Close() handler.deleteQueryIterator(txContext, queryStateNext.ID) // Send error msg back to chaincode. GetState will not trigger event @@ -812,7 +812,7 @@ func (handler *Handler) handleQueryStateNext(msg *pb.ChaincodeMessage) { }() } -// afterRangeQueryState handles a RANGE_QUERY_STATE_CLOSE request from the chaincode. +// afterRangeQueryState handles a QUERY_STATE_CLOSE request from the chaincode. func (handler *Handler) afterQueryStateClose(e *fsm.Event, state string) { msg, ok := e.Args[0].(*pb.ChaincodeMessage) if !ok { @@ -823,7 +823,7 @@ func (handler *Handler) afterQueryStateClose(e *fsm.Event, state string) { // Query ledger for state handler.handleQueryStateClose(msg) - chaincodeLogger.Debug("Exiting RANGE_QUERY_STATE_CLOSE") + chaincodeLogger.Debug("Exiting QUERY_STATE_CLOSE") } // Handles the closing of a state iterator @@ -852,7 +852,7 @@ func (handler *Handler) handleQueryStateClose(msg *pb.ChaincodeMessage) { unmarshalErr := proto.Unmarshal(msg.Payload, queryStateClose) if unmarshalErr != nil { payload := []byte(unmarshalErr.Error()) - chaincodeLogger.Errorf("Failed to unmarshall state range query close request. Sending %s", pb.ChaincodeMessage_ERROR) + chaincodeLogger.Errorf("Failed to unmarshall state query close request. Sending %s", pb.ChaincodeMessage_ERROR) serialSendMsg = &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_ERROR, Payload: payload, Txid: msg.Txid} return } @@ -923,7 +923,7 @@ func (handler *Handler) handleExecuteQueryState(msg *pb.ChaincodeMessage) { unmarshalErr := proto.Unmarshal(msg.Payload, executeQueryState) if unmarshalErr != nil { payload := []byte(unmarshalErr.Error()) - chaincodeLogger.Errorf("Failed to unmarshall range query request. Sending %s", pb.ChaincodeMessage_ERROR) + chaincodeLogger.Errorf("Failed to unmarshall query request. Sending %s", pb.ChaincodeMessage_ERROR) serialSendMsg = &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_ERROR, Payload: payload, Txid: msg.Txid} return } @@ -936,7 +936,7 @@ func (handler *Handler) handleExecuteQueryState(msg *pb.ChaincodeMessage) { if txContext == nil { return } - fmt.Println("==CENDHU==" + executeQueryState.Query) + executeIter, err := txContext.txsimulator.ExecuteQuery(executeQueryState.Query) if err != nil { // Send error msg back to chaincode. GetState will not trigger event @@ -960,8 +960,8 @@ func (handler *Handler) handleExecuteQueryState(msg *pb.ChaincodeMessage) { if qresult == nil { break } - kv := qresult.(*ledger.KV) - keyAndValue := pb.QueryStateKeyValue{Key: kv.Key, Value: kv.Value} + queryRecord := qresult.(*ledger.QueryRecord) + keyAndValue := pb.QueryStateKeyValue{Key: queryRecord.Key, Value: queryRecord.Record} keysAndValues = append(keysAndValues, &keyAndValue) } diff --git a/core/chaincode/shim/chaincode.go b/core/chaincode/shim/chaincode.go index bfde641209a..c054a681d1c 100644 --- a/core/chaincode/shim/chaincode.go +++ b/core/chaincode/shim/chaincode.go @@ -336,7 +336,12 @@ func (stub *ChaincodeStub) RangeQueryState(startKey, endKey string) (StateQueryI return &StateQueryIterator{stub.handler, stub.TxID, response, 0}, nil } -func (stub *ChaincodeStub) ExecuteQuery(query string) (StateQueryIteratorInterface, error) { +// GetQueryResult function can be invoked by a chaincode to perform a +// rich query against state database. Only supported by state database implementations +// that support rich query. The query string is in the syntax of the underlying +// state database. An iterator is returned which can be used to iterate (next) over +// the query result set +func (stub *ChaincodeStub) GetQueryResult(query string) (StateQueryIteratorInterface, error) { response, err := stub.handler.handleExecuteQueryState(query, stub.TxID) if err != nil { return nil, err diff --git a/core/chaincode/shim/handler.go b/core/chaincode/shim/handler.go index 0292ddf3a6e..c7f35ce2365 100644 --- a/core/chaincode/shim/handler.go +++ b/core/chaincode/shim/handler.go @@ -552,11 +552,11 @@ func (handler *Handler) handleQueryStateNext(id, txid string) (*pb.QueryStateRes defer handler.deleteChannel(txid) - // Send RANGE_QUERY_STATE_NEXT message to validator chaincode support + // Send QUERY_STATE_NEXT message to validator chaincode support payload := &pb.QueryStateNext{ID: id} payloadBytes, err := proto.Marshal(payload) if err != nil { - return nil, errors.New("Failed to process range query state next request") + return nil, errors.New("Failed to process query state next request") } msg := &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_QUERY_STATE_NEXT, Payload: payloadBytes, Txid: txid} chaincodeLogger.Debugf("[%s]Sending %s", shorttxid(msg.Txid), pb.ChaincodeMessage_QUERY_STATE_NEXT) @@ -574,7 +574,7 @@ func (handler *Handler) handleQueryStateNext(id, txid string) (*pb.QueryStateRes unmarshalErr := proto.Unmarshal(responseMsg.Payload, queryResponse) if unmarshalErr != nil { chaincodeLogger.Errorf("[%s]unmarshall error", shorttxid(responseMsg.Txid)) - return nil, errors.New("Error unmarshalling RangeQueryStateResponse.") + return nil, errors.New("Error unmarshalling QueryStateResponse.") } return queryResponse, nil @@ -600,11 +600,11 @@ func (handler *Handler) handleQueryStateClose(id, txid string) (*pb.QueryStateRe defer handler.deleteChannel(txid) - // Send RANGE_QUERY_STATE_CLOSE message to validator chaincode support + // Send QUERY_STATE_CLOSE message to validator chaincode support payload := &pb.QueryStateClose{ID: id} payloadBytes, err := proto.Marshal(payload) if err != nil { - return nil, errors.New("Failed to process range query state close request") + return nil, errors.New("Failed to process query state close request") } msg := &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_QUERY_STATE_CLOSE, Payload: payloadBytes, Txid: txid} chaincodeLogger.Debugf("[%s]Sending %s", shorttxid(msg.Txid), pb.ChaincodeMessage_QUERY_STATE_CLOSE) @@ -622,7 +622,7 @@ func (handler *Handler) handleQueryStateClose(id, txid string) (*pb.QueryStateRe unmarshalErr := proto.Unmarshal(responseMsg.Payload, queryResponse) if unmarshalErr != nil { chaincodeLogger.Errorf("[%s]unmarshall error", shorttxid(responseMsg.Txid)) - return nil, errors.New("Error unmarshalling RangeQueryStateResponse.") + return nil, errors.New("Error unmarshalling QueryStateResponse.") } return queryResponse, nil @@ -652,7 +652,7 @@ func (handler *Handler) handleExecuteQueryState(query string, txid string) (*pb. payload := &pb.ExecuteQueryState{Query: query} payloadBytes, err := proto.Marshal(payload) if err != nil { - return nil, errors.New("Failed to process range query state request") + return nil, errors.New("Failed to process query state request") } msg := &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_EXECUTE_QUERY_STATE, Payload: payloadBytes, Txid: txid} chaincodeLogger.Debugf("[%s]Sending %s", shorttxid(msg.Txid), pb.ChaincodeMessage_EXECUTE_QUERY_STATE) diff --git a/core/chaincode/shim/interfaces.go b/core/chaincode/shim/interfaces.go index c71936083d6..37b43583300 100644 --- a/core/chaincode/shim/interfaces.go +++ b/core/chaincode/shim/interfaces.go @@ -66,26 +66,31 @@ type ChaincodeStubInterface interface { // RangeQueryState function can be invoked by a chaincode to query of a range // of keys in the state. Assuming the startKey and endKey are in lexical // an iterator will be returned that can be used to iterate over all keys - // between the startKey and endKey, inclusive. The order in which keys are + // between the startKey (inclusive) and endKey (exclusive). The order in which keys are // returned by the iterator is random. RangeQueryState(startKey, endKey string) (StateQueryIteratorInterface, error) - //PartialCompositeKeyQuery function can be invoked by a chaincode to query the - //state based on a given partial composite key. This function returns an - //iterator which can be used to iterate over all composite keys whose prefix - //matches the given partial composite key. This function should be used only for - //a partial composite key. For a full composite key, an iter with empty response - //would be returned. + // PartialCompositeKeyQuery function can be invoked by a chaincode to query the + // state based on a given partial composite key. This function returns an + // iterator which can be used to iterate over all composite keys whose prefix + // matches the given partial composite key. This function should be used only for + // a partial composite key. For a full composite key, an iter with empty response + // would be returned. PartialCompositeKeyQuery(objectType string, keys []string) (StateQueryIteratorInterface, error) - //Given a list of attributes, CreateCompositeKey function combines these attributes - //to form a composite key. + // Given a list of attributes, CreateCompositeKey function combines these attributes + // to form a composite key. CreateCompositeKey(objectType string, attributes []string) (string, error) - ExecuteQuery(query string) (StateQueryIteratorInterface, error) + // GetQueryResult function can be invoked by a chaincode to perform a + // rich query against state database. Only supported by state database implementations + // that support rich query. The query string is in the syntax of the underlying + // state database. An iterator is returned which can be used to iterate (next) over + // the query result set + GetQueryResult(query string) (StateQueryIteratorInterface, error) - //Given a composite key, SplitCompositeKey function splits the key into attributes - //on which the composite key was formed. + // Given a composite key, SplitCompositeKey function splits the key into attributes + // on which the composite key was formed. SplitCompositeKey(compositeKey string) (string, []string, error) // GetCallerCertificate returns caller certificate diff --git a/core/chaincode/shim/mockstub.go b/core/chaincode/shim/mockstub.go index 326ae9eced9..e4a7edd1bbe 100644 --- a/core/chaincode/shim/mockstub.go +++ b/core/chaincode/shim/mockstub.go @@ -192,7 +192,15 @@ func (stub *MockStub) RangeQueryState(startKey, endKey string) (StateQueryIterat return NewMockStateRangeQueryIterator(stub, startKey, endKey), nil } -func (stub *MockStub) ExecuteQuery(query string) (StateQueryIteratorInterface, error) { +// GetQueryResult function can be invoked by a chaincode to perform a +// rich query against state database. Only supported by state database implementations +// that support rich query. The query string is in the syntax of the underlying +// state database. An iterator is returned which can be used to iterate (next) over +// the query result set +func (stub *MockStub) GetQueryResult(query string) (StateQueryIteratorInterface, error) { + // Not implemented since the mock engine does not have a query engine. + // However, a very simple query engine that supports string matching + // could be implemented to test that the framework supports queries return nil, errors.New("Not Implemented") } diff --git a/examples/chaincode/go/map/map.go b/examples/chaincode/go/map/map.go index 593e4f4631f..d3aebfbb2de 100644 --- a/examples/chaincode/go/map/map.go +++ b/examples/chaincode/go/map/map.go @@ -115,7 +115,7 @@ func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { return shim.Success(jsonKeys) case "query": query := args[0] - keysIter, err := stub.ExecuteQuery(query) + keysIter, err := stub.GetQueryResult(query) if err != nil { return shim.Error(fmt.Sprintf("query operation failed. Error accessing state: %s", err)) }