链码开发-marbles管理

  • 1. 概述
  • 2. marble弹珠管理
    • 2.1实现功能
    • 2.2chaincode链码
    • 2.3编写测试类
    • 2.4 跑测试类
  • 3 搭建本地测试环境 并测试链码
    • 3.1 挂载链码
    • 3.2 启动网络环境
    • 3.3 进入chaincode容器编译链码 提供链码服务
    • 3.4 进入cli容器 安装链码 实例化链码
    • 3.5 测试链码
  • 4 关闭网络

1. 概述

根据前面十篇文章的介绍,基本已经了解了fabric的网络环境和链码开发 部署 调试的过程。这一篇文章,再次巩固链码开发以及部署调用调试。

2. marble弹珠管理

marble

// 声明弹珠结构体
type Marble struct {// 对象类型ObjectType string `json:"objectType"`// 弹珠名称Name string `json:"name"`// 弹珠颜色Color string `json:"color"`// 弹珠大小Size int `json:"size"`// 弹珠拥有者Owner string `json:"owner"`
}

2.1实现功能

  1. 弹珠创建
  2. 弹珠查询
  3. 弹珠删除
  4. 弹珠交易
  5. 弹珠操作历史查询
  6. 查询某个用户的弹珠列表

2.2chaincode链码

markbels.go

package main// 引入依赖包
import ("fmt""github.com/hyperledger/fabric/core/chaincode/shim""github.com/hyperledger/fabric/protos/peer""time""bytes""strconv""encoding/json"
)// 声明结构体
type MarblesChaincode struct{}// 声明弹珠结构体
type Marble struct {// 对象类型ObjectType string `json:"objectType"`// 弹珠名称Name string `json:"name"`// 弹珠颜色Color string `json:"color"`// 弹珠大小Size int `json:"size"`// 弹珠拥有者Owner string `json:"owner"`
}// 实例化链码接口
func (t *MarblesChaincode) Init(stub shim.ChaincodeStubInterface) peer.Response {// 这里初始化不做操作fmt.Println("MarblesChaincode 链码实例化")return shim.Success(nil)
}// invoke 操作
func (t *MarblesChaincode) Invoke(stub shim.ChaincodeStubInterface) peer.Response {// 获取调用的方法和参数fn, args := stub.GetFunctionAndParameters()// 判断分发 业务方法if fn == "initMarble" {// 调用创建弹珠方法return t.initMarble(stub,args)}else if fn == "readMarble" {// 调用读取弹珠信息的方法return t.readMarble(stub,args)}else if fn == "deleteMarble" {// 调用删除弹珠信息return t.deleteMarble(stub,args)}else if fn == "transferMarble" {// 调用交易弹珠的方法return t.transferMarble(stub,args)}else if fn == "getMarbleByRange" {// 调用范围查询return t.getMarbleByRange(stub,args)}else if fn == "queryMarblesByOwner" {// 调用查询用户拥有的弹珠信息return t.queryMarblesByOwner(stub,args)}else if fn == "queryHistoryForMarble" {// 查询弹珠的历史操作信息return t.queryHistoryForMarble(stub,args)}// 如果没有对应的方法 返回错误return shim.Error(fn +" 方法不存在!")}// 创建marble args: name color size owner
func (t *MarblesChaincode) initMarble(stub shim.ChaincodeStubInterface,args []string) peer.Response {// 根据名称判断marble是否已经存在name := args[0]// 查找之前是否存在 名为 name的 marblemarbleBytes, err := stub.GetState(name)// 查询错误if err != nil {return shim.Error(err.Error())}// 如果marbleBytes 已经存在 if marbleBytes != nil {return shim.Error("名为"+ name + "的弹珠已经存在");}// 如果不存在 则写入到账本中color := args[1]size,err := strconv.Atoi(args[2])owner := args[3]// 组装测结构体marble := &Marble{"marble",name,color,size,owner}// 将marble 转成json字符串 存储到账本marbleJsonStr, err := json.Marshal(marble)if err != nil {return shim.Error(err.Error())}// PutState json信息写入账本err = stub.PutState(name,marbleJsonStr)if err != nil {return shim.Error(err.Error())}fmt.Println("创建弹珠成功!!")// 同时创建组合键用于查询indexName := "owner~record"indexKey, err := stub.CreateCompositeKey(indexName,[]string{ owner,string(marbleJsonStr)})if err != nil{return shim.Error(err.Error())}err = stub.PutState(indexKey,[]byte{0x00})if err != nil{return shim.Error(err.Error())}fmt.Println(indexKey)return shim.Success(nil)
}// 读取marble args:  marbleName
func (t *MarblesChaincode) readMarble(stub shim.ChaincodeStubInterface,args []string) peer.Response {// 获取参数 参数为marble的namename := args[0]// 根据name 读取marble的数据marbleBytes, err := stub.GetState(name)if err != nil {return shim.Error(err.Error())}if marbleBytes == nil {return shim.Error(name + " 的弹珠信息不存在")}// 返回信息 return shim.Success(marbleBytes)}// 删除marble args: marbleName
func (t *MarblesChaincode) deleteMarble(stub shim.ChaincodeStubInterface,args []string) peer.Response {// 从参数总获取到markble的namename := args[0]// 判断弹珠是否存在marbleBytes, err := stub.GetState(name)if err != nil {return shim.Error(err.Error())}if marbleBytes == nil {return shim.Error(name + "的弹珠信息不存在")}// 删除弹珠err = stub.DelState(name)if err != nil {return shim.Error(err.Error())}fmt.Println(name + " 弹珠删除成功!")return shim.Success(nil)
}// 交易marble args: marbleName newOwner
func (t *MarblesChaincode) transferMarble(stub shim.ChaincodeStubInterface,args []string) peer.Response {// 获取到参数marbleName := args[0]newOwner := args[1]// 检查弹珠是否存在marbleBytes, err := stub.GetState(marbleName)if err != nil{return shim.Error(err.Error())}if marbleBytes == nil {return shim.Error(marbleName + " 的弹珠信息不存在")}// 将账本中的信息转为 Marble 结构体marbleInfo := Marble{}err = json.Unmarshal(marbleBytes,&marbleInfo)if err != nil {return shim.Error(err.Error())}// 修改拥有者marbleInfo.Owner = newOwner// 转为json数据 newMarbleBytes,err := json.Marshal(marbleInfo)if err != nil {return shim.Error(err.Error())}// 写入账本err = stub.PutState(marbleName,newMarbleBytes)if err != nil {return shim.Error(err.Error())}fmt.Println(marbleName +"转给"+ newOwner+ "的弹珠交易完成")return shim.Success(nil)}// 查询某一范围内的marble args:startMarble endMarble
func (t *MarblesChaincode) getMarbleByRange(stub shim.ChaincodeStubInterface, args []string) peer.Response {// 获取参数startMarble := args[0]endMarble := args[1]// 调用查询方法resultIterator, err := stub.GetStateByRange(startMarble,endMarble)if err!=nil {return shim.Error(err.Error())}defer resultIterator.Close();var buffer bytes.Bufferbuffer.WriteString("[")isWriteSplit := false// 遍历resultIteratorfor resultIterator.HasNext() {item,err := resultIterator.Next()if err!= nil {return shim.Error(err.Error())}if isWriteSplit==true {buffer.WriteString(",")}buffer.WriteString("{\"key\":")buffer.WriteString("\""+item.Key+"\"")buffer.WriteString(",\"record\":")buffer.WriteString(string(item.Value))buffer.WriteString("}")isWriteSplit = true}buffer.WriteString("]")// 返回结果return shim.Success(buffer.Bytes())}// 查询用户拥有的弹珠信息
func (t *MarblesChaincode) queryMarblesByOwner(stub shim.ChaincodeStubInterface,args []string) peer.Response {// 获取参数 下面是通过couchdb的方式来查询 但是 我本地环境// 如果 启动了couchdb总是 在容器启动的时候cli容器无法连接couchdb // 猜测应该是couchdb在容器中启动未完成 cli就去尝试连接了。// 在chaincode-docker-devmode下 有个script.sh 是cli启动后要创建channel并加入channel的脚本// 在最上方添加 sleep 10s 就可以了 等待couchdb启动完成owner := args[0]fmt.Println("开始查询用户"+owner+"拥有的弹珠信息")queryString := fmt.Sprintf("{\"selector\":{\"owner\": \"%s\" }}",owner)resultIterator,err := stub.GetQueryResult(queryString)if err != nil {return shim.Error(err.Error())}defer resultIterator.Close();var buffer bytes.Bufferbuffer.WriteString("[")isWriteSplit := false// 遍历resultIteratorfor resultIterator.HasNext() {item,err := resultIterator.Next()if err!= nil {return shim.Error(err.Error())}if isWriteSplit==true {buffer.WriteString(",")}buffer.WriteString("{\"key\":")buffer.WriteString("\""+item.Key+"\"")buffer.WriteString(",\"record\":")buffer.WriteString(string(item.Value))buffer.WriteString("}")isWriteSplit = true}buffer.WriteString("]")// 返回结果return shim.Success(buffer.Bytes())}// 查询用户
func (t *MarblesChaincode) queryHistoryForMarble(stub shim.ChaincodeStubInterface,args []string) peer.Response {// 获取参数marbleName := args[0]// 获取历史信息resultIterator,err := stub.GetHistoryForKey(marbleName)if err != nil {return shim.Error(err.Error())}defer resultIterator.Close()var buffer bytes.Bufferbuffer.WriteString("[")isWriteSplit := false// 遍历resultIteratorfor resultIterator.HasNext() {item,err := resultIterator.Next()if err!= nil {return shim.Error(err.Error())}if isWriteSplit==true {buffer.WriteString(",")}buffer.WriteString("{\"TxId\":")buffer.WriteString("\""+item.TxId+"\"")buffer.WriteString(",\"Timestamp\":")buffer.WriteString(time.Unix(item.Timestamp.Seconds,int64(item.Timestamp.Nanos)).String())buffer.WriteString(",\"Value\":")buffer.WriteString(string(item.Value))buffer.WriteString(",\"IsDelete\":")buffer.WriteString(strconv.FormatBool(item.IsDelete))buffer.WriteString("}")isWriteSplit = true}buffer.WriteString("]")// 如果没有对应的方法 返回错误return shim.Success(buffer.Bytes())}// main 函数
func main (){err := shim.Start(new (MarblesChaincode))if err != nil {fmt.Printf("Error start MarblesChaincode")}
}

2.3编写测试类

markbels_test.go

package mainimport("fmt""testing""github.com/hyperledger/fabric/core/chaincode/shim")func checkInit(t *testing.T,stub *shim.MockStub,args [][]byte) {res := stub.MockInit("1",args)if (res.Status != shim.OK){fmt.Println(string(res.Message))t.FailNow()}}func checkInvoke(t *testing.T,stub *shim.MockStub,args [][]byte) {res := stub.MockInvoke("1",args)if (res.Status != shim.OK){fmt.Println(string(res.Message))t.FailNow()}}func checkReadMarble(t *testing.T,stub *shim.MockStub, name string) {res := stub.MockInvoke("1",[][]byte{[]byte("readMarble"),[]byte(name)})if(res.Status != shim.OK){fmt.Println(string(res.Message))t.FailNow()}if(res.Payload == nil){fmt.Println("checkReadMarble",name,"failed to get value")t.FailNow()}fmt.Println(string(res.Payload))}func checkReadMarbleByRange(t *testing.T,stub *shim.MockStub, startKey string,endKey string) {res := stub.MockInvoke("1",[][]byte{[]byte("getMarbleByRange"),[]byte(startKey),[]byte(endKey)})if(res.Status != shim.OK){fmt.Println(string(res.Message))t.FailNow()}if(res.Payload == nil){fmt.Println("checkReadMarbleByRange",startKey,endKey,"failed to get value")t.FailNow()}fmt.Println(string(res.Payload))}func checkQueryMarblesByOwner(t *testing.T,stub *shim.MockStub, owner string) {res := stub.MockInvoke("1",[][]byte{[]byte("queryMarblesByOwner"),[]byte(owner)})if(res.Status != shim.OK){fmt.Println(string(res.Message))t.FailNow()}if(res.Payload == nil){fmt.Println("checkQueryMarblesByOwner",owner,"failed to get value")t.FailNow()}fmt.Println(string(res.Payload))}func checkQueryMarblesHistoryByKey(t *testing.T,stub *shim.MockStub, marbleName string) {res := stub.MockInvoke("1",[][]byte{[]byte("queryHistoryForMarble"),[]byte(marbleName)})if(res.Status != shim.OK){fmt.Println(string(res.Message))t.FailNow()}if(res.Payload == nil){fmt.Println("checkReadMarbleByRange",marbleName,"failed to get value")t.FailNow()}fmt.Println(string(res.Payload))}func Test_MarblesChaincode(t *testing.T) {hello := new(MarblesChaincode)stub := shim.NewMockStub("marble",hello)checkInit(t,stub,nil)// name color size ownercheckInvoke(t,stub,[][]byte{[]byte("initMarble"),[]byte("marble-1"),[]byte("red"),[]byte("10"),[]byte("LH")})checkInvoke(t,stub,[][]byte{[]byte("initMarble"),[]byte("marble-2"),[]byte("yellow"),[]byte("11"),[]byte("LH")})checkInvoke(t,stub,[][]byte{[]byte("initMarble"),[]byte("marble-3"),[]byte("blue"),[]byte("12"),[]byte("WX")})checkQueryMarblesByOwner(t,stub,"WX")// checkReadMarble(t,stub,"marble-1")// checkInvoke(t,stub,[][]byte{[]byte("transferMarble"),[]byte("marble-1"),[]byte("WX")})// checkInvoke(t,stub,[][]byte{[]byte("transferMarble"),[]byte("marble-1"),[]byte("LH")})// checkInvoke(t,stub,[][]byte{[]byte("deleteMarble"),[]byte("marble-1")})// checkQueryMarblesHistoryByKey(t,stub,"marble-1")// checkInvoke(t,stub,[][]byte{[]byte("initMarble"),[]byte("marble-4"),[]byte("green"),[]byte("12"),[]byte("WX")})// checkReadMarbleByRange(t,stub,"marble-1","marble-4")// checkReadMarble(t,stub,"marble-1")   // checkInvoke(t,stub,[][]byte{[]byte("initMarble"),[]byte("marble-1"),[]byte("red"),[]byte("10"),[]byte("LH")})// checkReadMarble(t,stub,"marble-2")}

2.4 跑测试类

进入到 marbles.go 和 marbles_test.go所在的目录
我是放到了 $GOPATH/my_chaincode/marbles 目录下

cd $GOPATH/my_chaincode/marbles
go test marbles_test.go -v marbles.go --tags=nopkcs11

可以尝试修改marbles_test.go 来测试其他的方法

3 搭建本地测试环境 并测试链码

使用fabric-samples项目中 的chaincode-docker-devmode 环境测试

3.1 挂载链码

将编写好的 marbles.go 和marbles_test.go文件移动到

$GOAPTH/src/github.com/hyperledger/fabric-samples/chaincode

方便挂载到容器中

3.2 启动网络环境

进入到chaincode-docker-devmode目录下

cd $GOPATH/src/github.com/hyperledger/fabric-samples/chaincode-docker-devmode

利用docker-compose启动网络环境

docker-compose -f docker-compose-simple.yaml up

启动完成后的容器列表

CONTAINER ID        IMAGE                        COMMAND                  CREATED             STATUS              PORTS                                            NAMES
a7b22f7351fa        hyperledger/fabric-tools     "/bin/bash -c ./scri…"   7 seconds ago       Up 5 seconds                                                         cli
d761b06a034a        hyperledger/fabric-ccenv     "/bin/bash -c 'sleep…"   7 seconds ago       Up 5 seconds                                                         chaincode
7b329ef1311f        hyperledger/fabric-peer      "peer node start --p…"   8 seconds ago       Up 6 seconds        0.0.0.0:7051->7051/tcp, 0.0.0.0:7053->7053/tcp   peer
6302ffa111e2        hyperledger/fabric-orderer   "orderer"                9 seconds ago       Up 7 seconds        0.0.0.0:7050->7050/tcp                           orderer

3.3 进入chaincode容器编译链码 提供链码服务

启动一个新的终端

进入容器

docker exec -it chaincode /bin/bash

进入到挂载go文件目录

cd marbles/

编译程序

go build

编译完成后启动链码服务

CORE_PEER_ADDRESS=peer:7051 CORE_CHAINCODE_ID_NAME=mycc:0 ./marbles

3.4 进入cli容器 安装链码 实例化链码

启动一个新的终端
进入cli容器

docker exec -it cli /bin/bash

安装链码

peer chaincode install -p chaincodedev/chaincode/marbles -n mycc -v 0

初始化链码

peer chaincode instantiate -n mycc -v 0 -c '{"Args":[]}' -C myc

3.5 测试链码

创建三个弹珠

peer chaincode invoke -n mycc -c '{"Args":["initMarble","marble-1","red","10","LH"]}' -C myc
peer chaincode invoke -n mycc -c '{"Args":["initMarble","marble-2","yellow","11","LH"]}' -C myc
peer chaincode invoke -n mycc -c '{"Args":["initMarble","marble-3","blue","12","WX"]}' -C myc

查询弹珠

peer chaincode query -n mycc -c '{"Args":["readMarble","marble-1"]}' -C myc

范围查询

peer chaincode query -n mycc -c '{"Args":["getMarbleByRange","marble-1","marble-3"]}' -C myc

转让弹珠

peer chaincode invoke -n mycc -c '{"Args":["transferMarble","marble-1","WX"]}' -C myc

再查询marble-1:是否owner变为WX

peer chaincode query -n mycc -c '{"Args":["readMarble","marble-1"]}' -C myc

查询owner所有的弹珠

peer chaincode query -n mycc -c '{"Args":["queryMarblesByOwner","WX"]}' -C myc

查看弹珠修改历史:结果中 可以查询到一次 初始化交易 一次 转让交易

peer chaincode query -n mycc -c '{"Args":["queryHistoryForMarble","marble-1"]}' -C myc

4 关闭网络

在最开始启动网络的终端 按两次 control+c后执行

 docker-compose -f docker-compose-simple.yaml down

停止并关闭所有容器

十一、区块链学习-Hyperledger Fabric (基于release-1.0) 链码开发-marbles管理相关推荐

  1. 区块链:Hyperledger Fabric环境配置及fabric-sample测试运行

    环境准备 安装go1.11 以及以上版本 安装docker 17.06.2-ce 以及以上版本 安装docker-compose 1.14.0 以及以上版本 git 拉下 fabric-sample ...

  2. Linux搭建Hyperledger Fabric区块链框架 - Hyperledger Fabric模型概念

    企业选型的区块链底层技术 Hyperledger Fabric 概念 2015年,Linux基金会启动了Hyperledger项目,目标是发展跨行业的区块链技术. Hyperledger Fabric ...

  3. 《区块链国产化实践指南——基于Fabric 2.0》

    简介 区块链作为一项可以改变互联网底层基础设施服务的分布式账本技术,已经作为我国重点发展的战略技术,逐渐在我国各行业落地应用.在社会分工日益明细的趋势下,区块链的分布式技术可以在一定程度上解决因分工导 ...

  4. (Fabric学习八)部署区块链浏览器Hyperledger explorer

    区块链浏览器Hyperledger explorer: 区块链浏览器:官方网站https://github.com/hyperledger-labs/blockchain-explorer 可以看到他 ...

  5. 区块链学习8:超级账本项目Fabric中的背书、背书节点、背书策略、背书签名

    ☞ ░ 前往老猿Python博文目录 ░ 在Hyperledger Fabric区块链中,有背书节点进行背书,Hyperledger Fabric 使用背书策略来定义哪些节点需要执行交易. Hyper ...

  6. Fabric区块链学习

    目录 Fabric学习资料 1.架构概述 2.身份验证 3.使用OpenSSL构建CA证书 3.1.CA自签名证书 3.2.签发用户证书 3.3.代理数据下载 4.MSP成员服务提供器 5.启动最小的 ...

  7. 月薪 100K?还不来看看区块链学习清单?字字都是 Money!

    点击上方"CSDN",选择"置顶公众号" 关键时刻,第一时间送达! CSDN粉丝今日专属购书福利:全场书籍优惠,满100减50!仅限当日使用. 初春乍寒,又到了 ...

  8. 问道区块链_区块链学习_v1.0.0_持续更新。。。

    本系列内容参考图 创建 共识网络 调用 部署 挖矿 消耗 编写 超级链组件 节点 多节点 账号 智能合约 合约账号 燃料耗品代币 开发者 区块 尊重原创,转载请注明出处https://blog.csd ...

  9. 区块链学习路线及资料索引

    2019独角兽企业重金招聘Python工程师标准>>> 一.学习目标 比特币发展历史,挖矿,分叉以及相关应用 区块链底层技术,如共识算法, 侧链技术, 密码学知识等,理解PKI基本知 ...

最新文章

  1. 防止接口数据出问题,前端假数据调试
  2. linux c 解析生成json(jansson安装和使用)
  3. 抖音怎么设置保存路径_抖音限时可见视频怎么弄 设置限时可见作品方法
  4. cannot import name 'imresize' from 'scipy.misc'
  5. 综述 | Google团队发布,一文概览Transformer模型的17大高效变种
  6. mysqlslap 压力测试工具
  7. 一线互联网架构师设计思想解读开源框架!全套教学资料
  8. Identity Server 4 原理和实战(完结)_建立Angular 客户端
  9. http://blog.sina.com.cn/s/blog_6a01140c0100wimi.html
  10. MySql递归查询上级,下级
  11. U盘文件突然变成html文件,U盘里面的文件跟文件夹突然乱码了怎么办
  12. 煤矿智能更衣柜管理系统解决方案
  13. LED驱动电路设计及原理分析
  14. 制作u盘winpe启动盘_U启大师U盘启动盘制作教程(装机版)
  15. 什么是exploit
  16. 用 Mac 输入罗马数字
  17. vue 如何做到图片预览
  18. 对Excel选择性粘贴中的跳过空单元选项容易造成的两种误解
  19. 选型宝访谈:怎样构建端到端的IT透视能力?
  20. A类博士后年薪30万起!北邮人工智能学院郭军教授实验室招聘博士后研究人员...

热门文章

  1. java中什么是重写(举例说明)
  2. Java十年 十大人物 写在2005
  3. 【Matlab协同任务】二阶一致性算法多无人机协同编队动态仿真【含源码 1740期】
  4. vue实战——电子时钟
  5. 非周期连续傅立叶变换的推导
  6. Android Studio设置国内镜像网站
  7. ssh 远程复制文件_如何在不输入密码的情况下通过SSH远程复制文件
  8. Mooc_AutoCAD绘制建筑施工图_文字标注单元测验题
  9. 国内首批!阿里云云原生数据湖产品通过信通院评测认证
  10. 数字几何之笛卡儿的法国良心存在时间谭