github.com/inklabsfoundation/inkchain@v0.17.1-0.20181025012015-c3cef8062f19/core/scc/ascc/ascc.go (about) 1 /* 2 Copyright Ziggurat Corp. 2017 All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package ascc 8 9 import ( 10 "encoding/json" 11 "fmt" 12 "math/big" 13 "strconv" 14 15 "github.com/inklabsfoundation/inkchain/common/flogging" 16 "github.com/inklabsfoundation/inkchain/core/chaincode/shim" 17 "github.com/inklabsfoundation/inkchain/core/policy" 18 "github.com/inklabsfoundation/inkchain/core/policyprovider" 19 "github.com/inklabsfoundation/inkchain/msp/mgmt" 20 pb "github.com/inklabsfoundation/inkchain/protos/peer" 21 "bytes" 22 ) 23 24 // Create Logger 25 var tralogger = flogging.MustGetLogger("ascc") 26 27 // These are function names from Invoke first parameter 28 const ( 29 //invoke functions 30 RegisterAndIssueToken string = "registerAndIssueToken" 31 InvalidateToken string = "invalidateToken" 32 QueryToken string = "queryToken" 33 34 //token status 35 Created string = "created" 36 Delivered string = "issued" 37 Invalidate string = "invalidated" 38 ) 39 40 // type GenAccount 41 type Token struct { 42 // token name 43 Name string `json:"tokenName"` 44 // total supply of the token 45 totalSupply *big.Int `json:"totalSupply"` 46 // initial address to issue 47 Address string `json:"address"` 48 // token status : Created, Delivered, Invalidate 49 Status string `json:"status"` 50 // token decimals 51 Decimals int `json:"decimals"` 52 } 53 54 //-------------- the ascc ------------------ 55 type AssetSysCC struct { 56 // policyChecker is the interface used to perform 57 // access control 58 policyChecker policy.PolicyChecker 59 } 60 61 // Init initializes ascc 62 func (t *AssetSysCC) Init(stub shim.ChaincodeStubInterface) pb.Response { 63 tralogger.Info("Init ascc") 64 65 // Init policy checker for access control 66 t.policyChecker = policyprovider.GetPolicyChecker() 67 68 return shim.Success(nil) 69 } 70 71 // Invoke func 72 func (t *AssetSysCC) Invoke(stub shim.ChaincodeStubInterface) pb.Response { 73 function, args := stub.GetFunctionAndParameters() 74 75 tralogger.Debugf("ascc starts: %d args", len(args)) 76 // Handle ACL of ascc: 77 // 1. get the signed proposal 78 // sp, err := stub.GetSignedProposal() 79 // if err != nil { 80 // return shim.Error(fmt.Sprintf("Failed retrieving signed proposal on executing %s with error %s", function, err)) 81 // } 82 switch function { 83 84 case RegisterAndIssueToken: 85 if len(args) != 4 { //name, totalSupply, decimals, address 86 returnMessage := fmt.Sprint("Incorrect number of arguments for IssueToken, %d", len(args)) 87 tralogger.Debugf("Incorrect number of arguments for IssueToken, %d", len(args)) 88 return shim.Error(returnMessage) 89 } 90 91 // 2. check local MSP Admins policy 92 93 sp, err := stub.GetSignedProposal() 94 if err != nil { 95 return shim.Error(fmt.Sprintf("Failed retrieving signed proposal on executing %s with error %s", function, err)) 96 } 97 98 if err := t.policyChecker.CheckPolicyNoChannel(mgmt.Admins, sp); err != nil { 99 tralogger.Debugf(fmt.Sprintf("Authorization for RegisterAndIssueToken has been denied (error-%s)", err)) 100 return shim.Error(fmt.Sprintf("Authorization for RegisterAndIssueToken has been denied (error-%s)", err)) 101 } 102 tralogger.Debugf("Invoke function: %s", RegisterAndIssueToken) 103 return t.registerAndIssueToken(stub, args) 104 105 case InvalidateToken: 106 if len(args) != 1 { //name 107 returnMessage := fmt.Sprint("Incorrect number of arguments for InvalidateToken, %d", len(args)) 108 tralogger.Debugf("Incorrect number of arguments for InvalidateToken, %d", len(args)) 109 return shim.Error(returnMessage) 110 } 111 112 tralogger.Debugf("Invoke function: %s", InvalidateToken) 113 114 return t.invalidateToken(stub, args) 115 116 case QueryToken: 117 if len(args) < 1{ 118 returnMessage := fmt.Sprint("Need at least 1 arguments for QueryToken, %d", len(args)) 119 tralogger.Debugf("Need at least 1 arguments for QueryToken, %d", len(args)) 120 return shim.Error(returnMessage) 121 } 122 123 tralogger.Debugf("Invoke function: %s", QueryToken) 124 125 return t.queryToken(stub, args) 126 127 } 128 129 return shim.Error("Invalid invoke function name. Expecting \"registerAndIssueToken\" or \"invalidateToken\" or \"queryToken\".") 130 } 131 132 // issue Tokens Invoke 133 // invoke function 134 func (t *AssetSysCC) registerAndIssueToken(stub shim.ChaincodeStubInterface, args []string) pb.Response { 135 var err error 136 137 tokenName := args[0] 138 139 totalSupply := big.NewInt(0) 140 _, good := totalSupply.SetString(args[1], 10) 141 if !good { 142 return shim.Error("Expecting integer value for totalSupply.") 143 } 144 dec, _ := strconv.Atoi(args[2]) 145 addr := args[3] 146 147 //Get exist token 148 var existToken Token 149 existTokenBytes, err := stub.GetState(tokenName) 150 if err != nil { 151 msgCheck := "Check token existance error, fail to getState of " 152 msgCheck += tokenName 153 tralogger.Debug(msgCheck) 154 return shim.Error(msgCheck) 155 } 156 157 //Get the information of token 158 //If not exist, create a new token first 159 if existTokenBytes == nil { 160 //not exist 161 //create the token 162 existToken.Status = Created 163 existToken.Name = tokenName 164 existToken.totalSupply = totalSupply 165 existToken.Address = addr 166 existToken.Decimals = dec 167 } else { 168 //exist 169 //unmarshal the jsonBytes & check token information 170 err = json.Unmarshal(existTokenBytes, &existToken) 171 if err != nil { 172 msgUnmarshal := "Unmarshal exist tokenBytes err " 173 msgUnmarshal += tokenName 174 tralogger.Debug(msgUnmarshal) 175 return shim.Error(msgUnmarshal) 176 } 177 //check the status of token 178 if existToken.Status != Created { 179 msgCheckTS := "Token status err, fail to issue token." 180 tralogger.Debug(msgCheckTS) 181 return shim.Error(msgCheckTS) 182 } 183 //check the information of token 184 if existToken.Address != addr || existToken.totalSupply.Cmp(totalSupply) != 0 || existToken.Decimals != dec { 185 msgCheckTInfo := "Token info err, check fialed." 186 tralogger.Debug(msgCheckTInfo) 187 return shim.Error(msgCheckTInfo) 188 } 189 } 190 191 //set the token number to address 192 193 //get account of Address 194 account, err := stub.GetAccount(addr) 195 //check if token has been issued before 196 if err == nil { 197 if account != nil { 198 if _, ok := account.Balance[tokenName]; ok { 199 msgBalanceCheck := "Token " + tokenName + " already exist in " + addr 200 tralogger.Debug(msgBalanceCheck) 201 return shim.Error(msgBalanceCheck) 202 } 203 } 204 } 205 //token hasnot been issued, then 206 //issue token 207 err = stub.IssueToken(addr, tokenName, totalSupply) 208 if err != nil { 209 return shim.Error(err.Error()) 210 } 211 212 existToken.Status = Delivered 213 214 //store the latest status for token in ascc 215 existTokenJson, err := json.Marshal(&existToken) 216 err = stub.PutState(tokenName, existTokenJson) 217 218 if err != nil { 219 msgUpdate := "Store the latest token status err." 220 tralogger.Debug(msgUpdate) 221 return shim.Error(msgUpdate) 222 } 223 224 return shim.Success([]byte("Token issued success!")) 225 } 226 227 // invalidate Tokens Invoke 228 // invoke function 229 func (t *AssetSysCC) invalidateToken(stub shim.ChaincodeStubInterface, args []string) pb.Response { 230 var err error 231 232 tokenName := args[0] 233 234 //Get exist token 235 var existToken Token 236 existTokenBytes, err := stub.GetState(tokenName) 237 if err != nil { 238 msgCheck := "Check token existance error, fail to getState of " 239 msgCheck += tokenName 240 tralogger.Debug(msgCheck) 241 return shim.Error(msgCheck) 242 } 243 244 //Check token status 245 //If not exist, return err 246 if existTokenBytes == nil { 247 msgCheckExist := "Token not exist, fail to get status: " 248 msgCheckExist += tokenName 249 tralogger.Debug(msgCheckExist) 250 return shim.Error(msgCheckExist) 251 } 252 253 //Unmarshal tokenBytes 254 err = json.Unmarshal(existTokenBytes, &existToken) 255 if err != nil { 256 msgUnmarshal := "Unmarshal exist tokenBytes err " 257 msgUnmarshal += tokenName 258 tralogger.Debug(msgUnmarshal) 259 return shim.Error(msgUnmarshal) 260 } 261 262 //check the status of token 263 if existToken.Status == Invalidate { 264 return shim.Error("Token already invalidated.") 265 } 266 267 existToken.Status = Invalidate 268 269 //store the latest status for token 270 existTokenJson, err := json.Marshal(&existToken) 271 err = stub.PutState(tokenName, existTokenJson) 272 273 if err != nil { 274 msgUpdate := "Store the latest token status err." 275 tralogger.Debug(msgUpdate) 276 return shim.Error(msgUpdate) 277 } 278 279 return shim.Success([]byte("Token invalidate success!")) 280 } 281 282 // query Token Invoke 283 // implement for multi-token search 284 // invoke function 285 func (t *AssetSysCC) queryToken(stub shim.ChaincodeStubInterface, args []string) pb.Response { 286 287 // buffer is a JSON array containing QueryResults 288 var buffer bytes.Buffer 289 buffer.WriteString("[") 290 291 bArrayMemberAlreadyWritten := false 292 bArrayIndex := 1 293 294 // check every token to be searched 295 for i:=0; i<len(args); i++ { 296 tokenName := args[i] 297 tokenAsBytes, err := stub.GetState(tokenName) 298 if err != nil { 299 continue 300 } 301 if tokenAsBytes == nil { 302 continue 303 } 304 305 if bArrayMemberAlreadyWritten == true { 306 buffer.WriteString(",") 307 } 308 // index of the result 309 buffer.WriteString("{\"Number\":") 310 buffer.WriteString("\"") 311 bArrayIndexStr := strconv.Itoa(bArrayIndex) 312 buffer.WriteString(string(bArrayIndexStr)) 313 bArrayIndex += 1 314 buffer.WriteString("\"") 315 // information about current asset 316 buffer.WriteString(", \"Record\":") 317 buffer.WriteString(string(tokenAsBytes)) 318 buffer.WriteString("}") 319 bArrayMemberAlreadyWritten = true 320 321 } 322 323 buffer.WriteString("]") 324 325 return shim.Success(buffer.Bytes()) 326 }