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  }