From 7b0aef86f061adf20479cd01ea7e44a6d2427939 Mon Sep 17 00:00:00 2001 From: senthil Date: Wed, 4 Jan 2017 20:28:43 +0530 Subject: [PATCH] FAB-1257 Removal of Table API Removed Table API for the following reasons * The v0.5/v0.6 Pseedo-table API does not map well to current or next generation Fabric capabilities * Project teams have been confused and frustrated with table API limitations Encourage all new chaincode to use JSON-based data structures Change-Id: I3f01177e98b2dc40d6a00815ad9000132f9d9591 Signed-off-by: senthil --- bddtests/chaincode/go/table/table.go | 538 ------------------ core/chaincode/shim/chaincode.go | 473 ++------------- core/chaincode/shim/interfaces.go | 50 +- core/chaincode/shim/java/build.gradle | 5 - .../hyperledger/java/shim/ChaincodeStub.java | 307 ++-------- core/chaincode/shim/mockstub.go | 112 ++-- core/chaincode/shim/mockstub_test.go | 196 +++---- core/chaincode/shim/table.pb.go | 399 ------------- core/chaincode/shim/table.proto | 58 -- examples/chaincode/java/TableExample/pom.xml | 94 --- .../src/main/java/example/TableExample.java | 194 ------- 11 files changed, 188 insertions(+), 2238 deletions(-) delete mode 100644 bddtests/chaincode/go/table/table.go delete mode 100644 core/chaincode/shim/table.pb.go delete mode 100644 core/chaincode/shim/table.proto delete mode 100644 examples/chaincode/java/TableExample/pom.xml delete mode 100644 examples/chaincode/java/TableExample/src/main/java/example/TableExample.java diff --git a/bddtests/chaincode/go/table/table.go b/bddtests/chaincode/go/table/table.go deleted file mode 100644 index 1de608b9443..00000000000 --- a/bddtests/chaincode/go/table/table.go +++ /dev/null @@ -1,538 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package main - -import ( - "encoding/json" - "errors" - "fmt" - "strconv" - - "github.com/hyperledger/fabric/core/chaincode/shim" -) - -// SimpleChaincode example simple Chaincode implementation -type SimpleChaincode struct { -} - -// Init create tables for tests -func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) ([]byte, error) { - // Create table one - err := createTableOne(stub) - if err != nil { - return nil, fmt.Errorf("Error creating table one during init. %s", err) - } - - // Create table two - err = createTableTwo(stub) - if err != nil { - return nil, fmt.Errorf("Error creating table two during init. %s", err) - } - - // Create table three - err = createTableThree(stub) - if err != nil { - return nil, fmt.Errorf("Error creating table three during init. %s", err) - } - - // Create table four - err = createTableFour(stub) - if err != nil { - return nil, fmt.Errorf("Error creating table four during init. %s", err) - } - - return nil, nil -} - -// Invoke callback representing the invocation of a chaincode -// This chaincode will manage two accounts A and B and will transfer X units from A to B upon invoke -func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) ([]byte, error) { - function, args := stub.GetFunctionAndParameters() - switch function { - - case "insertRowTableOne": - if len(args) < 3 { - return nil, errors.New("insertTableOne failed. Must include 3 column values") - } - - col1Val := args[0] - col2Int, err := strconv.ParseInt(args[1], 10, 32) - if err != nil { - return nil, errors.New("insertTableOne failed. arg[1] must be convertable to int32") - } - col2Val := int32(col2Int) - col3Int, err := strconv.ParseInt(args[2], 10, 32) - if err != nil { - return nil, errors.New("insertTableOne failed. arg[2] must be convertable to int32") - } - col3Val := int32(col3Int) - - var columns []*shim.Column - col1 := shim.Column{Value: &shim.Column_String_{String_: col1Val}} - col2 := shim.Column{Value: &shim.Column_Int32{Int32: col2Val}} - col3 := shim.Column{Value: &shim.Column_Int32{Int32: col3Val}} - columns = append(columns, &col1) - columns = append(columns, &col2) - columns = append(columns, &col3) - - row := shim.Row{Columns: columns} - ok, err := stub.InsertRow("tableOne", row) - if err != nil { - return nil, fmt.Errorf("insertTableOne operation failed. %s", err) - } - if !ok { - return nil, errors.New("insertTableOne operation failed. Row with given key already exists") - } - - case "insertRowTableTwo": - if len(args) < 4 { - return nil, errors.New("insertRowTableTwo failed. Must include 4 column values") - } - - col1Val := args[0] - col2Int, err := strconv.ParseInt(args[1], 10, 32) - if err != nil { - return nil, errors.New("insertRowTableTwo failed. arg[1] must be convertable to int32") - } - col2Val := int32(col2Int) - col3Int, err := strconv.ParseInt(args[2], 10, 32) - if err != nil { - return nil, errors.New("insertRowTableTwo failed. arg[2] must be convertable to int32") - } - col3Val := int32(col3Int) - col4Val := args[3] - - var columns []*shim.Column - col1 := shim.Column{Value: &shim.Column_String_{String_: col1Val}} - col2 := shim.Column{Value: &shim.Column_Int32{Int32: col2Val}} - col3 := shim.Column{Value: &shim.Column_Int32{Int32: col3Val}} - col4 := shim.Column{Value: &shim.Column_String_{String_: col4Val}} - columns = append(columns, &col1) - columns = append(columns, &col2) - columns = append(columns, &col3) - columns = append(columns, &col4) - - row := shim.Row{Columns: columns} - ok, err := stub.InsertRow("tableTwo", row) - if err != nil { - return nil, fmt.Errorf("insertRowTableTwo operation failed. %s", err) - } - if !ok { - return nil, errors.New("insertRowTableTwo operation failed. Row with given key already exists") - } - - case "insertRowTableThree": - if len(args) < 7 { - return nil, errors.New("insertRowTableThree failed. Must include 7 column values") - } - - col1Val := args[0] - - col2Int, err := strconv.ParseInt(args[1], 10, 32) - if err != nil { - return nil, errors.New("insertRowTableThree failed. arg[1] must be convertable to int32") - } - col2Val := int32(col2Int) - - col3Val, err := strconv.ParseInt(args[2], 10, 64) - if err != nil { - return nil, errors.New("insertRowTableThree failed. arg[2] must be convertable to int64") - } - - col4Uint, err := strconv.ParseUint(args[3], 10, 32) - if err != nil { - return nil, errors.New("insertRowTableThree failed. arg[3] must be convertable to uint32") - } - col4Val := uint32(col4Uint) - - col5Val, err := strconv.ParseUint(args[4], 10, 64) - if err != nil { - return nil, errors.New("insertRowTableThree failed. arg[4] must be convertable to uint64") - } - - col6Val := []byte(args[5]) - - col7Val, err := strconv.ParseBool(args[6]) - if err != nil { - return nil, errors.New("insertRowTableThree failed. arg[6] must be convertable to bool") - } - - var columns []*shim.Column - col1 := shim.Column{Value: &shim.Column_String_{String_: col1Val}} - col2 := shim.Column{Value: &shim.Column_Int32{Int32: col2Val}} - col3 := shim.Column{Value: &shim.Column_Int64{Int64: col3Val}} - col4 := shim.Column{Value: &shim.Column_Uint32{Uint32: col4Val}} - col5 := shim.Column{Value: &shim.Column_Uint64{Uint64: col5Val}} - col6 := shim.Column{Value: &shim.Column_Bytes{Bytes: col6Val}} - col7 := shim.Column{Value: &shim.Column_Bool{Bool: col7Val}} - columns = append(columns, &col1) - columns = append(columns, &col2) - columns = append(columns, &col3) - columns = append(columns, &col4) - columns = append(columns, &col5) - columns = append(columns, &col6) - columns = append(columns, &col7) - - row := shim.Row{Columns: columns} - ok, err := stub.InsertRow("tableThree", row) - if err != nil { - return nil, fmt.Errorf("insertRowTableThree operation failed. %s", err) - } - if !ok { - return nil, errors.New("insertRowTableThree operation failed. Row with given key already exists") - } - - case "insertRowTableFour": - if len(args) < 1 { - return nil, errors.New("insertRowTableFour failed. Must include 1 column value1") - } - - col1Val := args[0] - - var columns []*shim.Column - col1 := shim.Column{Value: &shim.Column_String_{String_: col1Val}} - columns = append(columns, &col1) - - row := shim.Row{Columns: columns} - ok, err := stub.InsertRow("tableFour", row) - if err != nil { - return nil, fmt.Errorf("insertRowTableFour operation failed. %s", err) - } - if !ok { - return nil, errors.New("insertRowTableFour operation failed. Row with given key already exists") - } - - case "deleteRowTableOne": - if len(args) < 1 { - return nil, errors.New("deleteRowTableOne failed. Must include 1 key value") - } - - col1Val := args[0] - var columns []shim.Column - col1 := shim.Column{Value: &shim.Column_String_{String_: col1Val}} - columns = append(columns, col1) - - err := stub.DeleteRow("tableOne", columns) - if err != nil { - return nil, fmt.Errorf("deleteRowTableOne operation failed. %s", err) - } - - case "replaceRowTableOne": - if len(args) < 3 { - return nil, errors.New("replaceRowTableOne failed. Must include 3 column values") - } - - col1Val := args[0] - col2Int, err := strconv.ParseInt(args[1], 10, 32) - if err != nil { - return nil, errors.New("replaceRowTableOne failed. arg[1] must be convertable to int32") - } - col2Val := int32(col2Int) - col3Int, err := strconv.ParseInt(args[2], 10, 32) - if err != nil { - return nil, errors.New("replaceRowTableOne failed. arg[2] must be convertable to int32") - } - col3Val := int32(col3Int) - - var columns []*shim.Column - col1 := shim.Column{Value: &shim.Column_String_{String_: col1Val}} - col2 := shim.Column{Value: &shim.Column_Int32{Int32: col2Val}} - col3 := shim.Column{Value: &shim.Column_Int32{Int32: col3Val}} - columns = append(columns, &col1) - columns = append(columns, &col2) - columns = append(columns, &col3) - - row := shim.Row{Columns: columns} - ok, err := stub.ReplaceRow("tableOne", row) - if err != nil { - return nil, fmt.Errorf("replaceRowTableOne operation failed. %s", err) - } - if !ok { - return nil, errors.New("replaceRowTableOne operation failed. Row with given key does not exist") - } - - case "deleteAndRecreateTableOne": - - err := stub.DeleteTable("tableOne") - if err != nil { - return nil, fmt.Errorf("deleteAndRecreateTableOne operation failed. Error deleting table. %s", err) - } - - err = createTableOne(stub) - if err != nil { - return nil, fmt.Errorf("deleteAndRecreateTableOne operation failed. Error creating table. %s", err) - } - - return nil, nil - - default: - return nil, errors.New("Unsupported operation") - } - return nil, nil -} - -// Query callback representing the query of a chaincode -func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface) ([]byte, error) { - function, args := stub.GetFunctionAndParameters() - switch function { - - case "getRowTableOne": - if len(args) < 1 { - return nil, errors.New("getRowTableOne failed. Must include 1 key value") - } - - col1Val := args[0] - var columns []shim.Column - col1 := shim.Column{Value: &shim.Column_String_{String_: col1Val}} - columns = append(columns, col1) - - row, err := stub.GetRow("tableOne", columns) - if err != nil { - return nil, fmt.Errorf("getRowTableOne operation failed. %s", err) - } - - rowString := fmt.Sprintf("%s", row) - return []byte(rowString), nil - - case "getRowTableTwo": - if len(args) < 3 { - return nil, errors.New("getRowTableTwo failed. Must include 3 key values") - } - - col1Val := args[0] - col2Int, err := strconv.ParseInt(args[1], 10, 32) - if err != nil { - return nil, errors.New("getRowTableTwo failed. arg[1] must be convertable to int32") - } - col2Val := int32(col2Int) - col3Val := args[2] - var columns []shim.Column - col1 := shim.Column{Value: &shim.Column_String_{String_: col1Val}} - col2 := shim.Column{Value: &shim.Column_Int32{Int32: col2Val}} - col3 := shim.Column{Value: &shim.Column_String_{String_: col3Val}} - columns = append(columns, col1) - columns = append(columns, col2) - columns = append(columns, col3) - - row, err := stub.GetRow("tableTwo", columns) - if err != nil { - return nil, fmt.Errorf("getRowTableTwo operation failed. %s", err) - } - - rowString := fmt.Sprintf("%s", row) - return []byte(rowString), nil - - case "getRowTableThree": - if len(args) < 1 { - return nil, errors.New("getRowTableThree failed. Must include 1 key value") - } - - col1Val := args[0] - - var columns []shim.Column - col1 := shim.Column{Value: &shim.Column_String_{String_: col1Val}} - columns = append(columns, col1) - - row, err := stub.GetRow("tableThree", columns) - if err != nil { - return nil, fmt.Errorf("getRowTableThree operation failed. %s", err) - } - - rowString := fmt.Sprintf("%s", row) - return []byte(rowString), nil - - case "getRowsTableTwo": - if len(args) < 1 { - return nil, errors.New("getRowsTableTwo failed. Must include at least key values") - } - - var columns []shim.Column - - col1Val := args[0] - col1 := shim.Column{Value: &shim.Column_String_{String_: col1Val}} - columns = append(columns, col1) - - if len(args) > 1 { - col2Int, err := strconv.ParseInt(args[1], 10, 32) - if err != nil { - return nil, errors.New("getRowsTableTwo failed. arg[1] must be convertable to int32") - } - col2Val := int32(col2Int) - col2 := shim.Column{Value: &shim.Column_Int32{Int32: col2Val}} - columns = append(columns, col2) - } - - rowChannel, err := stub.GetRows("tableTwo", columns) - if err != nil { - return nil, fmt.Errorf("getRowsTableTwo operation failed. %s", err) - } - - var rows []shim.Row - for { - select { - case row, ok := <-rowChannel: - if !ok { - rowChannel = nil - } else { - rows = append(rows, row) - } - } - if rowChannel == nil { - break - } - } - - jsonRows, err := json.Marshal(rows) - if err != nil { - return nil, fmt.Errorf("getRowsTableTwo operation failed. Error marshaling JSON: %s", err) - } - - return jsonRows, nil - - case "getRowTableFour": - if len(args) < 1 { - return nil, errors.New("getRowTableFour failed. Must include 1 key") - } - - col1Val := args[0] - var columns []shim.Column - col1 := shim.Column{Value: &shim.Column_String_{String_: col1Val}} - columns = append(columns, col1) - - row, err := stub.GetRow("tableFour", columns) - if err != nil { - return nil, fmt.Errorf("getRowTableFour operation failed. %s", err) - } - - rowString := fmt.Sprintf("%s", row) - return []byte(rowString), nil - - case "getRowsTableFour": - if len(args) < 1 { - return nil, errors.New("getRowsTableFour failed. Must include 1 key value") - } - - var columns []shim.Column - - col1Val := args[0] - col1 := shim.Column{Value: &shim.Column_String_{String_: col1Val}} - columns = append(columns, col1) - - rowChannel, err := stub.GetRows("tableFour", columns) - if err != nil { - return nil, fmt.Errorf("getRowsTableFour operation failed. %s", err) - } - - var rows []shim.Row - for { - select { - case row, ok := <-rowChannel: - if !ok { - rowChannel = nil - } else { - rows = append(rows, row) - } - } - if rowChannel == nil { - break - } - } - - jsonRows, err := json.Marshal(rows) - if err != nil { - return nil, fmt.Errorf("getRowsTableFour operation failed. Error marshaling JSON: %s", err) - } - - return jsonRows, nil - - default: - return nil, errors.New("Unsupported operation") - } -} - -func main() { - err := shim.Start(new(SimpleChaincode)) - if err != nil { - fmt.Printf("Error starting Simple chaincode: %s", err) - } -} - -func createTableOne(stub shim.ChaincodeStubInterface) error { - // Create table one - var columnDefsTableOne []*shim.ColumnDefinition - columnOneTableOneDef := shim.ColumnDefinition{Name: "colOneTableOne", - Type: shim.ColumnDefinition_STRING, Key: true} - columnTwoTableOneDef := shim.ColumnDefinition{Name: "colTwoTableOne", - Type: shim.ColumnDefinition_INT32, Key: false} - columnThreeTableOneDef := shim.ColumnDefinition{Name: "colThreeTableOne", - Type: shim.ColumnDefinition_INT32, Key: false} - columnDefsTableOne = append(columnDefsTableOne, &columnOneTableOneDef) - columnDefsTableOne = append(columnDefsTableOne, &columnTwoTableOneDef) - columnDefsTableOne = append(columnDefsTableOne, &columnThreeTableOneDef) - return stub.CreateTable("tableOne", columnDefsTableOne) -} - -func createTableTwo(stub shim.ChaincodeStubInterface) error { - var columnDefsTableTwo []*shim.ColumnDefinition - columnOneTableTwoDef := shim.ColumnDefinition{Name: "colOneTableTwo", - Type: shim.ColumnDefinition_STRING, Key: true} - columnTwoTableTwoDef := shim.ColumnDefinition{Name: "colTwoTableTwo", - Type: shim.ColumnDefinition_INT32, Key: false} - columnThreeTableTwoDef := shim.ColumnDefinition{Name: "colThreeTableThree", - Type: shim.ColumnDefinition_INT32, Key: true} - columnFourTableTwoDef := shim.ColumnDefinition{Name: "colFourTableFour", - Type: shim.ColumnDefinition_STRING, Key: true} - columnDefsTableTwo = append(columnDefsTableTwo, &columnOneTableTwoDef) - columnDefsTableTwo = append(columnDefsTableTwo, &columnTwoTableTwoDef) - columnDefsTableTwo = append(columnDefsTableTwo, &columnThreeTableTwoDef) - columnDefsTableTwo = append(columnDefsTableTwo, &columnFourTableTwoDef) - return stub.CreateTable("tableTwo", columnDefsTableTwo) -} - -func createTableThree(stub shim.ChaincodeStubInterface) error { - var columnDefsTableThree []*shim.ColumnDefinition - columnOneTableThreeDef := shim.ColumnDefinition{Name: "colOneTableThree", - Type: shim.ColumnDefinition_STRING, Key: true} - columnTwoTableThreeDef := shim.ColumnDefinition{Name: "colTwoTableThree", - Type: shim.ColumnDefinition_INT32, Key: false} - columnThreeTableThreeDef := shim.ColumnDefinition{Name: "colThreeTableThree", - Type: shim.ColumnDefinition_INT64, Key: false} - columnFourTableThreeDef := shim.ColumnDefinition{Name: "colFourTableFour", - Type: shim.ColumnDefinition_UINT32, Key: false} - columnFiveTableThreeDef := shim.ColumnDefinition{Name: "colFourTableFive", - Type: shim.ColumnDefinition_UINT64, Key: false} - columnSixTableThreeDef := shim.ColumnDefinition{Name: "colFourTableSix", - Type: shim.ColumnDefinition_BYTES, Key: false} - columnSevenTableThreeDef := shim.ColumnDefinition{Name: "colFourTableSeven", - Type: shim.ColumnDefinition_BOOL, Key: false} - columnDefsTableThree = append(columnDefsTableThree, &columnOneTableThreeDef) - columnDefsTableThree = append(columnDefsTableThree, &columnTwoTableThreeDef) - columnDefsTableThree = append(columnDefsTableThree, &columnThreeTableThreeDef) - columnDefsTableThree = append(columnDefsTableThree, &columnFourTableThreeDef) - columnDefsTableThree = append(columnDefsTableThree, &columnFiveTableThreeDef) - columnDefsTableThree = append(columnDefsTableThree, &columnSixTableThreeDef) - columnDefsTableThree = append(columnDefsTableThree, &columnSevenTableThreeDef) - return stub.CreateTable("tableThree", columnDefsTableThree) -} - -func createTableFour(stub shim.ChaincodeStubInterface) error { - var columnDefsTableFour []*shim.ColumnDefinition - columnOneTableFourDef := shim.ColumnDefinition{Name: "colOneTableFour", - Type: shim.ColumnDefinition_STRING, Key: true} - columnDefsTableFour = append(columnDefsTableFour, &columnOneTableFourDef) - return stub.CreateTable("tableFour", columnDefsTableFour) -} diff --git a/core/chaincode/shim/chaincode.go b/core/chaincode/shim/chaincode.go index bdad14c08b8..6aadf188a31 100644 --- a/core/chaincode/shim/chaincode.go +++ b/core/chaincode/shim/chaincode.go @@ -335,6 +335,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 +//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) + for _, attribute := range attributes { + compositeKey.WriteString(strconv.Itoa(len(attribute))) + compositeKey.WriteString(attribute) + } + return compositeKey.String(), nil +} + +//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. +func (stub *ChaincodeStub) PartialCompositeKeyQuery(objectType string, attributes []string) (StateRangeQueryIteratorInterface, error) { + return partialCompositeKeyQuery(stub, objectType, attributes) +} + +func partialCompositeKeyQuery(stub ChaincodeStubInterface, objectType string, attributes []string) (StateRangeQueryIteratorInterface, error) { + partialCompositeKey, _ := stub.CreateCompositeKey(objectType, attributes) + keysIter, err := stub.RangeQueryState(partialCompositeKey+"1", partialCompositeKey+":") + if err != nil { + return nil, fmt.Errorf("Error fetching rows: %s", err) + } + return keysIter, nil +} + // HasNext returns true if the range query iterator contains additional keys // and values. func (iter *StateRangeQueryIterator) HasNext() bool { @@ -399,260 +434,6 @@ func (stub *ChaincodeStub) GetFunctionAndParameters() (function string, params [ return } -// TABLE FUNCTIONALITY -// TODO More comments here with documentation - -// Table Errors -var ( - // ErrTableNotFound if the specified table cannot be found - ErrTableNotFound = errors.New("chaincode: Table not found") -) - -// CreateTable creates a new table given the table name and column definitions -func (stub *ChaincodeStub) CreateTable(name string, columnDefinitions []*ColumnDefinition) error { - return createTableInternal(stub, name, columnDefinitions) -} - -func createTableInternal(stub ChaincodeStubInterface, name string, columnDefinitions []*ColumnDefinition) error { - _, err := getTable(stub, name) - if err == nil { - return fmt.Errorf("CreateTable operation failed. Table %s already exists.", name) - } - if err != ErrTableNotFound { - return fmt.Errorf("CreateTable operation failed. %s", err) - } - - if columnDefinitions == nil || len(columnDefinitions) == 0 { - return errors.New("Invalid column definitions. Tables must contain at least one column.") - } - - hasKey := false - nameMap := make(map[string]bool) - for i, definition := range columnDefinitions { - - // Check name - if definition == nil { - return fmt.Errorf("Column definition %d is invalid. Definition must not be nil.", i) - } - if len(definition.Name) == 0 { - return fmt.Errorf("Column definition %d is invalid. Name must be 1 or more characters.", i) - } - if _, exists := nameMap[definition.Name]; exists { - return fmt.Errorf("Invalid table. Table contains duplicate column name '%s'.", definition.Name) - } - nameMap[definition.Name] = true - - // Check type - switch definition.Type { - case ColumnDefinition_STRING: - case ColumnDefinition_INT32: - case ColumnDefinition_INT64: - case ColumnDefinition_UINT32: - case ColumnDefinition_UINT64: - case ColumnDefinition_BYTES: - case ColumnDefinition_BOOL: - default: - return fmt.Errorf("Column definition %s does not have a valid type.", definition.Name) - } - - if definition.Key { - hasKey = true - } - } - - if !hasKey { - return errors.New("Inavlid table. One or more columns must be a key.") - } - - table := &Table{name, columnDefinitions} - tableBytes, err := proto.Marshal(table) - if err != nil { - return fmt.Errorf("Error marshalling table: %s", err) - } - tableNameKey, err := getTableNameKey(name) - if err != nil { - return fmt.Errorf("Error creating table key: %s", err) - } - err = stub.PutState(tableNameKey, tableBytes) - if err != nil { - return fmt.Errorf("Error inserting table in state: %s", err) - } - return nil -} - -// GetTable returns the table for the specified table name or ErrTableNotFound -// if the table does not exist. -func (stub *ChaincodeStub) GetTable(tableName string) (*Table, error) { - return getTable(stub, tableName) -} - -// DeleteTable deletes an entire table and all associated rows. -func (stub *ChaincodeStub) DeleteTable(tableName string) error { - return deleteTableInternal(stub, tableName) -} - -func deleteTableInternal(stub ChaincodeStubInterface, tableName string) error { - tableNameKey, err := getTableNameKey(tableName) - if err != nil { - return err - } - - // Delete rows - iter, err := stub.RangeQueryState(tableNameKey+"1", tableNameKey+":") - if err != nil { - return fmt.Errorf("Error deleting table: %s", err) - } - defer iter.Close() - for iter.HasNext() { - key, _, err := iter.Next() - if err != nil { - return fmt.Errorf("Error deleting table: %s", err) - } - err = stub.DelState(key) - if err != nil { - return fmt.Errorf("Error deleting table: %s", err) - } - } - - return stub.DelState(tableNameKey) -} - -// InsertRow inserts a new row into the specified table. -// Returns - -// true and no error if the row is successfully inserted. -// false and no error if a row already exists for the given key. -// false and a TableNotFoundError if the specified table name does not exist. -// false and an error if there is an unexpected error condition. -func (stub *ChaincodeStub) InsertRow(tableName string, row Row) (bool, error) { - return insertRowInternal(stub, tableName, row, false) -} - -// ReplaceRow updates the row in the specified table. -// Returns - -// true and no error if the row is successfully updated. -// false and no error if a row does not exist the given key. -// flase and a TableNotFoundError if the specified table name does not exist. -// false and an error if there is an unexpected error condition. -func (stub *ChaincodeStub) ReplaceRow(tableName string, row Row) (bool, error) { - return insertRowInternal(stub, tableName, row, true) -} - -// GetRow fetches a row from the specified table for the given key. -func (stub *ChaincodeStub) GetRow(tableName string, key []Column) (Row, error) { - return getRowInternal(stub, tableName, key) -} - -func getRowInternal(stub ChaincodeStubInterface, tableName string, key []Column) (Row, error) { - - var row Row - - keyString, err := buildKeyString(tableName, key) - if err != nil { - return row, err - } - - rowBytes, err := stub.GetState(keyString) - if err != nil { - return row, fmt.Errorf("Error fetching row from DB: %s", err) - } - - err = proto.Unmarshal(rowBytes, &row) - if err != nil { - return row, fmt.Errorf("Error unmarshalling row: %s", err) - } - - return row, nil - -} - -// GetRows returns multiple rows based on a partial key. For example, given table -// | A | B | C | D | -// where A, C and D are keys, GetRows can be called with [A, C] to return -// all rows that have A, C and any value for D as their key. GetRows could -// also be called with A only to return all rows that have A and any value -// for C and D as their key. -func (stub *ChaincodeStub) GetRows(tableName string, key []Column) (<-chan Row, error) { - return getRowsInternal(stub, tableName, key) -} - -func getRowsInternal(stub ChaincodeStubInterface, tableName string, key []Column) (<-chan Row, error) { - - keyString, err := buildKeyString(tableName, key) - if err != nil { - return nil, err - } - - table, err := getTable(stub, tableName) - if err != nil { - return nil, err - } - - // Need to check for special case where table has a single column - if len(table.GetColumnDefinitions()) < 2 && len(key) > 0 { - - row, err := stub.GetRow(tableName, key) - if err != nil { - return nil, err - } - rows := make(chan Row) - go func() { - rows <- row - close(rows) - }() - return rows, nil - } - - iter, err := stub.RangeQueryState(keyString+"1", keyString+":") - if err != nil { - return nil, fmt.Errorf("Error fetching rows: %s", err) - } - defer iter.Close() - - rows := make(chan Row) - - go func() { - for iter.HasNext() { - _, rowBytes, err := iter.Next() - if err != nil { - close(rows) - } - - var row Row - err = proto.Unmarshal(rowBytes, &row) - if err != nil { - close(rows) - } - - rows <- row - - } - close(rows) - }() - - return rows, nil - -} - -// DeleteRow deletes the row for the given key from the specified table. -func (stub *ChaincodeStub) DeleteRow(tableName string, key []Column) error { - return deleteRowInternal(stub, tableName, key) -} - -func deleteRowInternal(stub ChaincodeStubInterface, tableName string, key []Column) error { - - keyString, err := buildKeyString(tableName, key) - if err != nil { - return err - } - - err = stub.DelState(keyString) - if err != nil { - return fmt.Errorf("DeleteRow operation error. Error deleting row: %s", err) - } - - return nil -} - // GetCallerCertificate returns caller certificate func (stub *ChaincodeStub) GetCallerCertificate() ([]byte, error) { return nil, nil @@ -681,190 +462,6 @@ func (stub *ChaincodeStub) GetTxTimestamp() (*timestamp.Timestamp, error) { return nil, nil } -func getTable(stub ChaincodeStubInterface, tableName string) (*Table, error) { - - tableName, err := getTableNameKey(tableName) - if err != nil { - return nil, err - } - - tableBytes, err := stub.GetState(tableName) - if tableBytes == nil { - return nil, ErrTableNotFound - } - if err != nil { - return nil, fmt.Errorf("Error fetching table: %s", err) - } - table := &Table{} - err = proto.Unmarshal(tableBytes, table) - if err != nil { - return nil, fmt.Errorf("Error unmarshalling table: %s", err) - } - - return table, nil -} - -func validateTableName(name string) error { - if len(name) == 0 { - return errors.New("Inavlid table name. Table name must be 1 or more characters.") - } - - return nil -} - -func getTableNameKey(name string) (string, error) { - err := validateTableName(name) - if err != nil { - return "", err - } - - return strconv.Itoa(len(name)) + name, nil -} - -func buildKeyString(tableName string, keys []Column) (string, error) { - - var keyBuffer bytes.Buffer - - tableNameKey, err := getTableNameKey(tableName) - if err != nil { - return "", err - } - - keyBuffer.WriteString(tableNameKey) - - for _, key := range keys { - - var keyString string - switch key.Value.(type) { - case *Column_String_: - keyString = key.GetString_() - case *Column_Int32: - // b := make([]byte, 4) - // binary.LittleEndian.PutUint32(b, uint32(key.GetInt32())) - // keyBuffer.Write(b) - keyString = strconv.FormatInt(int64(key.GetInt32()), 10) - case *Column_Int64: - keyString = strconv.FormatInt(key.GetInt64(), 10) - case *Column_Uint32: - keyString = strconv.FormatUint(uint64(key.GetUint32()), 10) - case *Column_Uint64: - keyString = strconv.FormatUint(key.GetUint64(), 10) - case *Column_Bytes: - keyString = string(key.GetBytes()) - case *Column_Bool: - keyString = strconv.FormatBool(key.GetBool()) - } - - keyBuffer.WriteString(strconv.Itoa(len(keyString))) - keyBuffer.WriteString(keyString) - } - - return keyBuffer.String(), nil -} - -func getKeyAndVerifyRow(table Table, row Row) ([]Column, error) { - - var keys []Column - - if row.Columns == nil || len(row.Columns) != len(table.ColumnDefinitions) { - return keys, fmt.Errorf("Table '%s' defines %d columns, but row has %d columns.", - table.Name, len(table.ColumnDefinitions), len(row.Columns)) - } - - for i, column := range row.Columns { - - // Check types - var expectedType bool - switch column.Value.(type) { - case *Column_String_: - expectedType = table.ColumnDefinitions[i].Type == ColumnDefinition_STRING - case *Column_Int32: - expectedType = table.ColumnDefinitions[i].Type == ColumnDefinition_INT32 - case *Column_Int64: - expectedType = table.ColumnDefinitions[i].Type == ColumnDefinition_INT64 - case *Column_Uint32: - expectedType = table.ColumnDefinitions[i].Type == ColumnDefinition_UINT32 - case *Column_Uint64: - expectedType = table.ColumnDefinitions[i].Type == ColumnDefinition_UINT64 - case *Column_Bytes: - expectedType = table.ColumnDefinitions[i].Type == ColumnDefinition_BYTES - case *Column_Bool: - expectedType = table.ColumnDefinitions[i].Type == ColumnDefinition_BOOL - default: - expectedType = false - } - if !expectedType { - return keys, fmt.Errorf("The type for table '%s', column '%s' is '%s', but the column in the row does not match.", - table.Name, table.ColumnDefinitions[i].Name, table.ColumnDefinitions[i].Type) - } - - if table.ColumnDefinitions[i].Key { - keys = append(keys, *column) - } - - } - - return keys, nil -} - -func isRowPresent(stub ChaincodeStubInterface, tableName string, key []Column) (bool, error) { - keyString, err := buildKeyString(tableName, key) - if err != nil { - return false, err - } - rowBytes, err := stub.GetState(keyString) - if err != nil { - return false, fmt.Errorf("Error fetching row for key %s: %s", keyString, err) - } - if rowBytes != nil { - return true, nil - } - return false, nil -} - -// insertRowInternal inserts a new row into the specified table. -// Returns - -// true and no error if the row is successfully inserted. -// false and no error if a row already exists for the given key. -// false and a TableNotFoundError if the specified table name does not exist. -// false and an error if there is an unexpected error condition. -func insertRowInternal(stub ChaincodeStubInterface, tableName string, row Row, update bool) (bool, error) { - - table, err := getTable(stub, tableName) - if err != nil { - return false, err - } - - key, err := getKeyAndVerifyRow(*table, row) - if err != nil { - return false, err - } - - present, err := isRowPresent(stub, tableName, key) - if err != nil { - return false, err - } - if (present && !update) || (!present && update) { - return false, nil - } - - rowBytes, err := proto.Marshal(&row) - if err != nil { - return false, fmt.Errorf("Error marshalling row: %s", err) - } - - keyString, err := buildKeyString(tableName, key) - if err != nil { - return false, err - } - err = stub.PutState(keyString, rowBytes) - if err != nil { - return false, fmt.Errorf("Error inserting row in table %s: %s", tableName, err) - } - - return true, nil -} - // ------------- ChaincodeEvent API ---------------------- // SetEvent saves the event to be sent when a transaction is made part of a block diff --git a/core/chaincode/shim/interfaces.go b/core/chaincode/shim/interfaces.go index cc4646a3401..cce5d22ec45 100644 --- a/core/chaincode/shim/interfaces.go +++ b/core/chaincode/shim/interfaces.go @@ -69,45 +69,17 @@ type ChaincodeStubInterface interface { // returned by the iterator is random. RangeQueryState(startKey, endKey string) (StateRangeQueryIteratorInterface, error) - // CreateTable creates a new table given the table name and column definitions - CreateTable(name string, columnDefinitions []*ColumnDefinition) error - - // GetTable returns the table for the specified table name or ErrTableNotFound - // if the table does not exist. - GetTable(tableName string) (*Table, error) - - // DeleteTable deletes an entire table and all associated rows. - DeleteTable(tableName string) error - - // InsertRow inserts a new row into the specified table. - // Returns - - // true and no error if the row is successfully inserted. - // false and no error if a row already exists for the given key. - // false and a TableNotFoundError if the specified table name does not exist. - // false and an error if there is an unexpected error condition. - InsertRow(tableName string, row Row) (bool, error) - - // ReplaceRow updates the row in the specified table. - // Returns - - // true and no error if the row is successfully updated. - // false and no error if a row does not exist the given key. - // flase and a TableNotFoundError if the specified table name does not exist. - // false and an error if there is an unexpected error condition. - ReplaceRow(tableName string, row Row) (bool, error) - - // GetRow fetches a row from the specified table for the given key. - GetRow(tableName string, key []Column) (Row, error) - - // GetRows returns multiple rows based on a partial key. For example, given table - // | A | B | C | D | - // where A, C and D are keys, GetRows can be called with [A, C] to return - // all rows that have A, C and any value for D as their key. GetRows could - // also be called with A only to return all rows that have A and any value - // for C and D as their key. - GetRows(tableName string, key []Column) (<-chan Row, error) - - // DeleteRow deletes the row for the given key from the specified table. - DeleteRow(tableName string, key []Column) 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(objectType string, keys []string) (StateRangeQueryIteratorInterface, error) + + //Given a list of attributes, createCompundKey function combines these attributes + //to form a composite key. + CreateCompositeKey(objectType string, attributes []string) (string, error) // GetCallerCertificate returns caller certificate GetCallerCertificate() ([]byte, error) diff --git a/core/chaincode/shim/java/build.gradle b/core/chaincode/shim/java/build.gradle index b92b1025230..72d71f0d37d 100644 --- a/core/chaincode/shim/java/build.gradle +++ b/core/chaincode/shim/java/build.gradle @@ -94,11 +94,6 @@ task copyProtos(type:Copy){ include '**/chaincodeevent.proto' include '**/chaincode.proto' } - from ("../") { - duplicatesStrategy.EXCLUDE - include '**/table.proto' - exclude 'java' - } into "${projectDir}/src/main/proto/peer" } diff --git a/core/chaincode/shim/java/src/main/java/org/hyperledger/java/shim/ChaincodeStub.java b/core/chaincode/shim/java/src/main/java/org/hyperledger/java/shim/ChaincodeStub.java index 1056d2aecec..f5bb20becb2 100644 --- a/core/chaincode/shim/java/src/main/java/org/hyperledger/java/shim/ChaincodeStub.java +++ b/core/chaincode/shim/java/src/main/java/org/hyperledger/java/shim/ChaincodeStub.java @@ -21,14 +21,13 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hyperledger.protos.Chaincode; -import org.hyperledger.protos.TableProto; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import static org.hyperledger.protos.TableProto.ColumnDefinition.Type.STRING; +//import static org.hyperledger.protos.TableProto.ColumnDefinition.Type.STRING; public class ChaincodeStub { private static Log logger = LogFactory.getLog(ChaincodeStub.class); @@ -110,6 +109,38 @@ public Map rangeQueryRawState(String startKey, String endKey return map; } + /** + * Given a partial composite key, this method returns a map of items (whose key's prefix + * matches the given partial composite key) with value converted to UTF-8 string and + * this methid should be used only for a partial composite key; For a full composite key, + * an iter with empty response would be returned. + * + * @param startKey + * @param endKey + * @return + */ + public Map partialCompositeKeyQuery(String objectType, String[] attributes) { + String partialCompositeKey = new String(); + partialCompositeKey = createCompositeKey(objectType, attributes); + return rangeQueryState(partialCompositeKey+"1", partialCompositeKey+":"); + } + + /** + * Given a set of attributes, this method combines these attributes to return a composite key. + * + * @param objectType + * @param attributes + * @return + */ + public String createCompositeKey(String objectType, String[] attributes) { + String compositeKey = new String(); + compositeKey = compositeKey + objectType; + for (String attribute : attributes) { + compositeKey = compositeKey + attribute.length() + attribute; + } + return compositeKey; + } + /** * @param chaincodeName * @param function @@ -161,276 +192,4 @@ public void putRawState(String key, ByteString value) { public ByteString invokeRawChaincode(String chaincodeName, String function, List args) { return handler.handleInvokeChaincode(chaincodeName, function, args, uuid); } - - public boolean createTable(String tableName, List columnDefinitions) - throws Exception { - if (validateTableName(tableName)) { - logger.debug("Table name %s is valid, continue table creation"); - - if (tableExist(tableName)) { - logger.error("Table with tableName already exist, Create table operation failed"); - return false;//table exist - } else { - if (columnDefinitions != null && columnDefinitions.size() == 0) { - logger.error("Invalid column definitions. Table must contain at least one column"); - return false; - } - Map nameMap = new HashMap<>(); - int idx = 0; - boolean hasKey = false; - logger.debug("Number of columns " + columnDefinitions.size()); - for (TableProto.ColumnDefinition colDef : columnDefinitions) { - logger.debug("Col information - " + colDef.getName()+ "=" + colDef.getType()+ "=" +colDef.isInitialized()); - - if (!colDef.isInitialized() || colDef.getName().length() == 0) { - logger.error("Column definition is invalid for index " + idx); - return false; - } - - if (!nameMap.isEmpty() && nameMap.containsKey(colDef.getName())){ - logger.error("Column already exist for colIdx " + idx + " with name " + colDef.getName()); - return false; - } - nameMap.put(colDef.getName(), true); - switch (colDef.getType()) { - case STRING: - break; - case INT32: - break; - case INT64: - break; - case UINT32: - break; - case UINT64: - break; - case BYTES: - break; - case BOOL: - break; - default: - logger.error("Invalid column type for index " + idx + " given type " + colDef.getType()); -// return false; - - } - - if (colDef.getKey()) hasKey = true; - - idx++; - } - if (!hasKey) { - logger.error("Invalid table. One or more columns must be a key."); - return false; - } - TableProto.Table table = TableProto.Table.newBuilder() - .setName(tableName) - .addAllColumnDefinitions(columnDefinitions) - .build(); - String tableNameKey = getTableNameKey(tableName); - putRawState(tableNameKey, table.toByteString()); - return true; - } - } - return false; - } - public boolean deleteTable(String tableName) { - String tableNameKey = getTableNameKey(tableName); - rangeQueryState(tableNameKey + "1", tableNameKey + ":") - .keySet().forEach(key -> delState(key)); - delState(tableNameKey); - return true; - } - public boolean insertRow(String tableName, TableProto.Row row) throws Exception { - try { - return insertRowInternal(tableName, row, false); - } catch (Exception e) { - logger.error("Error while inserting row on table - " + tableName); - logger.error(e.getMessage()); - - throw e; - } - } - - public boolean replaceRow(String tableName, TableProto.Row row) throws Exception { - try { - return insertRowInternal(tableName, row, true); - } catch (Exception e) { - logger.error("Error while updating row on table - " + tableName); - logger.error(e.getMessage()); - - throw e; - } - } - private List getKeyAndVerifyRow(TableProto.Table table, TableProto.Row row) throws Exception { - List keys = new ArrayList(); - //logger.debug("Entering getKeyAndVerifyRow with tableName -" + table.getName() ); - //logger.debug("Entering getKeyAndVerifyRow with rowcount -" + row.getColumnsCount() ); - if ( !row.isInitialized() || row.getColumnsCount() != table.getColumnDefinitionsCount()){ - logger.error("Table " + table.getName() + " define " - + table.getColumnDefinitionsCount() + " columns but row has " - + row.getColumnsCount() + " columns"); - return keys; - } - int colIdx = 0; - for (TableProto.Column col: row.getColumnsList()) { - boolean expectedType; - switch (col.getValueCase()){ - case STRING: - expectedType = table.getColumnDefinitions(colIdx).getType() - == STRING; - break; - case INT32: - expectedType = table.getColumnDefinitions(colIdx).getType() - == TableProto.ColumnDefinition.Type.INT32; - break; - case INT64: - expectedType = table.getColumnDefinitions(colIdx).getType() - == TableProto.ColumnDefinition.Type.INT64; - break; - case UINT32: - expectedType = table.getColumnDefinitions(colIdx).getType() - == TableProto.ColumnDefinition.Type.UINT32; - break; - case UINT64: - expectedType = table.getColumnDefinitions(colIdx).getType() - == TableProto.ColumnDefinition.Type.UINT64; - break; - case BYTES: - expectedType = table.getColumnDefinitions(colIdx).getType() - == TableProto.ColumnDefinition.Type.BYTES; - break; - case BOOL: - expectedType = table.getColumnDefinitions(colIdx).getType() - == TableProto.ColumnDefinition.Type.BOOL; - break; - default: - expectedType = false; - } - if (!expectedType){ - logger.error("The type for table " + table.getName() - + " column " + table.getColumnDefinitions(colIdx).getName() + " is " - + table.getColumnDefinitions(colIdx).getType() + " but the column in the row does not match" ); - throw new Exception(); - } - if (table.getColumnDefinitions(colIdx).getKey()){ - keys.add(col); - } - - colIdx++; - } - return keys; - } - private boolean isRowPresent(String tableName, List keys){ - String keyString = buildKeyString(tableName, keys); - ByteString rowBytes = getRawState(keyString); - return !rowBytes.isEmpty(); - } - - private String buildKeyString(String tableName, List keys){ - - StringBuffer sb = new StringBuffer(); - String tableNameKey = getTableNameKey(tableName); - - sb.append(tableNameKey); - String keyString=""; - for (TableProto.Column col: keys) { - - switch (col.getValueCase()){ - case STRING: - keyString = col.getString(); - break; - case INT32: - keyString = ""+col.getInt32(); - break; - case INT64: - keyString = ""+col.getInt64(); - break; - case UINT32: - keyString = ""+col.getUint32(); - break; - case UINT64: - keyString = ""+col.getUint64(); - break; - case BYTES: - keyString = col.getBytes().toString(); - break; - case BOOL: - keyString = ""+col.getBool(); - break; - } - - sb.append(keyString.length()); - sb.append(keyString); - - } - return sb.toString(); - } - public TableProto.Row getRow(String tableName, List key) throws InvalidProtocolBufferException { - - String keyString = buildKeyString(tableName, key); - try { - return TableProto.Row.parseFrom(getRawState(keyString)); - } catch (InvalidProtocolBufferException e) { - - logger.error("Error while retrieving row on table -" + tableName); - throw e; - } - } - - public boolean deleteRow(String tableName, List key){ - String keyString = buildKeyString(tableName, key); - delState(keyString); - return true; - } - - private boolean insertRowInternal(String tableName, TableProto.Row row, boolean update) - throws Exception{ - try { - //logger.debug("inside insertRowInternal with tname " + tableName); - TableProto.Table table = getTable(tableName); - //logger.debug("inside insertRowInternal with tableName " + table.getName()); - List keys = getKeyAndVerifyRow(table, row); - Boolean present = isRowPresent(tableName, keys); - if((present && !update) || (!present && update)){ - return false; - } - String keyString = buildKeyString(tableName, keys); - putRawState(keyString, row.toByteString()); - } catch (Exception e) { - logger.error("Unable to insert/update table -" + tableName); - logger.error(e.getMessage()); - throw e; - } - - return true; - } - - private TableProto.Table getTable(String tableName) throws Exception { -logger.info("Inside get tbale"); - String tName = getTableNameKey(tableName); - logger.debug("Table name key for getRawState - " + tName); - ByteString tableBytes = getRawState(tName); - logger.debug("Table after getrawState -" + tableBytes); - return TableProto.Table.parseFrom(tableBytes); - } - - private boolean tableExist(String tableName) throws Exception { - boolean tableExist = false; - //TODO Better way to check table existence ? - if (getTable(tableName).getName().equals(tableName)) { - tableExist = true; - } - return tableExist; - } - - private String getTableNameKey(String name) { - return name.length() + name; - } - - public boolean validateTableName(String name) throws Exception { - boolean validTableName = true; - if (name.length() == 0) { - validTableName = false; - } - return validTableName; - } } diff --git a/core/chaincode/shim/mockstub.go b/core/chaincode/shim/mockstub.go index 75bbeae892f..18559d775fe 100644 --- a/core/chaincode/shim/mockstub.go +++ b/core/chaincode/shim/mockstub.go @@ -190,60 +190,20 @@ func (stub *MockStub) RangeQueryState(startKey, endKey string) (StateRangeQueryI return NewMockStateRangeQueryIterator(stub, startKey, endKey), nil } -// CreateTable creates a new table given the table name and column definitions -func (stub *MockStub) CreateTable(name string, columnDefinitions []*ColumnDefinition) error { - return createTableInternal(stub, name, columnDefinitions) +//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. +func (stub *MockStub) PartialCompositeKeyQuery(objectType string, attributes []string) (StateRangeQueryIteratorInterface, error) { + return partialCompositeKeyQuery(stub, objectType, attributes) } -// GetTable returns the table for the specified table name or ErrTableNotFound -// if the table does not exist. -func (stub *MockStub) GetTable(tableName string) (*Table, error) { - return getTable(stub, tableName) -} - -// DeleteTable deletes an entire table and all associated rows. -func (stub *MockStub) DeleteTable(tableName string) error { - return deleteTableInternal(stub, tableName) -} - -// InsertRow inserts a new row into the specified table. -// Returns - -// true and no error if the row is successfully inserted. -// false and no error if a row already exists for the given key. -// false and a TableNotFoundError if the specified table name does not exist. -// false and an error if there is an unexpected error condition. -func (stub *MockStub) InsertRow(tableName string, row Row) (bool, error) { - return insertRowInternal(stub, tableName, row, false) -} - -// ReplaceRow updates the row in the specified table. -// Returns - -// true and no error if the row is successfully updated. -// false and no error if a row does not exist the given key. -// flase and a TableNotFoundError if the specified table name does not exist. -// false and an error if there is an unexpected error condition. -func (stub *MockStub) ReplaceRow(tableName string, row Row) (bool, error) { - return insertRowInternal(stub, tableName, row, true) -} - -// GetRow fetches a row from the specified table for the given key. -func (stub *MockStub) GetRow(tableName string, key []Column) (Row, error) { - return getRowInternal(stub, tableName, key) -} - -// GetRows returns multiple rows based on a partial key. For example, given table -// | A | B | C | D | -// where A, C and D are keys, GetRows can be called with [A, C] to return -// all rows that have A, C and any value for D as their key. GetRows could -// also be called with A only to return all rows that have A and any value -// for C and D as their key. -func (stub *MockStub) GetRows(tableName string, key []Column) (<-chan Row, error) { - return getRowsInternal(stub, tableName, key) -} - -// DeleteRow deletes the row for the given key from the specified table. -func (stub *MockStub) DeleteRow(tableName string, key []Column) error { - return deleteRowInternal(stub, tableName, key) +//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) } // Invokes a peered chaincode. @@ -329,20 +289,26 @@ func (iter *MockStateRangeQueryIterator) HasNext() bool { return false } - if iter.Current.Next() == nil { - // we've reached the end of the underlying values - mockLogger.Debug("HasNext() but no next") - return false - } + current := iter.Current + for current != nil { + comp1 := strings.Compare(current.Value.(string), iter.StartKey) + comp2 := strings.Compare(current.Value.(string), iter.EndKey) + if comp1 >= 0 { + if comp2 <= 0 { + mockLogger.Debug("HasNext() got next") + return true + } else { + mockLogger.Debug("HasNext() but no next") + return false - if iter.EndKey == iter.Current.Value { - // we've reached the end of the specified range - mockLogger.Debug("HasNext() at end of specified range") - return false + } + } + current = current.Next() } - mockLogger.Debug("HasNext() got next") - return true + // we've reached the end of the underlying values + mockLogger.Debug("HasNext() but no next") + return false } // Next returns the next key and value in the range query iterator. @@ -357,15 +323,19 @@ func (iter *MockStateRangeQueryIterator) Next() (string, []byte, error) { return "", nil, errors.New("MockStateRangeQueryIterator.Next() called when it does not HaveNext()") } - iter.Current = iter.Current.Next() - - if iter.Current == nil { - mockLogger.Error("MockStateRangeQueryIterator.Next() went past end of range") - return "", nil, errors.New("MockStateRangeQueryIterator.Next() went past end of range") + for iter.Current != nil { + comp1 := strings.Compare(iter.Current.Value.(string), iter.StartKey) + comp2 := strings.Compare(iter.Current.Value.(string), iter.EndKey) + if comp1 >= 0 && comp2 <= 0 { + key := iter.Current.Value.(string) + value, err := iter.Stub.GetState(key) + iter.Current = iter.Current.Next() + return key, value, err + } + iter.Current = iter.Current.Next() } - key := iter.Current.Value.(string) - value, err := iter.Stub.GetState(key) - return key, value, err + mockLogger.Error("MockStateRangeQueryIterator.Next() went past end of range") + return "", nil, errors.New("MockStateRangeQueryIterator.Next() went past end of range") } // Close closes the range query iterator. This should be called when done diff --git a/core/chaincode/shim/mockstub_test.go b/core/chaincode/shim/mockstub_test.go index 65f664e9333..ba94998c77d 100644 --- a/core/chaincode/shim/mockstub_test.go +++ b/core/chaincode/shim/mockstub_test.go @@ -17,108 +17,32 @@ limitations under the License. package shim import ( - "errors" + "encoding/json" "fmt" + "reflect" "testing" "github.com/spf13/viper" ) -func createTable(stub ChaincodeStubInterface) error { - // Create table one - var columnDefsTableOne []*ColumnDefinition - columnOneTableOneDef := ColumnDefinition{Name: "colOneTableOne", - Type: ColumnDefinition_STRING, Key: true} - columnTwoTableOneDef := ColumnDefinition{Name: "colTwoTableOne", - Type: ColumnDefinition_INT32, Key: false} - columnThreeTableOneDef := ColumnDefinition{Name: "colThreeTableOne", - Type: ColumnDefinition_INT32, Key: false} - columnDefsTableOne = append(columnDefsTableOne, &columnOneTableOneDef) - columnDefsTableOne = append(columnDefsTableOne, &columnTwoTableOneDef) - columnDefsTableOne = append(columnDefsTableOne, &columnThreeTableOneDef) - return stub.CreateTable("tableOne", columnDefsTableOne) -} - -func insertRow(stub ChaincodeStubInterface, col1Val string, col2Val int32, col3Val int32) error { - var columns []*Column - col1 := Column{Value: &Column_String_{String_: col1Val}} - col2 := Column{Value: &Column_Int32{Int32: col2Val}} - col3 := Column{Value: &Column_Int32{Int32: col3Val}} - columns = append(columns, &col1) - columns = append(columns, &col2) - columns = append(columns, &col3) - - row := Row{Columns: columns} - ok, err := stub.InsertRow("tableOne", row) - if err != nil { - return fmt.Errorf("insertTableOne operation failed. %s", err) - } - if !ok { - return errors.New("insertTableOne operation failed. Row with given key already exists") - } - return nil -} - -func getRow(stub ChaincodeStubInterface, col1Val string) (Row, error) { - var columns []Column - col1 := Column{Value: &Column_String_{String_: col1Val}} - columns = append(columns, col1) - - row, err := stub.GetRow("tableOne", columns) - if err != nil { - return row, fmt.Errorf("getRowTableOne operation failed. %s", err) - } - - return row, nil -} - -func getRows(stub ChaincodeStubInterface, col1Val string) ([]Row, error) { - var columns []Column - - col1 := Column{Value: &Column_String_{String_: col1Val}} - columns = append(columns, col1) - - rowChannel, err := stub.GetRows("tableOne", columns) - if err != nil { - return nil, fmt.Errorf("getRows operation failed. %s", err) - } - - var rows []Row - for { - select { - case row, ok := <-rowChannel: - if !ok { - rowChannel = nil - } else { - rows = append(rows, row) - } - } - if rowChannel == nil { - break - } - } - - return rows, nil -} - func TestMockStateRangeQueryIterator(t *testing.T) { stub := NewMockStub("rangeTest", nil) stub.MockTransactionStart("init") stub.PutState("1", []byte{61}) - stub.PutState("2", []byte{62}) + stub.PutState("0", []byte{62}) stub.PutState("5", []byte{65}) stub.PutState("3", []byte{63}) stub.PutState("4", []byte{64}) stub.PutState("6", []byte{66}) stub.MockTransactionEnd("init") - expectKeys := []string{"2", "3", "4"} - expectValues := [][]byte{{62}, {63}, {64}} + expectKeys := []string{"3", "4"} + expectValues := [][]byte{{63}, {64}} rqi := NewMockStateRangeQueryIterator(stub, "2", "4") fmt.Println("Running loop") - for i := 0; i < 3; i++ { + for i := 0; i < 2; i++ { key, value, err := rqi.Next() fmt.Println("Loop", i, "got", key, value, err) if expectKeys[i] != key { @@ -131,52 +55,6 @@ func TestMockStateRangeQueryIterator(t *testing.T) { } } -func TestMockTable(t *testing.T) { - stub := NewMockStub("CreateTable", nil) - stub.MockTransactionStart("init") - - //create a table - if err := createTable(stub); err != nil { - t.FailNow() - } - - type rowType struct { - col1 string - col2 int32 - col3 int32 - } - - //add some rows - rows := []rowType{{"one", 1, 11}, {"two", 2, 22}, {"three", 3, 33}} - for _, r := range rows { - if err := insertRow(stub, r.col1, r.col2, r.col3); err != nil { - t.FailNow() - } - } - - //get one row - if r, err := getRow(stub, "one"); err != nil { - t.FailNow() - } else if len(r.Columns) != 3 || r.Columns[0].GetString_() != "one" || r.Columns[1].GetInt32() != 1 || r.Columns[2].GetInt32() != 11 { - t.FailNow() - } - - /** we know GetRows is buggy and need to be fixed. Enable this test - * when it is - //get all rows - if rs,err := getRows(stub,"one"); err != nil { - fmt.Printf("getRows err %s\n", err) - t.FailNow() - } else if len(rs) != 1 { - fmt.Printf("getRows returned len %d(expected 1)\n", len(rs)) - t.FailNow() - } else if len(rs[0].Columns) != 3 || rs[0].Columns[0].GetString_() != "one" || rs[0].Columns[1].GetInt32() != 1 || rs[0].Columns[2].GetInt32() != 11 { - fmt.Printf("getRows invaid row %v\n", rs[0]) - t.FailNow() - } - ***/ -} - // TestSetChaincodeLoggingLevel uses the utlity function defined in chaincode.go to // set the chaincodeLogger's logging level func TestSetChaincodeLoggingLevel(t *testing.T) { @@ -190,3 +68,65 @@ func TestSetChaincodeLoggingLevel(t *testing.T) { t.FailNow() } } + +type Marble struct { + ObjectType string `json:"docType"` //docType is used to distinguish the various types of objects in state database + Name string `json:"name"` //the fieldtags are needed to keep case from bouncing around + Color string `json:"color"` + Size int `json:"size"` + Owner string `json:"owner"` +} + +// JSONBytesEqual compares the JSON in two byte slices. +func jsonBytesEqual(expected []byte, actual []byte) bool { + var infExpected, infActual interface{} + if err := json.Unmarshal(expected, &infExpected); err != nil { + return false + } + if err := json.Unmarshal(actual, &infActual); err != nil { + return false + } + return reflect.DeepEqual(infActual, infExpected) +} + +func TestPartialCompositeKeyQuery(t *testing.T) { + stub := NewMockStub("PartialCompositeKeyQueryTest", nil) + stub.MockTransactionStart("init") + + marble1 := &Marble{"marble", "set-1", "red", 5, "tom"} + // Convert marble1 to JSON with Color and Name as composite key + compositeKey1, _ := stub.CreateCompositeKey(marble1.ObjectType, []string{marble1.Name, marble1.Color}) + marbleJSONBytes1, _ := json.Marshal(marble1) + // Add marble1 JSON to state + stub.PutState(compositeKey1, marbleJSONBytes1) + + marble2 := &Marble{"marble", "set-1", "blue", 5, "jerry"} + compositeKey2, _ := stub.CreateCompositeKey(marble2.ObjectType, []string{marble2.Name, marble2.Color}) + marbleJSONBytes2, _ := json.Marshal(marble2) + stub.PutState(compositeKey2, marbleJSONBytes2) + + marble3 := &Marble{"marble", "set-2", "red", 5, "tom-jerry"} + compositeKey3, _ := stub.CreateCompositeKey(marble3.ObjectType, []string{marble3.Name, marble3.Color}) + marbleJSONBytes3, _ := json.Marshal(marble3) + stub.PutState(compositeKey3, marbleJSONBytes3) + + stub.MockTransactionEnd("init") + expectKeys := []string{compositeKey1, compositeKey2} + 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() + fmt.Println("Loop", i, "got", key, value, err) + if expectKeys[i] != key { + fmt.Println("Expected key", expectKeys[i], "got", key) + t.FailNow() + } + if jsonBytesEqual(expectValues[i], value) != true { + fmt.Println("Expected value", expectValues[i], "got", value) + t.FailNow() + } + } +} diff --git a/core/chaincode/shim/table.pb.go b/core/chaincode/shim/table.pb.go deleted file mode 100644 index 3b555527a28..00000000000 --- a/core/chaincode/shim/table.pb.go +++ /dev/null @@ -1,399 +0,0 @@ -// Code generated by protoc-gen-go. -// source: table.proto -// DO NOT EDIT! - -/* -Package shim is a generated protocol buffer package. - -It is generated from these files: - table.proto - -It has these top-level messages: - ColumnDefinition - Table - Column - Row -*/ -package shim - -import proto "github.com/golang/protobuf/proto" -import fmt "fmt" -import math "math" - -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf - -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion2 // please upgrade the proto package - -type ColumnDefinition_Type int32 - -const ( - ColumnDefinition_STRING ColumnDefinition_Type = 0 - ColumnDefinition_INT32 ColumnDefinition_Type = 1 - ColumnDefinition_INT64 ColumnDefinition_Type = 2 - ColumnDefinition_UINT32 ColumnDefinition_Type = 3 - ColumnDefinition_UINT64 ColumnDefinition_Type = 4 - ColumnDefinition_BYTES ColumnDefinition_Type = 5 - ColumnDefinition_BOOL ColumnDefinition_Type = 6 -) - -var ColumnDefinition_Type_name = map[int32]string{ - 0: "STRING", - 1: "INT32", - 2: "INT64", - 3: "UINT32", - 4: "UINT64", - 5: "BYTES", - 6: "BOOL", -} -var ColumnDefinition_Type_value = map[string]int32{ - "STRING": 0, - "INT32": 1, - "INT64": 2, - "UINT32": 3, - "UINT64": 4, - "BYTES": 5, - "BOOL": 6, -} - -func (x ColumnDefinition_Type) String() string { - return proto.EnumName(ColumnDefinition_Type_name, int32(x)) -} -func (ColumnDefinition_Type) EnumDescriptor() ([]byte, []int) { return fileDescriptor0, []int{0, 0} } - -type ColumnDefinition struct { - Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - Type ColumnDefinition_Type `protobuf:"varint,2,opt,name=type,enum=shim.ColumnDefinition_Type" json:"type,omitempty"` - Key bool `protobuf:"varint,3,opt,name=key" json:"key,omitempty"` -} - -func (m *ColumnDefinition) Reset() { *m = ColumnDefinition{} } -func (m *ColumnDefinition) String() string { return proto.CompactTextString(m) } -func (*ColumnDefinition) ProtoMessage() {} -func (*ColumnDefinition) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{0} } - -type Table struct { - Name string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - ColumnDefinitions []*ColumnDefinition `protobuf:"bytes,2,rep,name=columnDefinitions" json:"columnDefinitions,omitempty"` -} - -func (m *Table) Reset() { *m = Table{} } -func (m *Table) String() string { return proto.CompactTextString(m) } -func (*Table) ProtoMessage() {} -func (*Table) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{1} } - -func (m *Table) GetColumnDefinitions() []*ColumnDefinition { - if m != nil { - return m.ColumnDefinitions - } - return nil -} - -type Column struct { - // Types that are valid to be assigned to Value: - // *Column_String_ - // *Column_Int32 - // *Column_Int64 - // *Column_Uint32 - // *Column_Uint64 - // *Column_Bytes - // *Column_Bool - Value isColumn_Value `protobuf_oneof:"value"` -} - -func (m *Column) Reset() { *m = Column{} } -func (m *Column) String() string { return proto.CompactTextString(m) } -func (*Column) ProtoMessage() {} -func (*Column) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{2} } - -type isColumn_Value interface { - isColumn_Value() -} - -type Column_String_ struct { - String_ string `protobuf:"bytes,1,opt,name=string,oneof"` -} -type Column_Int32 struct { - Int32 int32 `protobuf:"varint,2,opt,name=int32,oneof"` -} -type Column_Int64 struct { - Int64 int64 `protobuf:"varint,3,opt,name=int64,oneof"` -} -type Column_Uint32 struct { - Uint32 uint32 `protobuf:"varint,4,opt,name=uint32,oneof"` -} -type Column_Uint64 struct { - Uint64 uint64 `protobuf:"varint,5,opt,name=uint64,oneof"` -} -type Column_Bytes struct { - Bytes []byte `protobuf:"bytes,6,opt,name=bytes,proto3,oneof"` -} -type Column_Bool struct { - Bool bool `protobuf:"varint,7,opt,name=bool,oneof"` -} - -func (*Column_String_) isColumn_Value() {} -func (*Column_Int32) isColumn_Value() {} -func (*Column_Int64) isColumn_Value() {} -func (*Column_Uint32) isColumn_Value() {} -func (*Column_Uint64) isColumn_Value() {} -func (*Column_Bytes) isColumn_Value() {} -func (*Column_Bool) isColumn_Value() {} - -func (m *Column) GetValue() isColumn_Value { - if m != nil { - return m.Value - } - return nil -} - -func (m *Column) GetString_() string { - if x, ok := m.GetValue().(*Column_String_); ok { - return x.String_ - } - return "" -} - -func (m *Column) GetInt32() int32 { - if x, ok := m.GetValue().(*Column_Int32); ok { - return x.Int32 - } - return 0 -} - -func (m *Column) GetInt64() int64 { - if x, ok := m.GetValue().(*Column_Int64); ok { - return x.Int64 - } - return 0 -} - -func (m *Column) GetUint32() uint32 { - if x, ok := m.GetValue().(*Column_Uint32); ok { - return x.Uint32 - } - return 0 -} - -func (m *Column) GetUint64() uint64 { - if x, ok := m.GetValue().(*Column_Uint64); ok { - return x.Uint64 - } - return 0 -} - -func (m *Column) GetBytes() []byte { - if x, ok := m.GetValue().(*Column_Bytes); ok { - return x.Bytes - } - return nil -} - -func (m *Column) GetBool() bool { - if x, ok := m.GetValue().(*Column_Bool); ok { - return x.Bool - } - return false -} - -// XXX_OneofFuncs is for the internal use of the proto package. -func (*Column) XXX_OneofFuncs() (func(msg proto.Message, b *proto.Buffer) error, func(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error), func(msg proto.Message) (n int), []interface{}) { - return _Column_OneofMarshaler, _Column_OneofUnmarshaler, _Column_OneofSizer, []interface{}{ - (*Column_String_)(nil), - (*Column_Int32)(nil), - (*Column_Int64)(nil), - (*Column_Uint32)(nil), - (*Column_Uint64)(nil), - (*Column_Bytes)(nil), - (*Column_Bool)(nil), - } -} - -func _Column_OneofMarshaler(msg proto.Message, b *proto.Buffer) error { - m := msg.(*Column) - // value - switch x := m.Value.(type) { - case *Column_String_: - b.EncodeVarint(1<<3 | proto.WireBytes) - b.EncodeStringBytes(x.String_) - case *Column_Int32: - b.EncodeVarint(2<<3 | proto.WireVarint) - b.EncodeVarint(uint64(x.Int32)) - case *Column_Int64: - b.EncodeVarint(3<<3 | proto.WireVarint) - b.EncodeVarint(uint64(x.Int64)) - case *Column_Uint32: - b.EncodeVarint(4<<3 | proto.WireVarint) - b.EncodeVarint(uint64(x.Uint32)) - case *Column_Uint64: - b.EncodeVarint(5<<3 | proto.WireVarint) - b.EncodeVarint(uint64(x.Uint64)) - case *Column_Bytes: - b.EncodeVarint(6<<3 | proto.WireBytes) - b.EncodeRawBytes(x.Bytes) - case *Column_Bool: - t := uint64(0) - if x.Bool { - t = 1 - } - b.EncodeVarint(7<<3 | proto.WireVarint) - b.EncodeVarint(t) - case nil: - default: - return fmt.Errorf("Column.Value has unexpected type %T", x) - } - return nil -} - -func _Column_OneofUnmarshaler(msg proto.Message, tag, wire int, b *proto.Buffer) (bool, error) { - m := msg.(*Column) - switch tag { - case 1: // value.string - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeStringBytes() - m.Value = &Column_String_{x} - return true, err - case 2: // value.int32 - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeVarint() - m.Value = &Column_Int32{int32(x)} - return true, err - case 3: // value.int64 - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeVarint() - m.Value = &Column_Int64{int64(x)} - return true, err - case 4: // value.uint32 - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeVarint() - m.Value = &Column_Uint32{uint32(x)} - return true, err - case 5: // value.uint64 - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeVarint() - m.Value = &Column_Uint64{x} - return true, err - case 6: // value.bytes - if wire != proto.WireBytes { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeRawBytes(true) - m.Value = &Column_Bytes{x} - return true, err - case 7: // value.bool - if wire != proto.WireVarint { - return true, proto.ErrInternalBadWireType - } - x, err := b.DecodeVarint() - m.Value = &Column_Bool{x != 0} - return true, err - default: - return false, nil - } -} - -func _Column_OneofSizer(msg proto.Message) (n int) { - m := msg.(*Column) - // value - switch x := m.Value.(type) { - case *Column_String_: - n += proto.SizeVarint(1<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(len(x.String_))) - n += len(x.String_) - case *Column_Int32: - n += proto.SizeVarint(2<<3 | proto.WireVarint) - n += proto.SizeVarint(uint64(x.Int32)) - case *Column_Int64: - n += proto.SizeVarint(3<<3 | proto.WireVarint) - n += proto.SizeVarint(uint64(x.Int64)) - case *Column_Uint32: - n += proto.SizeVarint(4<<3 | proto.WireVarint) - n += proto.SizeVarint(uint64(x.Uint32)) - case *Column_Uint64: - n += proto.SizeVarint(5<<3 | proto.WireVarint) - n += proto.SizeVarint(uint64(x.Uint64)) - case *Column_Bytes: - n += proto.SizeVarint(6<<3 | proto.WireBytes) - n += proto.SizeVarint(uint64(len(x.Bytes))) - n += len(x.Bytes) - case *Column_Bool: - n += proto.SizeVarint(7<<3 | proto.WireVarint) - n += 1 - case nil: - default: - panic(fmt.Sprintf("proto: unexpected type %T in oneof", x)) - } - return n -} - -type Row struct { - Columns []*Column `protobuf:"bytes,1,rep,name=columns" json:"columns,omitempty"` -} - -func (m *Row) Reset() { *m = Row{} } -func (m *Row) String() string { return proto.CompactTextString(m) } -func (*Row) ProtoMessage() {} -func (*Row) Descriptor() ([]byte, []int) { return fileDescriptor0, []int{3} } - -func (m *Row) GetColumns() []*Column { - if m != nil { - return m.Columns - } - return nil -} - -func init() { - proto.RegisterType((*ColumnDefinition)(nil), "shim.ColumnDefinition") - proto.RegisterType((*Table)(nil), "shim.Table") - proto.RegisterType((*Column)(nil), "shim.Column") - proto.RegisterType((*Row)(nil), "shim.Row") - proto.RegisterEnum("shim.ColumnDefinition_Type", ColumnDefinition_Type_name, ColumnDefinition_Type_value) -} - -func init() { proto.RegisterFile("table.proto", fileDescriptor0) } - -var fileDescriptor0 = []byte{ - // 413 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x6c, 0x52, 0xd1, 0x6a, 0xdb, 0x30, - 0x14, 0x8d, 0x62, 0xd9, 0x69, 0x6f, 0xbb, 0xa1, 0x89, 0x11, 0x04, 0x7b, 0x31, 0x7e, 0x18, 0x7e, - 0x99, 0xcd, 0x12, 0xe3, 0x0f, 0xf0, 0x3a, 0x96, 0xc2, 0x68, 0x87, 0xea, 0x32, 0xb6, 0x37, 0xdb, - 0x55, 0x13, 0x31, 0xc7, 0x0a, 0xb6, 0xb2, 0xe1, 0x8f, 0x1b, 0xec, 0xd3, 0x86, 0xa4, 0x04, 0x4a, - 0x9b, 0xb7, 0x7b, 0xee, 0x3d, 0xe7, 0xe8, 0xde, 0x83, 0xe0, 0x42, 0x57, 0x75, 0x2b, 0x92, 0x5d, - 0xaf, 0xb4, 0xa2, 0x78, 0xd8, 0xc8, 0x6d, 0xf4, 0x0f, 0x01, 0xf9, 0xa4, 0xda, 0xfd, 0xb6, 0xbb, - 0x12, 0x8f, 0xb2, 0x93, 0x5a, 0xaa, 0x8e, 0x52, 0xc0, 0x5d, 0xb5, 0x15, 0x0c, 0x85, 0x28, 0x3e, - 0xe7, 0xb6, 0xa6, 0x29, 0x60, 0x3d, 0xee, 0x04, 0x9b, 0x86, 0x28, 0x7e, 0xbd, 0x78, 0x97, 0x18, - 0x75, 0xf2, 0x5c, 0x99, 0x94, 0xe3, 0x4e, 0x70, 0x4b, 0xa4, 0x04, 0xbc, 0x5f, 0x62, 0x64, 0x5e, - 0x88, 0xe2, 0x33, 0x6e, 0xca, 0xe8, 0x1e, 0xb0, 0x99, 0x53, 0x80, 0xe0, 0xae, 0xe4, 0xd7, 0x37, - 0x5f, 0xc8, 0x84, 0x9e, 0x83, 0x7f, 0x7d, 0x53, 0x2e, 0x17, 0x04, 0x1d, 0xca, 0x3c, 0x23, 0x53, - 0xc3, 0xb8, 0x77, 0x6d, 0xef, 0x58, 0xe7, 0x19, 0xc1, 0x86, 0x52, 0xfc, 0x28, 0x3f, 0xdf, 0x11, - 0x9f, 0x9e, 0x01, 0x2e, 0x6e, 0x6f, 0xbf, 0x92, 0x20, 0xaa, 0xc0, 0x2f, 0xcd, 0x5d, 0x27, 0xd7, - 0xbe, 0x82, 0x37, 0xcd, 0xb3, 0x25, 0x07, 0x36, 0x0d, 0xbd, 0xf8, 0x62, 0x31, 0x3f, 0x7d, 0x03, - 0x7f, 0x29, 0x88, 0xfe, 0x22, 0x08, 0x1c, 0x8f, 0x32, 0x08, 0x06, 0xdd, 0xcb, 0x6e, 0xed, 0x9e, - 0x59, 0x4d, 0xf8, 0x01, 0xd3, 0x39, 0xf8, 0xb2, 0xd3, 0xcb, 0x85, 0x8d, 0xc8, 0x5f, 0x4d, 0xb8, - 0x83, 0x87, 0x7e, 0x9e, 0xd9, 0x28, 0xbc, 0x43, 0x3f, 0xcf, 0x8c, 0xd3, 0xde, 0x09, 0x70, 0x88, - 0xe2, 0x57, 0xc6, 0xc9, 0xe1, 0xe3, 0x24, 0xcf, 0x98, 0x1f, 0xa2, 0x18, 0x1f, 0x27, 0x79, 0x66, - 0xbc, 0xea, 0x51, 0x8b, 0x81, 0x05, 0x21, 0x8a, 0x2f, 0x8d, 0x97, 0x85, 0xf4, 0x2d, 0xe0, 0x5a, - 0xa9, 0x96, 0xcd, 0x4c, 0xda, 0xab, 0x09, 0xb7, 0xa8, 0x98, 0x81, 0xff, 0xbb, 0x6a, 0xf7, 0x22, - 0xfa, 0x00, 0x1e, 0x57, 0x7f, 0xe8, 0x7b, 0x98, 0xb9, 0xdb, 0x06, 0x86, 0x6c, 0x04, 0x97, 0x4f, - 0x23, 0xe0, 0xc7, 0x61, 0xf1, 0x1d, 0xe6, 0xaa, 0x5f, 0x27, 0x9b, 0x71, 0x27, 0xfa, 0x56, 0x3c, - 0xac, 0x45, 0xef, 0xfe, 0xcc, 0x50, 0x80, 0x4d, 0xfa, 0x9b, 0x01, 0x3f, 0x3f, 0xae, 0xa5, 0xde, - 0xec, 0xeb, 0xa4, 0x51, 0xdb, 0xf4, 0x09, 0x35, 0x7d, 0xac, 0xea, 0x5e, 0x36, 0x69, 0xa3, 0x7a, - 0x91, 0x36, 0x9b, 0x4a, 0x76, 0x8d, 0x7a, 0x10, 0xa9, 0x79, 0xa8, 0x0e, 0xac, 0xcd, 0xf2, 0x7f, - 0x00, 0x00, 0x00, 0xff, 0xff, 0x35, 0x1b, 0xaf, 0x40, 0x89, 0x02, 0x00, 0x00, -} diff --git a/core/chaincode/shim/table.proto b/core/chaincode/shim/table.proto deleted file mode 100644 index 056c890832c..00000000000 --- a/core/chaincode/shim/table.proto +++ /dev/null @@ -1,58 +0,0 @@ -/* -Copyright IBM Corp. 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -syntax = "proto3"; - -option go_package = "github.com/hyperledger/fabric/core/chaincode/shim" ; - -package shim; -option java_package = "org.hyperledger.protos"; -option java_outer_classname = "TableProto"; -message ColumnDefinition { - string name = 1; - enum Type { - STRING = 0; - INT32 = 1; - INT64 = 2; - UINT32 = 3; - UINT64 = 4; - BYTES = 5; - BOOL = 6; - } - Type type = 2; - bool key = 3; -} - -message Table { - string name = 1; - repeated ColumnDefinition columnDefinitions = 2; -} - -message Column { - oneof value { - string string = 1; - int32 int32 = 2; - int64 int64 = 3; - uint32 uint32 = 4; - uint64 uint64 = 5; - bytes bytes = 6; - bool bool = 7; - } -} - -message Row { - repeated Column columns = 1; -} diff --git a/examples/chaincode/java/TableExample/pom.xml b/examples/chaincode/java/TableExample/pom.xml deleted file mode 100644 index 856a62c30ea..00000000000 --- a/examples/chaincode/java/TableExample/pom.xml +++ /dev/null @@ -1,94 +0,0 @@ - - - - 1.8 - 1.8 - - - 4.0.0 - - example - chaincode-table - jar - java-table-example - 1.0 - http://maven.apache.org - - ${project.basedir}/build - chaincode - - - org.apache.maven.plugins - maven-jar-plugin - 3.0.2 - - ${dist.dir} - - - true - libs/ - example.TableExample - - - - - - org.apache.maven.plugins - maven-dependency-plugin - 2.10 - - - copy-dependencies - package - - copy-dependencies - - - ${project.build.directory}/libs - false - false - true - - - - - - - - - junit - junit - 3.8.1 - test - - - io.grpc - grpc-all - 0.13.2 - - - commons-cli - commons-cli - 1.3.1 - - - org.hyperledger - shim-client - 1.0 - - - diff --git a/examples/chaincode/java/TableExample/src/main/java/example/TableExample.java b/examples/chaincode/java/TableExample/src/main/java/example/TableExample.java deleted file mode 100644 index 857e79a6b21..00000000000 --- a/examples/chaincode/java/TableExample/src/main/java/example/TableExample.java +++ /dev/null @@ -1,194 +0,0 @@ -/* -Copyright DTCC 2016 All Rights Reserved. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -package example; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.hyperledger.java.shim.ChaincodeBase; -import org.hyperledger.java.shim.ChaincodeStub; -import org.hyperledger.protos.TableProto; - -import java.util.ArrayList; -import java.util.List; - - -public class TableExample extends ChaincodeBase { - private static String tableName = "MyNewTable1"; - private static Log log = LogFactory.getLog(TableExample.class); - @java.lang.Override - public String run(ChaincodeStub stub, String function, String[] args) { - log.info("In run, function:"+function); - switch (function) { - - case "init": - init(stub, function, args); - break; - case "insert": - insertRow(stub, args, false); - break; - case "update": - insertRow(stub, args, true); - break; - case "delete": - delete(stub, args); - break; - default: - log.error("No matching case for function:"+function); - - } - return null; - } - - private void insertRow(ChaincodeStub stub, String[] args, boolean update) { - - int fieldID = 0; - - try { - fieldID = Integer.parseInt(args[0]); - }catch (NumberFormatException e){ - log.error("Illegal field id -" + e.getMessage()); - return; - } - - TableProto.Column col1 = - TableProto.Column.newBuilder() - .setUint32(fieldID).build(); - TableProto.Column col2 = - TableProto.Column.newBuilder() - .setString(args[1]).build(); - List cols = new ArrayList(); - cols.add(col1); - cols.add(col2); - - TableProto.Row row = TableProto.Row.newBuilder() - .addAllColumns(cols) - .build(); - try { - - boolean success = false; - if(update){ - success = stub.replaceRow(tableName,row); - }else - { - success = stub.insertRow(tableName, row); - } - if (success){ - log.info("Row successfully inserted"); - } - } catch (Exception e) { - e.printStackTrace(); - } - } - - - public String init(ChaincodeStub stub, String function, String[] args) { - List cols = new ArrayList(); - - cols.add(TableProto.ColumnDefinition.newBuilder() - .setName("ID") - .setKey(true) - .setType(TableProto.ColumnDefinition.Type.UINT32) - .build() - ); - - cols.add(TableProto.ColumnDefinition.newBuilder() - .setName("Name") - .setKey(false) - .setType(TableProto.ColumnDefinition.Type.STRING) - .build() - ); - - - try { - try { - stub.deleteTable(tableName); - } catch (Exception e) { - e.printStackTrace(); - } - stub.createTable(tableName,cols); - } catch (Exception e) { - e.printStackTrace(); - } - return null; - } - - private boolean delete(ChaincodeStub stub, String[] args){ - int fieldID = 0; - - try { - fieldID = Integer.parseInt(args[0]); - }catch (NumberFormatException e){ - log.error("Illegal field id -" + e.getMessage()); - return false; - } - - - TableProto.Column queryCol = - TableProto.Column.newBuilder() - .setUint32(fieldID).build(); - List key = new ArrayList<>(); - key.add(queryCol); - return stub.deleteRow(tableName, key); - } - - @java.lang.Override - public String query(ChaincodeStub stub, String function, String[] args) { - log.info("query"); - int fieldID = 0; - - try { - fieldID = Integer.parseInt(args[0]); - }catch (NumberFormatException e){ - log.error("Illegal field id -" + e.getMessage()); - return "ERROR querying "; - } - TableProto.Column queryCol = - TableProto.Column.newBuilder() - .setUint32(fieldID).build(); - List key = new ArrayList<>(); - key.add(queryCol); - switch (function){ - case "get": { - try { - TableProto.Row tableRow = stub.getRow(tableName,key); - if (tableRow.getSerializedSize() > 0) { - return tableRow.getColumns(1).getString(); - }else - { - return "No record found !"; - } - } catch (Exception invalidProtocolBufferException) { - invalidProtocolBufferException.printStackTrace(); - } - } - default: - log.error("No matching case for function:"+function); - return ""; - } - - } - - @java.lang.Override - public String getChaincodeID() { - return "TableExample"; - } - - public static void main(String[] args) throws Exception { - log.info("starting"); - new TableExample().start(args); - } - -}