食品安全溯源区块链解决方案探索-转载
一篇挺好的文章,可以細品下
內(nèi)容摘要
這一部關(guān)于區(qū)塊鏈開發(fā)及運維的電子書。
為什么會寫區(qū)塊鏈電子書?因為2018年是區(qū)塊鏈年。
這本電子書是否會出版(紙質(zhì)圖書)? 不會,因為互聯(lián)網(wǎng)技術(shù)更迭太快,紙質(zhì)書籍的內(nèi)容無法實時更新,一本書動輒百元,很快就成為垃圾,你會發(fā)現(xiàn)目前市面的上區(qū)塊鏈書籍至少是一年前寫的,內(nèi)容已經(jīng)過時,很多例子無法正確運行。所以我不會出版,電子書的內(nèi)容會追逐技術(shù)發(fā)展,及時跟進軟件版本的升級,做到內(nèi)容最新,至少是主流。
這本電子書與其他區(qū)塊鏈書籍有什么不同?市面上大部分區(qū)塊鏈書籍都是用2/3去講區(qū)塊鏈原理,只要不到 1/3 的干貨,干貨不夠理論來湊,通篇將理論或是大談特談區(qū)塊鏈行業(yè),這些內(nèi)容更多是頭腦風(fēng)暴,展望區(qū)塊鏈,均無法落地實施。本書與那些書籍完全不同,不講理論和原理,面向應(yīng)用落地,注重例子,均是干貨。
電子書更新頻率?每天都會有新內(nèi)容加入,更新頻率最遲不會超過一周,更新內(nèi)容請關(guān)注 https://github.com/netkiller/netkiller.github.io/commits/master
本文采用碎片化寫作,原文會不定期更新,請盡量閱讀原文。
http://www.netkiller.cn/blockchain/index.html
您的打賞是我的寫作動力:http://www.netkiller.cn/blockchain/donations.html
==============================
33.2. 食品安全溯源案例
下面的方案,同樣適合藥品安全溯源
33.2.1. 背景
需求是通過區(qū)塊鏈跟蹤產(chǎn)品,實現(xiàn)產(chǎn)品產(chǎn)地,生產(chǎn),流通等環(huán)節(jié)溯源。
需求歸納,需要實現(xiàn)下面幾點:
產(chǎn)品具備通用的屬性,例如名稱,價格,重量,顏色,體積等等
生產(chǎn)銷售鏈條跟蹤
涉及環(huán)節(jié),農(nóng)產(chǎn)品的供應(yīng)鏈是一個非常復(fù)雜的過程,涉及多方,農(nóng)業(yè)局、衛(wèi)生局、藥監(jiān)局、工商局、環(huán)保局等多個部門交織其中。
參與者角色,我們?yōu)槊總€環(huán)節(jié)的參與者分配一個以太坊賬號,例如每個供應(yīng)商一個賬號,每個代理商一個賬號。這樣任何一方經(jīng)手后都會使用自己的賬號想合約中添加數(shù)據(jù)。
33.2.2. 安全問題
我將安全劃分為六層,分別是:
+----------+-----------------------------+| 實體層 | 物 |+----------+-----------------------------+| 用戶層 | 人 |+----------+-----------------------------+| 網(wǎng)絡(luò)層 | 網(wǎng)絡(luò) |+----------+-----------------------------+| 應(yīng)用層 | 操作系統(tǒng),應(yīng)用服務(wù)器 |+----------+-----------------------------+| 業(yè)務(wù)邏輯層 | 功能,業(yè)務(wù)邏輯 |+----------+-----------------------------+| 存儲層 | 物理存儲,硬盤 |+----------+-----------------------------+
并不是實施了區(qū)塊鏈技術(shù)就安全無憂了,安全分為很多層,區(qū)塊鏈只能做到網(wǎng)絡(luò)層和存儲層的安全。區(qū)塊鏈無法解決用戶層,應(yīng)用層,邏輯層等安全問題,他只能保證存儲在硬盤上的區(qū)塊不被修改。因為區(qū)塊鏈僅僅能解決數(shù)據(jù)存儲層的安全問題,不能保證上鏈的數(shù)據(jù)是真實的,上鏈前絕對不會被篡改;所以僅僅朔源,不考慮防偽是沒有意義的,防偽仍然是重中之重。
33.2.3. 防偽問題
如何做防偽呢,這個領(lǐng)域很多公司已經(jīng)探索多年,各種高科技應(yīng)用,武裝到牙齒,但仍沒有解決假貨問題。
區(qū)塊鏈的出現(xiàn)很可能是一個突破,我們只需將現(xiàn)有成熟的防偽技術(shù)與區(qū)塊鏈結(jié)合即可。
現(xiàn)在流行的訪問技術(shù)太多了,我傾向于采用二維碼技術(shù),二維碼與互聯(lián)網(wǎng)緊密相連。
?
33.2.4. 性能問題
區(qū)塊鏈目前的底層只適合做,低頻高價值的業(yè)務(wù)。
區(qū)塊鏈的讀取性能通常是沒有問題的,但是區(qū)塊鏈的寫入實際上無論你用多少個服務(wù)器節(jié)點都不能提升,因為寫入?yún)^(qū)塊需要做共識算法,這步操作,會在所有節(jié)點上進行,同時還需要加密運算,這些操作都是 CPU 密集型操作。所以寫入操作是存在瓶頸的。
解決這個問題,我想出了幾種方案:
性能解決方案
- 通過消息隊列技術(shù)異步寫入,將需要寫入的區(qū)塊放入隊列,異步完成上鏈操作。
- 并行寫入,我們可以建設(shè)多個區(qū)塊鏈平臺。多個平臺同時服務(wù)于業(yè)務(wù)。
?
為了達到去中心化并行寫入,我們將在客戶端通過算法,匹配服務(wù)器。而不是在兩個平臺前面增加負載均衡。因為這樣又回到了中心化系統(tǒng)。
33.2.5. 顆粒度問題
朔源的顆粒度問題,例如“紅酒”的溯源,我們是將單位溯源做到箱呢?還是打,或是瓶呢?
我們用“四象限法則”分析
高價值o || o|低頻率 --------------+------------- 高頻率 操作頻率|o | o |低價值 物品價值
通過觀察上面圖,我們可以看到可以有四種情況,低頻低價值,低頻高價值,高頻高價值,高頻低價值我認為對于低頻高價值和高頻高價值的業(yè)務(wù),盡量做到最小顆粒度。
而對于低頻低價值和高頻低價值的業(yè)務(wù),可以顆粒度更粗。
?
33.2.6. 存儲規(guī)劃
如果是高頻低價值的業(yè)務(wù),那么溯源數(shù)據(jù)源源將會不斷的被添加到區(qū)塊,以此同時區(qū)塊的訪問率極低。遲早會達到一個臨界值。
所以你要規(guī)劃存儲,例如溯源數(shù)據(jù)的過期時間,對于 hyperledger 可以使用 DelState(key) 刪除歷史數(shù)據(jù)。
如果是高頻高價值的業(yè)務(wù)是否要考慮永久保留數(shù)據(jù)呢?
這些問題都是需要考慮的。因為目前我們還不知道區(qū)塊鏈的存儲臨界值。
33.2.7. 大數(shù)據(jù)問題
區(qū)塊鏈替代不了數(shù)據(jù)庫,它與數(shù)據(jù)庫是互補關(guān)系。
對于低頻的業(yè)務(wù),通常傳統(tǒng)數(shù)據(jù)庫足以應(yīng)付。那么對于高頻操作的業(yè)務(wù)呢?暫時可能沒有問題,但總有一天會遇到瓶頸。
綜上所述,溯源項目數(shù)據(jù)庫規(guī)劃決不能少。同時還要考慮數(shù)據(jù)倉庫和后期數(shù)據(jù)挖掘。因為用戶使用微信或者我們的APP掃描二維碼,我們可以獲得很多有價值的數(shù)據(jù)。
手上沒有 Vision 使用文本簡單的繪制了一幅圖
+------------------------+| User -> QR Code |+------------------------+| | V V+---------------+ +---------------+ +---------------+| Search Engine |<-- | Microservice | | Microservice |+---------------+ +---------------+ +---------------+| |+----------------------------------+ || | | |V V V V+----------+ +------------+ +-------------+ | Database | | Big Data | | Blockchain |+----------+ +------------+ +-------------+| MySQL | | Hadoop | | Hyperledger || NoSQL | | Hive/Hbase | | Chaincode |+----------+ +------------+ +-------------+ | | ^ ^| +------ ETL -----| || |+----------- Message Queue ----------o
區(qū)塊鏈之外的很多復(fù)雜的需求我們需要借助大數(shù)據(jù)系統(tǒng)和搜索技術(shù)。區(qū)塊鏈的弱點是無法做復(fù)雜的查詢,這里我們會用到搜索引擎技術(shù)解決,實際上搜索引擎角色是給區(qū)塊鏈做索引。
上圖數(shù)據(jù)寫入時,保存了四份,分別在搜索引擎,關(guān)系型數(shù)據(jù)庫,數(shù)據(jù)倉庫和區(qū)塊的
具體怎么實現(xiàn),有很多方式,這里就不討論了,否則就跑題了。
33.2.8. BI商業(yè)智能
數(shù)據(jù)采集,大數(shù)據(jù)分析
溯源信息的查詢是通過用戶手機終端實現(xiàn),有幾種途徑,微信掃二維碼,APP掃二維碼,微信小程序等等。
我們可以收集到很多有價值的數(shù)據(jù),例如地理位置,手機號碼,性別,年齡等等......
有了這些數(shù)據(jù)便可以挖掘出有價值的數(shù)據(jù),甚至可以將數(shù)據(jù)提供給生產(chǎn)企業(yè)作參考。
大數(shù)據(jù)能做什么?
?
33.2.9. 采集終端
溯源數(shù)據(jù)怎么錄入呢?例如我們開發(fā)一個設(shè)備,二維碼掃描槍,內(nèi)置安卓系統(tǒng)。
我們不清楚他們的教育背景以及學(xué)習(xí)能力,所以設(shè)計原則是盡量傻瓜化,降低數(shù)據(jù)錄入難度和學(xué)習(xí)難度,終端開機后互動教學(xué),走一遍流程即可上手。
首先將溯源環(huán)節(jié)的每個節(jié)點通過后臺事先寫入數(shù)據(jù)庫,接下來通過GIS地理信息系統(tǒng)匹配。
UUID -> 二維碼 -> 設(shè)備掃描二維碼激活-> 入數(shù)據(jù)庫 -> 異步消息隊列 -> 上鏈 > ---+^ || |+------------------- 追加數(shù)據(jù) -----------------+
終端會幫助用戶欲錄入信息,用戶可以在信息基礎(chǔ)上修改或者重寫。同時終端支持圖片,圖像記錄上傳。對于圖片還能實現(xiàn) EXIF 數(shù)據(jù)保存,包括圖片描述信息,地理信息等等......
33.2.10. 多媒體數(shù)據(jù)
這里我們需要考慮是否需要記錄多媒體數(shù)據(jù),這里的多媒體指圖像,聲音,甚至3D掃描數(shù)據(jù)等等......
對于圖片、音頻與視頻,我們可以將它集成到采集終端上,然后異步上傳到去中心化的分布式文件系統(tǒng)中。
去中心化的分布式文件系統(tǒng)能實現(xiàn),一張圖片一個hash值,通過hash值訪問圖片,圖片被同步到相鄰節(jié)點實現(xiàn)去中心化,圖片被修改hash值隨之變化數(shù)據(jù)便無效。
33.2.11. 物流接口
使用物流單好通過物流公司提供的借口獲得物流數(shù)據(jù),然后寫入到區(qū)塊。
33.2.12. 如何激勵用戶
防偽技術(shù)做了,區(qū)塊鏈溯源也做了,那么對于用戶來說,他可能懶得去掃你的二維碼,怎么辦呢?
這里需要激勵用戶,怎樣激勵用戶,我的方案是送代幣。
首先代幣不僅能夠購買物品,還能交易,流通,形成一個小的商業(yè)閉環(huán)。其次目前代幣已經(jīng)泛濫 99% 可能是空氣幣,這里我們需要將代幣的價值與物品對價,類似金本位/銀本位。
怎樣操作呢?例如一個代幣等于一斤水果,無論代幣怎樣炒作,最終用戶不想玩下去了,就來換水果,也可以是大米,食用油等等...
關(guān)于怎樣使用代幣來做積分系統(tǒng)請參考我的另一篇文章 《使用代幣替代傳統(tǒng)積分系統(tǒng)》 ,你可以在搜索引擎中找到
根據(jù)業(yè)務(wù)需要,可以發(fā)行布置一套幣,例如水果幣,流量幣,話費幣,每種幣的功能不同,這些幣可以在交易所中撮合交易,例如賣出水果幣,換成流量幣等等。
由于國家的法規(guī)問題,代幣系統(tǒng)設(shè)計原則一定是代幣只能用來購買商城中的物品,不能直接兌換成RMB,否則會觸碰到國家的紅線。但是通過交易所,幣幣之間兌換我們就控制不了了。
另外掃描二維碼顯示溯源防偽信息的同時我們有很多可以操作空間,可以獲取用戶地理位置,手機號碼等等信息,為后面大數(shù)據(jù)分析埋點。
用戶激勵手段
?
等等,手段眾多,目的是讓用戶查詢溯源信息,手機用戶數(shù)據(jù),鼓勵代幣消費等等.......
33.2.13. 上鏈
并不是所有數(shù)據(jù)都上鏈,哪些數(shù)據(jù)上鏈呢?
產(chǎn)地(出生、生長)、采購、加工(檢疫、屠宰)、庫存、運輸、銷售、配送等等......
33.2.14. 以太坊解決方案
我們設(shè)計一個簡單的合約,模擬上面提到的解決方案
pragma solidity ^0.4.20;contract Trace {enum State { Origin, Factory, QA, Shipping, Received, Pending }string name;uint price;uint weight;bool lock = false; //合約鎖bool close = false; //合約狀態(tài)uint number = 1;uint attr_number = 1;mapping (address => string) guestbook; //客戶留言本 struct Attribute {address owner; // 供應(yīng)商string name; // 屬性的名字string date; // 生產(chǎn)日期string desc; // 描述信息}mapping (uint => Attribute) attribute;struct Logistics {address owner; // 中轉(zhuǎn)站string date; // 轉(zhuǎn)運日期State status; // 狀態(tài)string message; // 留言信息}mapping (uint => Logistics) stations;function Trace(string _name, uint _price, uint _weight) public {name = _name;price = _price;weight = _weight;}// 名稱function getName() public view returns(string){return name;}// 價格function getPrice() public view returns(uint){return price;}// 重量function getWeight() public view returns(uint){return weight;}// 增加商品屬性function putAttribute(address _owner,string _name, string _date, string _desc ) public{if(lock == false){Attribute memory item = Attribute(_owner, _name,_date,_desc);attribute[attr_number] = item;attr_number = attr_number + 1;}}// 獲得屬性function getAttribute(uint _attr_number) public view returns(address, string, string, string) {require(_attr_number < attr_number);Attribute memory item = attribute[_attr_number];return (item.owner, item.name, item.date, item.desc);}// 增加物流中轉(zhuǎn)信息function putLogistics(address _owner,string _date, State _status, string _message ) public{if(close == false){Logistics memory node = Logistics(_owner,_date,_status,_message);stations[number] = node;number = number + 1;lock = true;}if (_status == State.Received) {close = true;}}// 獲得中轉(zhuǎn)信息function getLogistics(uint _number) public view returns(address, string, State, string) {require(_number < number);Logistics memory node = stations[_number];return (node.owner, node.date, node.status, node.message);}// 或者轉(zhuǎn)中站數(shù)量function getLogisticsCount() public view returns(uint){return number;}// 客戶留言function addGuestbook(address _owner, string message) public{guestbook[_owner] = message;}}
怎樣使用這個合約呢?合約部署,需要輸入三個參數(shù),分別是名稱,價格和裝量Trace(string _name, uint _price, uint _weight)
產(chǎn)品屬性可以在出廠前設(shè)置,一旦出廠進入物流階段就不允許在更改了。33.2.14.1. 應(yīng)用場景一
調(diào)用合約案例一,這是沒有經(jīng)過深加工的原產(chǎn)品案例。例如 Trace("山羊肉", 25, 50)
var contract;Trace.deployed().then(function(instance){contract=instance;});contract.getName();contract.putAttribute("0x627306090abab3a6e1400e9345bc60c78a8bef57","顏色", "", "黑色")contract.putAttribute("0x627306090abab3a6e1400e9345bc60c78a8bef57","產(chǎn)地", "", "內(nèi)蒙古")contract.putAttribute("0x627306090abab3a6e1400e9345bc60c78a8bef57","出生", "2017-01-12", "XXX牧場")contract.putAttribute("0x627306090abab3a6e1400e9345bc60c78a8bef57","宰殺", "2018-02-12", "XXX宰殺")contract.putLogistics("0x627306090abab3a6e1400e9345bc60c78a8bef57","2018-02-20",0,"XXX牧場");contract.putLogistics("0x627306090abab3a6e1400e9345bc60c78a8bef57","2018-02-20",1,"XXX屠宰公司");contract.putLogistics("0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef","2018-02-22",2,"XXX檢驗檢疫");contract.putLogistics("0xf17f52151ebef6c7334fad080c5704d77216b732","2018-02-21",3,"XXX一級經(jīng)銷商");contract.putLogistics("0x821aea9a577a9b44299b9c15c88cf3087f3b5544","2018-02-23",3,"XXX二級經(jīng)銷商");contract.putLogistics("0x821aea9a577a9b44299b9c15c88cf3087f3b5544","2018-02-24",3,"XXX批發(fā)中心");contract.putLogistics("0x821aea9a577a9b44299b9c15c88cf3087f3b5544","2018-02-25",3,"XXX超市");contract.putLogistics("0x0d1d4e623d10f9fba5db95830f7d3839406c6af2","2018-02-26",4,"用戶包裹收到");contract.getNode(); // 獲得物流經(jīng)過的轉(zhuǎn)運站數(shù)量
33.2.14.2. 應(yīng)用場景二
調(diào)用合約案例二,這是深加工的產(chǎn)品案例。例如 Trace("牦牛肉干", 80, 500)
var contract;Trace.deployed().then(function(instance){contract=instance;});contract.getName();contract.putAttribute("0x627306090abab3a6e1400e9345bc60c78a8bef57","調(diào)和油", "2016-10-10", "銀龍魚牌")contract.putAttribute("0x627306090abab3a6e1400e9345bc60c78a8bef57","辣椒粉", "2016-10-30", "西藏XXX公司生產(chǎn)")contract.putAttribute("0x627306090abab3a6e1400e9345bc60c78a8bef57","生抽", "2016-01-12", "XXX生抽,XXX生產(chǎn)")contract.putAttribute("0x627306090abab3a6e1400e9345bc60c78a8bef57","山梨酸鉀", "2017-02-12", "XXX生產(chǎn)")contract.putAttribute("0x627306090abab3a6e1400e9345bc60c78a8bef57","防腐劑", "2017-02-12", "XXX生產(chǎn)")contract.putAttribute("0x627306090abab3a6e1400e9345bc60c78a8bef57","牦牛肉", "2017-02-12", "XXX牧場")contract.putLogistics("0x627306090abab3a6e1400e9345bc60c78a8bef57","2018-02-20",0,"XXX牧場");contract.putLogistics("0x627306090abab3a6e1400e9345bc60c78a8bef57","2018-02-20",1,"XXX公司生產(chǎn)");contract.putLogistics("0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef","2018-02-22",2,"XXX通過QA、QC");contract.putLogistics("0xf17f52151ebef6c7334fad080c5704d77216b732","2018-02-21",3,"XXX一級經(jīng)銷商");contract.putLogistics("0x821aea9a577a9b44299b9c15c88cf3087f3b5544","2018-02-23",3,"XXX二級經(jīng)銷商");contract.putLogistics("0x821aea9a577a9b44299b9c15c88cf3087f3b5544","2018-02-24",3,"XXX批發(fā)中心");contract.putLogistics("0x821aea9a577a9b44299b9c15c88cf3087f3b5544","2018-02-25",3,"XXX超市");contract.putLogistics("0x0d1d4e623d10f9fba5db95830f7d3839406c6af2","2018-02-26",4,"用戶包裹收到");contract.getNode(); // 獲得物流經(jīng)過的轉(zhuǎn)運站數(shù)量
33.2.14.3. 用戶留言
contract.addGuestbook("0x0d1d423e623d10f9d10f9d10f9d10f9d10f9fba5","東西好吃,下次還買,給好評");
33.2.15. Hyperledger 解決方案
由于家里在刷墻,服務(wù)器收起來了,沒有開發(fā)環(huán)境,只能提供部分參考代碼,無法提供合約完整代碼,只是給大家一個思路,原理很上面以太坊的合約類似。
33.2.15.1. 溯源合約涉及
package mainimport "fmt"import "encoding/json"const (Origin = iota // 0Factory // 1QA // 2Shipping // 3Received // 4Pending // 5Supermarket // 6)type structElement struct {Name string `json:"name"`Company string `json:"company"`Description string `json:"description"`}type structLogistics struct {Stations string `json:"stations"` // 中轉(zhuǎn)站Date string `json:"date"` // 轉(zhuǎn)運日期Status uint8 `json:"status"` // 狀態(tài)Message string `json:"message"` // 留言信息}type Trace struct {Name string `json:"name"`Address string `json:"address"`Attribute map[string]string `json:"attribute"`Element []structElement `json:"element"`Logistics map[string]structLogistics `json:"logistics"`}func (trace *Trace) setName(_name string) {trace.Name = _name}func (trace *Trace) getName() string {return trace.Name}func (trace *Trace) putAttribute(_key string, _value string) {trace.Attribute[_key] = _value}func (trace *Trace) putLogistics(_key string, _value structLogistics) {trace.Logistics[_key] = _value}func main(){trace := &Trace{Name: "牦牛肉干",Address: "內(nèi)蒙古呼和浩特",Attribute: map[string]string{},Element: []structElement{structElement{Name:"塑料袋",Company: "XXX塑料制品有限公司", Description: "外包裝"},structElement{Name:"辣椒粉",Company: "XXX調(diào)味品有限公司", Description: "采摘年份2016-10-10"},structElement{Name:"調(diào)和油",Company: "XXX調(diào)味品有限公司", Description: "生產(chǎn)日期2016-10-10"}},Logistics: map[string]structLogistics{}}trace.putAttribute("Color","Red")trace.putAttribute("Size","10")trace.putAttribute("Weight","100kg")trace.putLogistics("1", structLogistics{"呼和浩特","2016-10-15", Origin, "牦牛收購"})trace.putLogistics("2", structLogistics{"呼和浩特","2016-10-18", Factory, "牦牛宰殺"})trace.putLogistics("3", structLogistics{"呼和浩特","2016-10-15", QA, "經(jīng)過質(zhì)檢"})trace.putLogistics("4", structLogistics{"北京市","2016-10-15", Shipping, "運輸中"})trace.putLogistics("5", structLogistics{"杭州市","2016-10-15", Shipping, "XXX冷庫"})trace.putLogistics("5", structLogistics{"深圳市","2016-10-15", Supermarket, "XXX超市"})trace.putLogistics("5", structLogistics{"龍華區(qū)","2016-10-15", Received, "用戶簽收"})traceJson, _ := json.Marshal(trace)fmt.Println(string(traceJson))}
33.2.15.1.1. 食品安全朔源trace := &Trace{Name: "牦牛肉干",Address: "內(nèi)蒙古呼和浩特",Attribute: map[string]string{},Element: []structElement{structElement{Name:"塑料袋",Company: "XXX塑料制品有限公司", Description: "外包裝"},structElement{Name:"辣椒粉",Company: "XXX調(diào)味品有限公司", Description: "采摘年份2016-10-10"},structElement{Name:"調(diào)和油",Company: "XXX調(diào)味品有限公司", Description: "生產(chǎn)日期2016-10-10"}},Logistics: map[string]structLogistics{}}trace.putAttribute("Color","Red")trace.putAttribute("Size","10")trace.putAttribute("Weight","100kg")trace.putLogistics("1", structLogistics{"呼和浩特","2016-10-15", Origin, "牦牛收購"})trace.putLogistics("2", structLogistics{"呼和浩特","2016-10-18", Factory, "牦牛宰殺"})trace.putLogistics("3", structLogistics{"呼和浩特","2016-10-15", QA, "經(jīng)過質(zhì)檢"})trace.putLogistics("4", structLogistics{"北京市","2016-10-15", Shipping, "運輸中"})trace.putLogistics("5", structLogistics{"杭州市","2016-10-15", Shipping, "XXX冷庫"})trace.putLogistics("5", structLogistics{"深圳市","2016-10-15", Supermarket, "XXX超市"})trace.putLogistics("5", structLogistics{"龍華區(qū)","2016-10-15", Received, "用戶簽收"})
33.2.15.1.2. 水平移植
這個方案可以水平移植到其他領(lǐng)域,例如 藥品安全溯源
trace := &Trace{Name: "強身大力丸",Address: "深圳是XXX制藥有限公司",Attribute: map[string]string{},Element: []structElement{structElement{Name:"枸杞",Company: "寧夏XXX農(nóng)業(yè)有限公司", Description: "采摘年份2016-10-10,10g"},structElement{Name:"茯苓",Company: "河南XXX農(nóng)業(yè)有限公司", Description: "采摘年份2016-10-10,20kg"},structElement{Name:"XXX",Company: "XXX有限公司", Description: "生產(chǎn)日期2016-10-10"},structElement{Name:"XXX",Company: "XXX有限公司", Description: "生產(chǎn)日期2016-10-10"},......structElement{Name:"塑料包裝",Company: "XXX有限公司", Description: "生產(chǎn)日期2016-10-10"},structElement{Name:"包裝盒",Company: "XXX有限公司", Description: "生產(chǎn)日期2016-10-10"}},Logistics: map[string]structLogistics{}}trace.putAttribute("Color","Red")trace.putAttribute("Size","10")......trace.putAttribute("Weight","100kg")trace.putLogistics("1", structLogistics{"呼和浩特","2016-10-15", Origin, "原材料...."})trace.putLogistics("2", structLogistics{"呼和浩特","2016-10-18", Factory, "生產(chǎn)...."})trace.putLogistics("3", structLogistics{"呼和浩特","2016-10-15", QA, "經(jīng)過質(zhì)檢"})trace.putLogistics("3", structLogistics{"XXX市藥品監(jiān)督局","2016-10-15", QA, "經(jīng)過質(zhì)檢"})trace.putLogistics("4", structLogistics{"北京市","2016-10-15", Shipping, "運輸中"})trace.putLogistics("5", structLogistics{"杭州市","2016-10-15", Shipping, "XXX冷庫"})trace.putLogistics("5", structLogistics{"深圳市","2016-10-15", Supermarket, "XXX超市"})trace.putLogistics("5", structLogistics{"龍華區(qū)","2016-10-15", Received, "用戶簽收"})
合約落地,還需要做一些調(diào)整已適應(yīng)實際場景。但基本思路是通的。33.2.15.2. 積分通正(代幣)
我發(fā)現(xiàn)用以太坊思維,將以太坊代幣合約搬到 hyperledger 上,一樣可以實現(xiàn)代幣的功能,這個代幣除了不能上交易所,基本滿足我們替代積分系統(tǒng)的需求,下面是我寫了這樣一個合約,在超級賬本上實現(xiàn)類似以太坊的代幣轉(zhuǎn)賬功能。
package mainimport ("bytes""encoding/json""fmt""strconv""http://github.com/hyperledger/fabric/core/chaincode/shim"sc "http://github.com/hyperledger/fabric/protos/peer")// Define the Smart Contract structuretype SmartContract struct {}type Token struct {Owner string `json:"Owner"`TotalSupply uint `json:"TotalSupply"`TokenName string `json:"TokenName"`TokenSymbol string `json:"TokenSymbol"`BalanceOf map[string]uint `json:"BalanceOf"`}func (token *Token) initialSupply(){token.BalanceOf[token.Owner] = token.TotalSupply;}func (token *Token) transfer (_from string, _to string, _value uint){if(token.BalanceOf[_from] >= _value){token.BalanceOf[_from] -= _value;token.BalanceOf[_to] += _value;}}func (token *Token) balance (_from string) uint{return token.BalanceOf[_from]}func (token *Token) burn(_value uint) {if(token.BalanceOf[token.Owner] >= _value){token.BalanceOf[token.Owner] -= _value;token.TotalSupply -= _value;}}func (token *Token) burnFrom(_from string, _value uint) {if(token.BalanceOf[_from] >= _value){token.BalanceOf[_from] -= _value;token.TotalSupply -= _value;}}func (token *Token) mint(_value uint) {token.BalanceOf[token.Owner] += _value;token.TotalSupply += _value;}func (s *SmartContract) Init(stub shim.ChaincodeStubInterface) sc.Response {return shim.Success(nil)}func (s *SmartContract) initLedger(stub shim.ChaincodeStubInterface) sc.Response {token := &Token{Owner: "netkiller",TotalSupply: 10000,TokenName: "代幣通正",TokenSymbol: "COIN",BalanceOf: map[string]uint{}}token.initialSupply()tokenAsBytes, _ := json.Marshal(token)stub.PutState("Token", tokenAsBytes)fmt.Println("Added", tokenAsBytes)return shim.Success(nil)}func (s *SmartContract) transferToken(stub shim.ChaincodeStubInterface, args []string) sc.Response {if len(args) != 3 {return shim.Error("Incorrect number of arguments. Expecting 2")}tokenAsBytes, _ := stub.GetState(args[0])token := Token{}json.Unmarshal(tokenAsBytes, &token)token.transfer(args[1],args[2],args[3])tokenAsBytes, _ = json.Marshal(token)stub.PutState(args[0], tokenAsBytes)return shim.Success(nil)}func (s *SmartContract) balanceToken(stub shim.ChaincodeStubInterface, args []string) sc.Response {if len(args) != 1 {return shim.Error("Incorrect number of arguments. Expecting 1")}tokenAsBytes, _ := stub.GetState(args[0])token := Token{}json.Unmarshal(tokenAsBytes, &token)amount := token.balance(args[1])return shim.Success(amount)}func (s *SmartContract) Invoke(stub shim.ChaincodeStubInterface) sc.Response {// Retrieve the requested Smart Contract function and argumentsfunction, args := stub.GetFunctionAndParameters()// Route to the appropriate handler function to interact with the ledger appropriatelyif function == "balanceToken" {return s.balanceToken(stub, args)} else if function == "initLedger" {return s.initLedger(stub)} else if function == "transferToken" {return s.transferToken(stub, args)}return shim.Error("Invalid Smart Contract function name.")}// The main function is only relevant in unit test mode. Only included here for completeness.func main() {// Create a new Smart Contracterr := shim.Start(new(SmartContract))if err != nil {fmt.Printf("Error creating new Smart Contract: %s", err)}}
合約代碼的測試func main(){token := &Token{Owner: "netkiller", // 代幣管理者TotalSupply: 10000, // 代幣發(fā)行總量TokenName: "積分連", // 代幣名稱TokenSymbol: "NEO", // 代幣符號 NEOBalanceOf: map[string]uint{}}token.initialSupply() // 初始化代幣fmt.Println(token.balance("netkiller")) // 查詢余額token.transfer("netkiller","neo", 100) // 轉(zhuǎn)賬,這里賬號使用用戶ID,沒有使用以太坊錢包那樣的哈希值,因為哈希值不便于記憶。fmt.Println(token.balance("netkiller"))fmt.Println(token.balance("neo"))}
我們可以建立很多套這樣的比,例如水果幣,蔬菜幣,流量幣...開發(fā)一個小型交易所難度也不大,讓用戶在交易所中交易這些幣。
總結(jié)
以上是生活随笔為你收集整理的食品安全溯源区块链解决方案探索-转载的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何达到高并发的概念?-分享一下微信百亿
- 下一篇: 疫情之下,供应链金融的“危”与“机-转发