github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/imocc/chaincode/assetsExchange/assetsExchange.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"encoding/json"
     7  
     8  	"github.com/hyperledger/fabric/core/chaincode/shim"
     9  	pb "github.com/hyperledger/fabric/protos/peer"
    10  )
    11  
    12  type AssertsExchangeCC struct{}
    13  
    14  const (
    15  	originOwner = "originOwnerPlaceholder"
    16  )
    17  
    18  // 用户
    19  type User struct {
    20  	Name string `json:"name"` // messagepack || protobuf
    21  	Id   string `json:"id"`
    22  	//Assets map[string]string `json:"assets"` // 资产d --> 资产Name
    23  	Assets []string `json:"assets"`
    24  }
    25  
    26  // 资产
    27  type Asset struct {
    28  	Name string `json:"name"`
    29  	Id   string `json:"id"`
    30  	//Metadata map[string]string `json:"metadata"` // 特殊属性
    31  	Metadata string `json:"metadata"` // 特殊属性
    32  }
    33  
    34  // 资产变革
    35  type AssetHistory struct {
    36  	AssetId        string `json:"asset_id"`
    37  	OriginOwnerId  string `json:"origin_owner_id"`  // 资产的原始拥有者
    38  	CurrentOwnerId string `json:"current_owner_id"` // 变更后当前的拥有者
    39  }
    40  
    41  func constructUserKey(userId string) string {
    42  	return fmt.Sprintf("user_%s", userId)
    43  }
    44  
    45  func constructAssetKey(assetId string) string {
    46  	return fmt.Sprintf("asset_%s", assetId)
    47  }
    48  
    49  // 用户开户
    50  func userRegister(stub shim.ChaincodeStubInterface, args []string) pb.Response {
    51  	// 套路1:检查参数的个数
    52  	if len(args) != 2 {
    53  		return shim.Error("not enough args")
    54  	}
    55  
    56  	// 套路2:验证参数的正确性
    57  	name := args[0]
    58  	id := args[1]
    59  	if name == "" || id == "" {
    60  		return shim.Error("invalid args")
    61  	}
    62  
    63  	// 套路3:验证数据是否存在 应该存在 or 不应该存在
    64  	if userBytes, err := stub.GetState(constructUserKey(id)); err == nil && len(userBytes) != 0 {
    65  		return shim.Error("user already exist1")
    66  	}
    67  
    68  	// 套路4:写入状态
    69  	user := &User{
    70  		Name:   name,
    71  		Id:     id,
    72  		Assets: make([]string, 0),
    73  	}
    74  
    75  	// 序列化对象
    76  	userBytes, err := json.Marshal(user)
    77  	if err != nil {
    78  		return shim.Error(fmt.Sprintf("marshal user error %s", err))
    79  	}
    80  
    81  	if err := stub.PutState(constructUserKey(id), userBytes); err != nil {
    82  		return shim.Error(fmt.Sprintf("put user error %s", err))
    83  	}
    84  
    85  	// 成功返回
    86  	return shim.Success(nil)
    87  }
    88  
    89  // 用户销户
    90  func userDestroy(stub shim.ChaincodeStubInterface, args []string) pb.Response {
    91  	// 套路1:检查参数的个数
    92  	if len(args) != 1 {
    93  		return shim.Error("not enough args")
    94  	}
    95  
    96  	// 套路2:验证参数的正确性
    97  	id := args[0]
    98  	if id == "" {
    99  		return shim.Error("invalid args")
   100  	}
   101  
   102  	// 套路3:验证数据是否存在 应该存在 or 不应该存在
   103  	userBytes, err := stub.GetState(constructUserKey(id))
   104  	if err != nil || len(userBytes) == 0 {
   105  		return shim.Error("user not found")
   106  	}
   107  
   108  	// 套路4:写入状态
   109  	if err := stub.DelState(constructUserKey(id)); err != nil {
   110  		return shim.Error(fmt.Sprintf("delete user error: %s", err))
   111  	}
   112  
   113  	// 删除用户名下的资产
   114  	user := new(User)
   115  	if err := json.Unmarshal(userBytes, user); err != nil {
   116  		return shim.Error(fmt.Sprintf("unmarshal user error: %s", err))
   117  	}
   118  	for _, assetid := range user.Assets {
   119  		if err := stub.DelState(constructAssetKey(assetid)); err != nil {
   120  			return shim.Error(fmt.Sprintf("delete asset error: %s", err))
   121  		}
   122  	}
   123  
   124  	return shim.Success(nil)
   125  }
   126  
   127  // 资产登记
   128  func assetEnroll(stub shim.ChaincodeStubInterface, args []string) pb.Response {
   129  	// 套路1:检查参数的个数
   130  	if len(args) != 4 {
   131  		return shim.Error("not enough args")
   132  	}
   133  
   134  	// 套路2:验证参数的正确性
   135  	assetName := args[0]
   136  	assetId := args[1]
   137  	metadata := args[2]
   138  	ownerId := args[3]
   139  	if assetName == "" || assetId == "" || ownerId == "" {
   140  		return shim.Error("invalid args")
   141  	}
   142  
   143  	// 套路3:验证数据是否存在 应该存在 or 不应该存在
   144  	userBytes, err := stub.GetState(constructUserKey(ownerId))
   145  	if err != nil || len(userBytes) == 0 {
   146  		return shim.Error("user not found")
   147  	}
   148  
   149  	if assetBytes, err := stub.GetState(constructAssetKey(assetId)); err == nil && len(assetBytes) != 0 {
   150  		return shim.Error("asset already exist")
   151  	}
   152  
   153  	// 套路4:写入状态
   154  	// 1. 写入资产对象 2. 更新用户对象 3. 写入资产变更记录
   155  	asset := &Asset{
   156  		Name:     assetName,
   157  		Id:       assetId,
   158  		Metadata: metadata,
   159  	}
   160  	assetBytes, err := json.Marshal(asset)
   161  	if err != nil {
   162  		return shim.Error(fmt.Sprintf("marshal asset error: %s", err))
   163  	}
   164  	if err := stub.PutState(constructAssetKey(assetId), assetBytes); err != nil {
   165  		return shim.Error(fmt.Sprintf("save asset error: %s", err))
   166  	}
   167  
   168  	user := new(User)
   169  	// 反序列化user
   170  	if err := json.Unmarshal(userBytes, user); err != nil {
   171  		return shim.Error(fmt.Sprintf("unmarshal user error: %s", err))
   172  	}
   173  	user.Assets = append(user.Assets, assetId)
   174  	// 序列化user
   175  	userBytes, err = json.Marshal(user)
   176  	if err != nil {
   177  		return shim.Error(fmt.Sprintf("marshal user error: %s", err))
   178  	}
   179  	if err := stub.PutState(constructUserKey(user.Id), userBytes); err != nil {
   180  		return shim.Error(fmt.Sprintf("update user error: %s", err))
   181  	}
   182  
   183  	// 资产变更历史
   184  	history := &AssetHistory{
   185  		AssetId:        assetId,
   186  		OriginOwnerId:  originOwner,
   187  		CurrentOwnerId: ownerId,
   188  	}
   189  	historyBytes, err := json.Marshal(history)
   190  	if err != nil {
   191  		return shim.Error(fmt.Sprintf("marshal assert history error: %s", err))
   192  	}
   193  
   194  	historyKey, err := stub.CreateCompositeKey("history", []string{
   195  		assetId,
   196  		originOwner,
   197  		ownerId,
   198  	})
   199  	if err != nil {
   200  		return shim.Error(fmt.Sprintf("create key error: %s", err))
   201  	}
   202  
   203  	if err := stub.PutState(historyKey, historyBytes); err != nil {
   204  		return shim.Error(fmt.Sprintf("save assert history error: %s", err))
   205  	}
   206  
   207  	return shim.Success(nil)
   208  }
   209  
   210  // 资产转让
   211  func assetExchange(stub shim.ChaincodeStubInterface, args []string) pb.Response {
   212  	// 套路1:检查参数的个数
   213  	if len(args) != 3 {
   214  		return shim.Error("not enough args")
   215  	}
   216  
   217  	// 套路2:验证参数的正确性
   218  	ownerId := args[0]
   219  	assetId := args[1]
   220  	currentOwnerId := args[2]
   221  	if ownerId == "" || assetId == "" || currentOwnerId == "" {
   222  		return shim.Error("invalid args")
   223  	}
   224  
   225  	// 套路3:验证数据是否存在 应该存在 or 不应该存在
   226  	originOwnerBytes, err := stub.GetState(constructUserKey(ownerId))
   227  	if err != nil || len(originOwnerBytes) == 0 {
   228  		return shim.Error("user not found")
   229  	}
   230  
   231  	currentOwnerBytes, err := stub.GetState(constructUserKey(currentOwnerId))
   232  	if err != nil || len(currentOwnerBytes) == 0 {
   233  		return shim.Error("user not found")
   234  	}
   235  
   236  	assetBytes, err := stub.GetState(constructAssetKey(assetId))
   237  	if err != nil || len(assetBytes) == 0 {
   238  		return shim.Error("asset not found")
   239  	}
   240  
   241  	// 校验原始拥有者确实拥有当前变更的资产
   242  	originOwner := new(User)
   243  	// 反序列化user
   244  	if err := json.Unmarshal(originOwnerBytes, originOwner); err != nil {
   245  		return shim.Error(fmt.Sprintf("unmarshal user error: %s", err))
   246  	}
   247  	aidexist := false
   248  	for _, aid := range originOwner.Assets {
   249  		if aid == assetId {
   250  			aidexist = true
   251  			break
   252  		}
   253  	}
   254  	if !aidexist {
   255  		return shim.Error("asset owner not match")
   256  	}
   257  
   258  	// 套路4:写入状态
   259  	// 1. 原是拥有者删除资产id 2. 新拥有者加入资产id 3. 资产变更记录
   260  	assetIds := make([]string, 0)
   261  	for _, aid := range originOwner.Assets {
   262  		if aid == assetId {
   263  			continue
   264  		}
   265  
   266  		assetIds = append(assetIds, aid)
   267  	}
   268  	originOwner.Assets = assetIds
   269  
   270  	originOwnerBytes, err = json.Marshal(originOwner)
   271  	if err != nil {
   272  		return shim.Error(fmt.Sprintf("marshal user error: %s", err))
   273  	}
   274  	if err := stub.PutState(constructUserKey(ownerId), originOwnerBytes); err != nil {
   275  		return shim.Error(fmt.Sprintf("update user error: %s", err))
   276  	}
   277  
   278  	// 当前拥有者插入资产id
   279  	currentOwner := new(User)
   280  	// 反序列化user
   281  	if err := json.Unmarshal(currentOwnerBytes, currentOwner); err != nil {
   282  		return shim.Error(fmt.Sprintf("unmarshal user error: %s", err))
   283  	}
   284  	currentOwner.Assets = append(currentOwner.Assets, assetId)
   285  
   286  	currentOwnerBytes, err = json.Marshal(currentOwner)
   287  	if err != nil {
   288  		return shim.Error(fmt.Sprintf("marshal user error: %s", err))
   289  	}
   290  	if err := stub.PutState(constructUserKey(currentOwnerId), currentOwnerBytes); err != nil {
   291  		return shim.Error(fmt.Sprintf("update user error: %s", err))
   292  	}
   293  
   294  	// 插入资产变更记录
   295  	history := &AssetHistory{
   296  		AssetId:        assetId,
   297  		OriginOwnerId:  ownerId,
   298  		CurrentOwnerId: currentOwnerId,
   299  	}
   300  	historyBytes, err := json.Marshal(history)
   301  	if err != nil {
   302  		return shim.Error(fmt.Sprintf("marshal assert history error: %s", err))
   303  	}
   304  
   305  	historyKey, err := stub.CreateCompositeKey("history", []string{
   306  		assetId,
   307  		ownerId,
   308  		currentOwnerId,
   309  	})
   310  	if err != nil {
   311  		return shim.Error(fmt.Sprintf("create key error: %s", err))
   312  	}
   313  
   314  	if err := stub.PutState(historyKey, historyBytes); err != nil {
   315  		return shim.Error(fmt.Sprintf("save assert history error: %s", err))
   316  	}
   317  
   318  	return shim.Success(nil)
   319  }
   320  
   321  // 用户查询
   322  func queryUser(stub shim.ChaincodeStubInterface, args []string) pb.Response {
   323  	// 套路1:检查参数的个数
   324  	if len(args) != 1 {
   325  		return shim.Error("not enough args")
   326  	}
   327  
   328  	// 套路2:验证参数的正确性
   329  	ownerId := args[0]
   330  	if ownerId == "" {
   331  		return shim.Error("invalid args")
   332  	}
   333  
   334  	// 套路3:验证数据是否存在 应该存在 or 不应该存在
   335  	userBytes, err := stub.GetState(constructUserKey(ownerId))
   336  	if err != nil || len(userBytes) == 0 {
   337  		return shim.Error("user not found1")
   338  	}
   339  
   340  	return shim.Success(userBytes)
   341  }
   342  
   343  // 资产查询
   344  func queryAsset(stub shim.ChaincodeStubInterface, args []string) pb.Response {
   345  	// 套路1:检查参数的个数
   346  	if len(args) != 1 {
   347  		return shim.Error("not enough args")
   348  	}
   349  
   350  	// 套路2:验证参数的正确性
   351  	assetId := args[0]
   352  	if assetId == "" {
   353  		return shim.Error("invalid args")
   354  	}
   355  
   356  	// 套路3:验证数据是否存在 应该存在 or 不应该存在
   357  	assetBytes, err := stub.GetState(constructAssetKey(assetId))
   358  	if err != nil || len(assetBytes) == 0 {
   359  		return shim.Error("asset not found")
   360  	}
   361  
   362  	return shim.Success(assetBytes)
   363  }
   364  
   365  // 资产变更历史查询
   366  func queryAssetHistory(stub shim.ChaincodeStubInterface, args []string) pb.Response {
   367  	// 套路1:检查参数的个数
   368  	if len(args) != 2 && len(args) != 1 {
   369  		return shim.Error("not enough args")
   370  	}
   371  
   372  	// 套路2:验证参数的正确性
   373  	assetId := args[0]
   374  	if assetId == "" {
   375  		return shim.Error("invalid args")
   376  	}
   377  
   378  	queryType := "all"
   379  	if len(args) == 2 {
   380  		queryType = args[1]
   381  	}
   382  
   383  	if queryType != "all" && queryType != "enroll" && queryType != "exchange" {
   384  		return shim.Error(fmt.Sprintf("queryType unknown %s", queryType))
   385  	}
   386  
   387  	// 套路3:验证数据是否存在 应该存在 or 不应该存在
   388  	assetBytes, err := stub.GetState(constructAssetKey(assetId))
   389  	if err != nil || len(assetBytes) == 0 {
   390  		return shim.Error("asset not found")
   391  	}
   392  
   393  	// 查询相关数据
   394  	keys := make([]string, 0)
   395  	keys = append(keys, assetId)
   396  	switch queryType {
   397  	case "enroll":
   398  		keys = append(keys, originOwner)
   399  	case "exchange", "all": // 不添加任何附件key
   400  	default:
   401  		return shim.Error(fmt.Sprintf("unsupport queryType: %s", queryType))
   402  	}
   403  	result, err := stub.GetStateByPartialCompositeKey("history", keys)
   404  	if err != nil {
   405  		return shim.Error(fmt.Sprintf("query history error: %s", err))
   406  	}
   407  	defer result.Close()
   408  
   409  	histories := make([]*AssetHistory, 0)
   410  	for result.HasNext() {
   411  		historyVal, err := result.Next()
   412  		if err != nil {
   413  			return shim.Error(fmt.Sprintf("query error: %s", err))
   414  		}
   415  
   416  		history := new(AssetHistory)
   417  		if err := json.Unmarshal(historyVal.GetValue(), history); err != nil {
   418  			return shim.Error(fmt.Sprintf("unmarshal error: %s", err))
   419  		}
   420  
   421  		// 过滤掉不是资产转让的记录
   422  		if queryType == "exchange" && history.OriginOwnerId == originOwner {
   423  			continue
   424  		}
   425  
   426  		histories = append(histories, history)
   427  	}
   428  
   429  	historiesBytes, err := json.Marshal(histories)
   430  	if err != nil {
   431  		return shim.Error(fmt.Sprintf("marshal error: %s", err))
   432  	}
   433  
   434  	return shim.Success(historiesBytes)
   435  }
   436  
   437  // Init is called during Instantiate transaction after the chaincode container
   438  // has been established for the first time, allowing the chaincode to
   439  // initialize its internal data
   440  func (c *AssertsExchangeCC) Init(stub shim.ChaincodeStubInterface) pb.Response {
   441  	return shim.Success(nil)
   442  }
   443  
   444  // Invoke is called to update or query the ledger in a proposal transaction.
   445  // Updated state variables are not committed to the ledger until the
   446  // transaction is committed.
   447  func (c *AssertsExchangeCC) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
   448  	funcName, args := stub.GetFunctionAndParameters()
   449  
   450  	switch funcName {
   451  	case "userRegister":
   452  		return userRegister(stub, args)
   453  	case "userDestroy":
   454  		return userDestroy(stub, args)
   455  	case "assetEnroll":
   456  		return assetEnroll(stub, args)
   457  	case "assetExchange":
   458  		return assetExchange(stub, args)
   459  	case "queryUser":
   460  		return queryUser(stub, args)
   461  	case "queryAsset":
   462  		return queryAsset(stub, args)
   463  	case "queryAssetHistory":
   464  		return queryAssetHistory(stub, args)
   465  	default:
   466  		return shim.Error(fmt.Sprintf("unsupported function: %s", funcName))
   467  	}
   468  
   469  	// stub.SetEvent("name", []byte("data"))
   470  }
   471  
   472  func main() {
   473  	err := shim.Start(new(AssertsExchangeCC))
   474  	if err != nil {
   475  		fmt.Printf("Error starting AssertsExchange chaincode: %s", err)
   476  	}
   477  }