From 9c53af96cf6283d1a10f9c97e5ebcea807ee4074 Mon Sep 17 00:00:00 2001 From: quentingaulene Date: Sat, 6 Apr 2019 19:23:19 +0200 Subject: [PATCH] code cleaning and structure --- monnethic.go | 1077 --------------------- monnethic_environment_&_strcture_build.go | 204 ++++ monnethic_functions.go | 710 ++++++++++++++ monnethic_use_test.go | 129 +++ 4 files changed, 1043 insertions(+), 1077 deletions(-) delete mode 100644 monnethic.go create mode 100644 monnethic_environment_&_strcture_build.go create mode 100644 monnethic_functions.go create mode 100644 monnethic_use_test.go diff --git a/monnethic.go b/monnethic.go deleted file mode 100644 index c0c25e9..0000000 --- a/monnethic.go +++ /dev/null @@ -1,1077 +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 - -//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 ( - "bytes" - "encoding/json" - "fmt" - "strconv" - "strings" - "time" - - "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"` - Balance float64 `json:"balance"` - 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 == "setUserPermission" { - // change the permission of an account - return t.setUserPermission(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 == "setBalanceOnWallet" { - // set a new balance to a wallet - return t.setBalanceOnWallet(stub, args) - } else if function == "transaction" { - // make a transaction of X units from a wallet to an other - return t.transaction(stub, args) - } else if function == "queryWalletsByOwner" { - // make a transaction of X units from a wallet to an other - return t.queryWalletsByOwner(stub, args) - } else if function == "queryWalletsByType" { - // make a transaction of X units from a wallet to an other - return t.queryWalletsByType(stub, args) - } else if function == "queryWallets" { - // make a transaction of X units from a wallet to an other - return t.queryWallets(stub, args) - } else if function == "getHistoryForWallet" { - // make a transaction of X units from a wallet to an other - return t.getHistoryForWallet(stub, args) - } else if function == "getAllEntities" { - // get All Entities of the present ledger - return t.getAllEntities(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) -} - - -// =========================================================== -// set a permission of an account by setting authorization to create a wallet -// =========================================================== -func (t *SimpleChaincode) setUserPermission(stub shim.ChaincodeStubInterface, args []string) pb.Response { - - // 0 1 - // "name", "bob" - if len(args) < 1 { - return shim.Error("Incorrect number of arguments. Expecting 2") - } - - userId := args[0] - - fmt.Println("- start setUserPermission ", userId) - - // ==== 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 wallet doesn't exists: " + userId) - return shim.Error("This wallet doesn't exists: " + userId) - } - - ownerToSet := owner{} - err = json.Unmarshal(ownerAsBytes, &ownerToSet) //unmarshal it aka JSON - if err != nil { - return shim.Error(err.Error()) - } - - //if walletToSet.Owner - ownerToSet.UserAuthorized = true //change the permission - - ownerJSONasBytes, _ := json.Marshal(ownerToSet) - err = stub.PutState(userId, ownerJSONasBytes) //rewrite the wallet - if err != nil { - return shim.Error(err.Error()) - } - fmt.Println("- end setUserPermission (success)") - 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 := args[2] - balance := 0.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, balance, 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 := 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) setBalanceOnWallet(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] - newBalance, err := strconv.ParseFloat(args[1], 64) - fmt.Println("- start setBalanceOnWallet ", walletId, newBalance) - - // ==== 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()) - } - - //if walletToSet.Owner - walletToSet.Balance = walletToSet.Balance + newBalance //change the balance - - walletJSONasBytes, _ := json.Marshal(walletToSet) - err = stub.PutState(walletId, walletJSONasBytes) //rewrite the wallet - if err != nil { - return shim.Error(err.Error()) - } - fmt.Println("- end setBalanceOnWallet (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.ParseFloat(args[2], 64) - - 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) - } - - walletBalanceToSet := wallet{} - err = json.Unmarshal(walletAsBytes, &walletBalanceToSet) //unmarshal it aka JSON - if err != nil { - return shim.Error(err.Error()) - } - - if walletBalanceToSet.Balance <= 0 { - return shim.Error("This wallet is not allowed to make a transaction:" + walletId) - } else { - walletBalanceToSet.Balance = walletBalanceToSet.Balance - transactionValue //change the balance - } - - walletJSONasBytes, _ := json.Marshal(walletBalanceToSet) - err = stub.PutState(walletId, walletJSONasBytes) //rewrite the wallet - if err != nil { - return shim.Error(err.Error()) - } - - walletTargetBalanceToSet := wallet{} - err = json.Unmarshal(walletTargetAsBytes, &walletTargetBalanceToSet) //unmarshal it aka JSON - if err != nil { - return shim.Error(err.Error()) - } - - walletTargetBalanceToSet.Balance = walletTargetBalanceToSet.Balance + transactionValue - - walletTargetJSONasBytes, _ := json.Marshal(walletTargetBalanceToSet) - err = stub.PutState(walletTargetId, walletTargetJSONasBytes) //rewrite the wallet - if err != nil { - return shim.Error(err.Error()) - } - - fmt.Println("- end setBalanceOnWallet (success)") - return shim.Success(nil) -} - - -func (t *SimpleChaincode) queryWalletsByOwner(stub shim.ChaincodeStubInterface, args []string) pb.Response { - - // 0 - // "bob" - if len(args) < 1 { - return shim.Error("Incorrect number of arguments. Expecting 1") - } - - owner := args[0] - - queryString := fmt.Sprintf("{\"selector\":{\"docType\":\"wallet\",\"owner\":\"%s\"}}", owner) - - queryResults, err := getQueryResultForQueryString(stub, queryString) - if err != nil { - return shim.Error(err.Error()) - } - return shim.Success(queryResults) -} - - -func (t *SimpleChaincode) queryWalletsByType(stub shim.ChaincodeStubInterface, args []string) pb.Response { - - // 0 - // "bob" - if len(args) < 1 { - return shim.Error("Incorrect number of arguments. Expecting 1") - } - - walletType := strings.ToLower(args[0]) - - queryString := fmt.Sprintf("{\"selector\":{\"docType\":\"wallet\",\"walletType\":\"%s\"}}", walletType) - - queryResults, err := getQueryResultForQueryString(stub, queryString) - if err != nil { - return shim.Error(err.Error()) - } - return shim.Success(queryResults) -} - - -// ===== Example: Ad hoc rich query ======================================================== -// queryMarbles uses a query string to perform a query for marbles. -// Query string matching state database syntax is passed in and executed as is. -// Supports ad hoc queries that can be defined at runtime by the client. -// If this is not desired, follow the queryMarblesForOwner example for parameterized queries. -// Only available on state databases that support rich query (e.g. CouchDB) -// ========================================================================================= -func (t *SimpleChaincode) queryWallets(stub shim.ChaincodeStubInterface, args []string) pb.Response { - - // 0 - // "queryString" - if len(args) < 1 { - return shim.Error("Incorrect number of arguments. Expecting 1") - } - - queryString := args[0] - - queryResults, err := getQueryResultForQueryString(stub, queryString) - if err != nil { - return shim.Error(err.Error()) - } - return shim.Success(queryResults) -} - - -func (t *SimpleChaincode) getHistoryForWallet(stub shim.ChaincodeStubInterface, args []string) pb.Response { - - if len(args) < 1 { - return shim.Error("Incorrect number of arguments. Expecting 1") - } - - walletId := args[0] - - fmt.Printf("- start getHistoryForWallet: %s\n", walletId) - - resultsIterator, err := stub.GetHistoryForKey(walletId) - if err != nil { - return shim.Error(err.Error()) - } - defer resultsIterator.Close() - - if resultsIterator.HasNext() { - modification, err := resultsIterator.Next() - if err != nil { - return shim.Error(err.Error()) - } - fmt.Println("Returning information related to", string(modification.Value)) - } - - // buffer is a JSON array containing historic values for the marble - var buffer bytes.Buffer - buffer.WriteString("[") - - bArrayMemberAlreadyWritten := false - for resultsIterator.HasNext() { - response, err := resultsIterator.Next() - if err != nil { - return shim.Error(err.Error()) - } - // Add a comma before array members, suppress it for the first array member - if bArrayMemberAlreadyWritten == true { - buffer.WriteString(",") - } - buffer.WriteString("{\"TxId\":") - buffer.WriteString("\"") - buffer.WriteString(response.TxId) - buffer.WriteString("\"") - - buffer.WriteString(", \"Value\":") - - // if it was a delete operation on given key, then we need to set the - //corresponding value null. Else, we will write the response.Value - //as-is (as the Value itself a JSON marble) - if response.IsDelete { - buffer.WriteString("null") - } else { - buffer.WriteString(string(response.Value)) - } - - buffer.WriteString(", \"Timestamp\":") - buffer.WriteString("\"") - buffer.WriteString(time.Unix(response.Timestamp.Seconds, int64(response.Timestamp.Nanos)).String()) - buffer.WriteString("\"") - - buffer.WriteString(", \"IsDelete\":") - buffer.WriteString("\"") - buffer.WriteString(strconv.FormatBool(response.IsDelete)) - buffer.WriteString("\"") - - buffer.WriteString("}") - bArrayMemberAlreadyWritten = true - } - buffer.WriteString("]") - - fmt.Printf("- getHistoryForWallet returning:\n%s\n", buffer.String()) - - return shim.Success(buffer.Bytes()) -} - - -func (t *SimpleChaincode) getAllEntities(stub shim.ChaincodeStubInterface, args []string) pb.Response { - - if len(args) < 2 { - return shim.Error("Incorrect number of arguments. Expecting 2") - } - - startKey := args[0] - endKey := args[1] - - resultsIterator, err := stub.GetStateByRange(startKey, endKey) - if err != nil { - return shim.Error(err.Error()) - } - defer resultsIterator.Close() - - buffer, err := constructQueryResponseFromIterator(resultsIterator) - if err != nil { - return shim.Error(err.Error()) - } - - fmt.Printf("- getAllEntities queryResult:\n%s\n", buffer.String()) - - return shim.Success(buffer.Bytes()) -} - - -func main() { - err := shim.Start(new(SimpleChaincode)) - if err != nil { - fmt.Printf("Error starting Simple chaincode: %s", err) - } -} - - -// =========================================================================================== -// constructQueryResponseFromIterator constructs a JSON array containing query results from -// a given result iterator -// =========================================================================================== -func constructQueryResponseFromIterator(resultsIterator shim.StateQueryIteratorInterface) (*bytes.Buffer, error) { - // buffer is a JSON array containing QueryResults - var buffer bytes.Buffer - buffer.WriteString("[") - - bArrayMemberAlreadyWritten := false - for resultsIterator.HasNext() { - queryResponse, err := resultsIterator.Next() - if err != nil { - return nil, err - } - // Add a comma before array members, suppress it for the first array member - if bArrayMemberAlreadyWritten == true { - buffer.WriteString(",") - } - buffer.WriteString("{\"Key\":") - buffer.WriteString("\"") - buffer.WriteString(queryResponse.Key) - buffer.WriteString("\"") - - buffer.WriteString(", \"Record\":") - // Record is a JSON object, so we write as-is - buffer.WriteString(string(queryResponse.Value)) - buffer.WriteString("}") - bArrayMemberAlreadyWritten = true - } - buffer.WriteString("]") - - return &buffer, nil -} - - -// ========================================================================================= -// getQueryResultForQueryString executes the passed in query string. -// Result set is built and returned as a byte array containing the JSON results. -// ========================================================================================= -func getQueryResultForQueryString(stub shim.ChaincodeStubInterface, queryString string) ([]byte, error) { - - fmt.Printf("- getQueryResultForQueryString queryString:\n%s\n", queryString) - - resultsIterator, err := stub.GetQueryResult(queryString) - if err != nil { - return nil, err - } - defer resultsIterator.Close() - - buffer, err := constructQueryResponseFromIterator(resultsIterator) - if err != nil { - return nil, err - } - - fmt.Printf("- getQueryResultForQueryString queryResult:\n%s\n", buffer.String()) - - return buffer.Bytes(), nil -} diff --git a/monnethic_environment_&_strcture_build.go b/monnethic_environment_&_strcture_build.go new file mode 100644 index 0000000..bae27f2 --- /dev/null +++ b/monnethic_environment_&_strcture_build.go @@ -0,0 +1,204 @@ +/* +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 ( + "bytes" + "encoding/json" + "fmt" + "strconv" + "strings" + "time" + + "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"` + UserPhone string `json:"userPhone"` + 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"` + Balance float64 `json:"balance"` + Owner string `json:"owner"` +} + + +func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response { + fmt.Println("monnethic Init") + 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 == "setUserPermission" { + // change the permission of an account + return t.setUserPermission(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 == "setBalanceOnWallet" { + // set a new balance to a wallet + return t.setBalanceOnWallet(stub, args) + } else if function == "transaction" { + // make a transaction of X units from a wallet to an other + return t.transaction(stub, args) + } else if function == "queryWalletsByOwner" { + // get all wallets of a user by querying his specific account + return t.queryWalletsByOwner(stub, args) + } else if function == "queryWalletsByType" { + // get all wallets of a specific wallet type by querying a specific type + return t.queryWalletsByType(stub, args) + } else if function == "queryWallets" { + // get a specific wallet + return t.queryWallets(stub, args) + } else if function == "getHistoryForWallet" { + // query the full state history of a wallet + return t.getHistoryForWallet(stub, args) + } else if function == "getAllEntities" { + // get All Entities of the present ledger + return t.getAllEntities(stub, args) + } + + return shim.Error("Invalid invoke function name. Expecting \"invoke\" \"delete\" \"query\" \"register\"") +} + + +func main() { + err := shim.Start(new(SimpleChaincode)) + if err != nil { + fmt.Printf("Error starting Simple chaincode: %s", err) + } +} + + +// =========================================================================================== +// constructQueryResponseFromIterator constructs a JSON array containing query results from +// a given result iterator +// =========================================================================================== +func constructQueryResponseFromIterator(resultsIterator shim.StateQueryIteratorInterface) (*bytes.Buffer, error) { + + // buffer is a JSON array containing QueryResults + var buffer bytes.Buffer + buffer.WriteString("[") + + bArrayMemberAlreadyWritten := false + for resultsIterator.HasNext() { + queryResponse, err := resultsIterator.Next() + if err != nil { + return nil, err + } + + // Add a comma before array members, suppress it for the first array member + if bArrayMemberAlreadyWritten == true { + buffer.WriteString(",") + } + + buffer.WriteString("{\"Key\":") + buffer.WriteString("\"") + buffer.WriteString(queryResponse.Key) + buffer.WriteString("\"") + + buffer.WriteString(", \"Record\":") + + // Record is a JSON object, so we write as-is + buffer.WriteString(string(queryResponse.Value)) + buffer.WriteString("}") + bArrayMemberAlreadyWritten = true + } + buffer.WriteString("]") + + return &buffer, nil +} + + +// ========================================================================================= +// getQueryResultForQueryString executes the passed in query string. +// Result set is built and returned as a byte array containing the JSON results. +// ========================================================================================= +func getQueryResultForQueryString(stub shim.ChaincodeStubInterface, queryString string) ([]byte, error) { + + fmt.Printf("- getQueryResultForQueryString queryString:\n%s\n", queryString) + + resultsIterator, err := stub.GetQueryResult(queryString) + if err != nil { + return nil, err + } + defer resultsIterator.Close() + + buffer, err := constructQueryResponseFromIterator(resultsIterator) + if err != nil { + return nil, err + } + + fmt.Printf("- getQueryResultForQueryString queryResult:\n%s\n", buffer.String()) + + return buffer.Bytes(), nil +} \ No newline at end of file diff --git a/monnethic_functions.go b/monnethic_functions.go new file mode 100644 index 0000000..8a3061d --- /dev/null +++ b/monnethic_functions.go @@ -0,0 +1,710 @@ +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") + } + + + 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) +} + + +// =========================================================== +// set a permission of an account by setting authorization to create a wallet +// =========================================================== +func (t *SimpleChaincode) setUserPermission(stub shim.ChaincodeStubInterface, args []string) pb.Response { + + // 0 1 + // "name", "bob" + if len(args) < 1 { + return shim.Error("Incorrect number of arguments. Expecting 2") + } + + userId := args[0] + + fmt.Println("- start setUserPermission ", userId) + + // ==== 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 wallet doesn't exists: " + userId) + return shim.Error("This wallet doesn't exists: " + userId) + } + + ownerToSet := owner{} + err = json.Unmarshal(ownerAsBytes, &ownerToSet) //unmarshal it aka JSON + if err != nil { + return shim.Error(err.Error()) + } + + //if walletToSet.Owner + ownerToSet.UserAuthorized = true //change the permission + + ownerJSONasBytes, _ := json.Marshal(ownerToSet) + err = stub.PutState(userId, ownerJSONasBytes) //rewrite the wallet + if err != nil { + return shim.Error(err.Error()) + } + fmt.Println("- end setUserPermission (success)") + 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") + } + + walletId := args[0] + walletType := strings.ToLower(args[1]) + owner := args[2] + balance := 0.0 + + if err != nil { + return shim.Error("3rd argument must be a numeric string") + } + + // ==== 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, balance, 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 { + + if len(args) < 2 { + return shim.Error("Incorrect number of arguments. Expecting 2") + } + + walletId := args[0] + newOwner := 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) setBalanceOnWallet(stub shim.ChaincodeStubInterface, args []string) pb.Response { + + if len(args) < 2 { + return shim.Error("Incorrect number of arguments. Expecting 2") + } + + walletId := args[0] + newBalance, err := strconv.ParseFloat(args[1], 64) + fmt.Println("- start setBalanceOnWallet ", walletId, newBalance) + + // ==== 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()) + } + + //if walletToSet.Owner + walletToSet.Balance = walletToSet.Balance + newBalance //change the balance + + walletJSONasBytes, _ := json.Marshal(walletToSet) + err = stub.PutState(walletId, walletJSONasBytes) //rewrite the wallet + if err != nil { + return shim.Error(err.Error()) + } + + fmt.Println("- end setBalanceOnWallet (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.ParseFloat(args[2], 64) + + 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) + } + + walletBalanceToSet := wallet{} + err = json.Unmarshal(walletAsBytes, &walletBalanceToSet) //unmarshal it aka JSON + if err != nil { + return shim.Error(err.Error()) + } + + if walletBalanceToSet.Balance <= 0 { + return shim.Error("This wallet is not allowed to make a transaction:" + walletId) + } else { + walletBalanceToSet.Balance = walletBalanceToSet.Balance - transactionValue //change the balance + } + + walletJSONasBytes, _ := json.Marshal(walletBalanceToSet) + err = stub.PutState(walletId, walletJSONasBytes) //rewrite the wallet + if err != nil { + return shim.Error(err.Error()) + } + + walletTargetBalanceToSet := wallet{} + err = json.Unmarshal(walletTargetAsBytes, &walletTargetBalanceToSet) //unmarshal it aka JSON + if err != nil { + return shim.Error(err.Error()) + } + + walletTargetBalanceToSet.Balance = walletTargetBalanceToSet.Balance + transactionValue + + walletTargetJSONasBytes, _ := json.Marshal(walletTargetBalanceToSet) + err = stub.PutState(walletTargetId, walletTargetJSONasBytes) //rewrite the wallet + if err != nil { + return shim.Error(err.Error()) + } + + fmt.Println("- end setBalanceOnWallet (success)") + return shim.Success(nil) +} + + +func (t *SimpleChaincode) queryWalletsByOwner(stub shim.ChaincodeStubInterface, args []string) pb.Response { + + if len(args) < 1 { + return shim.Error("Incorrect number of arguments. Expecting 1") + } + + owner := args[0] + + queryString := fmt.Sprintf("{\"selector\":{\"docType\":\"wallet\",\"owner\":\"%s\"}}", owner) + + queryResults, err := getQueryResultForQueryString(stub, queryString) + if err != nil { + return shim.Error(err.Error()) + } + + return shim.Success(queryResults) +} + + +func (t *SimpleChaincode) queryWalletsByType(stub shim.ChaincodeStubInterface, args []string) pb.Response { + + if len(args) < 1 { + return shim.Error("Incorrect number of arguments. Expecting 1") + } + + walletType := strings.ToLower(args[0]) + + queryString := fmt.Sprintf("{\"selector\":{\"docType\":\"wallet\",\"walletType\":\"%s\"}}", walletType) + + queryResults, err := getQueryResultForQueryString(stub, queryString) + if err != nil { + return shim.Error(err.Error()) + } + + return shim.Success(queryResults) +} + + +// ===== Example: Ad hoc rich query ======================================================== +// queryMarbles uses a query string to perform a query for marbles. +// Query string matching state database syntax is passed in and executed as is. +// Supports ad hoc queries that can be defined at runtime by the client. +// If this is not desired, follow the queryMarblesForOwner example for parameterized queries. +// Only available on state databases that support rich query (e.g. CouchDB) +// ========================================================================================= +func (t *SimpleChaincode) queryWallets(stub shim.ChaincodeStubInterface, args []string) pb.Response { + + // "queryString" + if len(args) < 1 { + return shim.Error("Incorrect number of arguments. Expecting 1") + } + + queryString := args[0] + + queryResults, err := getQueryResultForQueryString(stub, queryString) + if err != nil { + return shim.Error(err.Error()) + } + + return shim.Success(queryResults) +} + + +func (t *SimpleChaincode) getHistoryForWallet(stub shim.ChaincodeStubInterface, args []string) pb.Response { + + if len(args) < 1 { + return shim.Error("Incorrect number of arguments. Expecting 1") + } + + walletId := args[0] + + fmt.Printf("- start getHistoryForWallet: %s\n", walletId) + + resultsIterator, err := stub.GetHistoryForKey(walletId) + if err != nil { + return shim.Error(err.Error()) + } + defer resultsIterator.Close() + + if resultsIterator.HasNext() { + modification, err := resultsIterator.Next() + if err != nil { + return shim.Error(err.Error()) + } + fmt.Println("Returning information related to", string(modification.Value)) + } + + // buffer is a JSON array containing historic values for the marble + var buffer bytes.Buffer + buffer.WriteString("[") + + bArrayMemberAlreadyWritten := false + for resultsIterator.HasNext() { + response, err := resultsIterator.Next() + if err != nil { + return shim.Error(err.Error()) + } + + // Add a comma before array members, suppress it for the first array member + if bArrayMemberAlreadyWritten == true { + buffer.WriteString(",") + } + + buffer.WriteString("{\"TxId\":") + buffer.WriteString("\"") + buffer.WriteString(response.TxId) + buffer.WriteString("\"") + + buffer.WriteString(", \"Value\":") + + + // if it was a delete operation on given key, then we need to set the + //corresponding value null. Else, we will write the response.Value + //as-is (as the Value itself a JSON marble) + if response.IsDelete { + buffer.WriteString("null") + } else { + buffer.WriteString(string(response.Value)) + } + + buffer.WriteString(", \"Timestamp\":") + buffer.WriteString("\"") + buffer.WriteString(time.Unix(response.Timestamp.Seconds, int64(response.Timestamp.Nanos)).String()) + buffer.WriteString("\"") + + buffer.WriteString(", \"IsDelete\":") + buffer.WriteString("\"") + buffer.WriteString(strconv.FormatBool(response.IsDelete)) + buffer.WriteString("\"") + + buffer.WriteString("}") + bArrayMemberAlreadyWritten = true + } + + buffer.WriteString("]") + + fmt.Printf("- getHistoryForWallet returning:\n%s\n", buffer.String()) + return shim.Success(buffer.Bytes()) +} + + +func (t *SimpleChaincode) getAllEntities(stub shim.ChaincodeStubInterface, args []string) pb.Response { + + if len(args) < 2 { + return shim.Error("Incorrect number of arguments. Expecting 2") + } + + startKey := args[0] + endKey := args[1] + + resultsIterator, err := stub.GetStateByRange(startKey, endKey) + if err != nil { + return shim.Error(err.Error()) + } + defer resultsIterator.Close() + + buffer, err := constructQueryResponseFromIterator(resultsIterator) + if err != nil { + return shim.Error(err.Error()) + } + + fmt.Printf("- getAllEntities queryResult:\n%s\n", buffer.String()) + return shim.Success(buffer.Bytes()) +} \ No newline at end of file diff --git a/monnethic_use_test.go b/monnethic_use_test.go new file mode 100644 index 0000000..a104d01 --- /dev/null +++ b/monnethic_use_test.go @@ -0,0 +1,129 @@ +// 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) +} \ No newline at end of file