github.com/inklabsfoundation/inkchain@v0.17.1-0.20181025012015-c3cef8062f19/examples/inkwork/inkwork.go (about) 1 package main 2 3 import ( 4 "github.com/inklabsfoundation/inkchain/core/chaincode/shim" 5 pb "github.com/inklabsfoundation/inkchain/protos/peer" 6 "fmt" 7 "encoding/json" 8 "strings" 9 "math/big" 10 "strconv" 11 "time" 12 "bytes" 13 ) 14 15 type WorkChainCode struct { 16 sysAddress string 17 TokenType string // as "INK" 18 } 19 20 func main() { 21 err := shim.Start(new(WorkChainCode)) 22 if err == nil { 23 fmt.Printf("Error starting WorkChaincode: %s", err) 24 } 25 } 26 27 func (w *WorkChainCode)Init(stub shim.ChaincodeStubInterface) pb.Response { 28 _, args := stub.GetFunctionAndParameters() 29 if len(args) != 2 { 30 return shim.Error("init, Incorrect number of arguments. Expecting 2") 31 } 32 w.sysAddress = args[0] 33 w.TokenType = args[1] 34 35 return shim.Success(nil) 36 } 37 38 func (w *WorkChainCode)Invoke(stub shim.ChaincodeStubInterface) pb.Response { 39 function, args := stub.GetFunctionAndParameters() 40 41 switch function { 42 case RegisterWork: 43 if len(args) != 3 { 44 return shim.Error("getWork, Incorrect number of arguments. Expecting 3") 45 } 46 return w.registerWork(stub, args) 47 case Purchase: 48 if len(args) != 1 { 49 return shim.Error("purchase, Incorrect number of arguments. Expecting 1") 50 } 51 return w.purchase(stub, args) 52 case Sell: 53 if len(args) != 3 { 54 return shim.Error("sell, Incorrect number of arguments. Expecting 3") 55 } 56 return w.sell(stub, args) 57 case Query: 58 if len(args) != 1 { 59 return shim.Error("query, Incorrect number of arguments. Expecting 1") 60 } 61 return w.query(stub, args) 62 case QueryInkwork: 63 if len(args) != 1 { 64 return shim.Error("queryInkwork, Incorrect number of arguments. Expecting 1") 65 } 66 return w.queryInkwork(stub, args) 67 } 68 69 return shim.Error("function is invalid: " + function) 70 } 71 72 func (w *WorkChainCode) workState(stub shim.ChaincodeStubInterface, workId string) (work *WorkDef, err error) { 73 var valAsbytes []byte 74 if valAsbytes, err = stub.GetState(workId); err != nil { 75 // Failed to get state 76 return nil, err 77 } else if valAsbytes == nil { 78 // work does not exist 79 fmt.Printf("%s work does not exist", workId) 80 return nil, nil 81 } 82 work = &WorkDef{} 83 err = json.Unmarshal([]byte(valAsbytes), work) 84 return 85 } 86 87 //@param workId 88 //@param level 89 //@param price 90 func (w *WorkChainCode) registerWork(stub shim.ChaincodeStubInterface, args []string) pb.Response { 91 workId := args[0] 92 var level, price int 93 var err error 94 if level, err = strconv.Atoi(args[1]); err != nil{ 95 return shim.Error(err.Error()) 96 } 97 if price, err = strconv.Atoi(args[2]); err != nil { 98 return shim.Error(err.Error()) 99 } 100 101 var sender string 102 if sender, err = stub.GetSender(); err != nil { 103 return shim.Error("Fail to get sender's address.") 104 } 105 sender = strings.ToLower(sender) 106 107 if bGet, err := w.getFreeState(stub, sender); err != nil { 108 return shim.Error("Fail to getFreeState") 109 } else if bGet == true { 110 return shim.Error("already get") 111 } 112 113 if data, err := w.workState(stub, workId); err != nil { 114 return shim.Error(err.Error()) 115 } else if data != nil { 116 return shim.Error("this work already exist") 117 } 118 119 txTimestamp, err := stub.GetTxTimestamp() 120 if err != nil { 121 return shim.Error("GetTxTimestamp failed") 122 } 123 work := &WorkDef { 124 WorkId: workId, 125 Level: level, 126 Birth: txTimestamp.String(), 127 Owner: sender, 128 Sale: 0, 129 Price: price, 130 SaleTime: 0, 131 } 132 133 if workJSONasByte, err := json.Marshal(work); err == nil { 134 if err = stub.PutState(workId, workJSONasByte); err != nil { 135 return shim.Error(err.Error()) 136 } 137 } else { 138 return shim.Error(err.Error()) 139 } 140 141 err = w.historyByComposite(stub, FreeHistory, []string{sender, workId}) 142 if err != nil { 143 return shim.Error(err.Error()) 144 } 145 146 result := fmt.Sprintf("register work:%v Succeed", workId) 147 return shim.Success([]byte(result)) 148 } 149 150 func (w *WorkChainCode) historyByComposite(stub shim.ChaincodeStubInterface, recordType string, args []string) (err error) { 151 var indexKey string 152 if indexKey, err = stub.CreateCompositeKey(recordType, args); err != nil { 153 return 154 } 155 156 value := []byte{0x00} 157 if err = stub.PutState(indexKey, value); err != nil { 158 return 159 } 160 return 161 } 162 163 func (w *WorkChainCode) getFreeState(stub shim.ChaincodeStubInterface, user string) (bool, error) { 164 resultsIterator, err := stub.GetStateByPartialCompositeKey(FreeHistory, []string{}) 165 if err != nil { 166 fmt.Println("getFreeState, stub.GetStateByPartialCompositeKey failed: " + err.Error()) 167 return false, err 168 } 169 for i := 0; resultsIterator.HasNext(); i++ { 170 responseRange, err := resultsIterator.Next() 171 if err != nil { 172 return false, err 173 } 174 _, compositeKeyParts, err := stub.SplitCompositeKey(responseRange.Key) 175 if err != nil { 176 return false, err 177 } 178 179 userAddr := compositeKeyParts[0] 180 if userAddr == user { 181 return true, nil 182 } 183 } 184 return false, nil 185 } 186 187 //@param workId 188 func (w *WorkChainCode) purchase(stub shim.ChaincodeStubInterface, args []string) pb.Response { 189 workId := args[0] 190 var data *WorkDef 191 var err error 192 if data, err = w.workState(stub, workId); err != nil { 193 return shim.Error(err.Error()) 194 } else if data == nil { 195 return shim.Error("this work not exist") 196 } 197 198 if 0 == data.Sale { 199 jsonResp := "{\"Error\":\"buy failed, work does not sale: " + workId + "\"}" 200 return shim.Error(jsonResp) 201 } 202 203 sender, err := stub.GetSender() 204 if err != nil { 205 return shim.Error("Fail to get sender's address.") 206 } 207 sender = strings.ToLower(sender) 208 if sender == data.Owner { 209 jsonResp := "{\"Error\":\"buy failed, already is work owner\"}" 210 return shim.Error(jsonResp) 211 } 212 balance := w.getBalance(stub, sender) 213 if balance < int64(data.Price) { 214 return shim.Error("bid failed, balance not enough") 215 } 216 217 // pay cost 218 amount := big.NewInt(0) 219 _, good := amount.SetString(strconv.Itoa(data.Price), 10) 220 if !good { 221 return shim.Error("Expecting integer value for amount") 222 } 223 err = stub.Transfer(data.Owner, w.TokenType, amount) 224 if err != nil { 225 return shim.Error("transfer error: " + err.Error()) 226 } 227 228 data.Owner = sender 229 data.Sale = 0 230 data.SaleTime = 0 231 if workAsbytes, err := json.Marshal(data); err != nil { 232 return shim.Error(err.Error()) 233 } else if err = stub.PutState(workId, workAsbytes); err != nil { 234 return shim.Error(err.Error()) 235 } 236 237 result := fmt.Sprintf("buy Work:%v Succeed", workId) 238 return shim.Success([]byte(result)) 239 } 240 241 func (w *WorkChainCode) getBalance(stub shim.ChaincodeStubInterface, userAddr string) int64 { 242 account, err := stub.GetAccount(userAddr) 243 if err != nil { 244 // account not exists 245 return 0 246 } 247 if account == nil || account.Balance[w.TokenType] == nil { 248 return 0 249 } 250 251 balance := account.Balance[w.TokenType].Int64() 252 return balance 253 } 254 255 //@param workId 256 //@param price 257 //@param sellState 258 func (w *WorkChainCode) sell(stub shim.ChaincodeStubInterface, args []string) pb.Response { 259 workId := args[0] 260 var work *WorkDef 261 var err error 262 sender, err := stub.GetSender() 263 if err != nil { 264 return shim.Error("Fail to get sender's address.") 265 } 266 sender = strings.ToLower(sender) 267 268 if work, err = w.workState(stub, workId); err != nil { 269 return shim.Error(err.Error()) 270 } else if work == nil { 271 return shim.Error("this work not exist") 272 } 273 274 if sender != work.Owner { 275 jsonResp := "{\"Error\":\"sell failed, not work owner\"}" 276 return shim.Error(jsonResp) 277 } 278 279 priceStr := args[1] 280 price, err := strconv.Atoi(priceStr) 281 if err != nil { 282 return shim.Error(err.Error()) 283 } 284 if 1 == work.Sale && price == work.Price { 285 jsonResp := "{\"Error\":\"invalid operate, nothing change\"}" 286 return shim.Error(jsonResp) 287 } 288 289 sale, err := strconv.Atoi(args[2]) 290 if err != nil { 291 return shim.Error(err.Error()) 292 } 293 var saleTime int64 = 0 294 if 1 == sale { 295 saleTime = time.Now().Unix() 296 } 297 work.Sale = sale 298 work.Price = price 299 work.SaleTime = saleTime 300 if workJSONasByte, err := json.Marshal(work); err != nil { 301 return shim.Error(err.Error()) 302 } else if err = stub.PutState(workId, workJSONasByte); err != nil { 303 return shim.Error(err.Error()) 304 } 305 306 result := fmt.Sprintf("sell work:%v, sale:%v, price:%v", workId, sale, price) 307 return shim.Success([]byte(result)) 308 } 309 310 //@param query_type 311 func (w *WorkChainCode)query(stub shim.ChaincodeStubInterface, args []string) pb.Response { 312 queryType := args[0] 313 nType, err := strconv.Atoi(queryType) 314 if err != nil { 315 return shim.Error(err.Error()) 316 } 317 if nType <= QueryStart || nType >= QueryEnd { 318 return shim.Error("{\"Error\":\"invalid query\"}") 319 } 320 321 sender, err := stub.GetSender() 322 if err != nil { 323 return shim.Error("Fail to get sender's address.") 324 } 325 sender = strings.ToLower(sender) 326 327 resultsIterator, err := stub.GetStateByRange("", "") 328 if err != nil { 329 return shim.Error(err.Error()) 330 } 331 defer resultsIterator.Close() 332 333 var buffer bytes.Buffer 334 buffer.WriteString("[") 335 336 bArrayMemberAlreadyWritten := false 337 bArrayIndex := 1 338 work := WorkDef{} 339 for resultsIterator.HasNext() { 340 queryResponse, err := resultsIterator.Next() 341 if err != nil { 342 return shim.Error(err.Error()) 343 } 344 err = json.Unmarshal(queryResponse.Value, &work) 345 if err != nil { 346 continue 347 } 348 switch nType { 349 case All: 350 case Sale: 351 if 0 == work.Sale { 352 continue 353 } 354 case Self: 355 if sender != work.Owner { 356 continue 357 } 358 default: 359 return shim.Error("{\"Error\":\"invalid query\"}") 360 } 361 362 if bArrayMemberAlreadyWritten == true { 363 buffer.WriteString(",") 364 } 365 366 buffer.WriteString("{\"Number\":") 367 buffer.WriteString("\"") 368 buffer.WriteString(strconv.Itoa(bArrayIndex)) 369 buffer.WriteString("\"") 370 buffer.WriteString(", \"Record\":") 371 buffer.WriteString(string(queryResponse.Value)) 372 buffer.WriteString("}") 373 bArrayMemberAlreadyWritten = true 374 bArrayIndex ++ 375 } 376 buffer.WriteString("]") 377 378 return shim.Success([]byte(buffer.String())) 379 } 380 381 //@param workId 382 func (w *WorkChainCode) queryInkwork(stub shim.ChaincodeStubInterface, args []string) pb.Response { 383 workId := args[0] 384 valAsbytes, err := stub.GetState(workId) 385 if err != nil { 386 jsonResp := "{\"Error\":\"Failed to get state for " + workId + "," + err.Error() + "\"}" 387 return shim.Error(jsonResp) 388 } else if valAsbytes == nil { 389 jsonResp := "{\"Error\":\"cat does not exist: " + workId + "\"}" 390 return shim.Error(jsonResp) 391 } 392 393 return shim.Success(valAsbytes) 394 }