代码拉取完成,页面将自动刷新
/*
Copyright IT People Corp. 2017 All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
///////////////////////////////////////////////////////////////////////
// Author : IT People - Mohan Venkataraman - Auction API for v1.0
// Purpose: Explore the Hyperledger/fabric and understand
// how to write an chain code, application/chain code boundaries
// The code is not the best as it has just hammered out in a day or two
// Feedback and updates are appreciated
///////////////////////////////////////////////////////////////////////
package main
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"os"
"runtime"
"strconv"
"time"
"github.com/hyperledger/fabric/core/chaincode/shim"
pb "github.com/hyperledger/fabric/protos/peer"
)
///////////////////////////////////////////////////////////////////////////////////////
// This creates a record of the Asset (Inventory)
// Includes Description, title, certificate of authenticity or image whatever..idea is to checkin a image and store it
// in encrypted form
// Example:
// Item { 113869, "Flower Urn on a Patio", "Liz Jardine", "10102007", "Original", "Floral", "Acrylic", "15 x 15 in", "sample_9.png","$600", "My Gallery }
///////////////////////////////////////////////////////////////////////////////////////
type ItemObject struct {
ItemID string
RecType string
ItemDesc string
ItemDetail string // Could included details such as who created the Art work if item is a Painting
ItemDate string
ItemType string
ItemSubject string
ItemMedia string
ItemSize string
ItemPicFN string
ItemImage []byte // This has to be generated AES encrypted using the file name
AES_Key []byte // This is generated by the AES Algorithms
ItemImageType string // should be used to regenerate the appropriate image type
ItemBasePrice string // Reserve Price at Auction must be greater than this price
CurrentOwnerID string // This is validated for a user registered record
TimeStamp string // This is the time stamp
}
////////////////////////////////////////////////////////////////////////////////
// Has an item entry every time the item changes hands
////////////////////////////////////////////////////////////////////////////////
type ItemLog struct {
ItemID string // PRIMARY KEY
Status string // SECONDARY KEY - OnAuc, OnSale, NA
AuctionedBy string // SECONDARY KEY - Auction House ID if applicable
RecType string // ITEMHIS
ItemDesc string
CurrentOwner string
Date string // Date when status changed
}
/////////////////////////////////////////////////////////////
// Create Buyer, Seller , Auction House, Authenticator
// Could establish valid UserTypes -
// AH (Auction House)
// TR (Buyer or Seller)
// AP (Appraiser)
// IN (Insurance)
// BK (bank)
// SH (Shipper)
/////////////////////////////////////////////////////////////
type UserObject struct {
UserID string
RecType string // Type = USER
Name string
UserType string // Auction House (AH), Bank (BK), Buyer or Seller (TR), Shipper (SH), Appraiser (AP)
Address string
Phone string
Email string
Bank string
AccountNo string
RoutingNo string
Timestamp string
}
/////////////////////////////////////////////////////////////////////////////
// Register a request for participating in an auction
// Usually posted by a seller who owns a piece of ITEM
// The Auction house will determine when to open the item for Auction
// The Auction House may conduct an appraisal and genuineness of the item
/////////////////////////////////////////////////////////////////////////////
type AuctionRequest struct {
AuctionID string
RecType string // AUCREQ
ItemID string
AuctionHouseID string // ID of the Auction House managing the auction
SellerID string // ID Of Seller - to verified against the Item CurrentOwnerId
RequestDate string // Date on which Auction Request was filed
ReservePrice string // reserver price > previous purchase price
BuyItNowPrice string // 0 (Zero) if not applicable else specify price
Status string // INIT, OPEN, CLOSED (To be Updated by Trgger Auction)
OpenDate string // Date on which auction will occur (To be Updated by Trigger Auction)
CloseDate string // Date and time when Auction will close (To be Updated by Trigger Auction)
TimeStamp string // The transaction Date and Time
}
/////////////////////////////////////////////////////////////
// POST the transaction after the Auction Completes
// Post an Auction Transaction
// Post an Updated Item Object
// Once an auction request is opened for auctions, a timer is kicked
// off and bids are accepted. When the timer expires, the highest bid
// is selected and converted into a Transaction
// This transaction is a simple view
/////////////////////////////////////////////////////////////
type ItemTransaction struct {
AuctionID string
RecType string // POSTTRAN
ItemID string
TransType string // Sale, Buy, Commission
UserId string // Buyer or Seller ID
TransDate string // Date of Settlement (Buyer or Seller)
HammerTime string // Time of hammer strike - SOLD
HammerPrice string // Total Settlement price
Details string // Details about the Transaction
}
////////////////////////////////////////////////////////////////
// This is a Bid. Bids are accepted only if an auction is OPEN
////////////////////////////////////////////////////////////////
type Bid struct {
AuctionID string
RecType string // BID
BidNo string
ItemID string
BuyerID string // ID Of Buyer - to be verified against the Item CurrentOwnerId
BidPrice string // BidPrice > Previous Bid
BidTime string // Time the bid was received
}
//////////////////////////////////////////////////////////////
// Invoke Functions based on Function name
// The function name gets resolved to one of the following calls
// during an invoke
//
//////////////////////////////////////////////////////////////
func InvokeFunction(fname string) func(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
InvokeFunc := map[string]func(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response{
"iPostItem": PostItem,
"iPostUser": PostUser,
"iPostAuctionRequest": PostAuctionRequest,
"iPostTransaction": PostTransaction,
"iPostBid": PostBid,
"iOpenAuctionForBids": OpenAuctionForBids,
"iBuyItNow": BuyItNow,
"iTransferItem": TransferItem,
"iCloseAuction": CloseAuction,
"iCloseOpenAuctions": CloseOpenAuctions,
"iDownloadImages": DownloadImages,
}
return InvokeFunc[fname]
}
//////////////////////////////////////////////////////////////
// Query Functions based on Function name
//
//////////////////////////////////////////////////////////////
func QueryFunction(fname string) func(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
QueryFunc := map[string]func(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response{
"qGetItem": GetItem,
"qGetUser": GetUser,
"qGetAuctionRequest": GetAuctionRequest,
"qGetTransaction": GetTransaction,
"qGetBid": GetBid,
"qGetLastBid": GetLastBid,
"qGetHighestBid": GetHighestBid,
"qGetNoOfBidsReceived": GetNoOfBidsReceived,
"qGetListOfBids": GetListOfBids,
"qGetItemLog": GetItemLog,
"qGetItemListByCat": GetItemListByCat,
"qGetUserListByCat": GetUserListByCat,
"qGetListOfInitAucs": GetListOfInitAucs,
"qGetListOfOpenAucs": GetListOfOpenAucs,
"qValidateItemOwnership": ValidateItemOwnership,
}
return QueryFunc[fname]
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// We are storing the PictureMap as a Key/Value pair to download the images on the container.
// This was done to run the Daily/Weeky Test Cases from CLI
/////////////////////////////////////////////////////////////////////////////////////////////////////
//func GetPictureUrl(picname string) string {
var PictureMap = map[string]string{
"art1.png": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/art1.png",
"art2.png": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/art2.png",
"art3.png": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/art3.png",
"art4.png": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/art4.png",
"art5.png": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/art5.png",
"art6.png": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/art6.png",
"art7.png": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/art7.png",
"item-001.jpg": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/item-001.jpg",
"item-002.jpg": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/item-002.jpg",
"item-003.jpg": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/item-003.jpg",
"item-004.jpg": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/item-004.jpg",
"item-005.jpg": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/item-005.jpg",
"item-006.jpg": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/item-006.jpg",
"item-007.jpg": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/item-007.jpg",
"item-008.jpg": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/item-008.jpg",
"people.gif": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/people.gif",
"mad-fb.jpg": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/mad-fb.gif",
"sample.png": "https://raw.githubusercontent.com/ITPeople-Blockchain/auction/v0.6/art/artchaincode/sample.png",
}
type SimpleChaincode struct {
}
////////////////////////////////////////////////////////////////////////////////
// Chain Code Kick-off Main function
////////////////////////////////////////////////////////////////////////////////
func main() {
// maximize CPU usage for maximum performance
runtime.GOMAXPROCS(runtime.NumCPU())
fmt.Println("Starting Item Auction Application chaincode BlueMix ver 21 Dated 2016-07-02 09.45.00: ")
//ccPath = fmt.Sprintf("%s/src/github.com/hyperledger/fabric/auction/art/artchaincode/", gopath)
// Start the shim -- running the fabric
err := shim.Start(new(SimpleChaincode))
if err != nil {
fmt.Println("Error starting Item Fun Application chaincode: %s", err)
}
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// We are storing the PictureMap as a Key/Value pair to download the images on the container.
// This was done to run the Daily/Weeky Test Cases from CLI
/////////////////////////////////////////////////////////////////////////////////////////////////////
func downloadFile(filepath string, url string) (err error) {
// Create the file
out, err := os.Create(filepath)
if err != nil {
return err
}
defer out.Close()
// Get the data
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
// Writer the body to file
_, err = io.Copy(out, resp.Body)
if err != nil {
return err
}
return nil
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SimpleChaincode - Init Chaincode implementation - The following sequence of transactions can be used to test the Chaincode
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
// TODO - Include all initialization to be complete before Invoke and Query
// Uses aucTables to delete tables if they exist and re-create them
//myLogger.Info("[Trade and Auction Application] Init")
fmt.Println("[Trade and Auction Application] Init")
fmt.Println("\nInit() Initialization Complete ")
return shim.Success(nil)
}
////////////////////////////////////////////////////////////////
// SimpleChaincode - INVOKE Chaincode implementation
// User Can Invoke
// - Register a user using PostUser
// - Register an item using PostItem
// - The Owner of the item (User) can request that the item be put on auction using PostAuctionRequest
// - The Auction House can request that the auction request be Opened for bids using OpenAuctionForBids
// - One the auction is OPEN, registered buyers (Buyers) can send in bids vis PostBid
// - No bid is accepted when the status of the auction request is INIT or CLOSED
// - Either manually or by OpenAuctionRequest, the auction can be closed using CloseAuction
// - The CloseAuction creates a transaction and invokes PostTransaction
////////////////////////////////////////////////////////////////
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
function, args := stub.GetFunctionAndParameters()
fmt.Println("==========================================================")
fmt.Println("BEGIN Function ====> ", function)
if function[0:1] == "i" {
fmt.Println("==========================================================")
return t.invoke(stub, function, args)
}
if function[0:1] == "q" {
fmt.Println("==========================================================")
return t.query(stub, function, args)
}
fmt.Println("==========================================================")
return shim.Error("Invoke: Invalid Function Name - function names begin with a q or i")
}
////////////////////////////////////////////////////////////////
// SimpleChaincode - INVOKE Chaincode implementation
// User Can Invoke
// - Register a user using PostUser
// - Register an item using PostItem
// - The Owner of the item (User) can request that the item be put on auction using PostAuctionRequest
// - The Auction House can request that the auction request be Opened for bids using OpenAuctionForBids
// - One the auction is OPEN, registered buyers (Buyers) can send in bids vis PostBid
// - No bid is accepted when the status of the auction request is INIT or CLOSED
// - Either manually or by OpenAuctionRequest, the auction can be closed using CloseAuction
// - The CloseAuction creates a transaction and invokes PostTransaction
////////////////////////////////////////////////////////////////
func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Check Type of Transaction and apply business rules
// before adding record to the block chain
// In this version, the assumption is that args[1] specifies recType for all defined structs
// Newer structs - the recType can be positioned anywhere and ChkReqType will check for recType
// example:
// ./peer chaincode invoke -l golang -n mycc -c '{"Function": "PostBid", "Args":["1111", "BID", "1", "1000", "300", "1200"]}'
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if ChkRecType(args) == true {
InvokeRequest := InvokeFunction(function)
if InvokeRequest != nil {
response := InvokeRequest(stub, function, args)
return (response)
}
} else {
fmt.Println("Invoke() Invalid recType : ", args, "\n")
error_str := "Invoke() : Invalid recType : " + args[0]
return shim.Error(error_str)
}
return shim.Success(nil)
}
//////////////////////////////////////////////////////////////////////////////////////////
// SimpleChaincode - query Chaincode implementation
// Client Can Query
// Sample Data
// ./peer chaincode query -l golang -n mycc -c '{"Function": "GetUser", "Args": ["4000"]}'
// ./peer chaincode query -l golang -n mycc -c '{"Function": "GetItem", "Args": ["2000"]}'
//////////////////////////////////////////////////////////////////////////////////////////
func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
// var buff []byte
var response pb.Response
fmt.Println("Query() : ID Extracted and Type = ", args[0])
fmt.Println("Query() : Args supplied : ", args)
if len(args) < 1 {
fmt.Println("Query() : Include at least 1 arguments Key ")
return shim.Error("Query() : Expecting Transaction type and Key value for query")
}
QueryRequest := QueryFunction(function)
if QueryRequest != nil {
response = QueryRequest(stub, function, args)
} else {
fmt.Println("Query() Invalid function call : ", function)
response_str := "Query() : Invalid function call : " + function
return shim.Error(response_str)
}
if response.Status != shim.OK {
fmt.Println("Query() Object not found : ", args[0])
response_str := "Query() : Object not found : " + args[0]
return shim.Error(response_str)
}
return response
}
//////////////////////////////////////////////////////////////////////////////////////////
// Download Images into Peer
//////////////////////////////////////////////////////////////////////////////////////////
func DownloadImages(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
fmt.Println("[Trade and Auction Application] DownloadImages")
var err error
for k, v := range PictureMap {
fmt.Printf("\n Downloading Image '%s' from URL: %s", k, v)
err = downloadFile(k, v)
if err != nil {
fmt.Println(err)
return shim.Error("Invoke: Invalid Function Name - function names begin with a q or i")
}
}
fmt.Println("\nDownloadImages() Complete ")
return shim.Success(nil)
}
//////////////////////////////////////////////////////////////////////////////////////////
// Retrieve User Information
// example:
// ./peer chaincode query -l golang -n mycc -c '{"Function": "GetUser", "Args": ["100"]}'
//
//////////////////////////////////////////////////////////////////////////////////////////
func GetUser(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
var err error
// Get the Object and Display it
Avalbytes, err := QueryObject(stub, "User", args)
if err != nil {
fmt.Println("GetUser() : Failed to Query Object ")
jsonResp := "{\"Error\":\"Failed to get Object Data for " + args[0] + "\"}"
return shim.Error(jsonResp)
}
if Avalbytes == nil {
fmt.Println("GetUser() : Incomplete Query Object ")
jsonResp := "{\"Error\":\"Incomplete information about the key for " + args[0] + "\"}"
return shim.Error(jsonResp)
}
fmt.Println("GetUser() : Response : Successful -")
return shim.Success(Avalbytes)
}
/////////////////////////////////////////////////////////////////////////////////////////
// Query callback representing the query of a chaincode
// Retrieve a Item by Item ID
// QueryObjectWithProcessingFunction takes a post processing function as argument
// peer chaincode query -l golang -n mycc -c '{"Args": ["qGetItem", "1000"]}
//
/////////////////////////////////////////////////////////////////////////////////////////
func GetItem(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
var err error
// Get the Objects and Display it
Avalbytes, err := QueryObjectWithProcessingFunction(stub, "Item", args, ProcessQueryResult)
if err != nil {
fmt.Println("GetItem() : Failed to Query Object ")
jsonResp := "{\"Error\":\"Failed to get Object Data for " + args[0] + "\"}"
return shim.Error(jsonResp)
}
if Avalbytes == nil {
fmt.Println("GetItem() : Incomplete Query Object ")
jsonResp := "{\"Error\":\"Incomplete information about the key for " + args[0] + "\"}"
return shim.Error(jsonResp)
}
// Masking ItemImage binary data
itemObj, _ := JSONtoAR(Avalbytes)
itemObj.ItemImage = []byte{}
Avalbytes, _ = ARtoJSON(itemObj)
fmt.Println("GetItem() : Response : Successful ")
return shim.Success(Avalbytes)
}
/////////////////////////////////////////////////////////////////////////////////////////
// Validates The Ownership of an Asset using ItemID, OwnerID, and HashKey
//
// peer chaincode query -l golang -n mycc -c '{"Function": "ValidateItemOwnership", "Args": ["1000", "100", "tGEBaZuKUBmwTjzNEyd+nr/fPUASuVJAZ1u7gha5fJg="]}'
//
/////////////////////////////////////////////////////////////////////////////////////////
func ValidateItemOwnership(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
var err error
if len(args) < 3 {
fmt.Println("ValidateItemOwnership() : Requires 3 arguments Item#, Owner# and Key ")
return shim.Error("ValidateItemOwnership() : Requires 3 arguments Item#, Owner# and Key")
}
// Get the Object Information
Avalbytes, err := QueryObject(stub, "Item", []string{args[0]})
if err != nil {
fmt.Println("ValidateItemOwnership() : Failed to Query Object ")
jsonResp := "{\"Error\":\"Failed to get Object Data for " + args[0] + "\"}"
return shim.Error(jsonResp)
}
if Avalbytes == nil {
fmt.Println("ValidateItemOwnership() : Incomplete Query Object ")
jsonResp := "{\"Error\":\"Incomplete information about the key for " + args[0] + "\"}"
return shim.Error(jsonResp)
}
myItem, err := JSONtoAR(Avalbytes)
if err != nil {
fmt.Println("ValidateItemOwnership() : Failed to Query Object ")
jsonResp := "{\"Error\":\"Failed to get Object Data for " + args[0] + "\"}"
return shim.Error(jsonResp)
}
myKey := GetKeyValue(Avalbytes, "AES_Key")
fmt.Println("Key String := ", myKey)
if myKey != args[2] {
fmt.Println("ValidateItemOwnership() : Key does not match supplied key ", args[2], " - ", myKey)
jsonResp := "{\"Error\":\"ValidateItemOwnership() : Key does not match asset owner supplied key " + args[0] + "\"}"
return shim.Error(jsonResp)
}
if myItem.CurrentOwnerID != args[1] {
fmt.Println("ValidateItemOwnership() : ValidateItemOwnership() : Owner-Id does not match supplied ID ", args[1])
jsonResp := "{\"Error\":\"ValidateItemOwnership() : Owner-Id does not match supplied ID " + args[0] + "\"}"
return shim.Error(jsonResp)
}
fmt.Print("ValidateItemOwnership() : Response : Successful - \n")
return shim.Success(Avalbytes)
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Retrieve Auction Information
// This query runs against the AuctionTable
// ./peer chaincode query -l golang -n mycc -c '{"Function": "GetAuctionRequest", "Args": ["1111"]}'
// There are two other tables just for query purposes - AucInitTable, AucOpenTable
//
/////////////////////////////////////////////////////////////////////////////////////////////////////
func GetAuctionRequest(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
var err error
// Get the Objects and Display it
Avalbytes, err := QueryObject(stub, "Auction", args)
if err != nil {
fmt.Println("GetAuctionRequest() : Failed to Query Object ")
jsonResp := "{\"Error\":\"Failed to get Object Data for " + args[0] + "\"}"
return shim.Error(jsonResp)
}
if Avalbytes == nil {
fmt.Println("GetAuctionRequest() : Incomplete Query Object ")
jsonResp := "{\"Error\":\"Incomplete information about the key for " + args[0] + "\"}"
return shim.Error(jsonResp)
}
fmt.Println("GetAuctionRequest() : Response : Successful - \n")
return shim.Success(Avalbytes)
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// Retrieve a Bid based on two keys - AucID, BidNo
// A Bid has two Keys - The Auction Request Number and Bid Number
// ./peer chaincode query -l golang -n mycc -c '{"Function": "GetLastBid", "Args": ["1111", "1"]}'
//
///////////////////////////////////////////////////////////////////////////////////////////////////
func GetBid(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
var err error
// Check there are 2 Arguments provided as per the struct - two are computed
// See example
if len(args) < 2 {
fmt.Println("GetBid(): Incorrect number of arguments. Expecting 2 ")
fmt.Println("GetBid(): ./peer chaincode query -l golang -n mycc -c '{\"Function\": \"GetBid\", \"Args\": [\"1111\",\"6\"]}'")
return shim.Error("GetBid(): Incorrect number of arguments. Expecting 2 ")
}
// Get the Objects and Display it
Avalbytes, err := QueryObject(stub, "Bid", args)
if err != nil {
fmt.Println("GetBid() : Failed to Query Object ")
jsonResp := "{\"Error\":\"Failed to get Object Data for " + args[0] + "\"}"
return shim.Error(jsonResp)
}
if Avalbytes == nil {
fmt.Println("GetBid() : Incomplete Query Object ")
jsonResp := "{\"Error\":\"Incomplete information about the key for " + args[0] + "\"}"
return shim.Error(jsonResp)
}
fmt.Println("GetBid() : Response : Successful -")
return shim.Success(Avalbytes)
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// Retrieve Auction Closeout Information. When an Auction closes
// The highest bid is retrieved and converted to a Transaction
// ./peer chaincode query -l golang -n mycc -c '{"Function": "GetTransaction", "Args": ["1111"]}'
//
///////////////////////////////////////////////////////////////////////////////////////////////////
func GetTransaction(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
//var err error
// Get the Objects and Display it
Avalbytes, err := QueryObject(stub, "Trans", args)
if Avalbytes == nil {
fmt.Println("GetTransaction() : Incomplete Query Object ")
jsonResp := "{\"Error\":\"Incomplete information about the key for " + args[0] + "\"}"
return shim.Error(jsonResp)
}
if err != nil {
fmt.Println("GetTransaction() : Failed to Query Object ")
jsonResp := "{\"Error\":\"Failed to get Object Data for " + args[0] + "\"}"
return shim.Error(jsonResp)
}
fmt.Println("GetTransaction() : Response : Successful")
return shim.Success(Avalbytes)
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Create a User Object. The first step is to have users
// registered
// There are different types of users - Traders (TRD), Auction Houses (AH)
// Shippers (SHP), Insurance Companies (INS), Banks (BNK)
// While this version of the chain code does not enforce strict validation
// the business process recommends validating each persona for the service
// they provide or their participation on the auction blockchain, future enhancements will do that
// ./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"]}'
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
func PostUser(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
record, err := CreateUserObject(args[0:]) //
if err != nil {
return shim.Error(err.Error())
}
buff, err := UsertoJSON(record) //
if err != nil {
error_str := "PostuserObject() : Failed Cannot create object buffer for write : " + args[1]
fmt.Println(error_str)
return shim.Error(error_str)
} else {
// Update the ledger with the Buffer Data
// err = stub.PutState(args[0], buff)
keys := []string{args[0]}
err = UpdateObject(stub, "User", keys, buff)
if err != nil {
fmt.Println("PostUser() : write error while inserting record")
return shim.Error("PostUser() : write error while inserting record : Error - " + err.Error())
}
// Post Entry into UserCat- i.e. User Category Table
keys = []string{"2016", args[3], args[0]}
err = UpdateObject(stub, "UserCat", keys, buff)
if err != nil {
error_str := "PostUser() : write error while inserting recordinto UserCat"
fmt.Println(error_str)
return shim.Error(error_str)
}
}
return shim.Success(buff)
}
func CreateUserObject(args []string) (UserObject, error) {
var err error
var aUser UserObject
// Check there are 11 Arguments
if len(args) != 11 {
fmt.Println("CreateUserObject(): Incorrect number of arguments. Expecting 11 ")
return aUser, errors.New("CreateUserObject() : Incorrect number of arguments. Expecting 11 ")
}
// Validate UserID is an integer
_, err = strconv.Atoi(args[0])
if err != nil {
return aUser, errors.New("CreateUserObject() : User ID should be an integer")
}
aUser = UserObject{args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10]}
fmt.Println("CreateUserObject() : User Object : ", aUser)
return aUser, nil
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Create a master Object of the Item
// Since the Owner Changes hands, a record has to be written for each
// Transaction with the updated Encryption Key of the new owner
// Example
//./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"]}'
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
func PostItem(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
itemObject, err := CreateItemObject(args[0:])
if err != nil {
fmt.Println("PostItem(): Cannot create item object \n")
return shim.Error("PostItem(): Cannot create item object")
}
// Check if the Owner ID specified is registered and valid
response := ValidateMember(stub, itemObject.CurrentOwnerID)
ownerInfo := response.Payload
fmt.Println("Owner information ", ownerInfo, itemObject.CurrentOwnerID)
if response.Status != shim.OK {
error_str := "PostItem() : Failed Owner information not found for " + itemObject.CurrentOwnerID
fmt.Println(error_str)
return shim.Error(error_str)
}
// Convert Item Object to JSON
buff, err := ARtoJSON(itemObject) //
if err != nil {
error_str := "PostItem() : Failed Cannot create object buffer for write : " + args[1]
fmt.Println(error_str)
return shim.Error(error_str)
} else {
// Update the ledger with the Buffer Data
// err = stub.PutState(args[0], buff)
keys := []string{args[0]}
err = UpdateObject(stub, "Item", keys, buff)
if err != nil {
fmt.Println("PostItem() : write error while inserting record\n")
return shim.Error("PostItem() : write error while inserting record : " + err.Error())
}
// Put an entry into the Item History Table
response := PostItemLog(stub, itemObject, "INITIAL", "DEFAULT", args[12])
if response.Status != shim.OK {
fmt.Println("PostItemLog() : write error while inserting record\n")
return shim.Error("PostItemLog() : write error while inserting record : Error : " + err.Error())
}
// Post Entry into ItemCatTable - i.e. Item Category Table
// The first key 2016 is a dummy (band aid) key to extract all values
keys = []string{"2016", args[6], args[0]}
err = UpdateObject(stub, "ItemCat", keys, buff)
if err != nil {
fmt.Println("PostItem() : Write error while inserting record into ItemCat \n")
return shim.Error("PostItem() : Write error while inserting record into ItemCat : Error : " + err.Error())
}
}
secret_key, _ := json.Marshal(itemObject.AES_Key)
fmt.Println(string(secret_key))
return shim.Success(secret_key)
}
func CreateItemObject(args []string) (ItemObject, error) {
var err error
var myItem ItemObject
// Check there are 13 Arguments provided as per the struct - two are computed
if len(args) != 13 {
fmt.Println("CreateItemObject(): Incorrect number of arguments. Expecting 13 ")
return myItem, errors.New("CreateItemObject(): Incorrect number of arguments. Expecting 13 ")
}
// Validate ItemID is an integer
_, err = strconv.Atoi(args[0])
if err != nil {
fmt.Println("CreateItemObject(): ART ID should be an integer create failed! ")
return myItem, errors.New("CreateItemObject(): ART ID should be an integer create failed!")
}
// Validate Picture File exists based on the name provided
// Looks for file in current directory of application and must be fixed for other locations
// Validate Picture File exists based on the name provided
// Looks for file in current directory of application and must be fixed for other locations
imagePath := args[9]
if _, err := os.Stat(imagePath); err == nil {
fmt.Println(imagePath, " exists!")
} else {
fmt.Println("CreateItemObject(): Cannot find or load Picture File = %s : %s\n", imagePath, err)
return myItem, errors.New("CreateItemObject(): ART Picture File not found " + imagePath)
}
// Get the Item Image and convert it to a byte array
imagebytes, fileType := ImageToByteArray(imagePath)
// Generate a new key and encrypt the image
AES_key, _ := GenAESKey()
AES_enc := Encrypt(AES_key, imagebytes)
// Append the AES Key, The Encrypted Image Byte Array and the file type
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]}
fmt.Println("CreateItemObject(): Item Object created: ", myItem.ItemID, myItem.AES_Key)
// Code to Validate the Item Object)
// If User presents Crypto Key then key is used to validate the picture that is stored as part of the title
// TODO
return myItem, nil
}
///////////////////////////////////////////////////////////////////////////////////
// Since the Owner Changes hands, a record has to be written for each
// Transaction with the updated Encryption Key of the new owner
// This function is internally invoked by PostTransaction and is not a Public API
///////////////////////////////////////////////////////////////////////////////////
func UpdateItemObject(stub shim.ChaincodeStubInterface, ar []byte, hammerPrice string, buyer string) pb.Response {
var err error
myItem, err := JSONtoAR(ar)
if err != nil {
fmt.Println("UpdateItemObject() : Failed to create Art Record Object from JSON ")
return shim.Error("UpdateItemObject() : Failed to create Art Record Object from JSON : Error : " + err.Error())
}
// Insert logic to re-encrypt image by first fetching the current Key
CurrentAES_Key := myItem.AES_Key
// Decrypt Image and Save Image in a file
image := Decrypt(CurrentAES_Key, myItem.ItemImage)
// Get a New Key & Encrypt Image with New Key
myItem.AES_Key, _ = GenAESKey()
myItem.ItemImage = Encrypt(myItem.AES_Key, image)
// Update the owner to the Buyer and update price to auction hammer price
myItem.ItemBasePrice = hammerPrice
myItem.CurrentOwnerID = buyer
ar, err = ARtoJSON(myItem)
// keys := []string{myItem.ItemID, myItem.CurrentOwnerID} // Was the original in v0.6
keys := []string{myItem.ItemID}
err = ReplaceObject(stub, "Item", keys, ar)
if err != nil {
fmt.Println("UpdateItemObject() : Failed ReplaceObject in ItemTable into Blockchain ")
return shim.Error("UpdateItemObject() : Failed ReplaceObject in ItemTable into Blockchain : Error : " + err.Error())
}
fmt.Println("UpdateItemObject() : ReplaceObject in Item successful ")
// Update entry in Item Category Table as it holds the Item object as wekk
keys = []string{"2016", myItem.ItemSubject, myItem.ItemID}
err = ReplaceObject(stub, "ItemCat", keys, ar)
if err != nil {
fmt.Println("UpdateItemObject() : Failed ReplaceObject in ItemCategory into Blockchain ")
return shim.Error("UpdateItemObject() : Failed ReplaceObject in ItemCategory into Blockchain : Error : " + err.Error())
}
fmt.Println("UpdateItemObject() : ReplaceObject in ItemCategory successful ")
return shim.Success(myItem.AES_Key)
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Obtain Asset Details and Validate Item
// Transfer Item to new owner - no change in price - In the example XFER is the recType
// ./peer chaincode invoke -l golang -n mycc -c '{"Function": "TransferItem", "Args": ["1000", "100", "tGEBaZuKUBmwTjzNEyd+nr/fPUASuVJAZ1u7gha5fJg=", "300", "XFER"]}'
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
func TransferItem(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
var err error
if len(args) < 6 {
fmt.Println("TransferItem() : Requires 6 arguments Item#, Owner#, Key#, newOwnerID#, XFER \n")
return shim.Error("TransferItem() : Requires 6 arguments Item#, Owner#, Key#, newOwnerID#, XFER")
}
// Let us make sure that the Item is not on Auction
err = VerifyIfItemIsOnAuction(stub, args[0])
if err != nil {
error_str := "TransferItem() : Failed Item is either initiated or opened for Auction " + args[0]
fmt.Println(error_str)
return shim.Error(error_str + ": Error : " + err.Error())
}
// Validate New Owner's ID
response := ValidateMember(stub, args[3])
if response.Status != shim.OK {
error_str := "TransferItem() : Failed transferee not Registered in Blockchain " + args[3]
fmt.Println(error_str)
return shim.Error(error_str + ": Error : " + response.Message)
}
// Validate Item or Asset Ownership
response = ValidateItemOwnership(stub, "ValidateItemOwnership", args[:3])
if response.Status != shim.OK {
error_str := "TransferItem() : ValidateItemOwnership() : Failed to authenticate item or asset ownership"
fmt.Println(error_str)
return shim.Error(error_str + ": Error : " + response.Message)
}
ar := response.Payload
myItem, err := JSONtoAR(ar)
if err != nil {
error_str := "TransferItem() : Failed to create item Object from JSON "
fmt.Println(error_str)
return shim.Error(error_str + ": Error : " + err.Error())
}
// Insert logic to re-encrypt image by first fetching the current Key
CurrentAES_Key := myItem.AES_Key
// Decrypt Image and Save Image in a file
image := Decrypt(CurrentAES_Key, myItem.ItemImage)
// Get a New Key & Encrypt Image with New Key
myItem.AES_Key, _ = GenAESKey()
myItem.ItemImage = Encrypt(myItem.AES_Key, image)
// Update the owner to the new owner transferred to
myItem.CurrentOwnerID = args[3]
ar, err = ARtoJSON(myItem)
keys := []string{myItem.ItemID}
err = ReplaceObject(stub, "Item", keys, ar)
if err != nil {
fmt.Println("TransferAsset() : Failed ReplaceObject in ItemTable into Blockchain ")
return shim.Error(err.Error())
}
fmt.Println("TransferAsset() : ReplaceObject in Item successful ")
// Update entry in Item Category Table as it holds the Item object as well
keys = []string{"2016", myItem.ItemSubject, myItem.ItemID}
err = ReplaceObject(stub, "ItemCat", keys, ar)
if err != nil {
fmt.Println("TransferAsset() : Failed ReplaceObject in ItemCategoryTable into Blockchain ")
return shim.Error(err.Error())
}
response = PostItemLog(stub, myItem, "Transfer", args[1], args[5])
if response.Status != shim.OK {
fmt.Println("TransferItem() : PostItemLog() write error while inserting record\n")
return shim.Error(err.Error())
}
fmt.Println("TransferAsset() : ReplaceObject in ItemCategory successful ")
return shim.Success(myItem.AES_Key)
}
////////////////////////////////////////////////////////////////////////////////////
// Validate Item Status - Is it currently on Auction, if so Reject Transfer Request
// This can be written better - will do so if things work
// The function return the Auction ID and the Status = OPEN or INIT
////////////////////////////////////////////////////////////////////////////////////
func VerifyIfItemIsOnAuction(stub shim.ChaincodeStubInterface, itemID string) error {
response := GetListOfOpenAucs(stub, "AucOpen", []string{"2016"})
if response.Status != shim.OK {
return fmt.Errorf("VerifyIfItemIsOnAuction() operation failed. Error retrieving values from AucOpen: %s", response.Message)
}
rows := response.Payload
tlist := make([]AuctionRequest, len(rows))
err := json.Unmarshal([]byte(rows), &tlist)
if err != nil {
fmt.Println("VerifyIfItemIsOnAuction: Unmarshal failed : ", err)
return fmt.Errorf("VerifyIfItemIsOnAuction: operation failed. Error un-marshaling JSON: %s", err)
}
for i := 0; i < len(tlist); i++ {
ar := tlist[i]
// Compare Auction IDs
if ar.ItemID == itemID {
fmt.Println("VerifyIfItemIsOnAuction() Failed : Ummarshall error")
return fmt.Errorf("VerifyIfItemIsOnAuction() operation failed. %s", itemID)
}
}
// Now Check if an Auction Has been inititiated
// If so , it has to be removed from Auction for a Transfer
response = GetListOfInitAucs(stub, "AucInit", []string{"2016"})
if response.Status != shim.OK {
return fmt.Errorf("VerifyIfItemIsOnAuction() operation failed. Error retrieving values from AucInit: %s", err)
}
rows = response.Payload
tlist = make([]AuctionRequest, len(rows))
err = json.Unmarshal([]byte(rows), &tlist)
if err != nil {
fmt.Println("VerifyIfItemIsOnAuction() Unmarshal failed : ", err)
return fmt.Errorf("VerifyIfItemIsOnAuction: operation failed. Error un-marshaling JSON: %s", err)
}
for i := 0; i < len(tlist); i++ {
ar := tlist[i]
if err != nil {
fmt.Println("VerifyIfItemIsOnAuction() Failed : Ummarshall error")
return fmt.Errorf("VerifyIfItemIsOnAuction() operation failed. %s", err)
}
// Compare Auction IDs
if ar.ItemID == itemID {
return fmt.Errorf("VerifyIfItemIsOnAuction() operation failed.")
}
}
return nil
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// POSTS A LOG ENTRY Every Time the Item is transacted
// Valid Status for ItemLog = OnAuc, OnSale, NA, INITIAL
// Valid AuctionedBy: This value is set to "DEFAULT" but when it is put on auction Auction House ID is assigned
// PostItemLog IS NOT A PUBLIC API and is invoked every time some event happens in the Item's life
// The currentDateTime must be provided by Client
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
func PostItemLog(stub shim.ChaincodeStubInterface, item ItemObject, status string, ah string, currentDateTime string) pb.Response {
iLog := ItemToItemLog(item, currentDateTime)
iLog.Status = status
iLog.AuctionedBy = ah
buff, err := ItemLogtoJSON(iLog)
if err != nil {
fmt.Println("PostItemLog() : Failed Cannot create object buffer for write : ", item.ItemID)
return shim.Error("PostItemLog(): Failed Cannot create object buffer for write : " + item.ItemID)
} else {
// Update the ledger with the Buffer Data
keys := []string{iLog.ItemID, iLog.Status, iLog.AuctionedBy, currentDateTime}
err = UpdateObject(stub, "ItemHistory", keys, buff)
if err != nil {
fmt.Println("PostItemLog() : write error while inserting record\n")
return shim.Error(err.Error())
}
}
return shim.Success(buff)
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Create an Auction Request
// The owner of an Item, when ready to put the item on an auction
// will create an auction request and specify a auction house.
//
// ./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"]}'
//
// The start and end time of the auction are actually assigned when the auction is opened by OpenAuctionForBids()
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
func PostAuctionRequest(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
ar, err := CreateAuctionRequest(args[0:])
if err != nil {
return shim.Error(err.Error())
}
// Let us make sure that the Item is not on Auction
err = VerifyIfItemIsOnAuction(stub, ar.ItemID)
if err != nil {
fmt.Println("PostAuctionRequest() : Failed Item is either initiated or opened for Auction ", args[0])
return shim.Error(err.Error())
}
// Validate Auction House to check it is a registered User
response := ValidateMember(stub, ar.AuctionHouseID)
if response.Status != shim.OK {
fmt.Println("PostAuctionRequest() : Failed Auction House not Registered in Blockchain ", ar.AuctionHouseID)
return shim.Error(err.Error())
}
aucHouse := response.Payload
fmt.Println("Auction House information ", aucHouse, " ID: ", ar.AuctionHouseID)
// Validate Item record
response = ValidateItemSubmission(stub, ar.ItemID)
if response.Status != shim.OK {
fmt.Println("PostAuctionRequest() : Failed Could not Validate Item Object in Blockchain ", ar.ItemID)
return shim.Error(err.Error())
}
itemObject := response.Payload
// Convert AuctionRequest to JSON
buff, err := AucReqtoJSON(ar) // Converting the auction request struct to []byte array
if err != nil {
fmt.Println("PostAuctionRequest() : Failed Cannot create object buffer for write : ", args[1])
return shim.Error("PostAuctionRequest(): Failed Cannot create object buffer for write : " + args[1])
} else {
// Update the ledger with the Buffer Data
//err = stub.PutState(args[0], buff)
keys := []string{args[0]}
err = UpdateObject(stub, "Auction", keys, buff)
if err != nil {
fmt.Println("PostAuctionRequest() : write error while inserting record\n")
return shim.Error(err.Error())
}
// Post an Item Log and the Auction House ID is included in the log
// Recall -- that by default that value is "DEFAULT"
io, err := JSONtoAR(itemObject)
response := PostItemLog(stub, io, "ReadyForAuc", ar.AuctionHouseID, ar.TimeStamp)
if response.Status != shim.OK {
fmt.Println("PostItemLog() : write error while inserting record\n")
return shim.Error(err.Error())
}
//An entry is made in the AuctionInitTable that this Item has been placed for Auction
// The UI can pull all items available for auction and the item can be Opened for accepting bids
// The 2016 is a dummy key and has notr value other than to get all rows
keys = []string{"2016", args[0]}
err = UpdateObject(stub, "AucInit", keys, buff)
if err != nil {
fmt.Println("PostAuctionRequest() : write error while inserting record into AucInit\n")
return shim.Error(err.Error())
}
}
return shim.Success(buff)
}
func CreateAuctionRequest(args []string) (AuctionRequest, error) {
var err error
var aucReg AuctionRequest
// Check there are 12 Arguments
// See example -- The Open and Close Dates are Dummy, and will be set by open auction
// '{"Function": "PostAuctionRequest", "Args":["1111", "AUCREQ", "1000", "200", "100", "04012016", "1200", "1800",
// "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"]}'
if len(args) != 12 {
fmt.Println("CreateAuctionRegistrationObject(): Incorrect number of arguments. Expecting 11 ")
return aucReg, errors.New("CreateAuctionRegistrationObject() : Incorrect number of arguments. Expecting 11 ")
}
// Validate UserID is an integer . I think this redundant and can be avoided
err = validateID(args[0])
if err != nil {
return aucReg, errors.New("CreateAuctionRequest() : User ID should be an integer")
}
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]}
fmt.Println("CreateAuctionObject() : Auction Registration : ", aucReg)
return aucReg, nil
}
//////////////////////////////////////////////////////////
// Create an Item Transaction record to process Request
// This is invoked by the CloseAuctionRequest
//
//
////////////////////////////////////////////////////////////
func PostTransaction(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
if function != "PostTransaction" {
return shim.Error("PostTransaction(): Invalid function name. Expecting \"PostTransaction\"")
}
ar, err := CreateTransactionRequest(args[0:]) //
if err != nil {
return shim.Error(err.Error())
}
// Validate buyer's ID
response := ValidateMember(stub, ar.UserId)
if response.Status != shim.OK {
fmt.Println("PostTransaction() : Failed Buyer not Registered in Blockchain ", ar.UserId)
return shim.Error(err.Error())
}
buyer := response.Payload
fmt.Println("PostTransaction(): Validated Buyer information Successfully ", buyer, ar.UserId)
// Validate Item record
response = ValidateItemSubmission(stub, ar.ItemID)
if response.Status != shim.OK {
fmt.Println("PostTransaction() : Failed Could not Validate Item Object in Blockchain ", ar.ItemID)
return shim.Error(err.Error())
}
lastUpdatedItemOBCObject := response.Payload
fmt.Println("PostTransaction() : Validated Item Object in Blockchain Successfully", ar.ItemID)
// Update Item Object with new Owner Key
response = UpdateItemObject(stub, lastUpdatedItemOBCObject, ar.HammerPrice, ar.UserId)
newKey := response.Payload
if response.Status != shim.OK {
fmt.Println("PostTransaction() : Failed to update Item Master Object in Blockchain ", ar.ItemID)
return shim.Error(err.Error())
} else {
// Write New Key to file
fmt.Println("PostTransaction() : New encryption Key is ", newKey)
}
fmt.Println("PostTransaction() : Updated Item Master Object in Blockchain Successfully", ar.ItemID)
// Post an Item Log
itemObject, err := JSONtoAR(lastUpdatedItemOBCObject)
if err != nil {
fmt.Println("PostTransaction() : Conversion error JSON to ItemRecord\n")
return shim.Error(err.Error())
}
// A life cycle event is added to say that the Item is no longer on auction
itemObject.ItemBasePrice = ar.HammerPrice
itemObject.CurrentOwnerID = ar.UserId
response = PostItemLog(stub, itemObject, "NA", "DEFAULT", args[5])
if response.Status != shim.OK {
fmt.Println("PostTransaction() : write error while inserting item log record\n")
return shim.Error(err.Error())
}
fmt.Println("PostTransaction() : Inserted item log record Successfully", ar.ItemID)
// Convert Transaction Object to JSON
buff, err := TrantoJSON(ar) //
if err != nil {
fmt.Println("GetObjectBuffer() : Failed to convert Transaction Object to JSON ", args[0])
return shim.Error(err.Error())
}
// Update the ledger with the Buffer Data
keys := []string{args[0], args[3]}
err = UpdateObject(stub, "Trans", keys, buff)
if err != nil {
fmt.Println("PostTransaction() : write error while inserting record\n")
return shim.Error(err.Error())
}
fmt.Println("PostTransaction() : Posted Transaction Record Successfully\n")
// Returns New Key. To get Transaction Details, run GetTransaction
secret_key, _ := json.Marshal(newKey)
fmt.Println(string(secret_key))
return shim.Success(secret_key)
}
func CreateTransactionRequest(args []string) (ItemTransaction, error) {
var at ItemTransaction
// Check there are 9 Arguments
if len(args) != 9 {
fmt.Println("CreateTransactionRequest(): Incorrect number of arguments. Expecting 9 ")
return at, errors.New("CreateTransactionRequest() : Incorrect number of arguments. Expecting 9 ")
}
at = ItemTransaction{args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]}
fmt.Println("CreateTransactionRequest() : Transaction Request: ", at)
return at, nil
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Create a Bid Object
// Once an Item has been opened for auction, bids can be submitted as long as the auction is "OPEN"
//./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"]}'
//./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"]}'
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
func PostBid(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
bid, err := CreateBidObject(args[0:]) //
if err != nil {
return shim.Error(err.Error())
}
// Reject the Bid if the Buyer Information Is not Valid or not registered on the Block Chain
response := ValidateMember(stub, args[4])
if response.Status != shim.OK {
fmt.Println("PostBid() : Failed Buyer not registered on the block-chain ", args[4])
return shim.Error(err.Error())
}
buyerInfo := response.Payload
fmt.Println("Buyer information ", buyerInfo, " ", args[4])
///////////////////////////////////////
// Reject Bid if Auction is not "OPEN"
///////////////////////////////////////
response = GetAuctionRequest(stub, "GetAuctionRequest", []string{args[0]})
if response.Status != shim.OK {
fmt.Println("PostBid() : Cannot find Auction record ", args[0])
return shim.Error("PostBid(): Cannot find Auction record : " + args[0])
}
RBytes := response.Payload
aucR, err := JSONtoAucReq(RBytes)
if err != nil {
fmt.Println("PostBid() : Cannot UnMarshall Auction record")
return shim.Error("PostBid(): Cannot UnMarshall Auction record: " + args[0])
}
if aucR.Status != "OPEN" {
fmt.Println("PostBid() : Cannot accept Bid as Auction is not OPEN ", args[0])
return shim.Error("PostBid(): Cannot accept Bid as Auction is not OPEN : " + args[0])
}
///////////////////////////////////////////////////////////////////
// Reject Bid if the time bid was received is > Auction Close Time
///////////////////////////////////////////////////////////////////
if tCompare(bid.BidTime, aucR.CloseDate) == false {
fmt.Println("PostBid() Failed : BidTime past the Auction Close Time")
error_str := fmt.Sprintf("PostBid() Failed : BidTime past the Auction Close Time %s, %s", bid.BidTime, aucR.CloseDate)
return shim.Error(error_str)
}
//////////////////////////////////////////////////////////////////
// Reject Bid if Item ID on Bid does not match Item ID on Auction
//////////////////////////////////////////////////////////////////
if aucR.ItemID != bid.ItemID {
fmt.Println("PostBid() Failed : Item ID mismatch on bid. Bid Rejected")
return shim.Error("PostBid() : Item ID mismatch on Bid. Bid Rejected")
}
//////////////////////////////////////////////////////////////////////
// Reject Bid if Bid Price is less than Reserve Price
// Convert Bid Price and Reserve Price to Integer (TODO - Float)
//////////////////////////////////////////////////////////////////////
bp, err := strconv.Atoi(bid.BidPrice)
if err != nil {
fmt.Println("PostBid() Failed : Bid price should be an integer")
return shim.Error("PostBid() : Bid price should be an integer")
}
hp, err := strconv.Atoi(aucR.ReservePrice)
if err != nil {
return shim.Error("PostItem() : Reserve Price should be an integer")
}
// Check if Bid Price is > Auction Request Reserve Price
if bp < hp {
return shim.Error("PostItem() : Bid Price must be greater than Reserve Price")
}
////////////////////////////
// Post or Accept the Bid
////////////////////////////
buff, err := BidtoJSON(bid) //
if err != nil {
fmt.Println("PostBid() : Failed Cannot create object buffer for write : ", args[1])
return shim.Error("PostBid(): Failed Cannot create object buffer for write : " + args[1])
} else {
// Update the ledger with the Buffer Data
// err = stub.PutState(args[0], buff)
keys := []string{args[0], args[2]}
err = UpdateObject(stub, "Bid", keys, buff)
if err != nil {
fmt.Println("PostBid() : write error while inserting record\n")
return shim.Error(err.Error())
}
}
return shim.Success(buff)
}
func CreateBidObject(args []string) (Bid, error) {
var err error
var aBid Bid
// Check there are 7 Arguments
// See example
if len(args) != 7 {
fmt.Println("CreateBidObject(): Incorrect number of arguments. Expecting 7 ")
return aBid, errors.New("CreateBidObject() : Incorrect number of arguments. Expecting 7 ")
}
// Validate Bid is an integer
_, err = strconv.Atoi(args[0])
if err != nil {
return aBid, errors.New("CreateBidObject() : Bid ID should be an integer")
}
_, err = strconv.Atoi(args[2])
if err != nil {
return aBid, errors.New("CreateBidObject() : Bid ID should be an integer")
}
// bidTime = args[6] sent by the client
aBid = Bid{args[0], args[1], args[2], args[3], args[4], args[5], args[6]}
fmt.Println("CreateBidObject() : Bid Object : ", aBid)
return aBid, nil
}
//////////////////////////////////////////////////////////
// JSON To args[] - return a map of the JSON string
//////////////////////////////////////////////////////////
func JSONtoArgs(Avalbytes []byte) (map[string]interface{}, error) {
var data map[string]interface{}
if err := json.Unmarshal(Avalbytes, &data); err != nil {
return nil, err
}
return data, nil
}
//////////////////////////////////////////////////////////
// Variation of the above - return value from a JSON string
//////////////////////////////////////////////////////////
func GetKeyValue(Avalbytes []byte, key string) string {
var dat map[string]interface{}
if err := json.Unmarshal(Avalbytes, &dat); err != nil {
panic(err)
}
val := dat[key].(string)
return val
}
//////////////////////////////////////////////////////////
// Time and Date Comparison
// tCompare("2016-06-28 18:40:57", "2016-06-27 18:45:39")
//////////////////////////////////////////////////////////
func tCompare(t1 string, t2 string) bool {
layout := "2006-01-02 15:04:05"
bidTime, err := time.Parse(layout, t1)
if err != nil {
fmt.Println("tCompare() Failed : time Conversion error on t1")
return false
}
aucCloseTime, err := time.Parse(layout, t2)
if err != nil {
fmt.Println("tCompare() Failed : time Conversion error on t2")
return false
}
if bidTime.Before(aucCloseTime) {
return true
}
return false
}
//////////////////////////////////////////////////////////
// Converts JSON String to an ART Object
//////////////////////////////////////////////////////////
func JSONtoAR(data []byte) (ItemObject, error) {
ar := ItemObject{}
err := json.Unmarshal([]byte(data), &ar)
if err != nil {
fmt.Println("Unmarshal failed : ", err)
}
return ar, err
}
//////////////////////////////////////////////////////////
// Converts an ART Object to a JSON String
//////////////////////////////////////////////////////////
func ARtoJSON(ar ItemObject) ([]byte, error) {
ajson, err := json.Marshal(ar)
if err != nil {
fmt.Println(err)
return nil, err
}
return ajson, nil
}
//////////////////////////////////////////////////////////
// Converts an BID to a JSON String
//////////////////////////////////////////////////////////
func ItemLogtoJSON(item ItemLog) ([]byte, error) {
ajson, err := json.Marshal(item)
if err != nil {
fmt.Println(err)
return nil, err
}
return ajson, nil
}
//////////////////////////////////////////////////////////
// Converts an User Object to a JSON String
//////////////////////////////////////////////////////////
func JSONtoItemLog(ithis []byte) (ItemLog, error) {
item := ItemLog{}
err := json.Unmarshal(ithis, &item)
if err != nil {
fmt.Println("JSONtoAucReq error: ", err)
return item, err
}
return item, err
}
//////////////////////////////////////////////////////////
// Converts an Auction Request to a JSON String
//////////////////////////////////////////////////////////
func AucReqtoJSON(ar AuctionRequest) ([]byte, error) {
ajson, err := json.Marshal(ar)
if err != nil {
fmt.Println(err)
return nil, err
}
return ajson, nil
}
//////////////////////////////////////////////////////////
// Converts an User Object to a JSON String
//////////////////////////////////////////////////////////
func JSONtoAucReq(areq []byte) (AuctionRequest, error) {
ar := AuctionRequest{}
err := json.Unmarshal(areq, &ar)
if err != nil {
fmt.Println("JSONtoAucReq error: ", err)
return ar, err
}
return ar, err
}
//////////////////////////////////////////////////////////
// Converts an BID to a JSON String
//////////////////////////////////////////////////////////
func BidtoJSON(myHand Bid) ([]byte, error) {
ajson, err := json.Marshal(myHand)
if err != nil {
fmt.Println(err)
return nil, err
}
return ajson, nil
}
//////////////////////////////////////////////////////////
// Converts an User Object to a JSON String
//////////////////////////////////////////////////////////
func JSONtoBid(areq []byte) (Bid, error) {
myHand := Bid{}
err := json.Unmarshal(areq, &myHand)
if err != nil {
fmt.Println("JSONtoAucReq error: ", err)
return myHand, err
}
return myHand, err
}
//////////////////////////////////////////////////////////
// Converts an User Object to a JSON String
//////////////////////////////////////////////////////////
func UsertoJSON(user UserObject) ([]byte, error) {
ajson, err := json.Marshal(user)
if err != nil {
fmt.Println("UsertoJSON error: ", err)
return nil, err
}
fmt.Println("UsertoJSON created: ", ajson)
return ajson, nil
}
//////////////////////////////////////////////////////////
// Converts an User Object to a JSON String
//////////////////////////////////////////////////////////
func JSONtoUser(user []byte) (UserObject, error) {
ur := UserObject{}
err := json.Unmarshal(user, &ur)
if err != nil {
fmt.Println("UsertoJSON error: ", err)
return ur, err
}
fmt.Println("UsertoJSON created: ", ur)
return ur, err
}
//////////////////////////////////////////////////////////
// Converts an Item Transaction to a JSON String
//////////////////////////////////////////////////////////
func TrantoJSON(at ItemTransaction) ([]byte, error) {
ajson, err := json.Marshal(at)
if err != nil {
fmt.Println(err)
return nil, err
}
return ajson, nil
}
//////////////////////////////////////////////////////////
// Converts an Trans Object to a JSON String
//////////////////////////////////////////////////////////
func JSONtoTran(areq []byte) (ItemTransaction, error) {
at := ItemTransaction{}
err := json.Unmarshal(areq, &at)
if err != nil {
fmt.Println("JSONtoTran error: ", err)
return at, err
}
return at, err
}
//////////////////////////////////////////////
// Validates an ID for Well Formed
//////////////////////////////////////////////
func validateID(id string) error {
// Validate UserID is an integer
_, err := strconv.Atoi(id)
if err != nil {
return errors.New("validateID(): User ID should be an integer")
}
return nil
}
//////////////////////////////////////////////
// Create an ItemLog from Item
//////////////////////////////////////////////
func ItemToItemLog(io ItemObject, cdt string) ItemLog {
iLog := ItemLog{}
iLog.ItemID = io.ItemID
iLog.Status = "INITIAL"
iLog.AuctionedBy = "DEFAULT"
iLog.RecType = "ILOG"
iLog.ItemDesc = io.ItemDesc
iLog.CurrentOwner = io.CurrentOwnerID
iLog.Date = cdt
return iLog
}
//////////////////////////////////////////////
// Convert Bid to Transaction for Posting
//////////////////////////////////////////////
func BidtoTransaction(bid Bid) ItemTransaction {
var t ItemTransaction
t.AuctionID = bid.AuctionID
t.RecType = "POSTTRAN"
t.ItemID = bid.ItemID
t.TransType = "SALE"
t.UserId = bid.BuyerID
// Ideally SystemChain Code must provide a TimeStamp Function
t.TransDate = bid.BidTime
t.HammerTime = bid.BidTime
t.HammerPrice = bid.BidPrice
t.Details = "The Highest Bidder does not always win"
return t
}
////////////////////////////////////////////////////////////////////////////
// Validate if the User Information Exists
// in the block-chain
////////////////////////////////////////////////////////////////////////////
func ValidateMember(stub shim.ChaincodeStubInterface, owner string) pb.Response {
// Get the Item Objects and Display it
// Avalbytes, err := stub.GetState(owner)
args := []string{owner}
Avalbytes, err := QueryObject(stub, "User", args)
if err != nil {
fmt.Println("ValidateMember() : Failed - Cannot find valid owner record for ART ", owner)
jsonResp := "{\"Error\":\"Failed to get Owner Object Data for " + owner + "\"}"
return shim.Error(jsonResp)
}
if Avalbytes == nil {
fmt.Println("ValidateMember() : Failed - Incomplete owner record for ART ", owner)
jsonResp := "{\"Error\":\"Failed - Incomplete information about the owner for " + owner + "\"}"
return shim.Error(jsonResp)
}
fmt.Println("ValidateMember() : Validated Item Owner:\n", owner)
return shim.Success(Avalbytes)
}
////////////////////////////////////////////////////////////////////////////
// Validate if the User Information Exists
// in the block-chain
////////////////////////////////////////////////////////////////////////////
func ValidateItemSubmission(stub shim.ChaincodeStubInterface, artId string) pb.Response {
// Get the Item Objects and Display it
args := []string{artId}
Avalbytes, err := QueryObject(stub, "Item", args)
if err != nil {
fmt.Println("ValidateItemSubmission() : Failed - Cannot find valid owner record for ART ", artId)
jsonResp := "{\"Error\":\"Failed to get Owner Object Data for " + artId + "\"}"
return shim.Error(jsonResp)
}
if Avalbytes == nil {
fmt.Println("ValidateItemSubmission() : Failed - Incomplete owner record for ART ", artId)
jsonResp := "{\"Error\":\"Failed - Incomplete information about the owner for " + artId + "\"}"
return shim.Error(jsonResp)
}
//fmt.Println("ValidateItemSubmission() : Validated Item Owner:", Avalbytes)
return shim.Success(Avalbytes)
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Get List of Bids for an Auction
// in the block-chain --
// ./peer chaincode query -l golang -n mycc -c '{"Function": "GetListOfBids", "Args": ["1111"]}'
// ./peer chaincode query -l golang -n mycc -c '{"Function": "GetLastBid", "Args": ["1111"]}'
// ./peer chaincode query -l golang -n mycc -c '{"Function": "GetHighestBid", "Args": ["1111"]}'
/////////////////////////////////////////////////////////////////////////////////////////////////////
func GetListOfBids(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
rs, err := GetList(stub, "Bid", args)
if err != nil {
error_str := fmt.Sprintf("GetListOfBids operation failed. Error marshaling JSON: %s", err)
return shim.Error(error_str)
}
defer rs.Close()
// Iterate through result set
var i int
var tlist []Bid // Define a list
for i = 0; rs.HasNext(); i++ {
// We can process whichever return value is of interest
responseRange, err := rs.Next()
if err != nil {
return shim.Success(nil)
}
bid, err := JSONtoBid(responseRange.Value)
if err != nil {
error_str := fmt.Sprintf("GetListOfBids() operation failed - Unmarshall Error. %s", err)
fmt.Println(error_str)
return shim.Error(error_str)
}
fmt.Println("GetList() : my Value : ", bid)
tlist = append(tlist, bid)
}
jsonRows, err := json.Marshal(tlist)
if err != nil {
error_str := fmt.Sprintf("GetListOfBids() operation failed - Unmarshall Error. %s", err)
fmt.Println(error_str)
return shim.Error(error_str)
}
fmt.Println("List of Bids Requested : ", jsonRows)
return shim.Success(jsonRows)
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
// Get List of Auctions that have been initiated
// in the block-chain
// This is a fixed Query to be issued as below
// peer chaincode query -l golang -n mycc -c '{"Args": ["qGetListOfInitAucs", "2016"]}'
////////////////////////////////////////////////////////////////////////////////////////////////////////
func GetListOfInitAucs(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
rs, err := GetList(stub, "AucInit", args)
if err != nil {
error_str := fmt.Sprintf("GetListOfInitAucs operation failed. Error marshaling JSON: %s", err)
return shim.Error(error_str)
}
defer rs.Close()
// Iterate through result set
var i int
var tlist []AuctionRequest // Define a list
for i = 0; rs.HasNext(); i++ {
// We can process whichever return value is of interest
responseRange, err := rs.Next()
if err != nil {
return shim.Success(nil)
}
ar, err := JSONtoAucReq(responseRange.Value)
if err != nil {
error_str := fmt.Sprintf("GetListOfInitAucs() operation failed - Unmarshall Error. %s", err)
fmt.Println(error_str)
return shim.Error(error_str)
}
fmt.Println("GetListOfInitAucs() : my Value : ", ar)
tlist = append(tlist, ar)
}
jsonRows, err := json.Marshal(tlist)
if err != nil {
error_str := fmt.Sprintf("GetListOfInitAucs() operation failed - Unmarshall Error. %s", err)
fmt.Println(error_str)
return shim.Error(error_str)
}
//fmt.Println("List of Auctions Requested : ", jsonRows)
return shim.Success(jsonRows)
}
////////////////////////////////////////////////////////////////////////////
// Get List of Open Auctions for which bids can be supplied
// in the block-chain
// This is a fixed Query to be issued as below
// peer chaincode query -l golang -n mycc -c '{"Args": ["qGetListOfOpenAucs", "2016"]}'
////////////////////////////////////////////////////////////////////////////
func GetListOfOpenAucs(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
rs, err := GetList(stub, "AucOpen", args)
if err != nil {
error_str := fmt.Sprintf("GetListOfOpenAucs operation failed. Error marshaling JSON: %s", err)
return shim.Error(error_str)
}
defer rs.Close()
// Iterate through result set
var i int
var tlist []AuctionRequest // Define a list
for i = 0; rs.HasNext(); i++ {
// We can process whichever return value is of interest
responseRange, err := rs.Next()
if err != nil {
return shim.Success(nil)
}
ar, err := JSONtoAucReq(responseRange.Value)
if err != nil {
error_str := fmt.Sprintf("GetListOfOpenAucs() operation failed - Unmarshall Error. %s", err)
fmt.Println(error_str)
return shim.Error(error_str)
}
fmt.Println("GetListOfOpenAucs() : my Value : ", ar)
tlist = append(tlist, ar)
}
jsonRows, err := json.Marshal(tlist)
if err != nil {
error_str := fmt.Sprintf("GetListOfInitAucs() operation failed - Unmarshall Error. %s", err)
fmt.Println(error_str)
return shim.Error(error_str)
}
//fmt.Println("List of Open Auctions : ", jsonRows)
return shim.Success(jsonRows)
}
////////////////////////////////////////////////////////////////////////////
// Get the Item History for an Item
// in the block-chain .. Pass the Item ID
// ./peer chaincode query -l golang -n mycc -c '{"Function": "GetItemLog", "Args": ["1000"]}'
////////////////////////////////////////////////////////////////////////////
func GetItemLog(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
// Check there are 1 Arguments provided as per the struct - two are computed
// See example
if len(args) < 1 {
fmt.Println("GetItemLog(): Incorrect number of arguments. Expecting 1 ")
fmt.Println("GetItemLog(): ./peer chaincode query -l golang -n mycc -c '{\"Function\": \"GetItem\", \"Args\": [\"1111\"]}'")
return shim.Error("CreateItemObject(): Incorrect number of arguments. Expecting 12 ")
}
rs, err := GetList(stub, "ItemHistory", args)
if err != nil {
error_str := fmt.Sprintf("GetItemLog operation failed. Error marshaling JSON: %s", err)
return shim.Error(error_str)
}
defer rs.Close()
// Iterate through result set
var i int
var tlist []ItemLog // Define a list
for i = 0; rs.HasNext(); i++ {
// We can process whichever return value is of interest
responseRange, err := rs.Next()
if err != nil {
return shim.Success(nil)
}
il, err := JSONtoItemLog(responseRange.Value)
if err != nil {
error_str := fmt.Sprintf("GetItemLog() operation failed - Unmarshall Error. %s", err)
fmt.Println(error_str)
return shim.Error(error_str)
}
fmt.Println("GetItemLog() : my Value : ", il)
tlist = append(tlist, il)
}
jsonRows, err := json.Marshal(tlist)
if err != nil {
error_str := fmt.Sprintf("GetItemLog() operation failed - Unmarshall Error. %s", err)
fmt.Println(error_str)
return shim.Error(error_str)
}
//fmt.Println("All History : ", jsonRows)
return shim.Success(jsonRows)
}
////////////////////////////////////////////////////////////////////////////
// Get a List of Items by Category
// in the block-chain
// Input is 2016 + Category
// Categories include whatever has been defined in the Item Tables - Landscape, Modern, ...
// See Sample data
// ./peer chaincode query -l golang -n mycc -c '{"Function": "GetItemListByCat", "Args": ["2016", "Modern"]}'
////////////////////////////////////////////////////////////////////////////
func GetItemListByCat(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
// Check there are 1 Arguments provided as per the struct - two are computed
// See example
if len(args) < 1 {
fmt.Println("GetItemListByCat(): Incorrect number of arguments. Expecting 1 ")
fmt.Println("GetItemListByCat(): ./peer chaincode query -l golang -n mycc -c '{\"Function\": \"GetItemListByCat\", \"Args\": [\"Modern\"]}'")
return shim.Error("CreateItemObject(): Incorrect number of arguments. Expecting 1 ")
}
rs, err := GetList(stub, "ItemCat", args)
if err != nil {
error_str := fmt.Sprintf("GetItemListByCat operation failed. Error marshaling JSON: %s", err)
return shim.Error(error_str)
}
defer rs.Close()
// Iterate through result set
var i int
var tlist []ItemObject // Define a list
for i = 0; rs.HasNext(); i++ {
// We can process whichever return value is of interest
responseRange, err := rs.Next()
if err != nil {
return shim.Success(nil)
}
io, err := JSONtoAR(responseRange.Value)
if err != nil {
error_str := fmt.Sprintf("GetItemListByCat() operation failed - Unmarshall Error. %s", err)
fmt.Println(error_str)
return shim.Error(error_str)
}
fmt.Println("GetItemListByCat() : my Value : ", io)
tlist = append(tlist, io)
}
jsonRows, err := json.Marshal(tlist)
if err != nil {
error_str := fmt.Sprintf("GetItemListByCat() operation failed - Unmarshall Error. %s", err)
fmt.Println(error_str)
return shim.Error(error_str)
}
//fmt.Println("All Items : ", jsonRows)
return shim.Success(jsonRows)
}
////////////////////////////////////////////////////////////////////////////
// Get a List of Users by Category
// in the block-chain
////////////////////////////////////////////////////////////////////////////
func GetUserListByCat(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
// Check there are 1 Arguments provided as per the struct - two are computed
// See example
if len(args) < 1 {
fmt.Println("GetUserListByCat(): Incorrect number of arguments. Expecting 1 ")
fmt.Println("GetUserListByCat(): ./peer chaincode query -l golang -n mycc -c '{\"Function\": \"GetUserListByCat\", \"Args\": [\"AH\"]}'")
return shim.Error("CreateUserObject(): Incorrect number of arguments. Expecting 1 ")
}
rs, err := GetList(stub, "UserCat", args)
if err != nil {
error_str := fmt.Sprintf("GetUserListByCat operation failed. Error marshaling JSON: %s", err)
return shim.Error(error_str)
}
defer rs.Close()
// Iterate through result set
var i int
var tlist []UserObject // Define a list
for i = 0; rs.HasNext(); i++ {
// We can process whichever return value is of interest
responseRange, err := rs.Next()
if err != nil {
return shim.Success(nil)
}
uo, err := JSONtoUser(responseRange.Value)
if err != nil {
error_str := fmt.Sprintf("GetUserListByCat() operation failed - Unmarshall Error. %s", err)
fmt.Println(error_str)
return shim.Error(error_str)
}
fmt.Println("GetUserListByCat() : my Value : ", uo)
tlist = append(tlist, uo)
}
jsonRows, err := json.Marshal(tlist)
if err != nil {
error_str := fmt.Sprintf("GetUserListByCat() operation failed - Unmarshall Error. %s", err)
fmt.Println(error_str)
return shim.Error(error_str)
}
//fmt.Println("All Users : ", jsonRows)
return shim.Success(jsonRows)
}
////////////////////////////////////////////////////////////////////////////
// Get The Highest Bid Received so far for an Auction
// in the block-chain
////////////////////////////////////////////////////////////////////////////
func GetLastBid(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
var Avalbytes []byte
layout := "2006-01-02 15:04:05"
highestTime, err := time.Parse(layout, layout)
rs, err := GetList(stub, "Bid", args)
if err != nil {
error_str := fmt.Sprintf("GetListOfBids operation failed. Error marshaling JSON: %s", err)
return shim.Error(error_str)
}
defer rs.Close()
// Iterate through result set
for i := 0; rs.HasNext(); i++ {
// We can process whichever return value is of interest
responseRange, err := rs.Next()
if err != nil {
return shim.Success(nil)
}
currentBid, err := JSONtoBid(responseRange.Value)
if err != nil {
error_str := fmt.Sprintf("GetHighestBid(0 operation failed. %s", err)
fmt.Println(error_str)
return shim.Error(error_str)
}
bidTime, err := time.Parse(layout, currentBid.BidTime)
if err != nil {
error_str := fmt.Sprintf("GetLastBid() Failed : time Conversion error on BidTime %s", err)
fmt.Println(error_str)
return shim.Error(error_str)
}
if bidTime.Sub(highestTime) > 0 {
highestTime = bidTime
Avalbytes = responseRange.Value
}
return shim.Success(Avalbytes)
}
return shim.Error("GetLastBid() : Failed - No Bids Found")
}
////////////////////////////////////////////////////////////////////////////
// Get The Highest Bid Received so far for an Auction
// in the block-chain
////////////////////////////////////////////////////////////////////////////
func GetNoOfBidsReceived(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
rs, err := GetList(stub, "Bid", args)
if err != nil {
error_str := fmt.Sprintf("GetListOfBids operation failed. Error marshaling JSON: %s", err)
return shim.Error(error_str)
}
defer rs.Close()
// Iterate through result set
var i int
for i = 0; rs.HasNext(); i++ {
// We can process whichever return value is of interest
_, err := rs.Next()
if err != nil {
return shim.Success(nil)
}
}
return shim.Success([]byte(strconv.Itoa(i)))
}
////////////////////////////////////////////////////////////////////////////
// Get the Highest Bid in the List
//
////////////////////////////////////////////////////////////////////////////
func GetHighestBid(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
var Avalbytes []byte
highestBid := 0
rs, err := GetList(stub, "Bid", args)
if err != nil {
error_str := fmt.Sprintf("GetListOfBids operation failed. Error marshaling JSON: %s", err)
return shim.Error(error_str)
}
defer rs.Close()
// Iterate through result set
var i int
for i = 0; rs.HasNext(); i++ {
// We can process whichever return value is of interest
responseRange, err := rs.Next()
if err != nil {
return shim.Success(nil)
}
currentBid, err := JSONtoBid(responseRange.Value)
if err != nil {
error_str := fmt.Sprintf("GetHighestBid(0 operation failed. %s", err)
fmt.Println(error_str)
return shim.Error(error_str)
}
bidPrice, err := strconv.Atoi(currentBid.BidPrice)
if err != nil {
error_str := fmt.Sprintf("GetHighestBid() Int Conversion error on BidPrice! failed. %s", err)
fmt.Println(error_str)
return shim.Error(error_str)
}
if bidPrice >= highestBid {
highestBid = bidPrice
Avalbytes = responseRange.Value
}
}
return shim.Success(Avalbytes)
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Trigger the Auction
// Structure of args auctionReqID, RecType, AucStartDateTime, Duration in Minutes ( 3 = 3 minutes)
// ./peer chaincode invoke -l golang -n mycc -c '{"Function": "OpenAuctionForBids", "Args":["1111", "OPENAUC", "3", "2006-01-02 15:04:05"]}'
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
func OpenAuctionForBids(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
// Fetch Auction Object and check its Status
Avalbytes, err := QueryObject(stub, "Auction", []string{args[0]})
if err != nil {
fmt.Println("OpenAuctionForBids(): Auction Object Retrieval Failed ")
return shim.Error("OpenAuctionForBids(): Auction Object Retrieval Failed ")
}
aucR, err := JSONtoAucReq(Avalbytes)
if err != nil {
fmt.Println("OpenAuctionForBids(): Auction Object Unmarshalling Failed ")
return shim.Error("OpenAuctionForBids(): Auction Object UnMarshalling Failed ")
}
if aucR.Status == "CLOSED" {
fmt.Println("OpenAuctionForBids(): Auction is Closed - Cannot Open for new bids ")
return shim.Error("OpenAuctionForBids(): is Closed - Cannot Open for new bids Failed ")
}
// Calculate Time Now and Duration of Auction
// Validate arg[1] is an integer as it represents Duration in Minutes
aucDuration, err := strconv.Atoi(args[2])
if err != nil {
fmt.Println("OpenAuctionForBids(): Auction Duration is an integer that represents minute! OpenAuctionForBids() Failed ")
return shim.Error("OpenAuctionForBids(): Auction Duration is an integer that represents minute! OpenAuctionForBids() Failed ")
}
aucStartDate, err := time.Parse("2006-01-02 15:04:05", args[3])
aucEndDate := aucStartDate.Add(time.Duration(aucDuration) * time.Minute)
// We don't use go routines anymore to time the auction
//sleepTime := time.Duration(aucDuration * 60 * 1000 * 1000 * 1000)
// Update Auction Object
aucR.OpenDate = aucStartDate.Format("2006-01-02 15:04:05")
aucR.CloseDate = aucEndDate.Format("2006-01-02 15:04:05")
aucR.Status = "OPEN"
response := UpdateAuctionStatus(stub, "Auction", aucR)
if response.Status != shim.OK {
fmt.Println("OpenAuctionForBids(): UpdateAuctionStatus() Failed ")
return shim.Error("OpenAuctionForBids(): UpdateAuctionStatus() Failed ")
}
buff := response.Payload
// Remove the Auction from INIT Bucket and move to OPEN bucket
// This was designed primarily to help the UI
keys := []string{"2016", aucR.AuctionID}
err = DeleteObject(stub, "AucInit", keys)
if err != nil {
fmt.Println("OpenAuctionForBids(): DeleteFromLedger() Failed ")
return shim.Error("OpenAuctionForBids(): DeleteFromLedger() Failed ")
}
// Add the Auction to Open Bucket
err = UpdateObject(stub, "AucOpen", keys, buff)
if err != nil {
fmt.Println("OpenAuctionForBids() : write error while inserting record into AucInit\n")
return shim.Error(err.Error())
}
return shim.Success(buff)
}
//////////////////////////////////////////////////////////////////////////
// Close Open Auctions
// 1. Read OpenAucTable
// 2. Compare now with expiry time with now
// 3. If now is > expiry time call CloseAuction
// ./peer chaincode invoke -l golang -n mycc -c '{"Function": "CloseOpenAuctions", "Args": ["2016", "CLAUC", currentDateTime]}'
//////////////////////////////////////////////////////////////////////////
func CloseOpenAuctions(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
response := GetListOfOpenAucs(stub, "AucOpen", []string{"2016"})
if response.Status != shim.OK {
error_str := fmt.Sprintf("CloseOpenAuctions() operation failed. Error retrieving values from AucOpen: %s", response.Message)
fmt.Println(error_str)
return shim.Error(error_str)
}
rows := response.Payload
tlist := make([]AuctionRequest, len(rows))
err := json.Unmarshal([]byte(rows), &tlist)
if err != nil {
error_str := fmt.Sprintf("CloseOpenAuctions() Unmarshal operation failed. Error retrieving values from AucOpen: %s", response.Message)
fmt.Println(error_str)
return shim.Error(error_str)
}
for i := 0; i < len(tlist); i++ {
ar := tlist[i]
fmt.Println("CloseOpenAuctions() ", ar)
// Compare Auction Times where args[2] = the CurrentTime sent by the client
fmt.Println("CloseOpenAuctions() : ", args[2], ": ar.CloseDate : ", ar.CloseDate)
if tCompare(args[2], ar.CloseDate) == false {
// Request Closing Auction
response := CloseAuction(stub, "CloseAuction", []string{ar.AuctionID})
if response.Status != shim.OK {
error_str := fmt.Sprintf("CloseOpenAuctions() operation failed. %s", err)
fmt.Println(error_str)
return shim.Error(error_str)
}
}
}
return shim.Success(nil)
}
//////////////////////////////////////////////////////////////////////////
// Close the Auction
// This is invoked by OpenAuctionForBids
// which kicks-off a go-routine timer for the duration of the auction
// When the timer expires, it creates a shell script to CloseAuction() and triggers it
// This function can also be invoked via CLI - the intent was to close as and when I implement BuyItNow()
// CloseAuction
// - Sets the status of the Auction to "CLOSED"
// - Removes the Auction from the Open Auction list (AucOpenTable)
// - Retrieves the Highest Bid and creates a Transaction
// - Posts The Transaction
//
// To invoke from Command Line via CLI or REST API
// ./peer chaincode invoke -l golang -n mycc -c '{"Function": "CloseAuction", "Args": ["1111", "AUCREQ"]}'
// ./peer chaincode invoke -l golang -n mycc -c '{"Function": "CloseAuction", "Args": ["1111", "AUCREQ"]}'
//
//////////////////////////////////////////////////////////////////////////
func CloseAuction(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
// Close The Auction - Fetch Auction Object
Avalbytes, err := QueryObject(stub, "Auction", []string{args[0]})
if err != nil {
fmt.Println("CloseAuction(): Auction Object Retrieval Failed ")
return shim.Error("CloseAuction(): Auction Object Retrieval Failed ")
}
aucR, err := JSONtoAucReq(Avalbytes)
if err != nil {
fmt.Println("CloseAuction(): Auction Object Unmarshalling Failed ")
return shim.Error("CloseAuction(): Auction Object UnMarshalling Failed ")
}
// Update Auction Status
aucR.Status = "CLOSED"
fmt.Println("CloseAuction(): UpdateAuctionStatus() successful ", aucR)
response := UpdateAuctionStatus(stub, "Auction", aucR)
if response.Status != shim.OK {
fmt.Println("CloseAuction(): UpdateAuctionStatus() Failed ")
return shim.Error("CloseAuction(): UpdateAuctionStatus() Failed ")
}
Avalbytes = response.Payload
// Remove the Auction from Open Bucket
keys := []string{"2016", aucR.AuctionID}
err = DeleteObject(stub, "AucOpen", keys)
if err != nil {
fmt.Println("CloseAuction(): DeleteFromLedger(AucOpenTable) Failed ")
return shim.Error("CloseAuction(): DeleteFromLedger(AucOpen) Failed ")
}
fmt.Println("CloseAuction(): Proceeding to process the highest bid ")
// Process Final Bid - Turn it into a Transaction
response = GetHighestBid(stub, "GetHighestBid", []string{args[0]})
Avalbytes = response.Payload
if Avalbytes == nil {
fmt.Println("CloseAuction(): No bids available, no change in Item Status - PostTransaction() Completed Successfully ")
return shim.Success(Avalbytes)
}
if response.Status != shim.OK {
fmt.Println("CloseAuction(): No bids available, error encountered - PostTransaction() failed ")
return shim.Error(err.Error())
}
bid, _ := JSONtoBid(Avalbytes)
fmt.Println("CloseAuction(): Proceeding to process the highest bid ", bid)
tran := BidtoTransaction(bid)
fmt.Println("CloseAuction(): Converting Bid to tran ", tran)
// Process the last bid once Time Expires
tranArgs := []string{tran.AuctionID, tran.RecType, tran.ItemID, tran.TransType, tran.UserId, tran.TransDate, tran.HammerTime, tran.HammerPrice, tran.Details}
fmt.Println("CloseAuction(): Proceeding to process the Transaction ", tranArgs)
response = PostTransaction(stub, "PostTransaction", tranArgs)
if response.Status != shim.OK {
fmt.Println("CloseAuction(): PostTransaction() Failed ")
return shim.Error("CloseAuction(): PostTransaction() Failed ")
}
Avalbytes = response.Payload
fmt.Println("CloseAuction(): PostTransaction() Completed Successfully ")
return shim.Success(Avalbytes)
}
////////////////////////////////////////////////////////////////////////////////////////////
// Buy It Now
// Rules:
// If Buy IT Now Option is available then a Buyer has the option to buy the ITEM
// before the bids exceed BuyITNow Price . Normally, The application should take of this
// at the UI level and this chain-code assumes application has validated that
////////////////////////////////////////////////////////////////////////////////////////////
func BuyItNow(stub shim.ChaincodeStubInterface, function string, args []string) pb.Response {
// Process Final Bid - Turn it into a Transaction
response := GetHighestBid(stub, "GetHighestBid", []string{args[0]})
bid, err := JSONtoBid(response.Payload)
if err != nil {
return shim.Error("BuyItNow() : JSONtoBid Error")
}
// Check if BuyItNow Price > Highest Bid so far
binP, err := strconv.Atoi(args[5])
if err != nil {
return shim.Error("BuyItNow() : Invalid BuyItNow Price")
}
hbP, err := strconv.Atoi(bid.BidPrice)
if err != nil {
return shim.Error("BuyItNow() : Invalid Highest Bid Price")
}
if hbP > binP {
return shim.Error("BuyItNow() : Highest Bid Price > BuyItNow Price - BuyItNow Rejected")
}
// Close The Auction - Fetch Auction Object
Avalbytes, err := QueryObject(stub, "Auction", []string{args[0]})
if err != nil {
fmt.Println("BuyItNow(): Auction Object Retrieval Failed ")
return shim.Error("BuyItNow(): Auction Object Retrieval Failed ")
}
aucR, err := JSONtoAucReq(Avalbytes)
if err != nil {
fmt.Println("BuyItNow(): Auction Object Unmarshalling Failed ")
return shim.Error("BuyItNow(): Auction Object UnMarshalling Failed ")
}
// Update Auction Status
aucR.Status = "CLOSED"
fmt.Println("BuyItNow(): UpdateAuctionStatus() successful ", aucR)
response = UpdateAuctionStatus(stub, "Auction", aucR)
if response.Status != shim.OK {
fmt.Println("BuyItNow(): UpdateAuctionStatus() Failed ")
return shim.Error("BuyItNow(): UpdateAuctionStatus() Failed ")
}
Avalbytes = response.Payload
// Remove the Auction from Open Bucket
keys := []string{"2016", aucR.AuctionID}
err = DeleteObject(stub, "AucOpen", keys)
if err != nil {
fmt.Println("BuyItNow(): DeleteFromLedger(AucOpen) Failed ")
return shim.Error("BuyItNow(): DeleteFromLedger(AucOpen) Failed ")
}
fmt.Println("BuyItNow(): Proceeding to process the highest bid ")
// Convert the BuyITNow to a Bid type struct
buyItNowBid, err := CreateBidObject(args[0:])
if err != nil {
return shim.Error(err.Error())
}
// Reject the offer if the Buyer Information Is not Valid or not registered on the Block Chain
response = ValidateMember(stub, args[4])
if response.Status != shim.OK {
fmt.Println("BuyItNow() : Failed Buyer not registered on the block-chain ", args[4])
return shim.Error(err.Error())
}
buyerInfo := response.Payload
fmt.Println("Buyer information ", buyerInfo, args[4])
tran := BidtoTransaction(buyItNowBid)
fmt.Println("BuyItNow(): Converting Bid to tran ", tran)
// Process the buy-it-now offer
tranArgs := []string{tran.AuctionID, tran.RecType, tran.ItemID, tran.TransType, tran.UserId, tran.TransDate, tran.HammerTime, tran.HammerPrice, tran.Details}
fmt.Println("BuyItNow(): Proceeding to process the Transaction ", tranArgs)
response = PostTransaction(stub, "PostTransaction", tranArgs)
if response.Status != shim.OK {
fmt.Println("BuyItNow(): PostTransaction() Failed ")
return shim.Error("CloseAuction(): PostTransaction() Failed ")
}
fmt.Println("BuyItNow(): PostTransaction() Completed Successfully ")
return response
}
//////////////////////////////////////////////////////////////////////////
// Update the Auction Object
// This function updates the status of the auction
// from INIT to OPEN to CLOSED
//////////////////////////////////////////////////////////////////////////
func UpdateAuctionStatus(stub shim.ChaincodeStubInterface, tableName string, ar AuctionRequest) pb.Response {
buff, err := AucReqtoJSON(ar)
if err != nil {
fmt.Println("UpdateAuctionStatus() : Failed Cannot create object buffer for write : ", ar.AuctionID)
return shim.Error("UpdateAuctionStatus(): Failed Cannot create object buffer for write : " + ar.AuctionID)
}
// Update the ledger with the Buffer Data
//keys := []string{ar.AuctionID, ar.ItemID}
keys := []string{ar.AuctionID}
err = ReplaceObject(stub, "Auction", keys, buff)
if err != nil {
fmt.Println("UpdateAuctionStatus() : write error while inserting record\n")
return shim.Error(err.Error())
}
return shim.Success(buff)
}
/////////////////////////////////////////////////////////////////////////////////////////////
// Return the right Object Buffer after validation to write to the ledger
// var recType = []string{"ARTINV", "USER", "BID", "AUCREQ", "POSTTRAN", "OPENAUC", "CLAUC"}
/////////////////////////////////////////////////////////////////////////////////////////////
func ProcessQueryResult(stub shim.ChaincodeStubInterface, Avalbytes []byte, args []string) error {
// Identify Record Type by scanning the args for one of the recTypes
// This is kind of a post-processor once the query fetches the results
// RecType is the style of programming in the punch card days ..
// ... well
var dat map[string]interface{}
if err := json.Unmarshal(Avalbytes, &dat); err != nil {
panic(err)
}
var recType string
recType = dat["RecType"].(string)
switch recType {
case "ARTINV":
ar, err := JSONtoAR(Avalbytes) //
if err != nil {
fmt.Println("ProcessRequestType(): Cannot create itemObject \n")
return err
}
// Decrypt Image and Save Image in a file
image := Decrypt(ar.AES_Key, ar.ItemImage)
if err != nil {
fmt.Println("ProcessRequestType() : Image decrytion failed ")
return err
}
fmt.Println("ProcessRequestType() : Image conversion from byte[] to file Successful ")
err = ByteArrayToImage(image, "copy."+ar.ItemPicFN)
if err != nil {
fmt.Println("ProcessRequestType() : Image conversion from byte[] to file failed ")
return err
}
return err
case "USER":
ur, err := JSONtoUser(Avalbytes) //
if err != nil {
return err
}
fmt.Println("ProcessRequestType() : ", ur)
return err
case "AUCREQ":
ar, err := JSONtoAucReq(Avalbytes) //
if err != nil {
return err
}
fmt.Println("ProcessRequestType() : ", ar)
return err
case "OPENAUC":
ar, err := JSONtoAucReq(Avalbytes) //
if err != nil {
return err
}
fmt.Println("ProcessRequestType() : ", ar)
return err
case "CLAUC":
ar, err := JSONtoAucReq(Avalbytes) //
if err != nil {
return err
}
fmt.Println("ProcessRequestType() : ", ar)
return err
case "POSTTRAN":
atr, err := JSONtoTran(Avalbytes) //
if err != nil {
return err
}
fmt.Println("ProcessRequestType() : ", atr)
return err
case "BID":
bid, err := JSONtoBid(Avalbytes) //
if err != nil {
return err
}
fmt.Println("ProcessRequestType() : ", bid)
return err
case "DEFAULT":
return nil
case "XFER":
return nil
default:
return errors.New("Unknown")
}
return nil
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。