chaincode/monnethic_functions.go
2019-04-06 19:23:19 +02:00

710 lines
22 KiB
Go

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())
}