Skip to content

Commit 6bbd90a

Browse files
committed
[FAB-1666] Add a chaincode API: SplitCompositeKey()
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 <[email protected]>
1 parent 1b53e6e commit 6bbd90a

File tree

4 files changed

+54
-12
lines changed

4 files changed

+54
-12
lines changed

core/chaincode/shim/chaincode.go

+29-9
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,18 @@ limitations under the License.
1919
package shim
2020

2121
import (
22-
"bytes"
2322
"errors"
2423
"flag"
2524
"fmt"
2625
"io"
2726
"os"
28-
"strconv"
2927
"strings"
3028

3129
"github.com/golang/protobuf/proto"
3230
"github.com/golang/protobuf/ptypes/timestamp"
3331
"github.com/hyperledger/fabric/common/util"
3432
"github.com/hyperledger/fabric/core/comm"
33+
coder "github.com/hyperledger/fabric/core/ledger/util"
3534
pb "github.com/hyperledger/fabric/protos/peer"
3635
"github.com/op/go-logging"
3736
"github.com/spf13/viper"
@@ -337,20 +336,41 @@ func (stub *ChaincodeStub) RangeQueryState(startKey, endKey string) (StateRangeQ
337336
return &StateRangeQueryIterator{stub.handler, stub.TxID, response, 0}, nil
338337
}
339338

340-
//Given a list of attributes, createCompositeKey function combines these attributes
339+
//Given a list of attributes, CreateCompositeKey function combines these attributes
341340
//to form a composite key.
342341
func (stub *ChaincodeStub) CreateCompositeKey(objectType string, attributes []string) (string, error) {
343342
return createCompositeKey(stub, objectType, attributes)
344343
}
345344

346345
func createCompositeKey(stub ChaincodeStubInterface, objectType string, attributes []string) (string, error) {
347-
var compositeKey bytes.Buffer
348-
compositeKey.WriteString(objectType)
346+
var compositeKey []byte
347+
compositeKey = append(compositeKey, coder.EncodeOrderPreservingVarUint64(uint64(len(objectType)))...)
348+
compositeKey = append(compositeKey, []byte(objectType)...)
349349
for _, attribute := range attributes {
350-
compositeKey.WriteString(strconv.Itoa(len(attribute)))
351-
compositeKey.WriteString(attribute)
350+
compositeKey = append(compositeKey, coder.EncodeOrderPreservingVarUint64(uint64(len(attribute)))...)
351+
compositeKey = append(compositeKey, []byte(attribute)...)
352352
}
353-
return compositeKey.String(), nil
353+
return string(compositeKey), nil
354+
}
355+
356+
//Given a composite key, SplitCompositeKey function splits the key into attributes
357+
//on which the composite key was formed.
358+
func (stub *ChaincodeStub) SplitCompositeKey(compositeKey string) (string, []string, error) {
359+
return splitCompositeKey(stub, compositeKey)
360+
}
361+
362+
func splitCompositeKey(stub ChaincodeStubInterface, compositeKey string) (string, []string, error) {
363+
startIndex := 0
364+
cKey := []byte(compositeKey)
365+
attributes := []string{}
366+
for startIndex < len(compositeKey) {
367+
len, bytesConsumed := coder.DecodeOrderPreservingVarUint64(cKey[startIndex:])
368+
attrBeginIndex := startIndex + int(bytesConsumed)
369+
attrEndIndex := attrBeginIndex + int(len)
370+
attributes = append(attributes, compositeKey[attrBeginIndex:attrEndIndex])
371+
startIndex = attrEndIndex
372+
}
373+
return attributes[0], attributes[1:], nil
354374
}
355375

356376
//PartialCompositeKeyQuery function can be invoked by a chaincode to query the
@@ -365,7 +385,7 @@ func (stub *ChaincodeStub) PartialCompositeKeyQuery(objectType string, attribute
365385

366386
func partialCompositeKeyQuery(stub ChaincodeStubInterface, objectType string, attributes []string) (StateRangeQueryIteratorInterface, error) {
367387
partialCompositeKey, _ := stub.CreateCompositeKey(objectType, attributes)
368-
keysIter, err := stub.RangeQueryState(partialCompositeKey+"1", partialCompositeKey+":")
388+
keysIter, err := stub.RangeQueryState(partialCompositeKey, partialCompositeKey+"\xFF")
369389
if err != nil {
370390
return nil, fmt.Errorf("Error fetching rows: %s", err)
371391
}

core/chaincode/shim/interfaces.go

+5-1
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,14 @@ type ChaincodeStubInterface interface {
7878
//would be returned.
7979
PartialCompositeKeyQuery(objectType string, keys []string) (StateRangeQueryIteratorInterface, error)
8080

81-
//Given a list of attributes, createCompundKey function combines these attributes
81+
//Given a list of attributes, CreateCompositeKey function combines these attributes
8282
//to form a composite key.
8383
CreateCompositeKey(objectType string, attributes []string) (string, error)
8484

85+
//Given a composite key, SplitCompositeKey function splits the key into attributes
86+
//on which the composite key was formed.
87+
SplitCompositeKey(compositeKey string) (string, []string, error)
88+
8589
// GetCallerCertificate returns caller certificate
8690
GetCallerCertificate() ([]byte, error)
8791

core/chaincode/shim/mockstub.go

+7-1
Original file line numberDiff line numberDiff line change
@@ -202,12 +202,18 @@ func (stub *MockStub) PartialCompositeKeyQuery(objectType string, attributes []s
202202
return partialCompositeKeyQuery(stub, objectType, attributes)
203203
}
204204

205-
//Given a list of attributes, createCompositeKey function combines these attributes
205+
//Given a list of attributes, CreateCompositeKey function combines these attributes
206206
//to form a composite key.
207207
func (stub *MockStub) CreateCompositeKey(objectType string, attributes []string) (string, error) {
208208
return createCompositeKey(stub, objectType, attributes)
209209
}
210210

211+
//Given a composite key, SplitCompositeKey function splits the key into attributes
212+
//on which the composite key was formed.
213+
func (stub *MockStub) SplitCompositeKey(compositeKey string) (string, []string, error) {
214+
return splitCompositeKey(stub, compositeKey)
215+
}
216+
211217
// Invokes a peered chaincode.
212218
// E.g. stub1.InvokeChaincode("stub2Hash", funcArgs)
213219
// Before calling this make sure to create another MockStub stub2, call stub2.MockInit(uuid, func, args)

core/chaincode/shim/mockstub_test.go

+13-1
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,10 @@ func TestPartialCompositeKeyQuery(t *testing.T) {
112112

113113
stub.MockTransactionEnd("init")
114114
expectKeys := []string{compositeKey1, compositeKey2}
115+
expectKeysAttributes := [][]string{{"set-1", "red"}, {"set-1", "blue"}}
115116
expectValues := [][]byte{marbleJSONBytes1, marbleJSONBytes2}
116117

117118
rqi, _ := stub.PartialCompositeKeyQuery("marble", []string{"set-1"})
118-
119119
fmt.Println("Running loop")
120120
for i := 0; i < 2; i++ {
121121
key, value, err := rqi.Next()
@@ -124,6 +124,18 @@ func TestPartialCompositeKeyQuery(t *testing.T) {
124124
fmt.Println("Expected key", expectKeys[i], "got", key)
125125
t.FailNow()
126126
}
127+
objectType, attributes, _ := stub.SplitCompositeKey(key)
128+
if objectType != "marble" {
129+
fmt.Println("Expected objectType", "marble", "got", objectType)
130+
t.FailNow()
131+
}
132+
fmt.Println(attributes)
133+
for index, attr := range attributes {
134+
if expectKeysAttributes[i][index] != attr {
135+
fmt.Println("Expected keys attribute", expectKeysAttributes[index][i], "got", attr)
136+
t.FailNow()
137+
}
138+
}
127139
if jsonBytesEqual(expectValues[i], value) != true {
128140
fmt.Println("Expected value", expectValues[i], "got", value)
129141
t.FailNow()

0 commit comments

Comments
 (0)