Skip to content

Commit

Permalink
[FAB-1666] Add a chaincode API: SplitCompositeKey()
Browse files Browse the repository at this point in the history
To parse keys returned by PartialCompositeKeyQuery(),
we have introduced a chaincode API called SplitCompositeKey()
that returns an array of attributes on which a given composite
key was created.

https://jira.hyperledger.org/browse/FAB-1666

Change-Id: I7947f907526c954af81079e6795c0d4c7dfec519
Signed-off-by: senthil <cendhu@gmail.com>
  • Loading branch information
cendhu committed Jan 25, 2017
1 parent 1b53e6e commit 6bbd90a
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 12 deletions.
38 changes: 29 additions & 9 deletions core/chaincode/shim/chaincode.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand All @@ -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)
}
Expand Down
6 changes: 5 additions & 1 deletion core/chaincode/shim/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
8 changes: 7 additions & 1 deletion core/chaincode/shim/mockstub.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
14 changes: 13 additions & 1 deletion core/chaincode/shim/mockstub_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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()
Expand Down

0 comments on commit 6bbd90a

Please sign in to comment.