614 lines
18 KiB
Go
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)
|
|
} |