防伪溯源区块链应用场景

标签:区块链应用
发布时间:2018年11月26日 价值:20000.00 / 共识:32

Netkiller Blockchain 手札

本文作者最近在找工作,有意向致电 13113668890

Mr. Neo Chan, 陈景峯(BG7NYT)

中国广东省深圳市望海路半岛城邦三期
518067
+86 13113668890

netkiller@msn.com
文档始创于2018-02-10

版权 © 2018 Netkiller(Neo Chan). All rights reserved.

版权声明

转载请与作者联系,转载时请务必标明文章原始出处和作者信息及本声明。

http://www.netkiller.cn
http://netkiller.github.io
http://netkiller.sourceforge.net

微信订阅号 netkiller-ebook (微信扫描二维码)
QQ:13721218 请注明“读者”
QQ群:128659835 请注明“读者”
2018-06-01

内容摘要

这一部关于区块链开发及运维的电子书。

为什么会写区块链电子书?因为2018年是区块链年,区块链是一个风口,前几个风口我都错过了。例如web2.0, 云, 大数据等等,都从身旁擦肩而过。所以我要抓住这次。

这本电子书是否会出版(纸质图书)? 不会,因为互联网技术更迭太快,纸质书籍的内容无法实时更新,一本书动辄百元,很快就成为垃圾,你会发现目前市面的上区块链书籍至少是一年前写的,内容已经过时,很多例子无法正确运行。所以我不会出版,电子书的内容会追逐技术发展,及时跟进软件版本的升级,做到内容最新,至少是主流。

这本电子书与其他区块链书籍有什么不同?市面上大部分区块链书籍都是用2/3去讲区块链原理,只要不到 1/3 的干货,干货不够理论来凑,通篇将理论或是大谈特谈区块链行业,这些内容更多是头脑风暴,展望区块链,均无法落地实施。本书与那些书籍完全不同,不讲理论和原理,面向应用落地,注重例子,均是干货。

写作原则,无法落地的项目作者绝对不会写。凡是写入电子的内容均具备可操作,可落地。

2.2. 防伪溯源区块链应用场景

食品安全溯源

下面的方案,同样适合药品安全溯源

2.2.1. 背景

需求是通过区块链跟踪产品,实现产品产地,生产,流通等环节溯源。

需求归纳,需要实现下面几点:

产品具备通用的属性,例如名称,价格,重量,颜色,体积等等

生产销售链条跟踪

涉及环节,农产品的供应链是一个非常复杂的过程,涉及多方,农业局、卫生局、药监局、工商局、环保局等多个部门交织其中。

参与者角色,我们为每个环节的参与者分配一个以太坊账号,例如每个供应商一个账号,每个代理商一个账号。这样任何一方经手后都会使用自己的账号想合约中添加数据。

2.2.2. 安全问题

我将安全划分为六层,分别是:

  1. +----------+-----------------------------+
  2. | 实体层 | |
  3. +----------+-----------------------------+
  4. | 用户层 | |
  5. +----------+-----------------------------+
  6. | 网络层 | 网络 |
  7. +----------+-----------------------------+
  8. | 应用层 | 操作系统,应用服务器 |
  9. +----------+-----------------------------+
  10. | 业务逻辑层 | 功能,业务逻辑 |
  11. +----------+-----------------------------+
  12. | 存储层 | 物理存储,硬盘 |
  13. +----------+-----------------------------+

并不是实施了区块链技术就安全无忧了,安全分为很多层,区块链只能做到网络层和存储层的安全。区块链无法解决用户层,应用层,逻辑层等安全问题,他只能保证存储在硬盘上的区块不被修改。

因为区块链仅仅能解决数据存储层的安全问题,不能保证上链的数据是真实的,上链前绝对不会被篡改;所以仅仅朔源,不考虑防伪是没有意义的,防伪仍然是重中之重。

2.2.3. 防伪问题

如何做防伪呢,这个领域很多公司已经探索多年,各种高科技应用,武装到牙齿,但仍没有解决假货问题。

区块链的出现很可能是一个突破,我们只需将现有成熟的防伪技术与区块链结合即可。

现在流行的访问技术太多了,我倾向于采用二维码技术,二维码与互联网紧密相连。

2.2.4. 性能问题

区块链目前的底层只适合做,低频高价值的业务。

区块链的读取性能通常是没有问题的,但是区块链的写入实际上无论你用多少个服务器节点都不能提升,因为写入区块需要做共识算法,这步操作,会在所有节点上进行,同时还需要加密运算,这些操作都是 CPU 密集型操作。所以写入操作是存在瓶颈的。

解决这个问题,我想出了几种方案:

性能解决方案

通过消息队列技术异步写入,将需要写入的区块放入队列,异步完成上链操作。

并行写入,我们可以建设多个区块链平台。多个平台同时服务于业务。

为了达到去中心化并行写入,我们将在客户端通过算法,匹配服务器。而不是在两个平台前面增加负载均衡。因为这样又回到了中心化系统。

2.2.5. 颗粒度问题

朔源的颗粒度问题,例如“红酒”的溯源,我们是将单位溯源做到箱呢?还是打,或是瓶呢?

我们用“四象限法则”分析

  1. 高价值
  2. o |
  3. | o
  4. |
  5. 低频率 --------------+------------- 高频率 操作频率
  6. |
  7. o | o
  8. |
  9. 低价值
  10. 物品价值

通过观察上面图,我们可以看到可以有四种情况,低频低价值,低频高价值,高频高价值,高频低价值

我认为对于低频高价值和高频高价值的业务,尽量做到最小颗粒度。

而对于低频低价值和高频低价值的业务,可以颗粒度更粗。

2.2.6. 存储规划

如果是高频低价值的业务,那么溯源数据源源将会不断的被添加到区块,以此同时区块的访问率极低。迟早会达到一个临界值。

所以你要规划存储,例如溯源数据的过期时间,对于 hyperledger 可以使用 DelState(key) 删除历史数据。

如果是高频高价值的业务是否要考虑永久保留数据呢?

这些问题都是需要考虑的。因为目前我们还不知道区块链的存储临界值。

2.2.7. 大数据问题

区块链替代不了数据库,它与数据库是互补关系。

对于低频的业务,通常传统数据库足以应付。那么对于高频操作的业务呢?暂时可能没有问题,但总有一天会遇到瓶颈。

综上所述,溯源项目数据库规划决不能少。同时还要考虑数据仓库和后期数据挖掘。因为用户使用微信或者我们的APP扫描二维码,我们可以获得很多有价值的数据。

手上没有 Vision 使用文本简单的绘制了一幅图

  1. +------------------------+
  2. | User -> QR Code |
  3. +------------------------+
  4. | |
  5. V V
  6. +---------------+ +---------------+ +---------------+
  7. | Search Engine |<-- | Microservice | | Microservice |
  8. +---------------+ +---------------+ +---------------+
  9. | |
  10. +----------------------------------+ |
  11. | | | |
  12. V V V V
  13. +----------+ +------------+ +-------------+
  14. | Database | | Big Data | | Blockchain |
  15. +----------+ +------------+ +-------------+
  16. | MySQL | | Hadoop | | Hyperledger |
  17. | NoSQL | | Hive/Hbase | | Chaincode |
  18. +----------+ +------------+ +-------------+
  19. | | ^ ^
  20. | +------ ETL -----| |
  21. | |
  22. +----------- Message Queue ----------o

区块链之外的很多复杂的需求我们需要借助大数据系统和搜索技术。

区块链的弱点是无法做复杂的查询,这里我们会用到搜索引擎技术解决,实际上搜索引擎角色是给区块链做索引。

上图数据写入时,保存了四份,分别在搜索引擎,关系型数据库,数据仓库和区块的

具体怎么实现,有很多方式,这里就不讨论了,否则就跑题了。

2.2.8. BI商业智能

数据采集,大数据分析

溯源信息的查询是通过用户手机终端实现,有几种途径,微信扫二维码,APP扫二维码,微信小程序等等。

扫码的同时还可以收集用户数据,我们可以收集到很多有价值的数据,例如地理位置,手机号码,性别,年龄等等……

有了这些数据便可以挖掘出有价值的数据,甚至可以将数据提供给生产企业作参考。

传统销售数据只能跟踪到地域,也就是统计出地域销量,没法监控到最后一公里的数据,而我们主要是采集商品最后一公里的数据。

我们能做到用户消费后,呼叫中心立即跟进回访,还能在用户快用完商品是向用户推送促销信息,以及客服二次跟进。

大数据能做什么?

用户行为分析,用户的喜好,这些数据能为后面精准推送提供支持。

消费与地理分析的关系

年龄段与购买力的关系

区域产品的存量,例如:用户扫描了一次二维码,可能用户就已经使用了改产品。我们就知道该地区投放的1000件商品被消耗了意见。

性别与消费习惯

两次间隔消费时间

活跃用户和沉睡用户

2.2.9. 采集终端

溯源数据怎么录入呢?例如我们开发一个设备,二维码扫描枪,内置安卓系统。

我们不清楚他们的教育背景以及学习能力,所以设计原则是尽量傻瓜化,降低数据录入难度和学习难度,终端开机后互动教学,走一遍流程即可上手。

首先将溯源环节的每个节点通过后台事先写入数据库,接下来通过GIS地理信息系统匹配。

  1. UUID -> 二维码 -> 设备扫描二维码激活-> 入数据库 -> 异步消息队列 -> 上链 > ---+
  2. ^ |
  3. | |
  4. +------------------- 追加数据 -----------------+

终端会帮助用户欲录入信息,用户可以在信息基础上修改或者重写。同时终端支持图片,图像记录上传。

对于图片还能实现 EXIF 数据保存,包括图片描述信息,地理信息等等……

2.2.10. 多媒体数据

这里我们需要考虑是否需要记录多媒体数据,这里的多媒体指图像,声音,甚至3D扫描数据等等……

对于图片、音频与视频,我们可以将它集成到采集终端上,然后异步上传到去中心化的分布式文件系统中。

去中心化的分布式文件系统能实现,一张图片一个hash值,通过hash值访问图片,图片被同步到相邻节点实现去中心化,图片被修改hash值随之变化数据便无效。

2.2.11. 物流接口

使用物流单好通过物流公司提供的借口获得物流数据,然后写入到区块。

2.2.12. 如何激励用户

防伪技术做了,区块链溯源也做了,那么对于用户来说,他可能懒得去扫你的二维码,怎么办呢?

这里需要激励用户,怎样激励用户,我的方案是送代币。

首先代币不仅能够购买物品,还能交易,流通,形成一个小的商业闭环。其次目前代币已经泛滥 99% 可能是空气币,这里我们需要将代币的价值与物品对价,类似金本位/银本位。

怎样操作呢?例如一个代币等于一斤水果,无论代币怎样炒作,最终用户不想玩下去了,就来换水果,也可以是大米,食用油等等…

关于怎样使用代币来做积分系统请参考我的另一篇文章 《使用代币替代传统积分系统》 ,你可以在搜索引擎中找到

根据业务需要,可以发行布置一套币,例如水果币,流量币,话费币,每种币的功能不同,这些币可以在交易所中撮合交易,例如卖出水果币,换成流量币等等。

由于国家的法规问题,代币系统设计原则一定是代币只能用来购买商城中的物品,不能直接兑换成RMB,否则会触碰到国家的红线。但是通过交易所,币币之间兑换我们就控制不了了。

另外扫描二维码显示溯源防伪信息的同时我们有很多可以操作空间,可以获取用户地理位置,手机号码等等信息,为后面大数据分析埋点。

用户激励手段

分享激励

好评激励

用户等级激励

代币激励

用户排名,PK排行榜

成就勋章

身份标签,黄马甲:)

等等,手段众多,目的是让用户查询溯源信息,手机用户数据,鼓励代币消费等等…….

2.2.13. 上链

并不是所有数据都上链,哪些数据上链呢?

产地(出生、生长)、采购、加工(检疫、屠宰)、库存、运输、销售、配送等等……

2.2.14. 以太坊解决方案

我们设计一个简单的合约,模拟上面提到的解决方案

  1. pragma solidity ^0.4.20;
  2. contract Trace {
  3. enum State { Origin, Factory, QA, Shipping, Received, Pending }
  4. string name;
  5. uint price;
  6. uint weight;
  7. bool lock = false; //合约锁
  8. bool close = false; //合约状态
  9. uint number = 1;
  10. uint attr_number = 1;
  11. mapping (address => string) guestbook; //客户留言本
  12. struct Attribute {
  13. address owner; // 供应商
  14. string name; // 属性的名字
  15. string date; // 生产日期
  16. string desc; // 描述信息
  17. }
  18. mapping (uint => Attribute) attribute;
  19. struct Logistics {
  20. address owner; // 中转站
  21. string date; // 转运日期
  22. State status; // 状态
  23. string message; // 留言信息
  24. }
  25. mapping (uint => Logistics) stations;
  26. function Trace(string _name, uint _price, uint _weight) public {
  27. name = _name;
  28. price = _price;
  29. weight = _weight;
  30. }
  31. // 名称
  32. function getName() public view returns(string){
  33. return name;
  34. }
  35. // 价格
  36. function getPrice() public view returns(uint){
  37. return price;
  38. }
  39. // 重量
  40. function getWeight() public view returns(uint){
  41. return weight;
  42. }
  43. // 增加商品属性
  44. function putAttribute(address _owner,string _name, string _date, string _desc ) public{
  45. if(lock == false){
  46. Attribute memory item = Attribute(_owner, _name,_date,_desc);
  47. attribute[attr_number] = item;
  48. attr_number = attr_number + 1;
  49. }
  50. }
  51. // 获得属性
  52. function getAttribute(uint _attr_number) public view returns(address, string, string, string) {
  53. require(_attr_number < attr_number);
  54. Attribute memory item = attribute[_attr_number];
  55. return (item.owner, item.name, item.date, item.desc);
  56. }
  57. // 增加物流中转信息
  58. function putLogistics(address _owner,string _date, State _status, string _message ) public{
  59. if(close == false){
  60. Logistics memory node = Logistics(_owner,_date,_status,_message);
  61. stations[number] = node;
  62. number = number + 1;
  63. lock = true;
  64. }
  65. if (_status == State.Received) {
  66. close = true;
  67. }
  68. }
  69. // 获得中转信息
  70. function getLogistics(uint _number) public view returns(address, string, State, string) {
  71. require(_number < number);
  72. Logistics memory node = stations[_number];
  73. return (node.owner, node.date, node.status, node.message);
  74. }
  75. // 或者转中站数量
  76. function getLogisticsCount() public view returns(uint){
  77. return number;
  78. }
  79. // 客户留言
  80. function addGuestbook(address _owner, string message) public{
  81. guestbook[_owner] = message;
  82. }
  83. }
  84. 怎样使用这个合约呢?合约部署,需要输入三个参数,分别是名称,价格和装量
  85. Trace(string _name, uint _price, uint _weight)
  86. 产品属性可以在出厂前设置,一旦出厂进入物流阶段就不允许在更改了。

2.2.14.1. 应用场景一

调用合约案例一,这是没有经过深加工的原产品案例。例如 Trace(“山羊肉”, 25, 50)

  1. var contract;
  2. Trace.deployed().then(function(instance){contract=instance;});
  3. contract.getName();
  4. contract.putAttribute("0x627306090abab3a6e1400e9345bc60c78a8bef57","颜色", "", "黑色")
  5. contract.putAttribute("0x627306090abab3a6e1400e9345bc60c78a8bef57","产地", "", "内蒙古")
  6. contract.putAttribute("0x627306090abab3a6e1400e9345bc60c78a8bef57","出生", "2017-01-12", "XXX牧场")
  7. contract.putAttribute("0x627306090abab3a6e1400e9345bc60c78a8bef57","宰杀", "2018-02-12", "XXX宰杀")
  8. contract.putLogistics("0x627306090abab3a6e1400e9345bc60c78a8bef57","2018-02-20",0,"XXX牧场");
  9. contract.putLogistics("0x627306090abab3a6e1400e9345bc60c78a8bef57","2018-02-20",1,"XXX屠宰公司");
  10. contract.putLogistics("0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef","2018-02-22",2,"XXX检验检疫");
  11. contract.putLogistics("0xf17f52151ebef6c7334fad080c5704d77216b732","2018-02-21",3,"XXX一级经销商");
  12. contract.putLogistics("0x821aea9a577a9b44299b9c15c88cf3087f3b5544","2018-02-23",3,"XXX二级经销商");
  13. contract.putLogistics("0x821aea9a577a9b44299b9c15c88cf3087f3b5544","2018-02-24",3,"XXX批发中心");
  14. contract.putLogistics("0x821aea9a577a9b44299b9c15c88cf3087f3b5544","2018-02-25",3,"XXX超市");
  15. contract.putLogistics("0x0d1d4e623d10f9fba5db95830f7d3839406c6af2","2018-02-26",4,"用户包裹收到");
  16. contract.getNode(); // 获得物流经过的转运站数量

2.2.14.2. 应用场景二

调用合约案例二,这是深加工的产品案例。例如 Trace(“牦牛肉干”, 80, 500)

  1. var contract;
  2. Trace.deployed().then(function(instance){contract=instance;});
  3. contract.getName();
  4. contract.putAttribute("0x627306090abab3a6e1400e9345bc60c78a8bef57","调和油", "2016-10-10", "银龙鱼牌")
  5. contract.putAttribute("0x627306090abab3a6e1400e9345bc60c78a8bef57","辣椒粉", "2016-10-30", "西藏XXX公司生产")
  6. contract.putAttribute("0x627306090abab3a6e1400e9345bc60c78a8bef57","生抽", "2016-01-12", "XXX生抽,XXX生产")
  7. contract.putAttribute("0x627306090abab3a6e1400e9345bc60c78a8bef57","山梨酸钾", "2017-02-12", "XXX生产")
  8. contract.putAttribute("0x627306090abab3a6e1400e9345bc60c78a8bef57","防腐剂", "2017-02-12", "XXX生产")
  9. contract.putAttribute("0x627306090abab3a6e1400e9345bc60c78a8bef57","牦牛肉", "2017-02-12", "XXX牧场")
  10. contract.putLogistics("0x627306090abab3a6e1400e9345bc60c78a8bef57","2018-02-20",0,"XXX牧场");
  11. contract.putLogistics("0x627306090abab3a6e1400e9345bc60c78a8bef57","2018-02-20",1,"XXX公司生产");
  12. contract.putLogistics("0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef","2018-02-22",2,"XXX通过QA、QC");
  13. contract.putLogistics("0xf17f52151ebef6c7334fad080c5704d77216b732","2018-02-21",3,"XXX一级经销商");
  14. contract.putLogistics("0x821aea9a577a9b44299b9c15c88cf3087f3b5544","2018-02-23",3,"XXX二级经销商");
  15. contract.putLogistics("0x821aea9a577a9b44299b9c15c88cf3087f3b5544","2018-02-24",3,"XXX批发中心");
  16. contract.putLogistics("0x821aea9a577a9b44299b9c15c88cf3087f3b5544","2018-02-25",3,"XXX超市");
  17. contract.putLogistics("0x0d1d4e623d10f9fba5db95830f7d3839406c6af2","2018-02-26",4,"用户包裹收到");
  18. contract.getNode(); // 获得物流经过的转运站数量

2.2.14.3. 用户留言

contract.addGuestbook(“0x0d1d423e623d10f9d10f9d10f9d10f9d10f9fba5”,”东西好吃,下次还买,给好评”);

2.2.15. Hyperledger 解决方案

由于家里在刷墙,服务器收起来了,没有开发环境,只能提供部分参考代码,无法提供合约完整代码,只是给大家一个思路,原理很上面以太坊的合约类似。

2.2.15.1. 溯源合约涉及

  1. package main
  2. import "fmt"
  3. import "encoding/json"
  4. const (
  5. Origin = iota // 0
  6. Factory // 1
  7. QA // 2
  8. Shipping // 3
  9. Received // 4
  10. Pending // 5
  11. Supermarket // 6
  12. )
  13. type structElement struct {
  14. Name string `json:"name"`
  15. Company string `json:"company"`
  16. Description string `json:"description"`
  17. }
  18. type structLogistics struct {
  19. Stations string `json:"stations"` // 中转站
  20. Date string `json:"date"` // 转运日期
  21. Status uint8 `json:"status"` // 状态
  22. Message string `json:"message"` // 留言信息
  23. }
  24. type Trace struct {
  25. Name string `json:"name"`
  26. Address string `json:"address"`
  27. Attribute map[string]string `json:"attribute"`
  28. Element []structElement `json:"element"`
  29. Logistics map[string]structLogistics `json:"logistics"`
  30. }
  31. func (trace *Trace) setName(_name string) {
  32. trace.Name = _name
  33. }
  34. func (trace *Trace) getName() string {
  35. return trace.Name
  36. }
  37. func (trace *Trace) putAttribute(_key string, _value string) {
  38. trace.Attribute[_key] = _value
  39. }
  40. func (trace *Trace) putLogistics(_key string, _value structLogistics) {
  41. trace.Logistics[_key] = _value
  42. }
  43. func main(){
  44. trace := &Trace{
  45. Name: "牦牛肉干",
  46. Address: "内蒙古呼和浩特",
  47. Attribute: map[string]string{},
  48. Element: []structElement{structElement{Name:"塑料袋",Company: "XXX塑料制品有限公司", Description: "外包装"},structElement{Name:"辣椒粉",Company: "XXX调味品有限公司", Description: "采摘年份2016-10-10"},structElement{Name:"调和油",Company: "XXX调味品有限公司", Description: "生产日期2016-10-10"}},
  49. Logistics: map[string]structLogistics{}}
  50. trace.putAttribute("Color","Red")
  51. trace.putAttribute("Size","10")
  52. trace.putAttribute("Weight","100kg")
  53. trace.putLogistics("1", structLogistics{"呼和浩特","2016-10-15", Origin, "牦牛收购"})
  54. trace.putLogistics("2", structLogistics{"呼和浩特","2016-10-18", Factory, "牦牛宰杀"})
  55. trace.putLogistics("3", structLogistics{"呼和浩特","2016-10-15", QA, "经过质检"})
  56. trace.putLogistics("4", structLogistics{"北京市","2016-10-15", Shipping, "运输中"})
  57. trace.putLogistics("5", structLogistics{"杭州市","2016-10-15", Shipping, "XXX冷库"})
  58. trace.putLogistics("5", structLogistics{"深圳市","2016-10-15", Supermarket, "XXX超市"})
  59. trace.putLogistics("5", structLogistics{"龙华区","2016-10-15", Received, "用户签收"})
  60. traceJson, _ := json.Marshal(trace)
  61. fmt.Println(string(traceJson))
  62. }

2.2.15.1.1. 食品安全朔源

  1. trace := &Trace{
  2. Name: "牦牛肉干",
  3. Address: "内蒙古呼和浩特",
  4. Attribute: map[string]string{},
  5. Element: []structElement{structElement{Name:"塑料袋",Company: "XXX塑料制品有限公司", Description: "外包装"},structElement{Name:"辣椒粉",Company: "XXX调味品有限公司", Description: "采摘年份2016-10-10"},structElement{Name:"调和油",Company: "XXX调味品有限公司", Description: "生产日期2016-10-10"}},
  6. Logistics: map[string]structLogistics{}}
  7. trace.putAttribute("Color","Red")
  8. trace.putAttribute("Size","10")
  9. trace.putAttribute("Weight","100kg")
  10. trace.putLogistics("1", structLogistics{"呼和浩特","2016-10-15", Origin, "牦牛收购"})
  11. trace.putLogistics("2", structLogistics{"呼和浩特","2016-10-18", Factory, "牦牛宰杀"})
  12. trace.putLogistics("3", structLogistics{"呼和浩特","2016-10-15", QA, "经过质检"})
  13. trace.putLogistics("4", structLogistics{"北京市","2016-10-15", Shipping, "运输中"})
  14. trace.putLogistics("5", structLogistics{"杭州市","2016-10-15", Shipping, "XXX冷库"})
  15. trace.putLogistics("5", structLogistics{"深圳市","2016-10-15", Supermarket, "XXX超市"})
  16. trace.putLogistics("5", structLogistics{"龙华区","2016-10-15", Received, "用户签收"})

2.2.15.1.2. 水平移植

这个方案可以水平移植到其他领域,例如 药品安全溯源

  1. trace := &Trace{
  2. Name: "强身大力丸",
  3. Address: "深圳是XXX制药有限公司",
  4. Attribute: map[string]string{},
  5. Element: []structElement{
  6. structElement{Name:"枸杞",Company: "宁夏XXX农业有限公司", Description: "采摘年份2016-10-10,10g"},
  7. structElement{Name:"茯苓",Company: "河南XXX农业有限公司", Description: "采摘年份2016-10-10,20kg"},
  8. structElement{Name:"XXX",Company: "XXX有限公司", Description: "生产日期2016-10-10"},
  9. structElement{Name:"XXX",Company: "XXX有限公司", Description: "生产日期2016-10-10"},
  10. ...
  11. ...
  12. structElement{Name:"塑料包装",Company: "XXX有限公司", Description: "生产日期2016-10-10"},
  13. structElement{Name:"包装盒",Company: "XXX有限公司", Description: "生产日期2016-10-10"}
  14. },
  15. Logistics: map[string]structLogistics{}}
  16. trace.putAttribute("Color","Red")
  17. trace.putAttribute("Size","10")
  18. ...
  19. ...
  20. trace.putAttribute("Weight","100kg")
  21. trace.putLogistics("1", structLogistics{"呼和浩特","2016-10-15", Origin, "原材料...."})
  22. trace.putLogistics("2", structLogistics{"呼和浩特","2016-10-18", Factory, "生产...."})
  23. trace.putLogistics("3", structLogistics{"呼和浩特","2016-10-15", QA, "经过质检"})
  24. trace.putLogistics("3", structLogistics{"XXX市药品监督局","2016-10-15", QA, "经过质检"})
  25. trace.putLogistics("4", structLogistics{"北京市","2016-10-15", Shipping, "运输中"})
  26. trace.putLogistics("5", structLogistics{"杭州市","2016-10-15", Shipping, "XXX冷库"})
  27. trace.putLogistics("5", structLogistics{"深圳市","2016-10-15", Supermarket, "XXX超市"})
  28. trace.putLogistics("5", structLogistics{"龙华区","2016-10-15", Received, "用户签收"})

合约落地,还需要做一些调整已适应实际场景。但基本思路是通的。

2.2.15.2. 积分通正(代币)

我发现用以太坊思维,将以太坊代币合约搬到 hyperledger 上,一样可以实现代币的功能,这个代币除了不能上交易所,基本满足我们替代积分系统的需求,下面是我写了这样一个合约,在超级账本上实现类似以太坊的代币转账功能。

  1. package main
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "strconv"
  7. "github.com/hyperledger/fabric/core/chaincode/shim"
  8. sc "github.com/hyperledger/fabric/protos/peer"
  9. )
  10. // Define the Smart Contract structure
  11. type SmartContract struct {
  12. }
  13. type Token struct {
  14. Owner string `json:"Owner"`
  15. TotalSupply uint `json:"TotalSupply"`
  16. TokenName string `json:"TokenName"`
  17. TokenSymbol string `json:"TokenSymbol"`
  18. BalanceOf map[string]uint `json:"BalanceOf"`
  19. }
  20. func (token *Token) initialSupply(){
  21. token.BalanceOf[token.Owner] = token.TotalSupply;
  22. }
  23. func (token *Token) transfer (_from string, _to string, _value uint){
  24. if(token.BalanceOf[_from] >= _value){
  25. token.BalanceOf[_from] -= _value;
  26. token.BalanceOf[_to] += _value;
  27. }
  28. }
  29. func (token *Token) balance (_from string) uint{
  30. return token.BalanceOf[_from]
  31. }
  32. func (token *Token) burn(_value uint) {
  33. if(token.BalanceOf[token.Owner] >= _value){
  34. token.BalanceOf[token.Owner] -= _value;
  35. token.TotalSupply -= _value;
  36. }
  37. }
  38. func (token *Token) burnFrom(_from string, _value uint) {
  39. if(token.BalanceOf[_from] >= _value){
  40. token.BalanceOf[_from] -= _value;
  41. token.TotalSupply -= _value;
  42. }
  43. }
  44. func (token *Token) mint(_value uint) {
  45. token.BalanceOf[token.Owner] += _value;
  46. token.TotalSupply += _value;
  47. }
  48. func (s *SmartContract) Init(stub shim.ChaincodeStubInterface) sc.Response {
  49. return shim.Success(nil)
  50. }
  51. func (s *SmartContract) initLedger(stub shim.ChaincodeStubInterface) sc.Response {
  52. token := &Token{
  53. Owner: "netkiller",
  54. TotalSupply: 10000,
  55. TokenName: "代币通正",
  56. TokenSymbol: "COIN",
  57. BalanceOf: map[string]uint{}}
  58. token.initialSupply()
  59. tokenAsBytes, _ := json.Marshal(token)
  60. stub.PutState("Token", tokenAsBytes)
  61. fmt.Println("Added", tokenAsBytes)
  62. return shim.Success(nil)
  63. }
  64. func (s *SmartContract) transferToken(stub shim.ChaincodeStubInterface, args []string) sc.Response {
  65. if len(args) != 3 {
  66. return shim.Error("Incorrect number of arguments. Expecting 2")
  67. }
  68. tokenAsBytes, _ := stub.GetState(args[0])
  69. token := Token{}
  70. json.Unmarshal(tokenAsBytes, &token)
  71. token.transfer(args[1],args[2],args[3])
  72. tokenAsBytes, _ = json.Marshal(token)
  73. stub.PutState(args[0], tokenAsBytes)
  74. return shim.Success(nil)
  75. }
  76. func (s *SmartContract) balanceToken(stub shim.ChaincodeStubInterface, args []string) sc.Response {
  77. if len(args) != 1 {
  78. return shim.Error("Incorrect number of arguments. Expecting 1")
  79. }
  80. tokenAsBytes, _ := stub.GetState(args[0])
  81. token := Token{}
  82. json.Unmarshal(tokenAsBytes, &token)
  83. amount := token.balance(args[1])
  84. return shim.Success(amount)
  85. }
  86. func (s *SmartContract) Invoke(stub shim.ChaincodeStubInterface) sc.Response {
  87. // Retrieve the requested Smart Contract function and arguments
  88. function, args := stub.GetFunctionAndParameters()
  89. // Route to the appropriate handler function to interact with the ledger appropriately
  90. if function == "balanceToken" {
  91. return s.balanceToken(stub, args)
  92. } else if function == "initLedger" {
  93. return s.initLedger(stub)
  94. } else if function == "transferToken" {
  95. return s.transferToken(stub, args)
  96. }
  97. return shim.Error("Invalid Smart Contract function name.")
  98. }
  99. // The main function is only relevant in unit test mode. Only included here for completeness.
  100. func main() {
  101. // Create a new Smart Contract
  102. err := shim.Start(new(SmartContract))
  103. if err != nil {
  104. fmt.Printf("Error creating new Smart Contract: %s", err)
  105. }
  106. }
  107. 合约代码的测试
  108. func main(){
  109. token := &Token{
  110. Owner: "netkiller", // 代币管理者
  111. TotalSupply: 10000, // 代币发行总量
  112. TokenName: "积分连", // 代币名称
  113. TokenSymbol: "NEO", // 代币符号 NEO
  114. BalanceOf: map[string]uint{}}
  115. token.initialSupply() // 初始化代币
  116. fmt.Println(token.balance("netkiller")) // 查询余额
  117. token.transfer("netkiller","neo", 100) // 转账,这里账号使用用户ID,没有使用以太坊钱包那样的哈希值,因为哈希值不便于记忆。
  118. fmt.Println(token.balance("netkiller"))
  119. fmt.Println(token.balance("neo"))
  120. }

我们可以建立很多套这样的比,例如水果币,蔬菜币,流量币…

开发一个小型交易所难度也不大,让用户在交易所中交易这些币。

  • 分享 收藏
0 条评论
  • 这篇文章暂无评论,赶紧评论一下吧~