github.com/inklabsfoundation/inkchain@v0.17.1-0.20181025012015-c3cef8062f19/examples/inkwork/inkwork.go (about)

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