chaincode/develop/Ledger_Writer_Class.go
2018-11-11 19:40:26 +01:00

614 lines
18 KiB
Go

package main
import (
"encoding/json"
"fmt"
"strconv"
"strings"
"github.com/hyperledger/fabric/core/chaincode/shim"
pb "github.com/hyperledger/fabric/protos/peer"
)
// ============================================================================================================================
// write() - genric write variable into ledger
//
// Shows Off PutState() - writting a key/value into the ledger
//
// Inputs - Array of strings
// 0 , 1
// key , value
// "abc" , "test"
// ============================================================================================================================
func write(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var key, value string
var err error
fmt.Println("starting write")
if len(args) != 2 {
return shim.Error("Incorrect number of arguments. Expecting 2. key of the variable and value to set")
}
// input sanitation
err = sanitize_arguments(args)
if err != nil {
return shim.Error(err.Error())
}
key = args[0]
value = args[1]
err = stub.PutState(key, []byte(value)) //write the variable into the ledger
if err != nil {
return shim.Error(err.Error())
}
fmt.Println("- end write")
return shim.Success(nil)
}
// ============================================================================================================================
// delete_wallet() - remove a wallet from state and from wallet index
//
// Shows Off DelState() - "removing" a key/value from the ledger
//
// Inputs - Array of strings
// 0 , 1
// id , authorized_by_association
// ============================================================================================================================
func delete_wallet(stub shim.ChaincodeStubInterface, args []string) (pb.Response) {
fmt.Println("starting delete_wallet")
if len(args) != 2 {
return shim.Error("Incorrect number of arguments. Expecting 2")
}
// input sanitation
err := sanitize_arguments(args)
if err != nil {
return shim.Error(err.Error())
}
id := args[0]
authorized_by_association := args[1]
// get the wallet
wallet, err := get_wallet(stub, id)
if err != nil{
fmt.Println("Failed to find wallet by id " + id)
return shim.Error(err.Error())
}
// check authorizing organisation
if wallet.Owner.Association != authorized_by_association{
return shim.Error("The association '" + authorized_by_association + "' cannot authorize deletion for '" + wallet.Owner.Association + "'.")
}
// remove the wallet
err = stub.DelState(id) //remove the key from chaincode state
if err != nil {
return shim.Error("Failed to delete state")
}
fmt.Println("- end delete_wallet")
return shim.Success(nil)
}
// ============================================================================================================================
// delete_owner() - remove an owner from state and from owner index
//
// ============================================================================================================================
func delete_owner(stub shim.ChaincodeStubInterface, args []string) (pb.Response) {
fmt.Println("starting delete_owner")
if len(args) != 2 {
return shim.Error("Incorrect number of arguments. Expecting 2")
}
// input sanitation
err := sanitize_arguments(args)
if err != nil {
return shim.Error(err.Error())
}
id := args[0]
authorized_by_association := args[1]
// get the owner
owner, err := get_owner(stub, id)
if err != nil{
fmt.Println("Failed to find owner by id " + id)
return shim.Error(err.Error())
}
// check authorizing organisation
if Owner.Association != authorized_by_association{
return shim.Error("The association '" + authorized_by_association + "' cannot authorize deletion for '" + Owner.Association + "'.")
}
// remove the owner
err = stub.DelState(id) //remove the key from chaincode state
if err != nil {
return shim.Error("Failed to delete state")
}
fmt.Println("- end delete_owner")
return shim.Success(nil)
}
// ============================================================================================================================
// delete_beneficiary() - remove a beneficiary from state and from beneficiary index
//
// ============================================================================================================================
func delete_beneficiary(stub shim.ChaincodeStubInterface, args []string) (pb.Response) {
fmt.Println("starting delete_beneficiary")
if len(args) != 2 {
return shim.Error("Incorrect number of arguments. Expecting 2")
}
// input sanitation
err := sanitize_arguments(args)
if err != nil {
return shim.Error(err.Error())
}
id := args[0]
authorized_by_association := args[1]
// get the beneficiary
beneficiary, err := get_beneficiary(stub, id)
if err != nil{
fmt.Println("Failed to find beneficiary by id " + id)
return shim.Error(err.Error())
}
// check authorizing organisation
if beneficiary.Owner.Association != authorized_by_association{
return shim.Error("The association '" + authorized_by_association + "' cannot authorize deletion for '" + beneficiary.Owner.Association + "'.")
}
// remove the beneficiary
err = stub.DelState(id) //remove the key from chaincode state
if err != nil {
return shim.Error("Failed to delete state")
}
fmt.Println("- end delete_beneficiary")
return shim.Success(nil)
}
// ============================================================================================================================
// Init Wallet - create a new wallet, store into chaincode state
//
// Shows off building a key's JSON value manually
//
// Inputs - Array of strings
// 0 , 1 , 2 , 3
// id , balance , owner id , authorization
// ============================================================================================================================
func init_wallet(stub shim.ChaincodeStubInterface, args []string) (pb.Response) {
var err error
fmt.Println("starting init_wallet")
if len(args) != 4 {
return shim.Error("Incorrect number of arguments. Expecting 4")
}
err = sanitize_arguments(args)
if err != nil {
return shim.Error(err.Error())
}
id := args[0]
owner_id := args[2]
authorized_by_association := args[3]
balance, err := strconv.Atoi(args[1])
if err != nil {
return shim.Error("Second argument must be a numeric string")
}
//check if new owner exists
owner, err := get_owner(stub, owner_id)
if err != nil {
fmt.Println("Failed to find owner - " + owner_id)
return shim.Error(err.Error())
}
//check authorizing organisation
if owner.Association != authorized_by_association{
return shim.Error("The association '" + authorized_by_association + "' cannot authorize creation for '" + owner.Association + "'.")
}
//check if wallet id already exists
wallet, err := get_wallet(stub, id)
if err == nil {
fmt.Println("This wallet already exists - " + id)
fmt.Println(wallet)
return shim.Error("This wallet already exists - " + id)
}
//build the wallet json string manually
str := `{
"docType":"wallet",
"id": "` + id + `",
"balance": "` + balance + `",
"owner": {
"id": "` + owner_id + `",
"name": "` + owner.Name + `",
"firstname": "` + owner.Firstname + `"
}
}`
err = stub.PutState(id, []byte(str)) //store wallet with id as key
if err != nil {
return shim.Error(err.Error())
}
fmt.Println("- end init_wallet")
return shim.Success(nil)
}
// ============================================================================================================================
// Init Owner - create a new owner, store into chaincode state
//
// Shows off building key's value from GoLang Structure
//
// ============================================================================================================================
func init_owner(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var err error
fmt.Println("starting init_owner")
if len(args) != 9 {
return shim.Error("Incorrect number of arguments. Expecting 9")
}
err = sanitize_arguments(args)
if err != nil {
return shim.Error(err.Error())
}
var owner Owner
owner.ObjectType = "wallet_owner"
owner.Id = args[0]
owner.Name = strings.ToLower(args[1])
owner.Firstname = strings.ToLower(args[2])
owner.Mail = strings.ToLower(args[3])
owner.Address = strings.ToLower(args[4])
owner.City = strings.ToLower(args[5])
owner.Password = strings.ToLower(args[7])
owner.Association = args[8]
owner.Enabled = true
Postalcode, err := strconv.Atoi(args[6])
if err != nil {
return shim.Error("Seventh argument must be a numeric string")
}
fmt.Println(owner)
//check if user already exists
_, err = get_owner(stub, owner.Id)
if err == nil {
fmt.Println("This owner already exists - " + owner.Id)
return shim.Error("This owner already exists - " + owner.Id)
}
//store user
ownerAsBytes, _ := json.Marshal(owner) //convert to array of bytes
err = stub.PutState(owner.Id, ownerAsBytes) //store owner by its Id
if err != nil {
fmt.Println("Could not store user")
return shim.Error(err.Error())
}
fmt.Println("- end init_owner wallet")
return shim.Success(nil)
}
// ============================================================================================================================
// Init Beneficiary - create a new beneficiary, store into chaincode state
//
// Shows off building a key's JSON value manually
//
// Inputs - Array of strings
// 0 , 1 , 2 , 3
// id , balance , owner id , authorization
// ============================================================================================================================
func init_beneficiary(stub shim.ChaincodeStubInterface, args []string) (pb.Response) {
var err error
fmt.Println("starting init_beneficiary")
if len(args) != 6 {
return shim.Error("Incorrect number of arguments. Expecting 6")
}
err = sanitize_arguments(args)
if err != nil {
return shim.Error(err.Error())
}
id := args[0]
idBenef := args[1]
nameBenef := strings.ToLower(args[2])
firstnameBenef := strings.ToLower(args[3])
owner_id := args[4]
authorized_by_association := args[5]
//check if new owner exists
owner, err := get_owner(stub, owner_id)
if err != nil {
fmt.Println("Failed to find owner - " + owner_id)
return shim.Error(err.Error())
}
//check authorizing organisation
if owner.Association != authorized_by_association{
return shim.Error("The association '" + authorized_by_association + "' cannot authorize creation for '" + owner.Association + "'.")
}
//check if beneficiary id already exists
beneficiary, err := get_beneficiary(stub, id)
if err == nil {
fmt.Println("This beneficiary already exists - " + id)
fmt.Println(beneficiary)
return shim.Error("This beneficiary already exists - " + id)
}
//build the beneficiary json string manually
str := `{
"docType":"beneficiary",
"id": "` + id + `",
"idbenef": "` + idbenef + `",
"namebenef": "` + namebenef + `",
"firstnamebenef": "` + firstnamebenef + `",
"owner": {
"id": "` + owner_id + `",
"name": "` + owner.Name + `",
"firstname": "` + owner.Firstname + `"
}
}`
err = stub.PutState(id, []byte(str)) //store beneficiary with id as key
if err != nil {
return shim.Error(err.Error())
}
fmt.Println("- end init_beneficiary")
return shim.Success(nil)
}
// ============================================================================================================================
// Set Owner on Wallet
//
// Shows off GetState() and PutState()
//
// ============================================================================================================================
func set_owner(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var err error
fmt.Println("starting set_owner")
// this is quirky
// todo - get the "association that authed the transfer" from the certificate instead of an argument
// should be possible since we can now add attributes to the enrollment cert
// as is.. this is a bit broken (security wise), but it's much much easier to demo! holding off for demos sake
if len(args) != 3 {
return shim.Error("Incorrect number of arguments. Expecting 3")
}
// input sanitation
err = sanitize_arguments(args)
if err != nil {
return shim.Error(err.Error())
}
var wallet_id = args[0]
var new_owner_id = args[1]
var authorized_by_association = args[2]
fmt.Println(wallet_id + "->" + new_owner_id + " - |" + authorized_by_association)
// check if user already exists
owner, err := get_owner(stub, new_owner_id)
if err != nil {
return shim.Error("This owner does not exist - " + new_owner_id)
}
// get wallet's current state
walletAsBytes, err := stub.GetState(wallet_id)
if err != nil {
return shim.Error("Failed to get wallet")
}
res := Wallet{}
json.Unmarshal(walletAsBytes, &res)
// check authorizing association
if res.Owner.Association != authorized_by_association{
return shim.Error("The Association '" + authorized_by_association + "' cannot authorize transfers for '" + res.Owner.Association + "'.")
}
// transfer the wallet
res.Owner.Id = new_owner_id //change the owner
res.Owner.Name = owner.Name
res.Owner.Firstname = owner.Firstname
res.Owner.Association = owner.Association
jsonAsBytes, _ := json.Marshal(res) //convert to array of bytes
err = stub.PutState(args[0], jsonAsBytes) //rewrite the wallet with id as key
if err != nil {
return shim.Error(err.Error())
}
fmt.Println("- end set owner")
return shim.Success(nil)
}
// ============================================================================================================================
// Set Beneficiaries
//
// ============================================================================================================================
func set_beneficiary(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var err error
fmt.Println("starting set_beneficiary")
if len(args) != 3 {
return shim.Error("Incorrect number of arguments. Expecting 3")
}
// input sanitation
err = sanitize_arguments(args)
if err != nil {
return shim.Error(err.Error())
}
var beneficiary_id = args[0]
var new_owner_id = args[1]
var authorized_by_association = args[2]
fmt.Println(beneficiary_id + "->" + new_owner_id + " - |" + authorized_by_association)
// check if user already exists
owner, err := get_owner(stub, new_owner_id)
if err != nil {
return shim.Error("This owner does not exist - " + new_owner_id)
}
// get beneficiary's current state
beneficiaryAsBytes, err := stub.GetState(beneficiary_id)
if err != nil {
return shim.Error("Failed to get beneficiary")
}
res := Beneficiary{}
json.Unmarshal(beneficiaryAsBytes, &res)
// check authorizing association
if res.Owner.Association != authorized_by_association{
return shim.Error("The Association '" + authorized_by_association + "' cannot authorize transfers for '" + res.Owner.Association + "'.")
}
// transfer the beneficiary
res.Owner.Id = new_owner_id //change the owner
res.Owner.Name = owner.Name
res.Owner.Firstname = owner.Firstname
res.Owner.Association = owner.Association
jsonAsBytes, _ := json.Marshal(res) //convert to array of bytes
err = stub.PutState(args[0], jsonAsBytes) //rewrite the wallet with id as key
if err != nil {
return shim.Error(err.Error())
}
fmt.Println("- end set owner")
return shim.Success(nil)
}
// ============================================================================================================================
// Disable Wallet Owner
//
// Shows off PutState()
// ============================================================================================================================
func disable_owner(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var err error
fmt.Println("starting disable_owner")
if len(args) != 2 {
return shim.Error("Incorrect number of arguments. Expecting 2")
}
// input sanitation
err = sanitize_arguments(args)
if err != nil {
return shim.Error(err.Error())
}
var owner_id = args[0]
var authorized_by_association = args[1]
// get the wallet owner data
owner, err := get_owner(stub, owner_id)
if err != nil {
return shim.Error("This owner does not exist - " + owner_id)
}
// check authorizing association
if owner.Association != authorized_by_association {
return shim.Error("The association '" + authorized_by_association + "' cannot change another association wallet owner")
}
// disable the owner
owner.Enabled = false
jsonAsBytes, _ := json.Marshal(owner) //convert to array of bytes
err = stub.PutState(args[0], jsonAsBytes) //rewrite the owner
if err != nil {
return shim.Error(err.Error())
}
fmt.Println("- end disable_owner")
return shim.Success(nil)
}
// ============================================================================================================================
// Transfer X Money From a User to a Recipient
//
// ============================================================================================================================
func transfer(stub shim.ChaincodeStubInterface, args []string) pb.Response {
var err error
fmt.Println("starting transfer")
if len(args) != 3 {
return shim.Error("Incorrect number of arguments. Expecting 3")
}
// input sanitation
err = sanitize_arguments(args)
if err != nil {
return shim.Error(err.Error())
}
id := args[0]
dest_id := args[1]
// Get the state from the ledger
// TODO: will be nice to have a GetAllState call to ledger
Avalbytes, err := stub.GetState(id)
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(dest_id)
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
value, err = strconv.Atoi(args[2])
Aval = Wallet.Balance - value
Bval = Wallet.Balance + value
fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)
// Write the state back to the ledger
err = stub.PutState(id, []byte(strconv.Itoa(Aval)))
if err != nil {
return nil, err
}
err = stub.PutState(dest_id, []byte(strconv.Itoa(Bval)))
if err != nil {
return nil, err
}
fmt.Println("- end transfer")
return shim.Success(nil)
}