github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/examples/chaincode/go/asset_management02/depository_handler.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package main 18 19 import ( 20 "errors" 21 22 "encoding/json" 23 "fmt" 24 25 "github.com/hyperledger/fabric/core/chaincode/shim" 26 ) 27 28 //DepositoryHandler provides APIs used to perform operations on CC's KV store 29 type depositoryHandler struct { 30 } 31 32 // NewDepositoryHandler create a new reference to CertHandler 33 func NewDepositoryHandler() *depositoryHandler { 34 return &depositoryHandler{} 35 } 36 37 type depositoryAccount struct { 38 AccountID string `json:"account_id"` 39 ContactInfo string `json:"contact_info"` 40 Amount uint64 `json:"amount"` 41 } 42 43 // assign allocates assets to account IDs in the chaincode state for each of the 44 // account ID passed in. 45 // accountID: account ID to be allocated with requested amount 46 // contactInfo: contact information of the owner of the account ID passed in 47 // amount: amount to be allocated to this account ID 48 func (t *depositoryHandler) assign(stub shim.ChaincodeStubInterface, 49 accountID string, 50 contactInfo string, 51 amount uint64) error { 52 53 myLogger.Debugf("insert accountID= %v", accountID) 54 55 // you can only assign balances to new account IDs 56 accountBytes, err := stub.GetState(accountID) 57 if err == nil && len(accountBytes) > 0 { 58 myLogger.Errorf("system error %v", err) 59 return errors.New("Asset was already assigned.") 60 } 61 62 account := depositoryAccount{ 63 AccountID: accountID, 64 ContactInfo: contactInfo, 65 Amount: amount, 66 } 67 accountBytes, err = json.Marshal(account) 68 if err != nil { 69 myLogger.Errorf("account marshaling error %v", err) 70 return errors.New("Failed to serialize account info." + err.Error()) 71 } 72 73 //update this account that includes contact information and balance 74 err = stub.PutState(accountID, accountBytes) 75 return err 76 } 77 78 // updateAccountBalance updates the balance amount of an account ID 79 // stub: chaincodestub 80 // accountID: account will be updated with the new balance 81 // contactInfo: contact information associated with the account owner (chaincode table does not allow me to perform updates on specific columns) 82 // amount: new amount to be udpated with 83 func (t *depositoryHandler) updateAccountBalance(stub shim.ChaincodeStubInterface, 84 accountID string, 85 contactInfo string, 86 amount uint64) error { 87 88 myLogger.Debugf("insert accountID= %v", accountID) 89 90 //replace the old record row associated with the account ID with the new record row 91 account := depositoryAccount{ 92 AccountID: accountID, 93 ContactInfo: contactInfo, 94 Amount: amount, 95 } 96 accountBytes, err := json.Marshal(account) 97 if err != nil { 98 myLogger.Errorf("account marshaling error %v", err) 99 return errors.New("Failed to serialize account info." + err.Error()) 100 } 101 102 //update this account that includes contact information and balance 103 err = stub.PutState(accountID, accountBytes) 104 return err 105 } 106 107 // deleteAccountRecord deletes the record row associated with an account ID on the chaincode state table 108 // stub: chaincodestub 109 // accountID: account ID (record matching this account ID will be deleted after calling this method) 110 func (t *depositoryHandler) deleteAccountRecord(stub shim.ChaincodeStubInterface, accountID string) error { 111 112 myLogger.Debugf("insert accountID= %v", accountID) 113 114 //delete record matching account ID passed in 115 err := stub.DelState(accountID) 116 117 if err != nil { 118 myLogger.Errorf("system error %v", err) 119 return errors.New("error in deleting account record") 120 } 121 return nil 122 } 123 124 // transfer transfers X amount of assets from "from account IDs" to a new account ID 125 // stub: chaincodestub 126 // fromAccounts: from account IDs with assets to be transferred 127 // toAccount: a new account ID on the table that will get assets transfered to 128 // toContact: contact information of the owner of "to account ID" 129 func (t *depositoryHandler) transfer(stub shim.ChaincodeStubInterface, fromAccounts []string, toAccount string, toContact string, amount uint64) error { 130 131 myLogger.Debugf("insert params= %v , %v , %v , %v ", fromAccounts, toAccount, toContact, amount) 132 133 //collecting assets need to be transfered 134 remaining := amount 135 for i := range fromAccounts { 136 contactInfo, acctBalance, err := t.queryAccount(stub, fromAccounts[i]) 137 if err != nil { 138 myLogger.Errorf("system error %v", err) 139 return errors.New("error in deleting account record") 140 } 141 142 if remaining > 0 { 143 //check if this account need to be spent entirely; if so, delete the 144 //account record row, otherwise just take out what' needed 145 if remaining >= acctBalance { 146 remaining -= acctBalance 147 //delete accounts with 0 balance, this step is optional 148 t.deleteAccountRecord(stub, fromAccounts[i]) 149 } else { 150 acctBalance -= remaining 151 remaining = 0 152 t.updateAccountBalance(stub, fromAccounts[i], contactInfo, acctBalance) 153 break 154 } 155 } 156 } 157 158 //check if toAccount already exist 159 acctBalance, err := t.queryBalance(stub, toAccount) 160 if err == nil || acctBalance > 0 { 161 myLogger.Errorf("system error %v", err) 162 return errors.New("error in deleting account record") 163 } 164 165 //create new toAccount in the Chaincode state table, and assign the total amount 166 //to its balance 167 return t.assign(stub, toAccount, toContact, amount) 168 169 } 170 171 // queryContactInfo queries the contact information matching a correponding account ID on the chaincode state table 172 // stub: chaincodestub 173 // accountID: account ID 174 func (t *depositoryHandler) queryContactInfo(stub shim.ChaincodeStubInterface, accountID string) (string, error) { 175 account, err := t.queryTable(stub, accountID) 176 if err != nil { 177 return "", err 178 } 179 180 return account.ContactInfo, nil 181 } 182 183 // queryBalance queries the balance information matching a correponding account ID on the chaincode state table 184 // stub: chaincodestub 185 // accountID: account ID 186 func (t *depositoryHandler) queryBalance(stub shim.ChaincodeStubInterface, accountID string) (uint64, error) { 187 188 myLogger.Debugf("insert accountID= %v", accountID) 189 190 account, err := t.queryTable(stub, accountID) 191 if err != nil { 192 return 0, err 193 } 194 195 return account.Amount, nil 196 } 197 198 // queryAccount queries the balance and contact information matching a correponding account ID on the chaincode state table 199 // stub: chaincodestub 200 // accountID: account ID 201 func (t *depositoryHandler) queryAccount(stub shim.ChaincodeStubInterface, accountID string) (string, uint64, error) { 202 account, err := t.queryTable(stub, accountID) 203 if err != nil { 204 return "", 0, err 205 } 206 207 return account.ContactInfo, account.Amount, nil 208 } 209 210 // queryTable returns the record row matching a correponding account ID on the chaincode state table 211 // stub: chaincodestub 212 // accountID: account ID 213 func (t *depositoryHandler) queryTable(stub shim.ChaincodeStubInterface, accountID string) (*depositoryAccount, error) { 214 215 accountBytes, err := stub.GetState(accountID) 216 if err != nil { 217 return nil, errors.New("Failed to get account." + err.Error()) 218 } 219 if len(accountBytes) == 0 { 220 return nil, fmt.Errorf("Account %s not exists.", accountID) 221 } 222 223 account := &depositoryAccount{} 224 err = json.Unmarshal(accountBytes, account) 225 if err != nil { 226 return nil, errors.New("Failed to parse account Info. " + err.Error()) 227 } 228 return account, nil 229 }