diff --git a/core/chaincode/shim/chaincode.go b/core/chaincode/shim/chaincode.go index 2345adef63a..bb88e9ed791 100644 --- a/core/chaincode/shim/chaincode.go +++ b/core/chaincode/shim/chaincode.go @@ -19,19 +19,18 @@ limitations under the License. package shim import ( - "bytes" "errors" "flag" "fmt" "io" "os" - "strconv" "strings" "github.com/golang/protobuf/proto" "github.com/golang/protobuf/ptypes/timestamp" "github.com/hyperledger/fabric/common/util" "github.com/hyperledger/fabric/core/comm" + coder "github.com/hyperledger/fabric/core/ledger/util" pb "github.com/hyperledger/fabric/protos/peer" "github.com/op/go-logging" "github.com/spf13/viper" @@ -337,20 +336,41 @@ func (stub *ChaincodeStub) RangeQueryState(startKey, endKey string) (StateRangeQ return &StateRangeQueryIterator{stub.handler, stub.TxID, response, 0}, nil } -//Given a list of attributes, createCompositeKey function combines these attributes +//Given a list of attributes, CreateCompositeKey function combines these attributes //to form a composite key. func (stub *ChaincodeStub) CreateCompositeKey(objectType string, attributes []string) (string, error) { return createCompositeKey(stub, objectType, attributes) } func createCompositeKey(stub ChaincodeStubInterface, objectType string, attributes []string) (string, error) { - var compositeKey bytes.Buffer - compositeKey.WriteString(objectType) + var compositeKey []byte + compositeKey = append(compositeKey, coder.EncodeOrderPreservingVarUint64(uint64(len(objectType)))...) + compositeKey = append(compositeKey, []byte(objectType)...) for _, attribute := range attributes { - compositeKey.WriteString(strconv.Itoa(len(attribute))) - compositeKey.WriteString(attribute) + compositeKey = append(compositeKey, coder.EncodeOrderPreservingVarUint64(uint64(len(attribute)))...) + compositeKey = append(compositeKey, []byte(attribute)...) } - return compositeKey.String(), nil + return string(compositeKey), nil +} + +//Given a composite key, SplitCompositeKey function splits the key into attributes +//on which the composite key was formed. +func (stub *ChaincodeStub) SplitCompositeKey(compositeKey string) (string, []string, error) { + return splitCompositeKey(stub, compositeKey) +} + +func splitCompositeKey(stub ChaincodeStubInterface, compositeKey string) (string, []string, error) { + startIndex := 0 + cKey := []byte(compositeKey) + attributes := []string{} + for startIndex < len(compositeKey) { + len, bytesConsumed := coder.DecodeOrderPreservingVarUint64(cKey[startIndex:]) + attrBeginIndex := startIndex + int(bytesConsumed) + attrEndIndex := attrBeginIndex + int(len) + attributes = append(attributes, compositeKey[attrBeginIndex:attrEndIndex]) + startIndex = attrEndIndex + } + return attributes[0], attributes[1:], nil } //PartialCompositeKeyQuery function can be invoked by a chaincode to query the @@ -365,7 +385,7 @@ func (stub *ChaincodeStub) PartialCompositeKeyQuery(objectType string, attribute func partialCompositeKeyQuery(stub ChaincodeStubInterface, objectType string, attributes []string) (StateRangeQueryIteratorInterface, error) { partialCompositeKey, _ := stub.CreateCompositeKey(objectType, attributes) - keysIter, err := stub.RangeQueryState(partialCompositeKey+"1", partialCompositeKey+":") + keysIter, err := stub.RangeQueryState(partialCompositeKey, partialCompositeKey+"\xFF") if err != nil { return nil, fmt.Errorf("Error fetching rows: %s", err) } diff --git a/core/chaincode/shim/interfaces.go b/core/chaincode/shim/interfaces.go index 34639520f01..21af5afe10d 100644 --- a/core/chaincode/shim/interfaces.go +++ b/core/chaincode/shim/interfaces.go @@ -78,10 +78,14 @@ type ChaincodeStubInterface interface { //would be returned. PartialCompositeKeyQuery(objectType string, keys []string) (StateRangeQueryIteratorInterface, error) - //Given a list of attributes, createCompundKey function combines these attributes + //Given a list of attributes, CreateCompositeKey function combines these attributes //to form a composite key. CreateCompositeKey(objectType string, attributes []string) (string, error) + //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 GetCallerCertificate() ([]byte, error) diff --git a/core/chaincode/shim/mockstub.go b/core/chaincode/shim/mockstub.go index bf209d4adea..7637e05be2d 100644 --- a/core/chaincode/shim/mockstub.go +++ b/core/chaincode/shim/mockstub.go @@ -202,12 +202,18 @@ func (stub *MockStub) PartialCompositeKeyQuery(objectType string, attributes []s return partialCompositeKeyQuery(stub, objectType, attributes) } -//Given a list of attributes, createCompositeKey function combines these attributes +//Given a list of attributes, CreateCompositeKey function combines these attributes //to form a composite key. func (stub *MockStub) CreateCompositeKey(objectType string, attributes []string) (string, error) { return createCompositeKey(stub, objectType, attributes) } +//Given a composite key, SplitCompositeKey function splits the key into attributes +//on which the composite key was formed. +func (stub *MockStub) SplitCompositeKey(compositeKey string) (string, []string, error) { + return splitCompositeKey(stub, compositeKey) +} + // Invokes a peered chaincode. // E.g. stub1.InvokeChaincode("stub2Hash", funcArgs) // Before calling this make sure to create another MockStub stub2, call stub2.MockInit(uuid, func, args) diff --git a/core/chaincode/shim/mockstub_test.go b/core/chaincode/shim/mockstub_test.go index ba94998c77d..762ea2956ae 100644 --- a/core/chaincode/shim/mockstub_test.go +++ b/core/chaincode/shim/mockstub_test.go @@ -112,10 +112,10 @@ func TestPartialCompositeKeyQuery(t *testing.T) { stub.MockTransactionEnd("init") expectKeys := []string{compositeKey1, compositeKey2} + expectKeysAttributes := [][]string{{"set-1", "red"}, {"set-1", "blue"}} expectValues := [][]byte{marbleJSONBytes1, marbleJSONBytes2} rqi, _ := stub.PartialCompositeKeyQuery("marble", []string{"set-1"}) - fmt.Println("Running loop") for i := 0; i < 2; i++ { key, value, err := rqi.Next() @@ -124,6 +124,18 @@ func TestPartialCompositeKeyQuery(t *testing.T) { fmt.Println("Expected key", expectKeys[i], "got", key) t.FailNow() } + objectType, attributes, _ := stub.SplitCompositeKey(key) + if objectType != "marble" { + fmt.Println("Expected objectType", "marble", "got", objectType) + t.FailNow() + } + fmt.Println(attributes) + for index, attr := range attributes { + if expectKeysAttributes[i][index] != attr { + fmt.Println("Expected keys attribute", expectKeysAttributes[index][i], "got", attr) + t.FailNow() + } + } if jsonBytesEqual(expectValues[i], value) != true { fmt.Println("Expected value", expectValues[i], "got", value) t.FailNow()