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 }