From 7744ecbffd25e94fc157c034747403ed3a88ad43 Mon Sep 17 00:00:00 2001 From: projet Date: Tue, 26 Mar 2019 22:57:19 +0100 Subject: [PATCH] chaincode useful version 1 --- chaincode_example02.go | 226 ------------ monnethic.go | 781 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 781 insertions(+), 226 deletions(-) delete mode 100644 chaincode_example02.go create mode 100644 monnethic.go diff --git a/chaincode_example02.go b/chaincode_example02.go deleted file mode 100644 index e509d6d..0000000 --- a/chaincode_example02.go +++ /dev/null @@ -1,226 +0,0 @@ -/* -Licensed to the Apache Software Foundation (ASF) under one -or more contributor license agreements. See the NOTICE file -distributed with this work for additional information -regarding copyright ownership. The ASF licenses this file -to you 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 ( - "errors" - "fmt" - "strconv" - - "github.com/hyperledger/fabric/core/chaincode/shim" -) - -// SimpleChaincode example simple Chaincode implementation -type SimpleChaincode struct { -} - -func (t *SimpleChaincode) Init(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) { - fmt.Printf("Init called, initializing chaincode") - - var A, B string // Entities - var Aval, Bval int // Asset holdings - var err error - - if len(args) != 4 { - return nil, errors.New("Incorrect number of arguments. Expecting 4") - } - - // Initialize the chaincode - A = args[0] - Aval, err = strconv.Atoi(args[1]) - if err != nil { - return nil, errors.New("Expecting integer value for asset holding") - } - B = args[2] - Bval, err = strconv.Atoi(args[3]) - if err != nil { - return nil, errors.New("Expecting integer value for asset holding") - } - fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval) - - // Write the state to the ledger - err = stub.PutState(A, []byte(strconv.Itoa(Aval))) - if err != nil { - return nil, err - } - - err = stub.PutState(B, []byte(strconv.Itoa(Bval))) - if err != nil { - return nil, err - } - - return nil, nil -} - -// Transaction makes payment of X units from A to B -func (t *SimpleChaincode) invoke(stub *shim.ChaincodeStub, args []string) ([]byte, error) { - fmt.Printf("Running invoke") - - var A, B string // Entities - var Aval, Bval int // Asset holdings - var X int // Transaction value - var err error - - if len(args) != 3 { - return nil, errors.New("Incorrect number of arguments. Expecting 3") - } - - A = args[0] - B = args[1] - - // Get the state from the ledger - // TODO: will be nice to have a GetAllState call to ledger - Avalbytes, err := stub.GetState(A) - if err != nil { - return nil, errors.New("Failed to get state") - } - if Avalbytes == nil { - return nil, errors.New("Entity not found") - } - Aval, _ = strconv.Atoi(string(Avalbytes)) - - Bvalbytes, err := stub.GetState(B) - if err != nil { - return nil, errors.New("Failed to get state") - } - if Bvalbytes == nil { - return nil, errors.New("Entity not found") - } - Bval, _ = strconv.Atoi(string(Bvalbytes)) - - // Perform the execution - X, err = strconv.Atoi(args[2]) - Aval = Aval - X - Bval = Bval + X - fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval) - - // Write the state back to the ledger - err = stub.PutState(A, []byte(strconv.Itoa(Aval))) - if err != nil { - return nil, err - } - - err = stub.PutState(B, []byte(strconv.Itoa(Bval))) - if err != nil { - return nil, err - } - - return nil, nil -} - -// Deletes an entity from state -func (t *SimpleChaincode) delete(stub *shim.ChaincodeStub, args []string) ([]byte, error) { - fmt.Printf("Running delete") - - if len(args) != 1 { - return nil, errors.New("Incorrect number of arguments. Expecting 3") - } - - A := args[0] - - // Delete the key from the state in ledger - err := stub.DelState(A) - if err != nil { - return nil, errors.New("Failed to delete state") - } - - 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.ChaincodeStub, function string, args []string) ([]byte, error) { - fmt.Printf("Invoke called, determining function") - - // Handle different functions - if function == "invoke" { - // Transaction makes payment of X units from A to B - fmt.Printf("Function is invoke") - return t.invoke(stub, args) - } else if function == "init" { - fmt.Printf("Function is init") - return t.Init(stub, function, args) - } else if function == "delete" { - // Deletes an entity from its state - fmt.Printf("Function is delete") - return t.delete(stub, args) - } - - return nil, errors.New("Received unknown function invocation") -} - -func (t* SimpleChaincode) Run(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) { - fmt.Printf("Run called, passing through to Invoke (same function)") - - // Handle different functions - if function == "invoke" { - // Transaction makes payment of X units from A to B - fmt.Printf("Function is invoke") - return t.invoke(stub, args) - } else if function == "init" { - fmt.Printf("Function is init") - return t.Init(stub, function, args) - } else if function == "delete" { - // Deletes an entity from its state - fmt.Printf("Function is delete") - return t.delete(stub, args) - } - - return nil, errors.New("Received unknown function invocation") -} - -// Query callback representing the query of a chaincode -func (t *SimpleChaincode) Query(stub *shim.ChaincodeStub, function string, args []string) ([]byte, error) { - fmt.Printf("Query called, determining function") - - if function != "query" { - fmt.Printf("Function is query") - return nil, errors.New("Invalid query function name. Expecting \"query\"") - } - var A string // Entities - var err error - - if len(args) != 1 { - return nil, errors.New("Incorrect number of arguments. Expecting name of the person to query") - } - - A = args[0] - - // Get the state from the ledger - Avalbytes, err := stub.GetState(A) - if err != nil { - jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}" - return nil, errors.New(jsonResp) - } - - if Avalbytes == nil { - jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}" - return nil, errors.New(jsonResp) - } - - jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}" - fmt.Printf("Query Response:%s\n", jsonResp) - return Avalbytes, nil -} - -func main() { - err := shim.Start(new(SimpleChaincode)) - if err != nil { - fmt.Printf("Error starting Simple chaincode: %s", err) - } -} \ No newline at end of file diff --git a/monnethic.go b/monnethic.go new file mode 100644 index 0000000..6bbcbcc --- /dev/null +++ b/monnethic.go @@ -0,0 +1,781 @@ +/* +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 + +//WARNING - this chaincode's ID is hard-coded in chaincode_example04 to illustrate one way of +//calling chaincode from a chaincode. If this example is modified, chaincode_example04.go has +//to be modified as well with the new ID of chaincode_example02. +//chaincode_example05 show's how chaincode ID can be passed in as a parameter instead of +//hard-coding. + +import ( + "encoding/json" + "fmt" + "strconv" + "strings" + + "github.com/hyperledger/fabric/core/chaincode/shim" + pb "github.com/hyperledger/fabric/protos/peer" +) + + +// SimpleChaincode example simple Chaincode implementation +type SimpleChaincode struct { +} + +type owner struct { + ObjectType string `json:"docType"` + UserId string `json:"userId"` + UserName string `json:"userName"` + UserFirstName string `json:"userFirstName"` +// Mail string `json:"userMail"` + UserPhone string `json:"userPhone"` +// Address string `json:"userAddress"` +// PostalCode string `json:"userPostalCode"` +// City int `json:"userCity"` + UserAssociation string `json:"userAssociation"` + UserAuthorized bool `json:"userAuthorized"` +} + +type wallet struct { + ObjectType string `json:"docType"` //docType is used to distinguish the various type$ + Id string `json:"id"` //the fieldtags are needed to keep case from bounci$ + WalletType string `json:"walletType"` + Sold int `json:"sold"` + Owner string `json:"owner"` +} + + +func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response { + fmt.Println("ex02 Init") + _, args := stub.GetFunctionAndParameters() + var A string // Entities + var Aval int // Asset holdings + var err error + + if len(args) != 2 { + return shim.Error("Incorrect number of arguments. Expecting 2") + } + + // Initialize the chaincode + A = args[0] + Aval, err = strconv.Atoi(args[1]) + if err != nil { + return shim.Error("Expecting integer value for asset holding") + } + fmt.Printf("Aval = %d\n", Aval) + + // Write the state to the ledger + err = stub.PutState(A, []byte(strconv.Itoa(Aval))) + if err != nil { + return shim.Error(err.Error()) + } + + return shim.Success(nil) +} + + +func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { + fmt.Println("ex02 Invoke") + function, args := stub.GetFunctionAndParameters() + if function == "invoke" { + // Make payment of X units from A to B + return t.invoke(stub, args) + } else if function == "delete" { + // Deletes an entity from its state + return t.delete(stub, args) + } else if function == "query" { + // the old "Query" is now implemtned in invoke + return t.query(stub, args) + } else if function == "register" { + // register a new user into the ledger + return t.register(stub, args) + } else if function == "registerUser" { + // initiate a new account + return t.registerUser(stub, args) + } else if function == "readUser" { + // query a specific user from the ledger + return t.readUser(stub, args) + } else if function == "deleteUser" { + // delete a specific user from the ledger + return t.deleteUser(stub, args) + } else if function == "initWallet" { + // initiate a new wallet + return t.initWallet(stub, args) + } else if function == "readWallet" { + // query a specific wallet from the ledger + return t.readWallet(stub, args) + } else if function == "deleteWallet" { + // delete a specific wallet from the ledger + return t.deleteWallet(stub, args) + } else if function == "transferWallet" { + // change the owner of a specific wallet + return t.transferWallet(stub, args) + } else if function == "setSoldOnWallet" { + // set a new sold to a wallet + return t.setSoldOnWallet(stub, args) + } else if function == "transaction" { + // make a transaction of X units from a wallet to an other + return t.transaction(stub, args) + } + + return shim.Error("Invalid invoke function name. Expecting \"invoke\" \"delete\" \"query\" \"register\"") +} + + +// Transaction makes payment of X units from A to B +func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response { + var A, B string // Entities + var Aval, Bval int // Asset holdings + var X int // Transaction value + var err error + + if len(args) != 3 { + return shim.Error("Incorrect number of arguments. Expecting 3") + } + + A = args[0] + B = args[1] + + // Get the state from the ledger + // TODO: will be nice to have a GetAllState call to ledger + Avalbytes, err := stub.GetState(A) + if err != nil { + return shim.Error("Failed to get state") + } + if Avalbytes == nil { + return shim.Error("Entity not found") + } + Aval, _ = strconv.Atoi(string(Avalbytes)) + + Bvalbytes, err := stub.GetState(B) + if err != nil { + return shim.Error("Failed to get state") + } + if Bvalbytes == nil { + return shim.Error("Entity not found") + } + Bval, _ = strconv.Atoi(string(Bvalbytes)) + + // Perform the execution + X, err = strconv.Atoi(args[2]) + if err != nil { + return shim.Error("Invalid transaction amount, expecting a integer value") + } + Aval = Aval - X + Bval = Bval + X + fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval) + + // Write the state back to the ledger + err = stub.PutState(A, []byte(strconv.Itoa(Aval))) + if err != nil { + return shim.Error(err.Error()) + } + + err = stub.PutState(B, []byte(strconv.Itoa(Bval))) + if err != nil { + return shim.Error(err.Error()) + } + + return shim.Success(nil) +} + + +// Deletes an entity from state +func (t *SimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response { + if len(args) != 1 { + return shim.Error("Incorrect number of arguments. Expecting 1") + } + + A := args[0] + + // Delete the key from the state in ledger + err := stub.DelState(A) + if err != nil { + return shim.Error("Failed to delete state") + } + + return shim.Success(nil) +} + + +// query callback representing the query of a chaincode +func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response { + var A string // Entities + var err error + + if len(args) != 1 { + return shim.Error("Incorrect number of arguments. Expecting name of the person to query") + } + + A = args[0] + + // Get the state from the ledger + Avalbytes, err := stub.GetState(A) + if err != nil { + jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}" + return shim.Error(jsonResp) + } + + if Avalbytes == nil { + jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}" + return shim.Error(jsonResp) + } + + jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}" + fmt.Printf("Query Response:%s\n", jsonResp) + return shim.Success(Avalbytes) +} + + +func (t *SimpleChaincode) register(stub shim.ChaincodeStubInterface, args []string) pb.Response { + var A string // Entities + var Aval int // Asset holdings + var err error + + if len(args) != 2 { + return shim.Error("Incorrect number of arguments. Expecting 2") + } + + // Initialize the chaincode + A = args[0] + Aval, err = strconv.Atoi(args[1]) + if err != nil { + return shim.Error("Expecting integer value for asset holding") + } + fmt.Printf("Aval = %d\n", Aval) + + // Write the state to the ledger + err = stub.PutState(A, []byte(strconv.Itoa(Aval))) + if err != nil { + return shim.Error(err.Error()) + } + return shim.Success(nil) +} + + +func (t *SimpleChaincode) registerUser(stub shim.ChaincodeStubInterface, args []string) pb.Response { + var err error + + if len(args) != 5 { + return shim.Error("Incorrect number of arguments. Expecting 6") + } + + // ==== Input sanitation ==== + fmt.Println("- start init user") + if len(args[0]) <= 0 { + return shim.Error("1st argument must be a non-empty string") + } + if len(args[1]) <= 0 { + return shim.Error("2nd argument must be a non-empty string") + } + if len(args[2]) <= 0 { + return shim.Error("3rd argument must be a non-empty string") + } + if len(args[3]) <= 0 { + return shim.Error("4th argument must be a non-empty string") + } + if len(args[4]) <= 0 { + return shim.Error("5th argument must be a non-empty string") + } + //if len(args[5]) <= 0 { + // return shim.Error("6th argument must be a non-empty string") + //} + + + userId := args[0] + userName := strings.ToLower(args[1]) + userFirstName := strings.ToLower(args[2]) + userPhone := strings.ToLower(args[3]) + userAssociation := strings.ToLower(args[4]) + userAuthorized := false + + if err != nil { + return shim.Error("3rd argument must be a numeric string") + } + + // ==== Check if user already exists ==== + ownerAsBytes, err := stub.GetState(userId) + if err != nil { + return shim.Error("Failed to get user: " + err.Error()) + } else if ownerAsBytes != nil { + fmt.Println("This user already exists: " + userId) + return shim.Error("This user already exists: " + userId) + } + + // ==== Create wallet object and marshal to JSON ==== + objectType := "owner" + owner := &owner{objectType, userId, userName, userFirstName, userPhone, userAssociation, userAuthorized} + ownerJSONasBytes, err := json.Marshal(owner) + if err != nil { + return shim.Error(err.Error()) + } + //Alternatively, build the marble json string manually if you don't want to us$ + //walletJSONasString := `{"docType":"Wallet", "id": "` + "walletType + `", "s$ + //walletJSONasBytes := []byte(str) + + // === Save user to state === + err = stub.PutState(userId, ownerJSONasBytes) + if err != nil { + return shim.Error(err.Error()) + } + + // ==== Index the wallet to enable type-based range queries, e.g. return all $ + // An 'index' is a normal key/value entry in state. + // The key is a composite key, with the elements that you want to range query$ + // In our case, the composite key is based on indexName~typeWallet~id. + // This will enable very efficient state range queries based on composite key$ + indexName := "userAssociation~userId" + ownerAssociationIdIndexKey, err := stub.CreateCompositeKey(indexName, []string{owner.UserAssociation, owner.UserId}) + if err != nil { + return shim.Error(err.Error()) + } + // Save index entry to state. Only the key name is needed, no need to store a$ + // Note - passing a 'nil' value will effectively delete the key from state, t$ + value := []byte{0x00} + stub.PutState(ownerAssociationIdIndexKey, value) + + // ==== User saved and indexed. Return success ==== + fmt.Println("- end init user") + return shim.Success(nil) +} + + +//=============================================== +// readUser - read a user from chaincode state +//=============================================== +func (t *SimpleChaincode) readUser(stub shim.ChaincodeStubInterface, args []string) pb.Response { + var userId, jsonResp string + var err error + + if len(args) != 1 { + return shim.Error("Incorrect number of arguments. Expecting name of the user to query") + } + + userId = args[0] + valAsbytes, err := stub.GetState(userId) //get the wallet from chaincode state + if err != nil { + jsonResp = "{\"Error\":\"Failed to get state for " + userId + "\"}" + return shim.Error(jsonResp) + } else if valAsbytes == nil { + jsonResp = "{\"Error\":\"Wallet does not exist: " + userId + "\"}" + return shim.Error(jsonResp) + } + + return shim.Success(valAsbytes) +} + + +// ================================================== +// delete - remove a wallet key/value pair from state +// ================================================== +func (t *SimpleChaincode) deleteUser(stub shim.ChaincodeStubInterface, args []string) pb.Response { + var jsonResp string + var ownerJSON owner + if len(args) != 1 { + return shim.Error("Incorrect number of arguments. Expecting 1") + } + userId := args[0] + + // to maintain the color~name index, we need to read the marble first and get its color + valAsbytes, err := stub.GetState(userId) //get the marble from chaincode state + if err != nil { + jsonResp = "{\"Error\":\"Failed to get state for " + userId + "\"}" + return shim.Error(jsonResp) + } else if valAsbytes == nil { + jsonResp = "{\"Error\":\"User does not exist: " + userId + "\"}" + return shim.Error(jsonResp) + } + + err = json.Unmarshal([]byte(valAsbytes), &ownerJSON) + + if err != nil { + jsonResp = "{\"Error\":\"Failed to get state for " + userId + "\"}" + return shim.Error(jsonResp) + } else if valAsbytes == nil { + jsonResp = "{\"Error\":\"User does not exist: " + userId + "\"}" + return shim.Error(jsonResp) + } + + err = json.Unmarshal([]byte(valAsbytes), &ownerJSON) + if err != nil { + jsonResp = "{\"Error\":\"Failed to decode JSON of: " + userId + "\"}" + return shim.Error(jsonResp) + } + + err = stub.DelState(userId) //remove the owner from chaincode state + if err != nil { + return shim.Error("Failed to delete state:" + err.Error()) + } + + // maintain the index + indexName := "userAssociation~userId" + ownerAssociationIdIndexKey, err := stub.CreateCompositeKey(indexName, []string{ownerJSON.UserAssociation, ownerJSON.UserId}) + if err != nil { + return shim.Error(err.Error()) + } + + // Delete index entry to state. + err = stub.DelState(ownerAssociationIdIndexKey) + if err != nil { + return shim.Error("Failed to delete state:" + err.Error()) + } + return shim.Success(nil) +} + + +func (t *SimpleChaincode) initWallet(stub shim.ChaincodeStubInterface, args []string) pb.Response { + var err error + + if len(args) != 3 { + return shim.Error("Incorrect number of arguments. Expecting 4") + } + + // ==== Input sanitation ==== + fmt.Println("- start init wallet") + if len(args[0]) <= 0 { + return shim.Error("1st argument must be a non-empty string") + } + if len(args[1]) <= 0 { + return shim.Error("2nd argument must be a non-empty string") + } + if len(args[2]) <= 0 { + return shim.Error("3rd argument must be a non-empty string") + } + //if len(args[3]) <= 0 { + // return shim.Error("4th argument must be a non-empty string") + //} + //if len(args[4]) <= 0 { + // return shim.Error("4th argument must be a non-empty string") + //} + + walletId := args[0] + walletType := strings.ToLower(args[1]) + owner := strings.ToLower(args[2]) + sold := 0 + //authorized_by_association := args[4] + + if err != nil { + return shim.Error("3rd argument must be a numeric string") + } + + //if owner.UserAssociation != authorized_by_association { + // return shim.Error("The association '" + authorized_by_association + "'cannot authorize creation for '" + owner.UserId + "'.") + //} + + // ==== Check if user already exists ==== + ownerAsBytes, err := stub.GetState(owner) + if err != nil { + return shim.Error("Failed to get owner: " + err.Error()) + } else if ownerAsBytes == nil { + fmt.Println("This user doesn't exists: " + owner) + return shim.Error("This user doesn't exists: " + owner) + } + + // ==== Check if wallet already exists ==== + walletAsBytes, err := stub.GetState(walletId) + if err != nil { + return shim.Error("Failed to get wallet: " + err.Error()) + } else if walletAsBytes != nil { + fmt.Println("This wallet already exists: " + walletId) + return shim.Error("This wallet already exists: " + walletId) + } + + // ==== Create wallet object and marshal to JSON ==== + objectType := "wallet" + wallet := &wallet{objectType, walletId, walletType, sold, owner} + walletJSONasBytes, err := json.Marshal(wallet) + if err != nil { + return shim.Error(err.Error()) + } + + //Alternatively, build the marble json string manually if you don't want to use struct marshalling + //walletJSONasString := `{"docType":"Wallet", "id": "` + "walletType + `", "sold": `, strconv.Itoa(size) , `"owner": "` + owner + `"}` + //walletJSONasBytes := []byte(str) + + // === Save wallet to state === + err = stub.PutState(walletId, walletJSONasBytes) + if err != nil { + return shim.Error(err.Error()) + } + + // ==== Index the wallet to enable type-based range queries, e.g. return all clients wallets ==== + // An 'index' is a normal key/value entry in state. + // The key is a composite key, with the elements that you want to range query on listed first. + // In our case, the composite key is based on indexName~typeWallet~id. + // This will enable very efficient state range queries based on composite keys matching indexName~type~* + indexName := "typeWallet~id" + walletTypeNameIndexKey, err := stub.CreateCompositeKey(indexName, []string{wallet.WalletType, wallet.Id}) + if err != nil { + return shim.Error(err.Error()) + } + + // Save index entry to state. Only the key name is needed, no need to store a duplicate copy of the marble. + // Note - passing a 'nil' value will effectively delete the key from state, therefore we pass null character as value + value := []byte{0x00} + stub.PutState(walletTypeNameIndexKey, value) + + // ==== Wallet saved and indexed. Return success ==== + fmt.Println("- end init wallet") + return shim.Success(nil) +} + + +// =============================================== +// readWallet - read a wallet from chaincode state +// =============================================== +func (t *SimpleChaincode) readWallet(stub shim.ChaincodeStubInterface, args []string) pb.Response { + var id, jsonResp string + var err error + + if len(args) != 1 { + return shim.Error("Incorrect number of arguments. Expecting name of the wallet to query") + } + + id = args[0] + valAsbytes, err := stub.GetState(id) //get the wallet from chaincode state + if err != nil { + jsonResp = "{\"Error\":\"Failed to get state for " + id + "\"}" + return shim.Error(jsonResp) + } else if valAsbytes == nil { + jsonResp = "{\"Error\":\"Wallet does not exist: " + id + "\"}" + return shim.Error(jsonResp) + } + + return shim.Success(valAsbytes) +} + +// ================================================== +// delete - remove a wallet key/value pair from state +// ================================================== +func (t *SimpleChaincode) deleteWallet(stub shim.ChaincodeStubInterface, args []string) pb.Response { + var jsonResp string + var walletJSON wallet + if len(args) != 1 { + return shim.Error("Incorrect number of arguments. Expecting 1") + } + Id := args[0] + + // to maintain the color~name index, we need to read the marble first and get its color + valAsbytes, err := stub.GetState(Id) //get the marble from chaincode state + if err != nil { + jsonResp = "{\"Error\":\"Failed to get state for " + Id + "\"}" + return shim.Error(jsonResp) + } else if valAsbytes == nil { + jsonResp = "{\"Error\":\"Wallet does not exist: " + Id + "\"}" + return shim.Error(jsonResp) + } + + err = json.Unmarshal([]byte(valAsbytes), &walletJSON) + + if err != nil { + jsonResp = "{\"Error\":\"Failed to get state for " + Id + "\"}" + return shim.Error(jsonResp) + } else if valAsbytes == nil { + jsonResp = "{\"Error\":\"Wallet does not exist: " + Id + "\"}" + return shim.Error(jsonResp) + } + + err = json.Unmarshal([]byte(valAsbytes), &walletJSON) + if err != nil { + jsonResp = "{\"Error\":\"Failed to decode JSON of: " + Id + "\"}" + return shim.Error(jsonResp) + } + + err = stub.DelState(Id) //remove the wallet from chaincode state + if err != nil { + return shim.Error("Failed to delete state:" + err.Error()) + } + + // maintain the index + indexName := "typeWallet~id" + walletTypeNameIndexKey, err := stub.CreateCompositeKey(indexName, []string{walletJSON.WalletType, walletJSON.Id}) + if err != nil { + return shim.Error(err.Error()) + } + + // Delete index entry to state. + err = stub.DelState(walletTypeNameIndexKey) + if err != nil { + return shim.Error("Failed to delete state:" + err.Error()) + } + return shim.Success(nil) +} + + +// =========================================================== +// transfer a wallet by setting a new owner name on the wallet +// =========================================================== +func (t *SimpleChaincode) transferWallet(stub shim.ChaincodeStubInterface, args []string) pb.Response { + + // 0 1 + // "name", "bob" + if len(args) < 2 { + return shim.Error("Incorrect number of arguments. Expecting 2") + } + + walletId := args[0] + newOwner := strings.ToLower(args[1]) + fmt.Println("- start transferWallet ", walletId, newOwner) + + // ==== Check if user already exists ==== + ownerAsBytes, err := stub.GetState(newOwner) + if err != nil { + return shim.Error("Failed to get user: " + err.Error()) + } else if ownerAsBytes == nil { + fmt.Println("This user doesn't exists: " + newOwner) + return shim.Error("This user doesn't exists: " + newOwner) + } + + + walletAsBytes, err := stub.GetState(walletId) + + if err != nil { + return shim.Error("Failed to get wallet:" + err.Error()) + } else if walletAsBytes == nil { + return shim.Error("wallet does not exist") + } + + walletToTransfer := wallet{} + err = json.Unmarshal(walletAsBytes, &walletToTransfer) //unmarshal it aka JSON + if err != nil { + return shim.Error(err.Error()) + } + walletToTransfer.Owner = newOwner //change the owner + + walletJSONasBytes, _ := json.Marshal(walletToTransfer) + err = stub.PutState(walletId, walletJSONasBytes) //rewrite the wallet + if err != nil { + return shim.Error(err.Error()) + } + + fmt.Println("- end transferWallet (success)") + return shim.Success(nil) +} + + +// =========================================================== +// set a sold of a wallet by setting a new owner name on the wallet +// =========================================================== +func (t *SimpleChaincode) setSoldOnWallet(stub shim.ChaincodeStubInterface, args []string) pb.Response { + + // 0 1 + // "name", "bob" + if len(args) < 2 { + return shim.Error("Incorrect number of arguments. Expecting 2") + } + + walletId := args[0] + newSold, err := strconv.Atoi(args[1]) + fmt.Println("- start setSoldOnWallet ", walletId, newSold) + + // ==== Check if wallet already exists ==== + walletAsBytes, err := stub.GetState(walletId) + if err != nil { + return shim.Error("Failed to get wallet: " + err.Error()) + } else if walletAsBytes == nil { + fmt.Println("This wallet doesn't exists: " + walletId) + return shim.Error("This wallet doesn't exists: " + walletId) + } + + walletToSet := wallet{} + err = json.Unmarshal(walletAsBytes, &walletToSet) //unmarshal it aka JSON + if err != nil { + return shim.Error(err.Error()) + } + walletToSet.Sold = newSold //change the sold + + walletJSONasBytes, _ := json.Marshal(walletToSet) + err = stub.PutState(walletId, walletJSONasBytes) //rewrite the wallet + if err != nil { + return shim.Error(err.Error()) + } + fmt.Println("- end setSoldOnWallet (success)") + return shim.Success(nil) +} + + +// Transaction makes payment of X units from A to B +func (t *SimpleChaincode) transaction(stub shim.ChaincodeStubInterface, args []string) pb.Response { + + if len(args) != 3 { + return shim.Error("Incorrect number of arguments. Expecting 3") + } + + walletId := args[0] + walletTargetId := args[1] + transactionValue, err := strconv.Atoi(args[2]) + + fmt.Println("- start transaction ", walletId, transactionValue) + + // ==== Check if wallet already exists ==== + walletAsBytes, err := stub.GetState(walletId) + if err != nil { + return shim.Error("Failed to get wallet: " + err.Error()) + } else if walletAsBytes == nil { + fmt.Println("This wallet doesn't exists: " + walletId) + return shim.Error("This wallet doesn't exists: " + walletId) + } + + // ==== Check if wallet already exists ==== + walletTargetAsBytes, err := stub.GetState(walletTargetId) + if err != nil { + return shim.Error("Failed to get wallet: " + err.Error()) + } else if walletTargetAsBytes == nil { + fmt.Println("This wallet doesn't exists: " + walletTargetId) + return shim.Error("This wallet doesn't exists: " + walletTargetId) + } + + walletSoldToSet := wallet{} + err = json.Unmarshal(walletAsBytes, &walletSoldToSet) //unmarshal it aka JSON + if err != nil { + return shim.Error(err.Error()) + } + + walletSoldToSet.Sold = walletSoldToSet.Sold - transactionValue //change the sold + + walletJSONasBytes, _ := json.Marshal(walletSoldToSet) + err = stub.PutState(walletId, walletJSONasBytes) //rewrite the wallet + if err != nil { + return shim.Error(err.Error()) + } + + walletTargetSoldToSet := wallet{} + err = json.Unmarshal(walletTargetAsBytes, &walletTargetSoldToSet) //unmarshal it aka JSON + if err != nil { + return shim.Error(err.Error()) + } + + walletTargetSoldToSet.Sold = walletTargetSoldToSet.Sold + transactionValue + + walletTargetJSONasBytes, _ := json.Marshal(walletTargetSoldToSet) + err = stub.PutState(walletTargetId, walletTargetJSONasBytes) //rewrite the wallet + if err != nil { + return shim.Error(err.Error()) + } + + fmt.Println("- end setSoldOnWallet (success)") + return shim.Success(nil) +} + + +func main() { + err := shim.Start(new(SimpleChaincode)) + if err != nil { + fmt.Printf("Error starting Simple chaincode: %s", err) + } +}