HyperLeger Fabric开发(十)——资产交易平台实战
HyperLeger Fabric开发(十)——资产交易平台实战
一、资产交易平台需求分析
1、资产交易平台的功能
A、用户开户、销户功能
B、资产登记,即资产上链,资产绑定到用户
C、资产转让,即资产所有权的变更
D、查询功能,包括用户查询、资产查询、资产历史变更查询
2、业务实体
A、用户,属性包括名字、标识、资产列表、
B、资产,属性包括名字、标识、特殊属性列表
C、资产变更记录,属性包括资产标识、资产源所有者、资产变更后所有者
3、交互方法
A、用户注册,参数包括用户名称、用户标识
B、销户,参数包括用户标识
C、资产登记,参数包括资产名称、资产标识、特殊属性列表、资产所有者
D、资产转让,参数包括资产所有者、资产标识、资产受让者
E、用户查询,参数包括用户标识,返回用户实体
F、资产查询,参数包括资产标识,返回资产实体
G、资产变更记录,参数包括资产标识,记录类型(登记/转让/全部),返回资产变更记录列表。
二、链码开发
1、链码编写
链码需要定义资产交易平台定义的所有实体和交互方法,然后在Invoke接口中调用相应的交互方法。
在Fabric工程目录AssetExchange/chaincode/assetexchange目录下进行链码开发,链码AssetExchangeChainCode.go实现如下:
package mainimport ("fmt""encoding/json""github.com/hyperledger/fabric/core/chaincode/shim""github.com/hyperledger/fabric/protos/peer"
)// 用户
type User struct {Name string `json:"name"`ID string `json:"id"`Assets []string `json:"assets"`
}
// 资产
type Asset struct {Name string `json:"name"`ID string `json:"id"`Metadata string `json:"metadata"`
}
// 资产变更记录
type AssetHistory struct {AssetID string `json:"asset_id"`OriginOwnerID string `json:"origin_owner_id"`CurrentOwnerID string `json:"current_owner_id"`
}
// 原始用户占位符
const (originOwner = "originOwnerPlaceholder"
)func constructUserKey(userId string)string{return fmt.Sprint("user_%s",userId)
}func constructAssetKey(assetID string)string{return fmt.Sprint("asset_%s",assetID)
}
// 用户注册(开户)
func userRegister(stub shim.ChaincodeStubInterface, args []string) peer.Response{// step 1:检查参数个数if len(args) != 2{return shim.Error("Not enough args")}// step 2:验证参数正确性name := args[0]id := args[1]if name == "" || id == ""{return shim.Error("Invalid args")}// step 3:验证数据是否存在if userBytes, err := stub.GetState(constructUserKey(id));err != nil || len(userBytes) != 0{return shim.Error("User alreay exist")}// step 4: 写入状态user := User{Name:name,ID:id,Assets:make([]string,0),}// 序列化对象userBytes, err := json.Marshal(user)if err != nil{return shim.Error(fmt.Sprint("marshal user error %s",err))}err = stub.PutState(constructUserKey(id), userBytes)if err != nil {return shim.Error(fmt.Sprint("put user error %s", err))}return shim.Success(nil)
}// 用户注销
func userDestroy(stub shim.ChaincodeStubInterface,args []string)peer.Response{// step 1:检查参数个数if len(args) != 1{return shim.Error("Not enough args")}// step 2:验证参数正确性id := args[0]if id == ""{return shim.Error("Invalid args")}// step 3:验证数据是否存在userBytes, err := stub.GetState(constructUserKey(id));if err != nil || len(userBytes) == 0{return shim.Error("User not found")}// step 4: 写入状态if err := stub.DelState(constructUserKey(id)); err != nil {return shim.Error(fmt.Sprintf("delete user error: %s", err))}// 删除用户名下的资产user := new(User)err = json.Unmarshal(userBytes,user)if err != nil{return shim.Error(fmt.Sprintf("unmarshal user error: %s", err))}for _,assetId := range user.Assets{if err := stub.DelState(constructAssetKey(assetId)); err != nil {return shim.Error(fmt.Sprintf("delete asset error: %s", err))}}return shim.Success(nil)
}// 资产登记
func assetEnroll(stub shim.ChaincodeStubInterface,args []string)peer.Response{// step 1:检查参数个数if len(args) != 4 {return shim.Error("Not enough args")}// step 2:验证参数正确性assetName := args[0]assetId := args[1]metadata := args[2]ownerId := args[3]if assetName == "" || assetId == "" || ownerId == ""{return shim.Error("Invalid args")}// step 3:验证数据是否存在userBytes, err := stub.GetState(constructUserKey(ownerId))if err != nil || len(userBytes) == 0{return shim.Error("User not found")}if assetBytes, err := stub.GetState(constructAssetKey(assetId)); err == nil && len(assetBytes) != 0 {return shim.Error("Asset already exist")}// step 4: 写入状态asset := &Asset{Name: assetName,ID: assetId,Metadata: metadata,}assetBytes, err := json.Marshal(asset)if err != nil {return shim.Error(fmt.Sprintf("marshal asset error: %s", err))}if err := stub.PutState(constructAssetKey(assetId), assetBytes); err != nil {return shim.Error(fmt.Sprintf("save asset error: %s", err))}user := new(User)// 反序列化userif err := json.Unmarshal(userBytes, user); err != nil {return shim.Error(fmt.Sprintf("unmarshal user error: %s", err))}user.Assets = append(user.Assets, assetId)// 序列化useruserBytes, err = json.Marshal(user)if err != nil {return shim.Error(fmt.Sprintf("marshal user error: %s", err))}if err := stub.PutState(constructUserKey(user.ID), userBytes); err != nil {return shim.Error(fmt.Sprintf("update user error: %s", err))}// 资产变更历史history := &AssetHistory{AssetID: assetId,OriginOwnerID: originOwner,CurrentOwnerID: ownerId,}historyBytes, err := json.Marshal(history)if err != nil {return shim.Error(fmt.Sprintf("marshal assert history error: %s", err))}historyKey, err := stub.CreateCompositeKey("history", []string{assetId,originOwner,ownerId,})if err != nil {return shim.Error(fmt.Sprintf("create key error: %s", err))}if err := stub.PutState(historyKey, historyBytes); err != nil {return shim.Error(fmt.Sprintf("save assert history error: %s", err))}return shim.Success(historyBytes)
}// 资产转让
func assetExchange(stub shim.ChaincodeStubInterface,args []string)peer.Response{// step 1:检查参数个数if len(args) != 3 {return shim.Error("Not enough args")}// step 2:验证参数正确性ownerID := args[0]assetID := args[1]currentOwnerID := args[2]if ownerID == "" || assetID == "" || currentOwnerID == ""{return shim.Error("Invalid args")}// step 3:验证数据是否存在originOwnerBytes, err := stub.GetState(constructUserKey(ownerID))if err != nil || len(originOwnerBytes) == 0 {return shim.Error("user not found")}currentOwnerBytes, err := stub.GetState(constructUserKey(currentOwnerID))if err != nil || len(currentOwnerBytes) == 0 {return shim.Error("user not found")}assetBytes, err := stub.GetState(constructAssetKey(assetID))if err != nil || len(assetBytes) == 0 {return shim.Error("asset not found")}// 校验原始拥有者确实拥有当前变更的资产originOwner := new(User)// 反序列化userif err := json.Unmarshal(originOwnerBytes, originOwner); err != nil {return shim.Error(fmt.Sprintf("unmarshal user error: %s", err))}aidexist := falsefor _, aid := range originOwner.Assets {if aid == assetID {aidexist = truebreak}}if !aidexist {return shim.Error("asset owner not match")}// step 4: 写入状态assetIds := make([]string, 0)for _, aid := range originOwner.Assets {if aid == assetID {continue}assetIds = append(assetIds, aid)}originOwner.Assets = assetIdsoriginOwnerBytes, err = json.Marshal(originOwner)if err != nil {return shim.Error(fmt.Sprintf("marshal user error: %s", err))}if err := stub.PutState(constructUserKey(ownerID), originOwnerBytes); err != nil {return shim.Error(fmt.Sprintf("update user error: %s", err))}// 当前拥有者插入资产idcurrentOwner := new(User)// 反序列化userif err := json.Unmarshal(currentOwnerBytes, currentOwner); err != nil {return shim.Error(fmt.Sprintf("unmarshal user error: %s", err))}currentOwner.Assets = append(currentOwner.Assets, assetID)currentOwnerBytes, err = json.Marshal(currentOwner)if err != nil {return shim.Error(fmt.Sprintf("marshal user error: %s", err))}if err := stub.PutState(constructUserKey(currentOwnerID), currentOwnerBytes); err != nil {return shim.Error(fmt.Sprintf("update user error: %s", err))}// 插入资产变更记录history := &AssetHistory{AssetID: assetID,OriginOwnerID: ownerID,CurrentOwnerID: currentOwnerID,}historyBytes, err := json.Marshal(history)if err != nil {return shim.Error(fmt.Sprintf("marshal asset history error: %s", err))}historyKey, err := stub.CreateCompositeKey("history", []string{assetID,ownerID,currentOwnerID,})if err != nil {return shim.Error(fmt.Sprintf("create key error: %s", err))}if err := stub.PutState(historyKey, historyBytes); err != nil {return shim.Error(fmt.Sprintf("save asset history error: %s", err))}return shim.Success(nil)
}// 用户查询
func queryUser(stub shim.ChaincodeStubInterface,args []string)peer.Response{// step 1:检查参数个数if len(args) != 1 {return shim.Error("Not enough args")}// step 2:验证参数正确性userID := args[0]if userID == ""{return shim.Error("Invalid args")}// step 3:验证数据是否存在userBytes, err := stub.GetState(constructUserKey(userID))if err != nil || len(userBytes) == 0 {return shim.Error("user not found")}return shim.Success(userBytes)
}// 资产查询
func queryAsset(stub shim.ChaincodeStubInterface,args []string)peer.Response{// step 1:检查参数个数if len(args) != 1 {return shim.Error("Not enough args")}// step 2:验证参数正确性assetID := args[0]if assetID == ""{return shim.Error("Invalid args")}// step 3:验证数据是否存在assetBytes, err := stub.GetState(constructAssetKey(assetID))if err != nil || len(assetBytes) == 0 {return shim.Error("asset not found")}return shim.Success(assetBytes)
}// 资产交易记录查询
func queryAssetHistory(stub shim.ChaincodeStubInterface,args []string)peer.Response{// step 1:检查参数个数if len(args) != 2 && len(args) != 1 {return shim.Error("Not enough args")}// step 2:验证参数正确性assetID := args[0]if assetID == ""{return shim.Error("Invalid args")}queryType := "all"if len(args) == 2 {queryType = args[1]}if queryType != "all" && queryType != "enroll" && queryType != "exchange" {return shim.Error(fmt.Sprintf("queryType unknown %s", queryType))}// step 3:验证数据是否存在assetBytes, err := stub.GetState(constructAssetKey(assetID))if err != nil || len(assetBytes) == 0 {return shim.Error("asset not found")}// 查询相关数据keys := make([]string, 0)keys = append(keys, assetID)switch queryType {case "enroll":keys = append(keys, originOwner)case "exchange", "all": // 不添加任何附件keydefault:return shim.Error(fmt.Sprintf("unsupport queryType: %s", queryType))}result, err := stub.GetStateByPartialCompositeKey("history", keys)if err != nil {return shim.Error(fmt.Sprintf("query history error: %s", err))}defer result.Close()histories := make([]*AssetHistory, 0)for result.HasNext() {historyVal, err := result.Next()if err != nil {return shim.Error(fmt.Sprintf("query error: %s", err))}history := new(AssetHistory)if err := json.Unmarshal(historyVal.GetValue(), history); err != nil {return shim.Error(fmt.Sprintf("unmarshal error: %s", err))}// 过滤掉不是资产转让的记录if queryType == "exchange" && history.OriginOwnerID == originOwner {continue}histories = append(histories, history)}historiesBytes, err := json.Marshal(histories)if err != nil {return shim.Error(fmt.Sprintf("marshal error: %s", err))}return shim.Success(historiesBytes)
}type AssetExchangeChainCode struct {}func (t *AssetExchangeChainCode) Init(stub shim.ChaincodeStubInterface) peer.Response{return shim.Success(nil)
}func (t *AssetExchangeChainCode) Invoke(stub shim.ChaincodeStubInterface) peer.Response{functionName, args := stub.GetFunctionAndParameters()switch functionName {case "userRegister":return userRegister(stub,args)case "userDestroy":return userDestroy(stub,args)case "assetEnroll":return assetEnroll(stub,args)case "assetExchange":return assetExchange(stub,args)case "queryUser":return queryUser(stub,args)case "queryAsset":return queryAsset(stub,args)case "queryAssetHistory":return queryAssetHistory(stub,args)default:return shim.Error(fmt.Sprintf("unsupported function: %s", functionName))}return shim.Success(nil)
}func main() {err := shim.Start(new(AssetExchangeChainCode))if err != nil {fmt.Printf("Error starting AssetExchange chaincode: %s", err)}
}
2、链码编译
在Fabric工程AssetExchange/chaincode/assetexchange目录下编译链码:
go build -o assetexchange
编译成功的关键在于确保Fabric依赖的第三方包能够正确被从网络上下载到本地。由于部分第三方依赖包可能从google.golang.org下载,因此需要确保网络可以正确下载。
三、链码部署
1、Fabric区块链网络部署
进入Fabric工程AssetExchange/deploy
docker-compose up
启动服务是否正确启动,确保orderer、peer、cli节点都正确启动。
docker ps
进入cli容器:
docker exec -it cli bash
进入/etc/hyperledger/channel-artifacts目录:
cd /etc/hyperledger/channel-artifacts
创建业务通道:
peer channel create -o orderer.example.com:7050 -c assetchannel -f assetchannel.tx
在当前目录下会生成assetchannel.block区块
加入通道
peer channel join -b assetchannel.block
设置主节点
peer channel update -o orderer.example.com:7050 -c assetchannel -f Org1MSPanchors.tx
2、链码安装
安装assetexchange链码:
peer chaincode install -n assetexchange -v 1.0.0 -l golang -p github.com/chaincode/assetexchange
3、链码实例化
实例化assetexchange链码:
peer chaincode instantiate -o orderer.example.com:7050 -C assetchannel -n assetexchange -l golang -v 1.0.0 -c '{"Args":["user1","0"]}'
4、链码交互
用户注册:
peer chaincode invoke -C assetchannel -n assetexchange -c '{"Args":["userRegister", "user1", "user1"]}'
资产登记:
peer chaincode invoke -C assetchannel -n assetexchange -c '{"Args":["assetEnroll", "asset1", "asset1", "metadata", "user1"]}'
用户注册:
peer chaincode invoke -C assetchannel -n assetexchange -c '{"Args":["userRegister", "user2", "user2"]}'
资产转让:
peer chaincode invoke -C assetchannel -n assetexchange -c '{"Args":["assetExchange", "user1", "asset1", "user2"]}'
用户注销:
peer chaincode invoke -C assetchannel -n assetexchange -c '{"Args":["userDestroy", "user1"]}'
5、链码查询
用户查询:
peer chaincode query -C assetchannel -n assetexchange -c '{"Args":["queryUser", "user1"]}'
资产查询:
peer chaincode query -C assetchannel -n assetexchange -c '{"Args":["queryAsset", "asset1"]}'
用户查询:
peer chaincode query -C assetchannel -n assetexchange -c '{"Args":["queryUser", "user2"]}'
资产交易记录查询:
peer chaincode query -C assetchannel -n assetexchange -c '{"Args":["queryAssetHistory", "asset1"]}'
peer chaincode query -C assetchannel -n assetexchange -c '{"Args":["queryAssetHistory", "asset1", "all"]}'
6、链码升级
peer chaincode install -n assetexchange -v 1.0.1 -l golang -p github.com/chaincode/assetexchange
peer chaincode upgrade -C assetchannel -n assetexchange -v 1.0.1 -c '{"Args":[""]}'
转载于:https://blog.51cto.com/9291927/2322310
HyperLeger Fabric开发(十)——资产交易平台实战相关推荐
- HyperLeger Fabric开发(七)——HyperLeger Fabric链码开发
HyperLeger Fabric开发(七)--HyperLeger Fabric链码开发 一.链码开发模式 1.链码开发模式简介 Fabric的链码开发调试比较繁琐.在不使用链码开发模式的情况下,链 ...
- HyperLeger Fabric学习(一)
HyperLeger Fabric学习(一) 一.HyperLeger简介 1.HyperLeger简介 2.Hyperledger社区组织结构 3.Hyperledger顶级项目 二.Hyperle ...
- hyperledger fabric 实战开发——水产品溯源交易平台(二)
文章目录 前言 一.技术学习 1.Hyperledger fabric 1.1 流程 1.2 配置 1.3 范例解析并自写 1.3 算法实现 二.Web编写 前言 hyperledger fabric ...
- hyperledger fabric 实战开发——水产品溯源交易平台(一)
文章目录 前言 环境准备 水产品溯源交易平台设计 实现步骤 1. 模板获取 2. 模板修改 虚拟机优化(根据个人喜好选择) 前言 在万字解析--区块链hyperledger fabric2.2部署实战 ...
- 链码实战(二)——资产交易平台
链码实战(二)--资产交易平台 本节代码都是按照教学课程敲出来的,参考教学课程在文末!强烈安利 一.需求分析 资产:某个人拥有的某个可被转让的东西 房产.车辆 1.平台功能 用户开户&销户 资 ...
- 开发属于自己的数字资产交易平台必须要了解的几点
在做几乎任何事情之前,准备和规划都是很重要的,开发平台重要是的Web开发阶段 - 无论是交易平台还是SaaS平台还是业务网站都很复杂.让我们来看看数字资产交换中必须具备的功能,以满足客户和所有者的需求 ...
- 5G 时代的 Android App 开发入门与项目实战
随着移动互联网的持续发展,Android系统从智能手机逐步拓展到平板电脑.智能电视.车载大屏.智能家居.智能手表等诸多设备,Android开发依然是前景可期的IT岗位. 当然,整个社会正在迈向5G时代 ...
- 利用Hyperledger Fabric开发你的第一个区块链应用
利用Hyperledger Fabric开发你的第一个区块链应用 本文示例源于fabric-samples中的fabcar https://github.com/hyperledger/fabric- ...
- 利用Hyperledger Fabric开发第一个区块链应用
利用Hyperledger Fabric开发第一个区块链应用 Fabric入门 Fabric 我们通过一个简单的示例程序来了解Fabric应用是如何运行的.在这个例子中使用的应用程序和智能合约(链码) ...
最新文章
- 程序员因重复记录日志撑爆ELK被辞退!
- tf.keras.losses.categorical_hinge 分类铰链 损失函数 示例
- 确定多重选择列表控件 (List Control) 中的选定内容
- 虚拟机——虚拟机的初步认识
- php正则大小写字母,php 常见email,url,英文大小写,字母数字组合等正则表达式详解...
- 盘点神奇却少为人知的IntelliJ IDEA快捷键
- 【渝粤教育】电大中专会计电算化作业 题库
- python game_Python游戏
- 小干货:Linux 系统的备份恢复
- 如何在 macOS 中将用户帐户拆分为两个单独的帐户?
- 12条人生规则《12 Rules for Life: An Antidote to Chaos》
- 第4章 最基础的分类算法-k近邻算法 kNN 学习笔记 中
- 如何做一个基于微信外卖点餐小程序系统毕业设计毕设作品
- Activity启动流程(二)system_server进程处理启动Activity请求
- 基于python的手机销售系统
- 97年大学计算机考试是 级,1997年4月等级考试一级笔试试卷、答案
- 授课型英硕申请Ph.D (带奖)历程
- 谷歌地图离线发布系列之偏移处理(三)纠偏算法
- 如何笔记本盖上连接显示器不熄屏?
- 异步爬虫(高效爬虫)