github.com/kchristidis/fabric@v1.0.4-0.20171028114726-837acd08cde1/test/chaincodes/AuctionApp/art.go (about) 1 /* 2 Copyright IT People Corp. 2017 All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 6 */ 7 8 /////////////////////////////////////////////////////////////////////// 9 // Author : IT People - Mohan Venkataraman - Auction API for v1.0 10 // Purpose: Explore the Hyperledger/fabric and understand 11 // how to write an chain code, application/chain code boundaries 12 // The code is not the best as it has just hammered out in a day or two 13 // Feedback and updates are appreciated 14 /////////////////////////////////////////////////////////////////////// 15 16 package main 17 18 import ( 19 "encoding/json" 20 "errors" 21 "fmt" 22 "io" 23 "net/http" 24 "os" 25 "runtime" 26 "strconv" 27 "time" 28 29 "github.com/hyperledger/fabric/core/chaincode/shim" 30 pb "github.com/hyperledger/fabric/protos/peer" 31 ) 32 33 /////////////////////////////////////////////////////////////////////////////////////// 34 // This creates a record of the Asset (Inventory) 35 // Includes Description, title, certificate of authenticity or image whatever..idea is to checkin a image and store it 36 // in encrypted form 37 // Example: 38 // Item { 113869, "Flower Urn on a Patio", "Liz Jardine", "10102007", "Original", "Floral", "Acrylic", "15 x 15 in", "sample_9.png","$600", "My Gallery } 39 /////////////////////////////////////////////////////////////////////////////////////// 40 41 type ItemObject struct { 42 ItemID string 43 RecType string 44 ItemDesc string 45 ItemDetail string // Could included details such as who created the Art work if item is a Painting 46 ItemDate string 47 ItemType string 48 ItemSubject string 49 ItemMedia string 50 ItemSize string 51 ItemPicFN string 52 ItemImage []byte // This has to be generated AES encrypted using the file name 53 AES_Key []byte // This is generated by the AES Algorithms 54 ItemImageType string // should be used to regenerate the appropriate image type 55 ItemBasePrice string // Reserve Price at Auction must be greater than this price 56 CurrentOwnerID string // This is validated for a user registered record 57 TimeStamp string // This is the time stamp 58 } 59 60 //////////////////////////////////////////////////////////////////////////////// 61 // Has an item entry every time the item changes hands 62 //////////////////////////////////////////////////////////////////////////////// 63 type ItemLog struct { 64 ItemID string // PRIMARY KEY 65 Status string // SECONDARY KEY - OnAuc, OnSale, NA 66 AuctionedBy string // SECONDARY KEY - Auction House ID if applicable 67 RecType string // ITEMHIS 68 ItemDesc string 69 CurrentOwner string 70 Date string // Date when status changed 71 } 72 73 ///////////////////////////////////////////////////////////// 74 // Create Buyer, Seller , Auction House, Authenticator 75 // Could establish valid UserTypes - 76 // AH (Auction House) 77 // TR (Buyer or Seller) 78 // AP (Appraiser) 79 // IN (Insurance) 80 // BK (bank) 81 // SH (Shipper) 82 ///////////////////////////////////////////////////////////// 83 type UserObject struct { 84 UserID string 85 RecType string // Type = USER 86 Name string 87 UserType string // Auction House (AH), Bank (BK), Buyer or Seller (TR), Shipper (SH), Appraiser (AP) 88 Address string 89 Phone string 90 Email string 91 Bank string 92 AccountNo string 93 RoutingNo string 94 Timestamp string 95 } 96 97 ///////////////////////////////////////////////////////////////////////////// 98 // Register a request for participating in an auction 99 // Usually posted by a seller who owns a piece of ITEM 100 // The Auction house will determine when to open the item for Auction 101 // The Auction House may conduct an appraisal and genuineness of the item 102 ///////////////////////////////////////////////////////////////////////////// 103 104 type AuctionRequest struct { 105 AuctionID string 106 RecType string // AUCREQ 107 ItemID string 108 AuctionHouseID string // ID of the Auction House managing the auction 109 SellerID string // ID Of Seller - to verified against the Item CurrentOwnerId 110 RequestDate string // Date on which Auction Request was filed 111 ReservePrice string // reserver price > previous purchase price 112 BuyItNowPrice string // 0 (Zero) if not applicable else specify price 113 Status string // INIT, OPEN, CLOSED (To be Updated by Trgger Auction) 114 OpenDate string // Date on which auction will occur (To be Updated by Trigger Auction) 115 CloseDate string // Date and time when Auction will close (To be Updated by Trigger Auction) 116 TimeStamp string // The transaction Date and Time 117 } 118 119 ///////////////////////////////////////////////////////////// 120 // POST the transaction after the Auction Completes 121 // Post an Auction Transaction 122 // Post an Updated Item Object 123 // Once an auction request is opened for auctions, a timer is kicked 124 // off and bids are accepted. When the timer expires, the highest bid 125 // is selected and converted into a Transaction 126 // This transaction is a simple view 127 ///////////////////////////////////////////////////////////// 128 129 type ItemTransaction struct { 130 AuctionID string 131 RecType string // POSTTRAN 132 ItemID string 133 TransType string // Sale, Buy, Commission 134 UserId string // Buyer or Seller ID 135 TransDate string // Date of Settlement (Buyer or Seller) 136 HammerTime string // Time of hammer strike - SOLD 137 HammerPrice string // Total Settlement price 138 Details string // Details about the Transaction 139 } 140 141 //////////////////////////////////////////////////////////////// 142 // This is a Bid. Bids are accepted only if an auction is OPEN 143 //////////////////////////////////////////////////////////////// 144 145 type Bid struct { 146 AuctionID string 147 RecType string // BID 148 BidNo string 149 ItemID string 150 BuyerID string // ID Of Buyer - to be verified against the Item CurrentOwnerId 151 BidPrice string // BidPrice > Previous Bid 152 BidTime string // Time the bid was received 153 } 154 155 ////////////////////////////////////////////////////////////// 156 // Invoke Functions based on Function name 157 // The function name gets resolved to one of the following calls 158 // during an invoke 159 // 160 ////////////////////////////////////////////////////////////// 161 func InvokeFunction(fname string) func(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 162 InvokeFunc := map[string]func(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response{ 163 "iPostItem": PostItem, 164 "iPostUser": PostUser, 165 "iPostAuctionRequest": PostAuctionRequest, 166 "iPostTransaction": PostTransaction, 167 "iPostBid": PostBid, 168 "iOpenAuctionForBids": OpenAuctionForBids, 169 "iBuyItNow": BuyItNow, 170 "iTransferItem": TransferItem, 171 "iCloseAuction": CloseAuction, 172 "iCloseOpenAuctions": CloseOpenAuctions, 173 "iDownloadImages": DownloadImages, 174 } 175 return InvokeFunc[fname] 176 } 177 178 ////////////////////////////////////////////////////////////// 179 // Query Functions based on Function name 180 // 181 ////////////////////////////////////////////////////////////// 182 func QueryFunction(fname string) func(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 183 QueryFunc := map[string]func(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response{ 184 "qGetItem": GetItem, 185 "qGetUser": GetUser, 186 "qGetAuctionRequest": GetAuctionRequest, 187 "qGetTransaction": GetTransaction, 188 "qGetBid": GetBid, 189 "qGetLastBid": GetLastBid, 190 "qGetHighestBid": GetHighestBid, 191 "qGetNoOfBidsReceived": GetNoOfBidsReceived, 192 "qGetListOfBids": GetListOfBids, 193 "qGetItemLog": GetItemLog, 194 "qGetItemListByCat": GetItemListByCat, 195 "qGetUserListByCat": GetUserListByCat, 196 "qGetListOfInitAucs": GetListOfInitAucs, 197 "qGetListOfOpenAucs": GetListOfOpenAucs, 198 "qValidateItemOwnership": ValidateItemOwnership, 199 } 200 return QueryFunc[fname] 201 } 202 203 ///////////////////////////////////////////////////////////////////////////////////////////////////// 204 // We are storing the PictureMap as a Key/Value pair to download the images on the container. 205 // This was done to run the Daily/Weeky Test Cases from CLI 206 ///////////////////////////////////////////////////////////////////////////////////////////////////// 207 208 //func GetPictureUrl(picname string) string { 209 var PictureMap = map[string]string{ 210 "art1.png": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/art1.png", 211 "art2.png": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/art2.png", 212 "art3.png": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/art3.png", 213 "art4.png": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/art4.png", 214 "art5.png": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/art5.png", 215 "art6.png": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/art6.png", 216 "art7.png": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/art7.png", 217 "item-001.jpg": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/item-001.jpg", 218 "item-002.jpg": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/item-002.jpg", 219 "item-003.jpg": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/item-003.jpg", 220 "item-004.jpg": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/item-004.jpg", 221 "item-005.jpg": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/item-005.jpg", 222 "item-006.jpg": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/item-006.jpg", 223 "item-007.jpg": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/item-007.jpg", 224 "item-008.jpg": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/item-008.jpg", 225 "people.gif": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/people.gif", 226 "mad-fb.jpg": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/mad-fb.gif", 227 "sample.png": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/sample.png", 228 } 229 230 type SimpleChaincode struct { 231 } 232 233 //////////////////////////////////////////////////////////////////////////////// 234 // Chain Code Kick-off Main function 235 //////////////////////////////////////////////////////////////////////////////// 236 func main() { 237 238 // maximize CPU usage for maximum performance 239 runtime.GOMAXPROCS(runtime.NumCPU()) 240 fmt.Println("Starting Item Auction Application chaincode BlueMix ver 21 Dated 2016-07-02 09.45.00: ") 241 242 //ccPath = fmt.Sprintf("%s/src/github.com/hyperledger/fabric/auction/art/artchaincode/", gopath) 243 // Start the shim -- running the fabric 244 err := shim.Start(new(SimpleChaincode)) 245 if err != nil { 246 fmt.Println("Error starting Item Fun Application chaincode: %s", err) 247 } 248 249 } 250 251 ///////////////////////////////////////////////////////////////////////////////////////////////////// 252 // We are storing the PictureMap as a Key/Value pair to download the images on the container. 253 // This was done to run the Daily/Weeky Test Cases from CLI 254 ///////////////////////////////////////////////////////////////////////////////////////////////////// 255 256 func downloadFile(filepath string, url string) (err error) { 257 258 // Create the file 259 out, err := os.Create(filepath) 260 if err != nil { 261 return err 262 } 263 defer out.Close() 264 265 // Get the data 266 resp, err := http.Get(url) 267 if err != nil { 268 return err 269 } 270 defer resp.Body.Close() 271 272 // Writer the body to file 273 _, err = io.Copy(out, resp.Body) 274 if err != nil { 275 return err 276 } 277 278 return nil 279 } 280 281 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 282 // SimpleChaincode - Init Chaincode implementation - The following sequence of transactions can be used to test the Chaincode 283 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 284 285 func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response { 286 287 // TODO - Include all initialization to be complete before Invoke and Query 288 // Uses aucTables to delete tables if they exist and re-create them 289 290 //myLogger.Info("[Trade and Auction Application] Init") 291 fmt.Println("[Trade and Auction Application] Init") 292 fmt.Println("\nInit() Initialization Complete ") 293 return shim.Success(nil) 294 } 295 296 //////////////////////////////////////////////////////////////// 297 // SimpleChaincode - INVOKE Chaincode implementation 298 // User Can Invoke 299 // - Register a user using PostUser 300 // - Register an item using PostItem 301 // - The Owner of the item (User) can request that the item be put on auction using PostAuctionRequest 302 // - The Auction House can request that the auction request be Opened for bids using OpenAuctionForBids 303 // - One the auction is OPEN, registered buyers (Buyers) can send in bids vis PostBid 304 // - No bid is accepted when the status of the auction request is INIT or CLOSED 305 // - Either manually or by OpenAuctionRequest, the auction can be closed using CloseAuction 306 // - The CloseAuction creates a transaction and invokes PostTransaction 307 //////////////////////////////////////////////////////////////// 308 309 func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response { 310 311 function, args := stub.GetFunctionAndParameters() 312 fmt.Println("==========================================================") 313 fmt.Println("BEGIN Function ====> ", function) 314 if function[0:1] == "i" { 315 fmt.Println("==========================================================") 316 return t.invoke(stub, function, args) 317 } 318 319 if function[0:1] == "q" { 320 fmt.Println("==========================================================") 321 return t.query(stub, function, args) 322 } 323 324 fmt.Println("==========================================================") 325 326 return shim.Error("Invoke: Invalid Function Name - function names begin with a q or i") 327 328 } 329 330 //////////////////////////////////////////////////////////////// 331 // SimpleChaincode - INVOKE Chaincode implementation 332 // User Can Invoke 333 // - Register a user using PostUser 334 // - Register an item using PostItem 335 // - The Owner of the item (User) can request that the item be put on auction using PostAuctionRequest 336 // - The Auction House can request that the auction request be Opened for bids using OpenAuctionForBids 337 // - One the auction is OPEN, registered buyers (Buyers) can send in bids vis PostBid 338 // - No bid is accepted when the status of the auction request is INIT or CLOSED 339 // - Either manually or by OpenAuctionRequest, the auction can be closed using CloseAuction 340 // - The CloseAuction creates a transaction and invokes PostTransaction 341 //////////////////////////////////////////////////////////////// 342 343 func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 344 345 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 346 // Check Type of Transaction and apply business rules 347 // before adding record to the block chain 348 // In this version, the assumption is that args[1] specifies recType for all defined structs 349 // Newer structs - the recType can be positioned anywhere and ChkReqType will check for recType 350 // example: 351 // ./peer chaincode invoke -l golang -n mycc -c '{"Function": "PostBid", "Args":["1111", "BID", "1", "1000", "300", "1200"]}' 352 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 353 354 if ChkRecType(args) == true { 355 356 InvokeRequest := InvokeFunction(function) 357 if InvokeRequest != nil { 358 response := InvokeRequest(stub, function, args) 359 return (response) 360 } 361 } else { 362 fmt.Println("Invoke() Invalid recType : ", args, "\n") 363 error_str := "Invoke() : Invalid recType : " + args[0] 364 return shim.Error(error_str) 365 } 366 367 return shim.Success(nil) 368 } 369 370 ////////////////////////////////////////////////////////////////////////////////////////// 371 // SimpleChaincode - query Chaincode implementation 372 // Client Can Query 373 // Sample Data 374 // ./peer chaincode query -l golang -n mycc -c '{"Function": "GetUser", "Args": ["4000"]}' 375 // ./peer chaincode query -l golang -n mycc -c '{"Function": "GetItem", "Args": ["2000"]}' 376 ////////////////////////////////////////////////////////////////////////////////////////// 377 378 func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 379 380 // var buff []byte 381 var response pb.Response 382 fmt.Println("Query() : ID Extracted and Type = ", args[0]) 383 fmt.Println("Query() : Args supplied : ", args) 384 385 if len(args) < 1 { 386 fmt.Println("Query() : Include at least 1 arguments Key ") 387 return shim.Error("Query() : Expecting Transaction type and Key value for query") 388 } 389 390 QueryRequest := QueryFunction(function) 391 if QueryRequest != nil { 392 response = QueryRequest(stub, function, args) 393 } else { 394 fmt.Println("Query() Invalid function call : ", function) 395 response_str := "Query() : Invalid function call : " + function 396 return shim.Error(response_str) 397 } 398 399 if response.Status != shim.OK { 400 fmt.Println("Query() Object not found : ", args[0]) 401 response_str := "Query() : Object not found : " + args[0] 402 return shim.Error(response_str) 403 } 404 return response 405 } 406 407 ////////////////////////////////////////////////////////////////////////////////////////// 408 // Download Images into Peer 409 ////////////////////////////////////////////////////////////////////////////////////////// 410 func DownloadImages(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 411 412 fmt.Println("[Trade and Auction Application] DownloadImages") 413 var err error 414 for k, v := range PictureMap { 415 fmt.Printf("\n Downloading Image '%s' from URL: %s", k, v) 416 err = downloadFile(k, v) 417 if err != nil { 418 fmt.Println(err) 419 return shim.Error("Invoke: Invalid Function Name - function names begin with a q or i") 420 } 421 } 422 fmt.Println("\nDownloadImages() Complete ") 423 return shim.Success(nil) 424 } 425 426 ////////////////////////////////////////////////////////////////////////////////////////// 427 // Retrieve User Information 428 // example: 429 // ./peer chaincode query -l golang -n mycc -c '{"Function": "GetUser", "Args": ["100"]}' 430 // 431 ////////////////////////////////////////////////////////////////////////////////////////// 432 func GetUser(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 433 434 var err error 435 436 // Get the Object and Display it 437 Avalbytes, err := QueryObject(stub, "User", args) 438 if err != nil { 439 fmt.Println("GetUser() : Failed to Query Object ") 440 jsonResp := "{\"Error\":\"Failed to get Object Data for " + args[0] + "\"}" 441 return shim.Error(jsonResp) 442 } 443 444 if Avalbytes == nil { 445 fmt.Println("GetUser() : Incomplete Query Object ") 446 jsonResp := "{\"Error\":\"Incomplete information about the key for " + args[0] + "\"}" 447 return shim.Error(jsonResp) 448 } 449 450 fmt.Println("GetUser() : Response : Successful -") 451 return shim.Success(Avalbytes) 452 } 453 454 ///////////////////////////////////////////////////////////////////////////////////////// 455 // Query callback representing the query of a chaincode 456 // Retrieve a Item by Item ID 457 // QueryObjectWithProcessingFunction takes a post processing function as argument 458 // peer chaincode query -l golang -n mycc -c '{"Args": ["qGetItem", "1000"]} 459 // 460 ///////////////////////////////////////////////////////////////////////////////////////// 461 func GetItem(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 462 463 var err error 464 465 // Get the Objects and Display it 466 Avalbytes, err := QueryObjectWithProcessingFunction(stub, "Item", args, ProcessQueryResult) 467 if err != nil { 468 fmt.Println("GetItem() : Failed to Query Object ") 469 jsonResp := "{\"Error\":\"Failed to get Object Data for " + args[0] + "\"}" 470 return shim.Error(jsonResp) 471 } 472 473 if Avalbytes == nil { 474 fmt.Println("GetItem() : Incomplete Query Object ") 475 jsonResp := "{\"Error\":\"Incomplete information about the key for " + args[0] + "\"}" 476 return shim.Error(jsonResp) 477 } 478 479 // Masking ItemImage binary data 480 itemObj, _ := JSONtoAR(Avalbytes) 481 itemObj.ItemImage = []byte{} 482 Avalbytes, _ = ARtoJSON(itemObj) 483 484 fmt.Println("GetItem() : Response : Successful ") 485 return shim.Success(Avalbytes) 486 } 487 488 ///////////////////////////////////////////////////////////////////////////////////////// 489 // Validates The Ownership of an Asset using ItemID, OwnerID, and HashKey 490 // 491 // peer chaincode query -l golang -n mycc -c '{"Function": "ValidateItemOwnership", "Args": ["1000", "100", "tGEBaZuKUBmwTjzNEyd+nr/fPUASuVJAZ1u7gha5fJg="]}' 492 // 493 ///////////////////////////////////////////////////////////////////////////////////////// 494 func ValidateItemOwnership(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 495 496 var err error 497 498 if len(args) < 3 { 499 fmt.Println("ValidateItemOwnership() : Requires 3 arguments Item#, Owner# and Key ") 500 return shim.Error("ValidateItemOwnership() : Requires 3 arguments Item#, Owner# and Key") 501 } 502 503 // Get the Object Information 504 Avalbytes, err := QueryObject(stub, "Item", []string{args[0]}) 505 if err != nil { 506 fmt.Println("ValidateItemOwnership() : Failed to Query Object ") 507 jsonResp := "{\"Error\":\"Failed to get Object Data for " + args[0] + "\"}" 508 return shim.Error(jsonResp) 509 } 510 511 if Avalbytes == nil { 512 fmt.Println("ValidateItemOwnership() : Incomplete Query Object ") 513 jsonResp := "{\"Error\":\"Incomplete information about the key for " + args[0] + "\"}" 514 return shim.Error(jsonResp) 515 } 516 517 myItem, err := JSONtoAR(Avalbytes) 518 if err != nil { 519 fmt.Println("ValidateItemOwnership() : Failed to Query Object ") 520 jsonResp := "{\"Error\":\"Failed to get Object Data for " + args[0] + "\"}" 521 return shim.Error(jsonResp) 522 } 523 524 myKey := GetKeyValue(Avalbytes, "AES_Key") 525 fmt.Println("Key String := ", myKey) 526 527 if myKey != args[2] { 528 fmt.Println("ValidateItemOwnership() : Key does not match supplied key ", args[2], " - ", myKey) 529 jsonResp := "{\"Error\":\"ValidateItemOwnership() : Key does not match asset owner supplied key " + args[0] + "\"}" 530 return shim.Error(jsonResp) 531 } 532 533 if myItem.CurrentOwnerID != args[1] { 534 fmt.Println("ValidateItemOwnership() : ValidateItemOwnership() : Owner-Id does not match supplied ID ", args[1]) 535 jsonResp := "{\"Error\":\"ValidateItemOwnership() : Owner-Id does not match supplied ID " + args[0] + "\"}" 536 return shim.Error(jsonResp) 537 } 538 539 fmt.Print("ValidateItemOwnership() : Response : Successful - \n") 540 return shim.Success(Avalbytes) 541 } 542 543 ///////////////////////////////////////////////////////////////////////////////////////////////////// 544 // Retrieve Auction Information 545 // This query runs against the AuctionTable 546 // ./peer chaincode query -l golang -n mycc -c '{"Function": "GetAuctionRequest", "Args": ["1111"]}' 547 // There are two other tables just for query purposes - AucInitTable, AucOpenTable 548 // 549 ///////////////////////////////////////////////////////////////////////////////////////////////////// 550 func GetAuctionRequest(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 551 552 var err error 553 554 // Get the Objects and Display it 555 Avalbytes, err := QueryObject(stub, "Auction", args) 556 if err != nil { 557 fmt.Println("GetAuctionRequest() : Failed to Query Object ") 558 jsonResp := "{\"Error\":\"Failed to get Object Data for " + args[0] + "\"}" 559 return shim.Error(jsonResp) 560 } 561 562 if Avalbytes == nil { 563 fmt.Println("GetAuctionRequest() : Incomplete Query Object ") 564 jsonResp := "{\"Error\":\"Incomplete information about the key for " + args[0] + "\"}" 565 return shim.Error(jsonResp) 566 } 567 568 fmt.Println("GetAuctionRequest() : Response : Successful - \n") 569 return shim.Success(Avalbytes) 570 } 571 572 /////////////////////////////////////////////////////////////////////////////////////////////////// 573 // Retrieve a Bid based on two keys - AucID, BidNo 574 // A Bid has two Keys - The Auction Request Number and Bid Number 575 // ./peer chaincode query -l golang -n mycc -c '{"Function": "GetLastBid", "Args": ["1111", "1"]}' 576 // 577 /////////////////////////////////////////////////////////////////////////////////////////////////// 578 func GetBid(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 579 580 var err error 581 582 // Check there are 2 Arguments provided as per the struct - two are computed 583 // See example 584 if len(args) < 2 { 585 fmt.Println("GetBid(): Incorrect number of arguments. Expecting 2 ") 586 fmt.Println("GetBid(): ./peer chaincode query -l golang -n mycc -c '{\"Function\": \"GetBid\", \"Args\": [\"1111\",\"6\"]}'") 587 return shim.Error("GetBid(): Incorrect number of arguments. Expecting 2 ") 588 } 589 590 // Get the Objects and Display it 591 Avalbytes, err := QueryObject(stub, "Bid", args) 592 if err != nil { 593 fmt.Println("GetBid() : Failed to Query Object ") 594 jsonResp := "{\"Error\":\"Failed to get Object Data for " + args[0] + "\"}" 595 return shim.Error(jsonResp) 596 } 597 598 if Avalbytes == nil { 599 fmt.Println("GetBid() : Incomplete Query Object ") 600 jsonResp := "{\"Error\":\"Incomplete information about the key for " + args[0] + "\"}" 601 return shim.Error(jsonResp) 602 } 603 604 fmt.Println("GetBid() : Response : Successful -") 605 return shim.Success(Avalbytes) 606 } 607 608 /////////////////////////////////////////////////////////////////////////////////////////////////// 609 // Retrieve Auction Closeout Information. When an Auction closes 610 // The highest bid is retrieved and converted to a Transaction 611 // ./peer chaincode query -l golang -n mycc -c '{"Function": "GetTransaction", "Args": ["1111"]}' 612 // 613 /////////////////////////////////////////////////////////////////////////////////////////////////// 614 func GetTransaction(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 615 616 //var err error 617 618 // Get the Objects and Display it 619 Avalbytes, err := QueryObject(stub, "Trans", args) 620 if Avalbytes == nil { 621 fmt.Println("GetTransaction() : Incomplete Query Object ") 622 jsonResp := "{\"Error\":\"Incomplete information about the key for " + args[0] + "\"}" 623 return shim.Error(jsonResp) 624 } 625 626 if err != nil { 627 fmt.Println("GetTransaction() : Failed to Query Object ") 628 jsonResp := "{\"Error\":\"Failed to get Object Data for " + args[0] + "\"}" 629 return shim.Error(jsonResp) 630 } 631 632 fmt.Println("GetTransaction() : Response : Successful") 633 return shim.Success(Avalbytes) 634 } 635 636 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 637 // Create a User Object. The first step is to have users 638 // registered 639 // There are different types of users - Traders (TRD), Auction Houses (AH) 640 // Shippers (SHP), Insurance Companies (INS), Banks (BNK) 641 // While this version of the chain code does not enforce strict validation 642 // the business process recommends validating each persona for the service 643 // they provide or their participation on the auction blockchain, future enhancements will do that 644 // ./peer chaincode invoke -l golang -n mycc -c '{"Function": "PostUser", "Args":["100", "USER", "Ashley Hart", "TRD", "Morrisville Parkway, #216, Morrisville, NC 27560", "9198063535", "ashley@itpeople.com", "SUNTRUST", "00017102345", "0234678"]}' 645 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 646 647 func PostUser(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 648 649 record, err := CreateUserObject(args[0:]) // 650 if err != nil { 651 return shim.Error(err.Error()) 652 } 653 buff, err := UsertoJSON(record) // 654 655 if err != nil { 656 error_str := "PostuserObject() : Failed Cannot create object buffer for write : " + args[1] 657 fmt.Println(error_str) 658 return shim.Error(error_str) 659 } else { 660 // Update the ledger with the Buffer Data 661 // err = stub.PutState(args[0], buff) 662 keys := []string{args[0]} 663 err = UpdateObject(stub, "User", keys, buff) 664 if err != nil { 665 fmt.Println("PostUser() : write error while inserting record") 666 return shim.Error("PostUser() : write error while inserting record : Error - " + err.Error()) 667 } 668 669 // Post Entry into UserCat- i.e. User Category Table 670 keys = []string{"2016", args[3], args[0]} 671 err = UpdateObject(stub, "UserCat", keys, buff) 672 if err != nil { 673 error_str := "PostUser() : write error while inserting recordinto UserCat" 674 fmt.Println(error_str) 675 return shim.Error(error_str) 676 } 677 } 678 679 return shim.Success(buff) 680 } 681 682 func CreateUserObject(args []string) (UserObject, error) { 683 684 var err error 685 var aUser UserObject 686 687 // Check there are 11 Arguments 688 if len(args) != 11 { 689 fmt.Println("CreateUserObject(): Incorrect number of arguments. Expecting 11 ") 690 return aUser, errors.New("CreateUserObject() : Incorrect number of arguments. Expecting 11 ") 691 } 692 693 // Validate UserID is an integer 694 695 _, err = strconv.Atoi(args[0]) 696 if err != nil { 697 return aUser, errors.New("CreateUserObject() : User ID should be an integer") 698 } 699 700 aUser = UserObject{args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10]} 701 fmt.Println("CreateUserObject() : User Object : ", aUser) 702 703 return aUser, nil 704 } 705 706 ///////////////////////////////////////////////////////////////////////////////////////////////////////////// 707 // Create a master Object of the Item 708 // Since the Owner Changes hands, a record has to be written for each 709 // Transaction with the updated Encryption Key of the new owner 710 // Example 711 //./peer chaincode invoke -l golang -n mycc -c '{"Function": "PostItem", "Args":["1000", "ARTINV", "Shadows by Asppen", "Asppen Messer", "20140202", "Original", "Landscape" , "Canvas", "15 x 15 in", "sample_7.png","$600", "100", "2016-02-02 03:000:00"]}' 712 ///////////////////////////////////////////////////////////////////////////////////////////////////////////// 713 714 func PostItem(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 715 716 itemObject, err := CreateItemObject(args[0:]) 717 if err != nil { 718 fmt.Println("PostItem(): Cannot create item object \n") 719 return shim.Error("PostItem(): Cannot create item object") 720 } 721 722 // Check if the Owner ID specified is registered and valid 723 response := ValidateMember(stub, itemObject.CurrentOwnerID) 724 ownerInfo := response.Payload 725 fmt.Println("Owner information ", ownerInfo, itemObject.CurrentOwnerID) 726 if response.Status != shim.OK { 727 error_str := "PostItem() : Failed Owner information not found for " + itemObject.CurrentOwnerID 728 fmt.Println(error_str) 729 return shim.Error(error_str) 730 } 731 732 // Convert Item Object to JSON 733 buff, err := ARtoJSON(itemObject) // 734 if err != nil { 735 error_str := "PostItem() : Failed Cannot create object buffer for write : " + args[1] 736 fmt.Println(error_str) 737 return shim.Error(error_str) 738 } else { 739 // Update the ledger with the Buffer Data 740 // err = stub.PutState(args[0], buff) 741 keys := []string{args[0]} 742 err = UpdateObject(stub, "Item", keys, buff) 743 if err != nil { 744 fmt.Println("PostItem() : write error while inserting record\n") 745 return shim.Error("PostItem() : write error while inserting record : " + err.Error()) 746 } 747 748 // Put an entry into the Item History Table 749 response := PostItemLog(stub, itemObject, "INITIAL", "DEFAULT", args[12]) 750 if response.Status != shim.OK { 751 fmt.Println("PostItemLog() : write error while inserting record\n") 752 return shim.Error("PostItemLog() : write error while inserting record : Error : " + err.Error()) 753 } 754 755 // Post Entry into ItemCatTable - i.e. Item Category Table 756 // The first key 2016 is a dummy (band aid) key to extract all values 757 keys = []string{"2016", args[6], args[0]} 758 err = UpdateObject(stub, "ItemCat", keys, buff) 759 if err != nil { 760 fmt.Println("PostItem() : Write error while inserting record into ItemCat \n") 761 return shim.Error("PostItem() : Write error while inserting record into ItemCat : Error : " + err.Error()) 762 } 763 } 764 765 secret_key, _ := json.Marshal(itemObject.AES_Key) 766 fmt.Println(string(secret_key)) 767 return shim.Success(secret_key) 768 } 769 770 func CreateItemObject(args []string) (ItemObject, error) { 771 772 var err error 773 var myItem ItemObject 774 775 // Check there are 13 Arguments provided as per the struct - two are computed 776 if len(args) != 13 { 777 fmt.Println("CreateItemObject(): Incorrect number of arguments. Expecting 13 ") 778 return myItem, errors.New("CreateItemObject(): Incorrect number of arguments. Expecting 13 ") 779 } 780 781 // Validate ItemID is an integer 782 783 _, err = strconv.Atoi(args[0]) 784 if err != nil { 785 fmt.Println("CreateItemObject(): ART ID should be an integer create failed! ") 786 return myItem, errors.New("CreateItemObject(): ART ID should be an integer create failed!") 787 } 788 789 // Validate Picture File exists based on the name provided 790 // Looks for file in current directory of application and must be fixed for other locations 791 792 // Validate Picture File exists based on the name provided 793 // Looks for file in current directory of application and must be fixed for other locations 794 imagePath := args[9] 795 if _, err := os.Stat(imagePath); err == nil { 796 fmt.Println(imagePath, " exists!") 797 } else { 798 fmt.Println("CreateItemObject(): Cannot find or load Picture File = %s : %s\n", imagePath, err) 799 return myItem, errors.New("CreateItemObject(): ART Picture File not found " + imagePath) 800 } 801 802 // Get the Item Image and convert it to a byte array 803 imagebytes, fileType := ImageToByteArray(imagePath) 804 805 // Generate a new key and encrypt the image 806 807 AES_key, _ := GenAESKey() 808 AES_enc := Encrypt(AES_key, imagebytes) 809 810 // Append the AES Key, The Encrypted Image Byte Array and the file type 811 myItem = ItemObject{args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], AES_enc, AES_key, fileType, args[10], args[11], args[12]} 812 813 fmt.Println("CreateItemObject(): Item Object created: ", myItem.ItemID, myItem.AES_Key) 814 815 // Code to Validate the Item Object) 816 // If User presents Crypto Key then key is used to validate the picture that is stored as part of the title 817 // TODO 818 819 return myItem, nil 820 } 821 822 /////////////////////////////////////////////////////////////////////////////////// 823 // Since the Owner Changes hands, a record has to be written for each 824 // Transaction with the updated Encryption Key of the new owner 825 // This function is internally invoked by PostTransaction and is not a Public API 826 /////////////////////////////////////////////////////////////////////////////////// 827 828 func UpdateItemObject(stub shim.ChaincodeStubInterface, ar []byte, hammerPrice string, buyer string) pb.Response { 829 830 var err error 831 myItem, err := JSONtoAR(ar) 832 if err != nil { 833 fmt.Println("UpdateItemObject() : Failed to create Art Record Object from JSON ") 834 return shim.Error("UpdateItemObject() : Failed to create Art Record Object from JSON : Error : " + err.Error()) 835 } 836 837 // Insert logic to re-encrypt image by first fetching the current Key 838 CurrentAES_Key := myItem.AES_Key 839 // Decrypt Image and Save Image in a file 840 image := Decrypt(CurrentAES_Key, myItem.ItemImage) 841 842 // Get a New Key & Encrypt Image with New Key 843 myItem.AES_Key, _ = GenAESKey() 844 myItem.ItemImage = Encrypt(myItem.AES_Key, image) 845 846 // Update the owner to the Buyer and update price to auction hammer price 847 myItem.ItemBasePrice = hammerPrice 848 myItem.CurrentOwnerID = buyer 849 850 ar, err = ARtoJSON(myItem) 851 // keys := []string{myItem.ItemID, myItem.CurrentOwnerID} // Was the original in v0.6 852 keys := []string{myItem.ItemID} 853 err = ReplaceObject(stub, "Item", keys, ar) 854 if err != nil { 855 fmt.Println("UpdateItemObject() : Failed ReplaceObject in ItemTable into Blockchain ") 856 return shim.Error("UpdateItemObject() : Failed ReplaceObject in ItemTable into Blockchain : Error : " + err.Error()) 857 } 858 fmt.Println("UpdateItemObject() : ReplaceObject in Item successful ") 859 860 // Update entry in Item Category Table as it holds the Item object as wekk 861 keys = []string{"2016", myItem.ItemSubject, myItem.ItemID} 862 err = ReplaceObject(stub, "ItemCat", keys, ar) 863 if err != nil { 864 fmt.Println("UpdateItemObject() : Failed ReplaceObject in ItemCategory into Blockchain ") 865 return shim.Error("UpdateItemObject() : Failed ReplaceObject in ItemCategory into Blockchain : Error : " + err.Error()) 866 } 867 868 fmt.Println("UpdateItemObject() : ReplaceObject in ItemCategory successful ") 869 return shim.Success(myItem.AES_Key) 870 } 871 872 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 873 // Obtain Asset Details and Validate Item 874 // Transfer Item to new owner - no change in price - In the example XFER is the recType 875 // ./peer chaincode invoke -l golang -n mycc -c '{"Function": "TransferItem", "Args": ["1000", "100", "tGEBaZuKUBmwTjzNEyd+nr/fPUASuVJAZ1u7gha5fJg=", "300", "XFER"]}' 876 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 877 func TransferItem(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 878 879 var err error 880 881 if len(args) < 6 { 882 fmt.Println("TransferItem() : Requires 6 arguments Item#, Owner#, Key#, newOwnerID#, XFER \n") 883 return shim.Error("TransferItem() : Requires 6 arguments Item#, Owner#, Key#, newOwnerID#, XFER") 884 } 885 886 // Let us make sure that the Item is not on Auction 887 err = VerifyIfItemIsOnAuction(stub, args[0]) 888 if err != nil { 889 error_str := "TransferItem() : Failed Item is either initiated or opened for Auction " + args[0] 890 fmt.Println(error_str) 891 return shim.Error(error_str + ": Error : " + err.Error()) 892 } 893 894 // Validate New Owner's ID 895 response := ValidateMember(stub, args[3]) 896 if response.Status != shim.OK { 897 error_str := "TransferItem() : Failed transferee not Registered in Blockchain " + args[3] 898 fmt.Println(error_str) 899 return shim.Error(error_str + ": Error : " + response.Message) 900 } 901 902 // Validate Item or Asset Ownership 903 response = ValidateItemOwnership(stub, "ValidateItemOwnership", args[:3]) 904 if response.Status != shim.OK { 905 error_str := "TransferItem() : ValidateItemOwnership() : Failed to authenticate item or asset ownership" 906 fmt.Println(error_str) 907 return shim.Error(error_str + ": Error : " + response.Message) 908 } 909 910 ar := response.Payload 911 myItem, err := JSONtoAR(ar) 912 if err != nil { 913 error_str := "TransferItem() : Failed to create item Object from JSON " 914 fmt.Println(error_str) 915 return shim.Error(error_str + ": Error : " + err.Error()) 916 } 917 918 // Insert logic to re-encrypt image by first fetching the current Key 919 CurrentAES_Key := myItem.AES_Key 920 // Decrypt Image and Save Image in a file 921 image := Decrypt(CurrentAES_Key, myItem.ItemImage) 922 923 // Get a New Key & Encrypt Image with New Key 924 myItem.AES_Key, _ = GenAESKey() 925 myItem.ItemImage = Encrypt(myItem.AES_Key, image) 926 927 // Update the owner to the new owner transferred to 928 myItem.CurrentOwnerID = args[3] 929 930 ar, err = ARtoJSON(myItem) 931 keys := []string{myItem.ItemID} 932 err = ReplaceObject(stub, "Item", keys, ar) 933 if err != nil { 934 fmt.Println("TransferAsset() : Failed ReplaceObject in ItemTable into Blockchain ") 935 return shim.Error(err.Error()) 936 } 937 fmt.Println("TransferAsset() : ReplaceObject in Item successful ") 938 939 // Update entry in Item Category Table as it holds the Item object as well 940 keys = []string{"2016", myItem.ItemSubject, myItem.ItemID} 941 err = ReplaceObject(stub, "ItemCat", keys, ar) 942 if err != nil { 943 fmt.Println("TransferAsset() : Failed ReplaceObject in ItemCategoryTable into Blockchain ") 944 return shim.Error(err.Error()) 945 } 946 947 response = PostItemLog(stub, myItem, "Transfer", args[1], args[5]) 948 if response.Status != shim.OK { 949 fmt.Println("TransferItem() : PostItemLog() write error while inserting record\n") 950 return shim.Error(err.Error()) 951 } 952 953 fmt.Println("TransferAsset() : ReplaceObject in ItemCategory successful ") 954 return shim.Success(myItem.AES_Key) 955 } 956 957 //////////////////////////////////////////////////////////////////////////////////// 958 // Validate Item Status - Is it currently on Auction, if so Reject Transfer Request 959 // This can be written better - will do so if things work 960 // The function return the Auction ID and the Status = OPEN or INIT 961 //////////////////////////////////////////////////////////////////////////////////// 962 963 func VerifyIfItemIsOnAuction(stub shim.ChaincodeStubInterface, itemID string) error { 964 965 response := GetListOfOpenAucs(stub, "AucOpen", []string{"2016"}) 966 if response.Status != shim.OK { 967 return fmt.Errorf("VerifyIfItemIsOnAuction() operation failed. Error retrieving values from AucOpen: %s", response.Message) 968 } 969 970 rows := response.Payload 971 tlist := make([]AuctionRequest, len(rows)) 972 err := json.Unmarshal([]byte(rows), &tlist) 973 if err != nil { 974 fmt.Println("VerifyIfItemIsOnAuction: Unmarshal failed : ", err) 975 return fmt.Errorf("VerifyIfItemIsOnAuction: operation failed. Error un-marshaling JSON: %s", err) 976 } 977 978 for i := 0; i < len(tlist); i++ { 979 ar := tlist[i] 980 981 // Compare Auction IDs 982 if ar.ItemID == itemID { 983 fmt.Println("VerifyIfItemIsOnAuction() Failed : Ummarshall error") 984 return fmt.Errorf("VerifyIfItemIsOnAuction() operation failed. %s", itemID) 985 } 986 } 987 988 // Now Check if an Auction Has been inititiated 989 // If so , it has to be removed from Auction for a Transfer 990 991 response = GetListOfInitAucs(stub, "AucInit", []string{"2016"}) 992 if response.Status != shim.OK { 993 return fmt.Errorf("VerifyIfItemIsOnAuction() operation failed. Error retrieving values from AucInit: %s", err) 994 } 995 996 rows = response.Payload 997 tlist = make([]AuctionRequest, len(rows)) 998 err = json.Unmarshal([]byte(rows), &tlist) 999 if err != nil { 1000 fmt.Println("VerifyIfItemIsOnAuction() Unmarshal failed : ", err) 1001 return fmt.Errorf("VerifyIfItemIsOnAuction: operation failed. Error un-marshaling JSON: %s", err) 1002 } 1003 1004 for i := 0; i < len(tlist); i++ { 1005 ar := tlist[i] 1006 if err != nil { 1007 fmt.Println("VerifyIfItemIsOnAuction() Failed : Ummarshall error") 1008 return fmt.Errorf("VerifyIfItemIsOnAuction() operation failed. %s", err) 1009 } 1010 1011 // Compare Auction IDs 1012 if ar.ItemID == itemID { 1013 return fmt.Errorf("VerifyIfItemIsOnAuction() operation failed.") 1014 } 1015 } 1016 1017 return nil 1018 } 1019 1020 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1021 // POSTS A LOG ENTRY Every Time the Item is transacted 1022 // Valid Status for ItemLog = OnAuc, OnSale, NA, INITIAL 1023 // Valid AuctionedBy: This value is set to "DEFAULT" but when it is put on auction Auction House ID is assigned 1024 // PostItemLog IS NOT A PUBLIC API and is invoked every time some event happens in the Item's life 1025 // The currentDateTime must be provided by Client 1026 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1027 1028 func PostItemLog(stub shim.ChaincodeStubInterface, item ItemObject, status string, ah string, currentDateTime string) pb.Response { 1029 1030 iLog := ItemToItemLog(item, currentDateTime) 1031 iLog.Status = status 1032 iLog.AuctionedBy = ah 1033 1034 buff, err := ItemLogtoJSON(iLog) 1035 if err != nil { 1036 fmt.Println("PostItemLog() : Failed Cannot create object buffer for write : ", item.ItemID) 1037 return shim.Error("PostItemLog(): Failed Cannot create object buffer for write : " + item.ItemID) 1038 } else { 1039 // Update the ledger with the Buffer Data 1040 keys := []string{iLog.ItemID, iLog.Status, iLog.AuctionedBy, currentDateTime} 1041 err = UpdateObject(stub, "ItemHistory", keys, buff) 1042 if err != nil { 1043 fmt.Println("PostItemLog() : write error while inserting record\n") 1044 return shim.Error(err.Error()) 1045 } 1046 } 1047 return shim.Success(buff) 1048 } 1049 1050 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1051 // Create an Auction Request 1052 // The owner of an Item, when ready to put the item on an auction 1053 // will create an auction request and specify a auction house. 1054 // 1055 // ./peer chaincode invoke -l golang -n mycc -c '{"Function": "PostAuctionRequest", "Args":["1111", "AUCREQ", "1700", "200", "400", "04012016", "1200", "INIT", "2016-05-20 11:00:00.3 +0000 UTC","2016-05-23 11:00:00.3 +0000 UTC", "2016-05-23 11:00:00.3 +0000 UTC"]}' 1056 // 1057 // The start and end time of the auction are actually assigned when the auction is opened by OpenAuctionForBids() 1058 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1059 1060 func PostAuctionRequest(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 1061 1062 ar, err := CreateAuctionRequest(args[0:]) 1063 if err != nil { 1064 return shim.Error(err.Error()) 1065 } 1066 1067 // Let us make sure that the Item is not on Auction 1068 err = VerifyIfItemIsOnAuction(stub, ar.ItemID) 1069 if err != nil { 1070 fmt.Println("PostAuctionRequest() : Failed Item is either initiated or opened for Auction ", args[0]) 1071 return shim.Error(err.Error()) 1072 } 1073 1074 // Validate Auction House to check it is a registered User 1075 response := ValidateMember(stub, ar.AuctionHouseID) 1076 if response.Status != shim.OK { 1077 fmt.Println("PostAuctionRequest() : Failed Auction House not Registered in Blockchain ", ar.AuctionHouseID) 1078 return shim.Error(err.Error()) 1079 } 1080 1081 aucHouse := response.Payload 1082 fmt.Println("Auction House information ", aucHouse, " ID: ", ar.AuctionHouseID) 1083 1084 // Validate Item record 1085 response = ValidateItemSubmission(stub, ar.ItemID) 1086 if response.Status != shim.OK { 1087 fmt.Println("PostAuctionRequest() : Failed Could not Validate Item Object in Blockchain ", ar.ItemID) 1088 return shim.Error(err.Error()) 1089 } 1090 1091 itemObject := response.Payload 1092 1093 // Convert AuctionRequest to JSON 1094 buff, err := AucReqtoJSON(ar) // Converting the auction request struct to []byte array 1095 if err != nil { 1096 fmt.Println("PostAuctionRequest() : Failed Cannot create object buffer for write : ", args[1]) 1097 return shim.Error("PostAuctionRequest(): Failed Cannot create object buffer for write : " + args[1]) 1098 } else { 1099 // Update the ledger with the Buffer Data 1100 //err = stub.PutState(args[0], buff) 1101 keys := []string{args[0]} 1102 err = UpdateObject(stub, "Auction", keys, buff) 1103 if err != nil { 1104 fmt.Println("PostAuctionRequest() : write error while inserting record\n") 1105 return shim.Error(err.Error()) 1106 } 1107 1108 // Post an Item Log and the Auction House ID is included in the log 1109 // Recall -- that by default that value is "DEFAULT" 1110 1111 io, err := JSONtoAR(itemObject) 1112 response := PostItemLog(stub, io, "ReadyForAuc", ar.AuctionHouseID, ar.TimeStamp) 1113 if response.Status != shim.OK { 1114 fmt.Println("PostItemLog() : write error while inserting record\n") 1115 return shim.Error(err.Error()) 1116 } 1117 1118 //An entry is made in the AuctionInitTable that this Item has been placed for Auction 1119 // The UI can pull all items available for auction and the item can be Opened for accepting bids 1120 // The 2016 is a dummy key and has notr value other than to get all rows 1121 1122 keys = []string{"2016", args[0]} 1123 err = UpdateObject(stub, "AucInit", keys, buff) 1124 if err != nil { 1125 fmt.Println("PostAuctionRequest() : write error while inserting record into AucInit\n") 1126 return shim.Error(err.Error()) 1127 } 1128 1129 } 1130 1131 return shim.Success(buff) 1132 } 1133 1134 func CreateAuctionRequest(args []string) (AuctionRequest, error) { 1135 var err error 1136 var aucReg AuctionRequest 1137 1138 // Check there are 12 Arguments 1139 // See example -- The Open and Close Dates are Dummy, and will be set by open auction 1140 // '{"Function": "PostAuctionRequest", "Args":["1111", "AUCREQ", "1000", "200", "100", "04012016", "1200", "1800", 1141 // "INIT", "2016-05-20 11:00:00.3 +0000 UTC","2016-05-23 11:00:00.3 +0000 UTC", "2016-05-23 11:00:00.3 +0000 UTC"]}' 1142 if len(args) != 12 { 1143 fmt.Println("CreateAuctionRegistrationObject(): Incorrect number of arguments. Expecting 11 ") 1144 return aucReg, errors.New("CreateAuctionRegistrationObject() : Incorrect number of arguments. Expecting 11 ") 1145 } 1146 1147 // Validate UserID is an integer . I think this redundant and can be avoided 1148 1149 err = validateID(args[0]) 1150 if err != nil { 1151 return aucReg, errors.New("CreateAuctionRequest() : User ID should be an integer") 1152 } 1153 1154 aucReg = AuctionRequest{args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11]} 1155 fmt.Println("CreateAuctionObject() : Auction Registration : ", aucReg) 1156 1157 return aucReg, nil 1158 } 1159 1160 ////////////////////////////////////////////////////////// 1161 // Create an Item Transaction record to process Request 1162 // This is invoked by the CloseAuctionRequest 1163 // 1164 // 1165 //////////////////////////////////////////////////////////// 1166 func PostTransaction(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 1167 1168 if function != "PostTransaction" { 1169 return shim.Error("PostTransaction(): Invalid function name. Expecting \"PostTransaction\"") 1170 } 1171 1172 ar, err := CreateTransactionRequest(args[0:]) // 1173 if err != nil { 1174 return shim.Error(err.Error()) 1175 } 1176 1177 // Validate buyer's ID 1178 response := ValidateMember(stub, ar.UserId) 1179 if response.Status != shim.OK { 1180 fmt.Println("PostTransaction() : Failed Buyer not Registered in Blockchain ", ar.UserId) 1181 return shim.Error(err.Error()) 1182 } 1183 1184 buyer := response.Payload 1185 1186 fmt.Println("PostTransaction(): Validated Buyer information Successfully ", buyer, ar.UserId) 1187 1188 // Validate Item record 1189 response = ValidateItemSubmission(stub, ar.ItemID) 1190 if response.Status != shim.OK { 1191 fmt.Println("PostTransaction() : Failed Could not Validate Item Object in Blockchain ", ar.ItemID) 1192 return shim.Error(err.Error()) 1193 } 1194 1195 lastUpdatedItemOBCObject := response.Payload 1196 fmt.Println("PostTransaction() : Validated Item Object in Blockchain Successfully", ar.ItemID) 1197 1198 // Update Item Object with new Owner Key 1199 response = UpdateItemObject(stub, lastUpdatedItemOBCObject, ar.HammerPrice, ar.UserId) 1200 newKey := response.Payload 1201 if response.Status != shim.OK { 1202 fmt.Println("PostTransaction() : Failed to update Item Master Object in Blockchain ", ar.ItemID) 1203 return shim.Error(err.Error()) 1204 } else { 1205 // Write New Key to file 1206 fmt.Println("PostTransaction() : New encryption Key is ", newKey) 1207 } 1208 1209 fmt.Println("PostTransaction() : Updated Item Master Object in Blockchain Successfully", ar.ItemID) 1210 1211 // Post an Item Log 1212 itemObject, err := JSONtoAR(lastUpdatedItemOBCObject) 1213 if err != nil { 1214 fmt.Println("PostTransaction() : Conversion error JSON to ItemRecord\n") 1215 return shim.Error(err.Error()) 1216 } 1217 1218 // A life cycle event is added to say that the Item is no longer on auction 1219 itemObject.ItemBasePrice = ar.HammerPrice 1220 itemObject.CurrentOwnerID = ar.UserId 1221 1222 response = PostItemLog(stub, itemObject, "NA", "DEFAULT", args[5]) 1223 if response.Status != shim.OK { 1224 fmt.Println("PostTransaction() : write error while inserting item log record\n") 1225 return shim.Error(err.Error()) 1226 } 1227 1228 fmt.Println("PostTransaction() : Inserted item log record Successfully", ar.ItemID) 1229 1230 // Convert Transaction Object to JSON 1231 buff, err := TrantoJSON(ar) // 1232 if err != nil { 1233 fmt.Println("GetObjectBuffer() : Failed to convert Transaction Object to JSON ", args[0]) 1234 return shim.Error(err.Error()) 1235 } 1236 1237 // Update the ledger with the Buffer Data 1238 keys := []string{args[0], args[3]} 1239 err = UpdateObject(stub, "Trans", keys, buff) 1240 if err != nil { 1241 fmt.Println("PostTransaction() : write error while inserting record\n") 1242 return shim.Error(err.Error()) 1243 } 1244 1245 fmt.Println("PostTransaction() : Posted Transaction Record Successfully\n") 1246 1247 // Returns New Key. To get Transaction Details, run GetTransaction 1248 1249 secret_key, _ := json.Marshal(newKey) 1250 fmt.Println(string(secret_key)) 1251 return shim.Success(secret_key) 1252 1253 } 1254 1255 func CreateTransactionRequest(args []string) (ItemTransaction, error) { 1256 1257 var at ItemTransaction 1258 1259 // Check there are 9 Arguments 1260 if len(args) != 9 { 1261 fmt.Println("CreateTransactionRequest(): Incorrect number of arguments. Expecting 9 ") 1262 return at, errors.New("CreateTransactionRequest() : Incorrect number of arguments. Expecting 9 ") 1263 } 1264 1265 at = ItemTransaction{args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]} 1266 fmt.Println("CreateTransactionRequest() : Transaction Request: ", at) 1267 1268 return at, nil 1269 } 1270 1271 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1272 // Create a Bid Object 1273 // Once an Item has been opened for auction, bids can be submitted as long as the auction is "OPEN" 1274 //./peer chaincode invoke -l golang -n mycc -c '{"Function": "PostBid", "Args":["1111", "BID", "1", "1000", "300", "1200", "2017-01-23 14:00:00.3 +0000 UTC"]}' 1275 //./peer chaincode invoke -l golang -n mycc -c '{"Function": "PostBid", "Args":["1111", "BID", "2", "1000", "400", "3000","2017-01-23 14:00:00.3 +0000 UTC"]}' 1276 // 1277 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 1278 1279 func PostBid(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 1280 1281 bid, err := CreateBidObject(args[0:]) // 1282 if err != nil { 1283 return shim.Error(err.Error()) 1284 } 1285 1286 // Reject the Bid if the Buyer Information Is not Valid or not registered on the Block Chain 1287 response := ValidateMember(stub, args[4]) 1288 if response.Status != shim.OK { 1289 fmt.Println("PostBid() : Failed Buyer not registered on the block-chain ", args[4]) 1290 return shim.Error(err.Error()) 1291 } 1292 1293 buyerInfo := response.Payload 1294 fmt.Println("Buyer information ", buyerInfo, " ", args[4]) 1295 1296 /////////////////////////////////////// 1297 // Reject Bid if Auction is not "OPEN" 1298 /////////////////////////////////////// 1299 response = GetAuctionRequest(stub, "GetAuctionRequest", []string{args[0]}) 1300 if response.Status != shim.OK { 1301 fmt.Println("PostBid() : Cannot find Auction record ", args[0]) 1302 return shim.Error("PostBid(): Cannot find Auction record : " + args[0]) 1303 } 1304 1305 RBytes := response.Payload 1306 1307 aucR, err := JSONtoAucReq(RBytes) 1308 if err != nil { 1309 fmt.Println("PostBid() : Cannot UnMarshall Auction record") 1310 return shim.Error("PostBid(): Cannot UnMarshall Auction record: " + args[0]) 1311 } 1312 1313 if aucR.Status != "OPEN" { 1314 fmt.Println("PostBid() : Cannot accept Bid as Auction is not OPEN ", args[0]) 1315 return shim.Error("PostBid(): Cannot accept Bid as Auction is not OPEN : " + args[0]) 1316 } 1317 1318 /////////////////////////////////////////////////////////////////// 1319 // Reject Bid if the time bid was received is > Auction Close Time 1320 /////////////////////////////////////////////////////////////////// 1321 if tCompare(bid.BidTime, aucR.CloseDate) == false { 1322 fmt.Println("PostBid() Failed : BidTime past the Auction Close Time") 1323 error_str := fmt.Sprintf("PostBid() Failed : BidTime past the Auction Close Time %s, %s", bid.BidTime, aucR.CloseDate) 1324 return shim.Error(error_str) 1325 } 1326 1327 ////////////////////////////////////////////////////////////////// 1328 // Reject Bid if Item ID on Bid does not match Item ID on Auction 1329 ////////////////////////////////////////////////////////////////// 1330 if aucR.ItemID != bid.ItemID { 1331 fmt.Println("PostBid() Failed : Item ID mismatch on bid. Bid Rejected") 1332 return shim.Error("PostBid() : Item ID mismatch on Bid. Bid Rejected") 1333 } 1334 1335 ////////////////////////////////////////////////////////////////////// 1336 // Reject Bid if Bid Price is less than Reserve Price 1337 // Convert Bid Price and Reserve Price to Integer (TODO - Float) 1338 ////////////////////////////////////////////////////////////////////// 1339 bp, err := strconv.Atoi(bid.BidPrice) 1340 if err != nil { 1341 fmt.Println("PostBid() Failed : Bid price should be an integer") 1342 return shim.Error("PostBid() : Bid price should be an integer") 1343 } 1344 1345 hp, err := strconv.Atoi(aucR.ReservePrice) 1346 if err != nil { 1347 return shim.Error("PostItem() : Reserve Price should be an integer") 1348 } 1349 1350 // Check if Bid Price is > Auction Request Reserve Price 1351 if bp < hp { 1352 return shim.Error("PostItem() : Bid Price must be greater than Reserve Price") 1353 } 1354 1355 //////////////////////////// 1356 // Post or Accept the Bid 1357 //////////////////////////// 1358 buff, err := BidtoJSON(bid) // 1359 1360 if err != nil { 1361 fmt.Println("PostBid() : Failed Cannot create object buffer for write : ", args[1]) 1362 return shim.Error("PostBid(): Failed Cannot create object buffer for write : " + args[1]) 1363 } else { 1364 // Update the ledger with the Buffer Data 1365 // err = stub.PutState(args[0], buff) 1366 keys := []string{args[0], args[2]} 1367 err = UpdateObject(stub, "Bid", keys, buff) 1368 if err != nil { 1369 fmt.Println("PostBid() : write error while inserting record\n") 1370 return shim.Error(err.Error()) 1371 } 1372 } 1373 1374 return shim.Success(buff) 1375 } 1376 1377 func CreateBidObject(args []string) (Bid, error) { 1378 var err error 1379 var aBid Bid 1380 1381 // Check there are 7 Arguments 1382 // See example 1383 if len(args) != 7 { 1384 fmt.Println("CreateBidObject(): Incorrect number of arguments. Expecting 7 ") 1385 return aBid, errors.New("CreateBidObject() : Incorrect number of arguments. Expecting 7 ") 1386 } 1387 1388 // Validate Bid is an integer 1389 1390 _, err = strconv.Atoi(args[0]) 1391 if err != nil { 1392 return aBid, errors.New("CreateBidObject() : Bid ID should be an integer") 1393 } 1394 1395 _, err = strconv.Atoi(args[2]) 1396 if err != nil { 1397 return aBid, errors.New("CreateBidObject() : Bid ID should be an integer") 1398 } 1399 1400 // bidTime = args[6] sent by the client 1401 aBid = Bid{args[0], args[1], args[2], args[3], args[4], args[5], args[6]} 1402 fmt.Println("CreateBidObject() : Bid Object : ", aBid) 1403 1404 return aBid, nil 1405 } 1406 1407 ////////////////////////////////////////////////////////// 1408 // JSON To args[] - return a map of the JSON string 1409 ////////////////////////////////////////////////////////// 1410 func JSONtoArgs(Avalbytes []byte) (map[string]interface{}, error) { 1411 1412 var data map[string]interface{} 1413 1414 if err := json.Unmarshal(Avalbytes, &data); err != nil { 1415 return nil, err 1416 } 1417 1418 return data, nil 1419 } 1420 1421 ////////////////////////////////////////////////////////// 1422 // Variation of the above - return value from a JSON string 1423 ////////////////////////////////////////////////////////// 1424 1425 func GetKeyValue(Avalbytes []byte, key string) string { 1426 var dat map[string]interface{} 1427 if err := json.Unmarshal(Avalbytes, &dat); err != nil { 1428 panic(err) 1429 } 1430 1431 val := dat[key].(string) 1432 return val 1433 } 1434 1435 ////////////////////////////////////////////////////////// 1436 // Time and Date Comparison 1437 // tCompare("2016-06-28 18:40:57", "2016-06-27 18:45:39") 1438 ////////////////////////////////////////////////////////// 1439 func tCompare(t1 string, t2 string) bool { 1440 1441 layout := "2006-01-02 15:04:05" 1442 bidTime, err := time.Parse(layout, t1) 1443 if err != nil { 1444 fmt.Println("tCompare() Failed : time Conversion error on t1") 1445 return false 1446 } 1447 1448 aucCloseTime, err := time.Parse(layout, t2) 1449 if err != nil { 1450 fmt.Println("tCompare() Failed : time Conversion error on t2") 1451 return false 1452 } 1453 1454 if bidTime.Before(aucCloseTime) { 1455 return true 1456 } 1457 1458 return false 1459 } 1460 1461 ////////////////////////////////////////////////////////// 1462 // Converts JSON String to an ART Object 1463 ////////////////////////////////////////////////////////// 1464 func JSONtoAR(data []byte) (ItemObject, error) { 1465 1466 ar := ItemObject{} 1467 err := json.Unmarshal([]byte(data), &ar) 1468 if err != nil { 1469 fmt.Println("Unmarshal failed : ", err) 1470 } 1471 1472 return ar, err 1473 } 1474 1475 ////////////////////////////////////////////////////////// 1476 // Converts an ART Object to a JSON String 1477 ////////////////////////////////////////////////////////// 1478 func ARtoJSON(ar ItemObject) ([]byte, error) { 1479 1480 ajson, err := json.Marshal(ar) 1481 if err != nil { 1482 fmt.Println(err) 1483 return nil, err 1484 } 1485 return ajson, nil 1486 } 1487 1488 ////////////////////////////////////////////////////////// 1489 // Converts an BID to a JSON String 1490 ////////////////////////////////////////////////////////// 1491 func ItemLogtoJSON(item ItemLog) ([]byte, error) { 1492 1493 ajson, err := json.Marshal(item) 1494 if err != nil { 1495 fmt.Println(err) 1496 return nil, err 1497 } 1498 return ajson, nil 1499 } 1500 1501 ////////////////////////////////////////////////////////// 1502 // Converts an User Object to a JSON String 1503 ////////////////////////////////////////////////////////// 1504 func JSONtoItemLog(ithis []byte) (ItemLog, error) { 1505 1506 item := ItemLog{} 1507 err := json.Unmarshal(ithis, &item) 1508 if err != nil { 1509 fmt.Println("JSONtoAucReq error: ", err) 1510 return item, err 1511 } 1512 return item, err 1513 } 1514 1515 ////////////////////////////////////////////////////////// 1516 // Converts an Auction Request to a JSON String 1517 ////////////////////////////////////////////////////////// 1518 func AucReqtoJSON(ar AuctionRequest) ([]byte, error) { 1519 1520 ajson, err := json.Marshal(ar) 1521 if err != nil { 1522 fmt.Println(err) 1523 return nil, err 1524 } 1525 return ajson, nil 1526 } 1527 1528 ////////////////////////////////////////////////////////// 1529 // Converts an User Object to a JSON String 1530 ////////////////////////////////////////////////////////// 1531 func JSONtoAucReq(areq []byte) (AuctionRequest, error) { 1532 1533 ar := AuctionRequest{} 1534 err := json.Unmarshal(areq, &ar) 1535 if err != nil { 1536 fmt.Println("JSONtoAucReq error: ", err) 1537 return ar, err 1538 } 1539 return ar, err 1540 } 1541 1542 ////////////////////////////////////////////////////////// 1543 // Converts an BID to a JSON String 1544 ////////////////////////////////////////////////////////// 1545 func BidtoJSON(myHand Bid) ([]byte, error) { 1546 1547 ajson, err := json.Marshal(myHand) 1548 if err != nil { 1549 fmt.Println(err) 1550 return nil, err 1551 } 1552 return ajson, nil 1553 } 1554 1555 ////////////////////////////////////////////////////////// 1556 // Converts an User Object to a JSON String 1557 ////////////////////////////////////////////////////////// 1558 func JSONtoBid(areq []byte) (Bid, error) { 1559 1560 myHand := Bid{} 1561 err := json.Unmarshal(areq, &myHand) 1562 if err != nil { 1563 fmt.Println("JSONtoAucReq error: ", err) 1564 return myHand, err 1565 } 1566 return myHand, err 1567 } 1568 1569 ////////////////////////////////////////////////////////// 1570 // Converts an User Object to a JSON String 1571 ////////////////////////////////////////////////////////// 1572 func UsertoJSON(user UserObject) ([]byte, error) { 1573 1574 ajson, err := json.Marshal(user) 1575 if err != nil { 1576 fmt.Println("UsertoJSON error: ", err) 1577 return nil, err 1578 } 1579 fmt.Println("UsertoJSON created: ", ajson) 1580 return ajson, nil 1581 } 1582 1583 ////////////////////////////////////////////////////////// 1584 // Converts an User Object to a JSON String 1585 ////////////////////////////////////////////////////////// 1586 func JSONtoUser(user []byte) (UserObject, error) { 1587 1588 ur := UserObject{} 1589 err := json.Unmarshal(user, &ur) 1590 if err != nil { 1591 fmt.Println("UsertoJSON error: ", err) 1592 return ur, err 1593 } 1594 fmt.Println("UsertoJSON created: ", ur) 1595 return ur, err 1596 } 1597 1598 ////////////////////////////////////////////////////////// 1599 // Converts an Item Transaction to a JSON String 1600 ////////////////////////////////////////////////////////// 1601 func TrantoJSON(at ItemTransaction) ([]byte, error) { 1602 1603 ajson, err := json.Marshal(at) 1604 if err != nil { 1605 fmt.Println(err) 1606 return nil, err 1607 } 1608 return ajson, nil 1609 } 1610 1611 ////////////////////////////////////////////////////////// 1612 // Converts an Trans Object to a JSON String 1613 ////////////////////////////////////////////////////////// 1614 func JSONtoTran(areq []byte) (ItemTransaction, error) { 1615 1616 at := ItemTransaction{} 1617 err := json.Unmarshal(areq, &at) 1618 if err != nil { 1619 fmt.Println("JSONtoTran error: ", err) 1620 return at, err 1621 } 1622 return at, err 1623 } 1624 1625 ////////////////////////////////////////////// 1626 // Validates an ID for Well Formed 1627 ////////////////////////////////////////////// 1628 1629 func validateID(id string) error { 1630 // Validate UserID is an integer 1631 1632 _, err := strconv.Atoi(id) 1633 if err != nil { 1634 return errors.New("validateID(): User ID should be an integer") 1635 } 1636 return nil 1637 } 1638 1639 ////////////////////////////////////////////// 1640 // Create an ItemLog from Item 1641 ////////////////////////////////////////////// 1642 1643 func ItemToItemLog(io ItemObject, cdt string) ItemLog { 1644 1645 iLog := ItemLog{} 1646 iLog.ItemID = io.ItemID 1647 iLog.Status = "INITIAL" 1648 iLog.AuctionedBy = "DEFAULT" 1649 iLog.RecType = "ILOG" 1650 iLog.ItemDesc = io.ItemDesc 1651 iLog.CurrentOwner = io.CurrentOwnerID 1652 iLog.Date = cdt 1653 1654 return iLog 1655 } 1656 1657 ////////////////////////////////////////////// 1658 // Convert Bid to Transaction for Posting 1659 ////////////////////////////////////////////// 1660 1661 func BidtoTransaction(bid Bid) ItemTransaction { 1662 1663 var t ItemTransaction 1664 t.AuctionID = bid.AuctionID 1665 t.RecType = "POSTTRAN" 1666 t.ItemID = bid.ItemID 1667 t.TransType = "SALE" 1668 t.UserId = bid.BuyerID 1669 // Ideally SystemChain Code must provide a TimeStamp Function 1670 t.TransDate = bid.BidTime 1671 t.HammerTime = bid.BidTime 1672 t.HammerPrice = bid.BidPrice 1673 t.Details = "The Highest Bidder does not always win" 1674 1675 return t 1676 } 1677 1678 //////////////////////////////////////////////////////////////////////////// 1679 // Validate if the User Information Exists 1680 // in the block-chain 1681 //////////////////////////////////////////////////////////////////////////// 1682 func ValidateMember(stub shim.ChaincodeStubInterface, owner string) pb.Response { 1683 1684 // Get the Item Objects and Display it 1685 // Avalbytes, err := stub.GetState(owner) 1686 args := []string{owner} 1687 Avalbytes, err := QueryObject(stub, "User", args) 1688 1689 if err != nil { 1690 fmt.Println("ValidateMember() : Failed - Cannot find valid owner record for ART ", owner) 1691 jsonResp := "{\"Error\":\"Failed to get Owner Object Data for " + owner + "\"}" 1692 return shim.Error(jsonResp) 1693 } 1694 1695 if Avalbytes == nil { 1696 fmt.Println("ValidateMember() : Failed - Incomplete owner record for ART ", owner) 1697 jsonResp := "{\"Error\":\"Failed - Incomplete information about the owner for " + owner + "\"}" 1698 return shim.Error(jsonResp) 1699 } 1700 1701 fmt.Println("ValidateMember() : Validated Item Owner:\n", owner) 1702 return shim.Success(Avalbytes) 1703 } 1704 1705 //////////////////////////////////////////////////////////////////////////// 1706 // Validate if the User Information Exists 1707 // in the block-chain 1708 //////////////////////////////////////////////////////////////////////////// 1709 func ValidateItemSubmission(stub shim.ChaincodeStubInterface, artId string) pb.Response { 1710 1711 // Get the Item Objects and Display it 1712 args := []string{artId} 1713 Avalbytes, err := QueryObject(stub, "Item", args) 1714 if err != nil { 1715 fmt.Println("ValidateItemSubmission() : Failed - Cannot find valid owner record for ART ", artId) 1716 jsonResp := "{\"Error\":\"Failed to get Owner Object Data for " + artId + "\"}" 1717 return shim.Error(jsonResp) 1718 } 1719 1720 if Avalbytes == nil { 1721 fmt.Println("ValidateItemSubmission() : Failed - Incomplete owner record for ART ", artId) 1722 jsonResp := "{\"Error\":\"Failed - Incomplete information about the owner for " + artId + "\"}" 1723 return shim.Error(jsonResp) 1724 } 1725 1726 //fmt.Println("ValidateItemSubmission() : Validated Item Owner:", Avalbytes) 1727 return shim.Success(Avalbytes) 1728 } 1729 1730 ///////////////////////////////////////////////////////////////////////////////////////////////////// 1731 // Get List of Bids for an Auction 1732 // in the block-chain -- 1733 // ./peer chaincode query -l golang -n mycc -c '{"Function": "GetListOfBids", "Args": ["1111"]}' 1734 // ./peer chaincode query -l golang -n mycc -c '{"Function": "GetLastBid", "Args": ["1111"]}' 1735 // ./peer chaincode query -l golang -n mycc -c '{"Function": "GetHighestBid", "Args": ["1111"]}' 1736 ///////////////////////////////////////////////////////////////////////////////////////////////////// 1737 func GetListOfBids(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 1738 1739 rs, err := GetList(stub, "Bid", args) 1740 if err != nil { 1741 error_str := fmt.Sprintf("GetListOfBids operation failed. Error marshaling JSON: %s", err) 1742 return shim.Error(error_str) 1743 } 1744 1745 defer rs.Close() 1746 1747 // Iterate through result set 1748 var i int 1749 var tlist []Bid // Define a list 1750 for i = 0; rs.HasNext(); i++ { 1751 1752 // We can process whichever return value is of interest 1753 responseRange, err := rs.Next() 1754 1755 if err != nil { 1756 return shim.Success(nil) 1757 } 1758 bid, err := JSONtoBid(responseRange.Value) 1759 if err != nil { 1760 error_str := fmt.Sprintf("GetListOfBids() operation failed - Unmarshall Error. %s", err) 1761 fmt.Println(error_str) 1762 return shim.Error(error_str) 1763 } 1764 fmt.Println("GetList() : my Value : ", bid) 1765 tlist = append(tlist, bid) 1766 } 1767 1768 jsonRows, err := json.Marshal(tlist) 1769 if err != nil { 1770 error_str := fmt.Sprintf("GetListOfBids() operation failed - Unmarshall Error. %s", err) 1771 fmt.Println(error_str) 1772 return shim.Error(error_str) 1773 } 1774 1775 fmt.Println("List of Bids Requested : ", jsonRows) 1776 return shim.Success(jsonRows) 1777 1778 } 1779 1780 //////////////////////////////////////////////////////////////////////////////////////////////////////// 1781 // Get List of Auctions that have been initiated 1782 // in the block-chain 1783 // This is a fixed Query to be issued as below 1784 // peer chaincode query -l golang -n mycc -c '{"Args": ["qGetListOfInitAucs", "2016"]}' 1785 //////////////////////////////////////////////////////////////////////////////////////////////////////// 1786 func GetListOfInitAucs(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 1787 1788 rs, err := GetList(stub, "AucInit", args) 1789 if err != nil { 1790 error_str := fmt.Sprintf("GetListOfInitAucs operation failed. Error marshaling JSON: %s", err) 1791 return shim.Error(error_str) 1792 } 1793 1794 defer rs.Close() 1795 1796 // Iterate through result set 1797 var i int 1798 var tlist []AuctionRequest // Define a list 1799 for i = 0; rs.HasNext(); i++ { 1800 1801 // We can process whichever return value is of interest 1802 responseRange, err := rs.Next() 1803 if err != nil { 1804 return shim.Success(nil) 1805 } 1806 ar, err := JSONtoAucReq(responseRange.Value) 1807 if err != nil { 1808 error_str := fmt.Sprintf("GetListOfInitAucs() operation failed - Unmarshall Error. %s", err) 1809 fmt.Println(error_str) 1810 return shim.Error(error_str) 1811 } 1812 fmt.Println("GetListOfInitAucs() : my Value : ", ar) 1813 tlist = append(tlist, ar) 1814 } 1815 1816 jsonRows, err := json.Marshal(tlist) 1817 if err != nil { 1818 error_str := fmt.Sprintf("GetListOfInitAucs() operation failed - Unmarshall Error. %s", err) 1819 fmt.Println(error_str) 1820 return shim.Error(error_str) 1821 } 1822 1823 //fmt.Println("List of Auctions Requested : ", jsonRows) 1824 return shim.Success(jsonRows) 1825 1826 } 1827 1828 //////////////////////////////////////////////////////////////////////////// 1829 // Get List of Open Auctions for which bids can be supplied 1830 // in the block-chain 1831 // This is a fixed Query to be issued as below 1832 // peer chaincode query -l golang -n mycc -c '{"Args": ["qGetListOfOpenAucs", "2016"]}' 1833 //////////////////////////////////////////////////////////////////////////// 1834 func GetListOfOpenAucs(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 1835 1836 rs, err := GetList(stub, "AucOpen", args) 1837 if err != nil { 1838 error_str := fmt.Sprintf("GetListOfOpenAucs operation failed. Error marshaling JSON: %s", err) 1839 return shim.Error(error_str) 1840 } 1841 defer rs.Close() 1842 1843 // Iterate through result set 1844 var i int 1845 var tlist []AuctionRequest // Define a list 1846 for i = 0; rs.HasNext(); i++ { 1847 1848 // We can process whichever return value is of interest 1849 responseRange, err := rs.Next() 1850 if err != nil { 1851 return shim.Success(nil) 1852 } 1853 ar, err := JSONtoAucReq(responseRange.Value) 1854 if err != nil { 1855 error_str := fmt.Sprintf("GetListOfOpenAucs() operation failed - Unmarshall Error. %s", err) 1856 fmt.Println(error_str) 1857 return shim.Error(error_str) 1858 } 1859 fmt.Println("GetListOfOpenAucs() : my Value : ", ar) 1860 tlist = append(tlist, ar) 1861 } 1862 1863 jsonRows, err := json.Marshal(tlist) 1864 if err != nil { 1865 error_str := fmt.Sprintf("GetListOfInitAucs() operation failed - Unmarshall Error. %s", err) 1866 fmt.Println(error_str) 1867 return shim.Error(error_str) 1868 } 1869 1870 //fmt.Println("List of Open Auctions : ", jsonRows) 1871 return shim.Success(jsonRows) 1872 1873 } 1874 1875 //////////////////////////////////////////////////////////////////////////// 1876 // Get the Item History for an Item 1877 // in the block-chain .. Pass the Item ID 1878 // ./peer chaincode query -l golang -n mycc -c '{"Function": "GetItemLog", "Args": ["1000"]}' 1879 //////////////////////////////////////////////////////////////////////////// 1880 func GetItemLog(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 1881 1882 // Check there are 1 Arguments provided as per the struct - two are computed 1883 // See example 1884 if len(args) < 1 { 1885 fmt.Println("GetItemLog(): Incorrect number of arguments. Expecting 1 ") 1886 fmt.Println("GetItemLog(): ./peer chaincode query -l golang -n mycc -c '{\"Function\": \"GetItem\", \"Args\": [\"1111\"]}'") 1887 return shim.Error("CreateItemObject(): Incorrect number of arguments. Expecting 12 ") 1888 } 1889 1890 rs, err := GetList(stub, "ItemHistory", args) 1891 if err != nil { 1892 error_str := fmt.Sprintf("GetItemLog operation failed. Error marshaling JSON: %s", err) 1893 return shim.Error(error_str) 1894 } 1895 1896 defer rs.Close() 1897 1898 // Iterate through result set 1899 var i int 1900 var tlist []ItemLog // Define a list 1901 for i = 0; rs.HasNext(); i++ { 1902 1903 // We can process whichever return value is of interest 1904 responseRange, err := rs.Next() 1905 if err != nil { 1906 return shim.Success(nil) 1907 } 1908 il, err := JSONtoItemLog(responseRange.Value) 1909 if err != nil { 1910 error_str := fmt.Sprintf("GetItemLog() operation failed - Unmarshall Error. %s", err) 1911 fmt.Println(error_str) 1912 return shim.Error(error_str) 1913 } 1914 fmt.Println("GetItemLog() : my Value : ", il) 1915 tlist = append(tlist, il) 1916 } 1917 1918 jsonRows, err := json.Marshal(tlist) 1919 if err != nil { 1920 error_str := fmt.Sprintf("GetItemLog() operation failed - Unmarshall Error. %s", err) 1921 fmt.Println(error_str) 1922 return shim.Error(error_str) 1923 } 1924 1925 //fmt.Println("All History : ", jsonRows) 1926 return shim.Success(jsonRows) 1927 1928 } 1929 1930 //////////////////////////////////////////////////////////////////////////// 1931 // Get a List of Items by Category 1932 // in the block-chain 1933 // Input is 2016 + Category 1934 // Categories include whatever has been defined in the Item Tables - Landscape, Modern, ... 1935 // See Sample data 1936 // ./peer chaincode query -l golang -n mycc -c '{"Function": "GetItemListByCat", "Args": ["2016", "Modern"]}' 1937 //////////////////////////////////////////////////////////////////////////// 1938 func GetItemListByCat(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 1939 1940 // Check there are 1 Arguments provided as per the struct - two are computed 1941 // See example 1942 if len(args) < 1 { 1943 fmt.Println("GetItemListByCat(): Incorrect number of arguments. Expecting 1 ") 1944 fmt.Println("GetItemListByCat(): ./peer chaincode query -l golang -n mycc -c '{\"Function\": \"GetItemListByCat\", \"Args\": [\"Modern\"]}'") 1945 return shim.Error("CreateItemObject(): Incorrect number of arguments. Expecting 1 ") 1946 } 1947 1948 rs, err := GetList(stub, "ItemCat", args) 1949 if err != nil { 1950 error_str := fmt.Sprintf("GetItemListByCat operation failed. Error marshaling JSON: %s", err) 1951 return shim.Error(error_str) 1952 } 1953 1954 defer rs.Close() 1955 1956 // Iterate through result set 1957 var i int 1958 var tlist []ItemObject // Define a list 1959 for i = 0; rs.HasNext(); i++ { 1960 1961 // We can process whichever return value is of interest 1962 responseRange, err := rs.Next() 1963 if err != nil { 1964 return shim.Success(nil) 1965 } 1966 io, err := JSONtoAR(responseRange.Value) 1967 if err != nil { 1968 error_str := fmt.Sprintf("GetItemListByCat() operation failed - Unmarshall Error. %s", err) 1969 fmt.Println(error_str) 1970 return shim.Error(error_str) 1971 } 1972 1973 fmt.Println("GetItemListByCat() : my Value : ", io) 1974 tlist = append(tlist, io) 1975 } 1976 1977 jsonRows, err := json.Marshal(tlist) 1978 if err != nil { 1979 error_str := fmt.Sprintf("GetItemListByCat() operation failed - Unmarshall Error. %s", err) 1980 fmt.Println(error_str) 1981 return shim.Error(error_str) 1982 } 1983 1984 //fmt.Println("All Items : ", jsonRows) 1985 return shim.Success(jsonRows) 1986 1987 } 1988 1989 //////////////////////////////////////////////////////////////////////////// 1990 // Get a List of Users by Category 1991 // in the block-chain 1992 //////////////////////////////////////////////////////////////////////////// 1993 func GetUserListByCat(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 1994 1995 // Check there are 1 Arguments provided as per the struct - two are computed 1996 // See example 1997 if len(args) < 1 { 1998 fmt.Println("GetUserListByCat(): Incorrect number of arguments. Expecting 1 ") 1999 fmt.Println("GetUserListByCat(): ./peer chaincode query -l golang -n mycc -c '{\"Function\": \"GetUserListByCat\", \"Args\": [\"AH\"]}'") 2000 return shim.Error("CreateUserObject(): Incorrect number of arguments. Expecting 1 ") 2001 } 2002 2003 rs, err := GetList(stub, "UserCat", args) 2004 if err != nil { 2005 error_str := fmt.Sprintf("GetUserListByCat operation failed. Error marshaling JSON: %s", err) 2006 return shim.Error(error_str) 2007 } 2008 2009 defer rs.Close() 2010 2011 // Iterate through result set 2012 var i int 2013 var tlist []UserObject // Define a list 2014 for i = 0; rs.HasNext(); i++ { 2015 2016 // We can process whichever return value is of interest 2017 responseRange, err := rs.Next() 2018 if err != nil { 2019 return shim.Success(nil) 2020 } 2021 uo, err := JSONtoUser(responseRange.Value) 2022 if err != nil { 2023 error_str := fmt.Sprintf("GetUserListByCat() operation failed - Unmarshall Error. %s", err) 2024 fmt.Println(error_str) 2025 return shim.Error(error_str) 2026 } 2027 2028 fmt.Println("GetUserListByCat() : my Value : ", uo) 2029 tlist = append(tlist, uo) 2030 } 2031 2032 jsonRows, err := json.Marshal(tlist) 2033 if err != nil { 2034 error_str := fmt.Sprintf("GetUserListByCat() operation failed - Unmarshall Error. %s", err) 2035 fmt.Println(error_str) 2036 return shim.Error(error_str) 2037 } 2038 2039 //fmt.Println("All Users : ", jsonRows) 2040 return shim.Success(jsonRows) 2041 2042 } 2043 2044 //////////////////////////////////////////////////////////////////////////// 2045 // Get The Highest Bid Received so far for an Auction 2046 // in the block-chain 2047 //////////////////////////////////////////////////////////////////////////// 2048 func GetLastBid(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 2049 2050 var Avalbytes []byte 2051 2052 layout := "2006-01-02 15:04:05" 2053 highestTime, err := time.Parse(layout, layout) 2054 2055 rs, err := GetList(stub, "Bid", args) 2056 if err != nil { 2057 error_str := fmt.Sprintf("GetListOfBids operation failed. Error marshaling JSON: %s", err) 2058 return shim.Error(error_str) 2059 } 2060 2061 defer rs.Close() 2062 // Iterate through result set 2063 2064 for i := 0; rs.HasNext(); i++ { 2065 2066 // We can process whichever return value is of interest 2067 responseRange, err := rs.Next() 2068 if err != nil { 2069 return shim.Success(nil) 2070 } 2071 currentBid, err := JSONtoBid(responseRange.Value) 2072 if err != nil { 2073 error_str := fmt.Sprintf("GetHighestBid(0 operation failed. %s", err) 2074 fmt.Println(error_str) 2075 return shim.Error(error_str) 2076 } 2077 2078 bidTime, err := time.Parse(layout, currentBid.BidTime) 2079 if err != nil { 2080 error_str := fmt.Sprintf("GetLastBid() Failed : time Conversion error on BidTime %s", err) 2081 fmt.Println(error_str) 2082 return shim.Error(error_str) 2083 } 2084 2085 if bidTime.Sub(highestTime) > 0 { 2086 highestTime = bidTime 2087 Avalbytes = responseRange.Value 2088 } 2089 return shim.Success(Avalbytes) 2090 } 2091 return shim.Error("GetLastBid() : Failed - No Bids Found") 2092 } 2093 2094 //////////////////////////////////////////////////////////////////////////// 2095 // Get The Highest Bid Received so far for an Auction 2096 // in the block-chain 2097 //////////////////////////////////////////////////////////////////////////// 2098 func GetNoOfBidsReceived(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 2099 2100 rs, err := GetList(stub, "Bid", args) 2101 if err != nil { 2102 error_str := fmt.Sprintf("GetListOfBids operation failed. Error marshaling JSON: %s", err) 2103 return shim.Error(error_str) 2104 } 2105 2106 defer rs.Close() 2107 2108 // Iterate through result set 2109 var i int 2110 for i = 0; rs.HasNext(); i++ { 2111 2112 // We can process whichever return value is of interest 2113 _, err := rs.Next() 2114 if err != nil { 2115 return shim.Success(nil) 2116 } 2117 } 2118 return shim.Success([]byte(strconv.Itoa(i))) 2119 } 2120 2121 //////////////////////////////////////////////////////////////////////////// 2122 // Get the Highest Bid in the List 2123 // 2124 //////////////////////////////////////////////////////////////////////////// 2125 func GetHighestBid(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 2126 2127 var Avalbytes []byte 2128 highestBid := 0 2129 rs, err := GetList(stub, "Bid", args) 2130 if err != nil { 2131 error_str := fmt.Sprintf("GetListOfBids operation failed. Error marshaling JSON: %s", err) 2132 return shim.Error(error_str) 2133 } 2134 2135 defer rs.Close() 2136 2137 // Iterate through result set 2138 var i int 2139 for i = 0; rs.HasNext(); i++ { 2140 2141 // We can process whichever return value is of interest 2142 responseRange, err := rs.Next() 2143 if err != nil { 2144 return shim.Success(nil) 2145 } 2146 currentBid, err := JSONtoBid(responseRange.Value) 2147 if err != nil { 2148 error_str := fmt.Sprintf("GetHighestBid(0 operation failed. %s", err) 2149 fmt.Println(error_str) 2150 return shim.Error(error_str) 2151 } 2152 2153 bidPrice, err := strconv.Atoi(currentBid.BidPrice) 2154 if err != nil { 2155 error_str := fmt.Sprintf("GetHighestBid() Int Conversion error on BidPrice! failed. %s", err) 2156 fmt.Println(error_str) 2157 return shim.Error(error_str) 2158 } 2159 2160 if bidPrice >= highestBid { 2161 highestBid = bidPrice 2162 Avalbytes = responseRange.Value 2163 2164 } 2165 } 2166 2167 return shim.Success(Avalbytes) 2168 } 2169 2170 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 2171 // Trigger the Auction 2172 // Structure of args auctionReqID, RecType, AucStartDateTime, Duration in Minutes ( 3 = 3 minutes) 2173 // ./peer chaincode invoke -l golang -n mycc -c '{"Function": "OpenAuctionForBids", "Args":["1111", "OPENAUC", "3", "2006-01-02 15:04:05"]}' 2174 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 2175 2176 func OpenAuctionForBids(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 2177 2178 // Fetch Auction Object and check its Status 2179 Avalbytes, err := QueryObject(stub, "Auction", []string{args[0]}) 2180 if err != nil { 2181 fmt.Println("OpenAuctionForBids(): Auction Object Retrieval Failed ") 2182 return shim.Error("OpenAuctionForBids(): Auction Object Retrieval Failed ") 2183 } 2184 2185 aucR, err := JSONtoAucReq(Avalbytes) 2186 if err != nil { 2187 fmt.Println("OpenAuctionForBids(): Auction Object Unmarshalling Failed ") 2188 return shim.Error("OpenAuctionForBids(): Auction Object UnMarshalling Failed ") 2189 } 2190 2191 if aucR.Status == "CLOSED" { 2192 fmt.Println("OpenAuctionForBids(): Auction is Closed - Cannot Open for new bids ") 2193 return shim.Error("OpenAuctionForBids(): is Closed - Cannot Open for new bids Failed ") 2194 } 2195 2196 // Calculate Time Now and Duration of Auction 2197 2198 // Validate arg[1] is an integer as it represents Duration in Minutes 2199 aucDuration, err := strconv.Atoi(args[2]) 2200 if err != nil { 2201 fmt.Println("OpenAuctionForBids(): Auction Duration is an integer that represents minute! OpenAuctionForBids() Failed ") 2202 return shim.Error("OpenAuctionForBids(): Auction Duration is an integer that represents minute! OpenAuctionForBids() Failed ") 2203 } 2204 2205 aucStartDate, err := time.Parse("2006-01-02 15:04:05", args[3]) 2206 aucEndDate := aucStartDate.Add(time.Duration(aucDuration) * time.Minute) 2207 2208 // We don't use go routines anymore to time the auction 2209 //sleepTime := time.Duration(aucDuration * 60 * 1000 * 1000 * 1000) 2210 2211 // Update Auction Object 2212 aucR.OpenDate = aucStartDate.Format("2006-01-02 15:04:05") 2213 aucR.CloseDate = aucEndDate.Format("2006-01-02 15:04:05") 2214 aucR.Status = "OPEN" 2215 2216 response := UpdateAuctionStatus(stub, "Auction", aucR) 2217 if response.Status != shim.OK { 2218 fmt.Println("OpenAuctionForBids(): UpdateAuctionStatus() Failed ") 2219 return shim.Error("OpenAuctionForBids(): UpdateAuctionStatus() Failed ") 2220 } 2221 2222 buff := response.Payload 2223 2224 // Remove the Auction from INIT Bucket and move to OPEN bucket 2225 // This was designed primarily to help the UI 2226 2227 keys := []string{"2016", aucR.AuctionID} 2228 err = DeleteObject(stub, "AucInit", keys) 2229 if err != nil { 2230 fmt.Println("OpenAuctionForBids(): DeleteFromLedger() Failed ") 2231 return shim.Error("OpenAuctionForBids(): DeleteFromLedger() Failed ") 2232 } 2233 2234 // Add the Auction to Open Bucket 2235 err = UpdateObject(stub, "AucOpen", keys, buff) 2236 if err != nil { 2237 fmt.Println("OpenAuctionForBids() : write error while inserting record into AucInit\n") 2238 return shim.Error(err.Error()) 2239 } 2240 2241 return shim.Success(buff) 2242 } 2243 2244 ////////////////////////////////////////////////////////////////////////// 2245 // Close Open Auctions 2246 // 1. Read OpenAucTable 2247 // 2. Compare now with expiry time with now 2248 // 3. If now is > expiry time call CloseAuction 2249 // ./peer chaincode invoke -l golang -n mycc -c '{"Function": "CloseOpenAuctions", "Args": ["2016", "CLAUC", currentDateTime]}' 2250 ////////////////////////////////////////////////////////////////////////// 2251 2252 func CloseOpenAuctions(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 2253 2254 response := GetListOfOpenAucs(stub, "AucOpen", []string{"2016"}) 2255 if response.Status != shim.OK { 2256 error_str := fmt.Sprintf("CloseOpenAuctions() operation failed. Error retrieving values from AucOpen: %s", response.Message) 2257 fmt.Println(error_str) 2258 return shim.Error(error_str) 2259 } 2260 2261 rows := response.Payload 2262 tlist := make([]AuctionRequest, len(rows)) 2263 err := json.Unmarshal([]byte(rows), &tlist) 2264 if err != nil { 2265 error_str := fmt.Sprintf("CloseOpenAuctions() Unmarshal operation failed. Error retrieving values from AucOpen: %s", response.Message) 2266 fmt.Println(error_str) 2267 return shim.Error(error_str) 2268 } 2269 2270 for i := 0; i < len(tlist); i++ { 2271 ar := tlist[i] 2272 2273 fmt.Println("CloseOpenAuctions() ", ar) 2274 2275 // Compare Auction Times where args[2] = the CurrentTime sent by the client 2276 fmt.Println("CloseOpenAuctions() : ", args[2], ": ar.CloseDate : ", ar.CloseDate) 2277 if tCompare(args[2], ar.CloseDate) == false { 2278 2279 // Request Closing Auction 2280 response := CloseAuction(stub, "CloseAuction", []string{ar.AuctionID}) 2281 if response.Status != shim.OK { 2282 error_str := fmt.Sprintf("CloseOpenAuctions() operation failed. %s", err) 2283 fmt.Println(error_str) 2284 return shim.Error(error_str) 2285 } 2286 } 2287 } 2288 2289 return shim.Success(nil) 2290 } 2291 2292 ////////////////////////////////////////////////////////////////////////// 2293 // Close the Auction 2294 // This is invoked by OpenAuctionForBids 2295 // which kicks-off a go-routine timer for the duration of the auction 2296 // When the timer expires, it creates a shell script to CloseAuction() and triggers it 2297 // This function can also be invoked via CLI - the intent was to close as and when I implement BuyItNow() 2298 // CloseAuction 2299 // - Sets the status of the Auction to "CLOSED" 2300 // - Removes the Auction from the Open Auction list (AucOpenTable) 2301 // - Retrieves the Highest Bid and creates a Transaction 2302 // - Posts The Transaction 2303 // 2304 // To invoke from Command Line via CLI or REST API 2305 // ./peer chaincode invoke -l golang -n mycc -c '{"Function": "CloseAuction", "Args": ["1111", "AUCREQ"]}' 2306 // ./peer chaincode invoke -l golang -n mycc -c '{"Function": "CloseAuction", "Args": ["1111", "AUCREQ"]}' 2307 // 2308 ////////////////////////////////////////////////////////////////////////// 2309 2310 func CloseAuction(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 2311 2312 // Close The Auction - Fetch Auction Object 2313 Avalbytes, err := QueryObject(stub, "Auction", []string{args[0]}) 2314 if err != nil { 2315 fmt.Println("CloseAuction(): Auction Object Retrieval Failed ") 2316 return shim.Error("CloseAuction(): Auction Object Retrieval Failed ") 2317 } 2318 2319 aucR, err := JSONtoAucReq(Avalbytes) 2320 if err != nil { 2321 fmt.Println("CloseAuction(): Auction Object Unmarshalling Failed ") 2322 return shim.Error("CloseAuction(): Auction Object UnMarshalling Failed ") 2323 } 2324 2325 // Update Auction Status 2326 aucR.Status = "CLOSED" 2327 fmt.Println("CloseAuction(): UpdateAuctionStatus() successful ", aucR) 2328 2329 response := UpdateAuctionStatus(stub, "Auction", aucR) 2330 if response.Status != shim.OK { 2331 fmt.Println("CloseAuction(): UpdateAuctionStatus() Failed ") 2332 return shim.Error("CloseAuction(): UpdateAuctionStatus() Failed ") 2333 } 2334 Avalbytes = response.Payload 2335 2336 // Remove the Auction from Open Bucket 2337 keys := []string{"2016", aucR.AuctionID} 2338 err = DeleteObject(stub, "AucOpen", keys) 2339 if err != nil { 2340 fmt.Println("CloseAuction(): DeleteFromLedger(AucOpenTable) Failed ") 2341 return shim.Error("CloseAuction(): DeleteFromLedger(AucOpen) Failed ") 2342 } 2343 2344 fmt.Println("CloseAuction(): Proceeding to process the highest bid ") 2345 2346 // Process Final Bid - Turn it into a Transaction 2347 response = GetHighestBid(stub, "GetHighestBid", []string{args[0]}) 2348 Avalbytes = response.Payload 2349 if Avalbytes == nil { 2350 fmt.Println("CloseAuction(): No bids available, no change in Item Status - PostTransaction() Completed Successfully ") 2351 return shim.Success(Avalbytes) 2352 } 2353 2354 if response.Status != shim.OK { 2355 fmt.Println("CloseAuction(): No bids available, error encountered - PostTransaction() failed ") 2356 return shim.Error(err.Error()) 2357 } 2358 2359 bid, _ := JSONtoBid(Avalbytes) 2360 fmt.Println("CloseAuction(): Proceeding to process the highest bid ", bid) 2361 tran := BidtoTransaction(bid) 2362 fmt.Println("CloseAuction(): Converting Bid to tran ", tran) 2363 2364 // Process the last bid once Time Expires 2365 tranArgs := []string{tran.AuctionID, tran.RecType, tran.ItemID, tran.TransType, tran.UserId, tran.TransDate, tran.HammerTime, tran.HammerPrice, tran.Details} 2366 fmt.Println("CloseAuction(): Proceeding to process the Transaction ", tranArgs) 2367 2368 response = PostTransaction(stub, "PostTransaction", tranArgs) 2369 if response.Status != shim.OK { 2370 fmt.Println("CloseAuction(): PostTransaction() Failed ") 2371 return shim.Error("CloseAuction(): PostTransaction() Failed ") 2372 } 2373 Avalbytes = response.Payload 2374 fmt.Println("CloseAuction(): PostTransaction() Completed Successfully ") 2375 return shim.Success(Avalbytes) 2376 2377 } 2378 2379 //////////////////////////////////////////////////////////////////////////////////////////// 2380 // Buy It Now 2381 // Rules: 2382 // If Buy IT Now Option is available then a Buyer has the option to buy the ITEM 2383 // before the bids exceed BuyITNow Price . Normally, The application should take of this 2384 // at the UI level and this chain-code assumes application has validated that 2385 //////////////////////////////////////////////////////////////////////////////////////////// 2386 2387 func BuyItNow(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response { 2388 2389 // Process Final Bid - Turn it into a Transaction 2390 response := GetHighestBid(stub, "GetHighestBid", []string{args[0]}) 2391 bid, err := JSONtoBid(response.Payload) 2392 if err != nil { 2393 return shim.Error("BuyItNow() : JSONtoBid Error") 2394 } 2395 2396 // Check if BuyItNow Price > Highest Bid so far 2397 binP, err := strconv.Atoi(args[5]) 2398 if err != nil { 2399 return shim.Error("BuyItNow() : Invalid BuyItNow Price") 2400 } 2401 2402 hbP, err := strconv.Atoi(bid.BidPrice) 2403 if err != nil { 2404 return shim.Error("BuyItNow() : Invalid Highest Bid Price") 2405 } 2406 2407 if hbP > binP { 2408 return shim.Error("BuyItNow() : Highest Bid Price > BuyItNow Price - BuyItNow Rejected") 2409 } 2410 2411 // Close The Auction - Fetch Auction Object 2412 Avalbytes, err := QueryObject(stub, "Auction", []string{args[0]}) 2413 if err != nil { 2414 fmt.Println("BuyItNow(): Auction Object Retrieval Failed ") 2415 return shim.Error("BuyItNow(): Auction Object Retrieval Failed ") 2416 } 2417 2418 aucR, err := JSONtoAucReq(Avalbytes) 2419 if err != nil { 2420 fmt.Println("BuyItNow(): Auction Object Unmarshalling Failed ") 2421 return shim.Error("BuyItNow(): Auction Object UnMarshalling Failed ") 2422 } 2423 2424 // Update Auction Status 2425 aucR.Status = "CLOSED" 2426 fmt.Println("BuyItNow(): UpdateAuctionStatus() successful ", aucR) 2427 2428 response = UpdateAuctionStatus(stub, "Auction", aucR) 2429 if response.Status != shim.OK { 2430 fmt.Println("BuyItNow(): UpdateAuctionStatus() Failed ") 2431 return shim.Error("BuyItNow(): UpdateAuctionStatus() Failed ") 2432 } 2433 Avalbytes = response.Payload 2434 2435 // Remove the Auction from Open Bucket 2436 keys := []string{"2016", aucR.AuctionID} 2437 err = DeleteObject(stub, "AucOpen", keys) 2438 if err != nil { 2439 fmt.Println("BuyItNow(): DeleteFromLedger(AucOpen) Failed ") 2440 return shim.Error("BuyItNow(): DeleteFromLedger(AucOpen) Failed ") 2441 } 2442 2443 fmt.Println("BuyItNow(): Proceeding to process the highest bid ") 2444 2445 // Convert the BuyITNow to a Bid type struct 2446 buyItNowBid, err := CreateBidObject(args[0:]) 2447 if err != nil { 2448 return shim.Error(err.Error()) 2449 } 2450 2451 // Reject the offer if the Buyer Information Is not Valid or not registered on the Block Chain 2452 response = ValidateMember(stub, args[4]) 2453 if response.Status != shim.OK { 2454 fmt.Println("BuyItNow() : Failed Buyer not registered on the block-chain ", args[4]) 2455 return shim.Error(err.Error()) 2456 } 2457 2458 buyerInfo := response.Payload 2459 fmt.Println("Buyer information ", buyerInfo, args[4]) 2460 2461 tran := BidtoTransaction(buyItNowBid) 2462 fmt.Println("BuyItNow(): Converting Bid to tran ", tran) 2463 2464 // Process the buy-it-now offer 2465 tranArgs := []string{tran.AuctionID, tran.RecType, tran.ItemID, tran.TransType, tran.UserId, tran.TransDate, tran.HammerTime, tran.HammerPrice, tran.Details} 2466 fmt.Println("BuyItNow(): Proceeding to process the Transaction ", tranArgs) 2467 2468 response = PostTransaction(stub, "PostTransaction", tranArgs) 2469 if response.Status != shim.OK { 2470 fmt.Println("BuyItNow(): PostTransaction() Failed ") 2471 return shim.Error("CloseAuction(): PostTransaction() Failed ") 2472 } 2473 2474 fmt.Println("BuyItNow(): PostTransaction() Completed Successfully ") 2475 return response 2476 } 2477 2478 ////////////////////////////////////////////////////////////////////////// 2479 // Update the Auction Object 2480 // This function updates the status of the auction 2481 // from INIT to OPEN to CLOSED 2482 ////////////////////////////////////////////////////////////////////////// 2483 2484 func UpdateAuctionStatus(stub shim.ChaincodeStubInterface, tableName string, ar AuctionRequest) pb.Response { 2485 2486 buff, err := AucReqtoJSON(ar) 2487 if err != nil { 2488 fmt.Println("UpdateAuctionStatus() : Failed Cannot create object buffer for write : ", ar.AuctionID) 2489 return shim.Error("UpdateAuctionStatus(): Failed Cannot create object buffer for write : " + ar.AuctionID) 2490 } 2491 2492 // Update the ledger with the Buffer Data 2493 //keys := []string{ar.AuctionID, ar.ItemID} 2494 keys := []string{ar.AuctionID} 2495 err = ReplaceObject(stub, "Auction", keys, buff) 2496 if err != nil { 2497 fmt.Println("UpdateAuctionStatus() : write error while inserting record\n") 2498 return shim.Error(err.Error()) 2499 } 2500 return shim.Success(buff) 2501 } 2502 2503 ///////////////////////////////////////////////////////////////////////////////////////////// 2504 // Return the right Object Buffer after validation to write to the ledger 2505 // var recType = []string{"ARTINV", "USER", "BID", "AUCREQ", "POSTTRAN", "OPENAUC", "CLAUC"} 2506 ///////////////////////////////////////////////////////////////////////////////////////////// 2507 2508 func ProcessQueryResult(stub shim.ChaincodeStubInterface, Avalbytes []byte, args []string) error { 2509 2510 // Identify Record Type by scanning the args for one of the recTypes 2511 // This is kind of a post-processor once the query fetches the results 2512 // RecType is the style of programming in the punch card days .. 2513 // ... well 2514 2515 var dat map[string]interface{} 2516 2517 if err := json.Unmarshal(Avalbytes, &dat); err != nil { 2518 panic(err) 2519 } 2520 2521 var recType string 2522 recType = dat["RecType"].(string) 2523 switch recType { 2524 2525 case "ARTINV": 2526 2527 ar, err := JSONtoAR(Avalbytes) // 2528 if err != nil { 2529 fmt.Println("ProcessRequestType(): Cannot create itemObject \n") 2530 return err 2531 } 2532 // Decrypt Image and Save Image in a file 2533 image := Decrypt(ar.AES_Key, ar.ItemImage) 2534 if err != nil { 2535 fmt.Println("ProcessRequestType() : Image decrytion failed ") 2536 return err 2537 } 2538 fmt.Println("ProcessRequestType() : Image conversion from byte[] to file Successful ") 2539 err = ByteArrayToImage(image, "copy."+ar.ItemPicFN) 2540 if err != nil { 2541 2542 fmt.Println("ProcessRequestType() : Image conversion from byte[] to file failed ") 2543 return err 2544 } 2545 return err 2546 2547 case "USER": 2548 ur, err := JSONtoUser(Avalbytes) // 2549 if err != nil { 2550 return err 2551 } 2552 fmt.Println("ProcessRequestType() : ", ur) 2553 return err 2554 2555 case "AUCREQ": 2556 ar, err := JSONtoAucReq(Avalbytes) // 2557 if err != nil { 2558 return err 2559 } 2560 fmt.Println("ProcessRequestType() : ", ar) 2561 return err 2562 2563 case "OPENAUC": 2564 ar, err := JSONtoAucReq(Avalbytes) // 2565 if err != nil { 2566 return err 2567 } 2568 fmt.Println("ProcessRequestType() : ", ar) 2569 return err 2570 case "CLAUC": 2571 ar, err := JSONtoAucReq(Avalbytes) // 2572 if err != nil { 2573 return err 2574 } 2575 fmt.Println("ProcessRequestType() : ", ar) 2576 return err 2577 case "POSTTRAN": 2578 atr, err := JSONtoTran(Avalbytes) // 2579 if err != nil { 2580 return err 2581 } 2582 fmt.Println("ProcessRequestType() : ", atr) 2583 return err 2584 case "BID": 2585 bid, err := JSONtoBid(Avalbytes) // 2586 if err != nil { 2587 return err 2588 } 2589 fmt.Println("ProcessRequestType() : ", bid) 2590 return err 2591 case "DEFAULT": 2592 return nil 2593 case "XFER": 2594 return nil 2595 default: 2596 return errors.New("Unknown") 2597 } 2598 return nil 2599 2600 }