第一章 緒論 1
1.1研究背景和意義 1
1.2國內外研究現狀及發展態勢分析 2
1.2.1區塊鏈應用研究現狀 2
1.2.2區塊鏈共識機制研究現狀 4
1.3論文工作和結構安排 5
第二章 區塊鏈工作原理與關鍵技術 6
2.1區塊鏈架構 6
2.1.1以太坊 6
2.1.2智能合約 8
2.2共識機制 9
2.2.1PBFT 9
2.2.2Raft 9
2.3密碼學技術 11
2.3.1加密算法 11
2.3.2哈希算法 13
2.4星際文件系統 13
2.5 本章總結 14
第三章 基于區塊鏈的智慧糧倉綜合信息管理系統設計 16
3.1功能性需求分析 16
3.1.1系統管理需求分析 16
3.1.2倉儲檢測需求分析 16
3.1.3交易管理需求分析 17
3.1.4資產管理需求分析 18
3.2非功能性需求分析 18
3.3系統總體設計 19
3.4前端架構設計 20
3.5后端架構設計 22
3.6智能合約數據結構設計 23
3.7本章小結 28
第四章 基于區塊鏈的智慧糧倉綜合信息管理系統實現 29
4.1系統開發環境 29
4.2功能模塊實現 30
4.2.1系統管理模塊 31
4.2.2倉儲檢測模塊 34
4.2.3交易管理模塊 37
4.2.4資產管理模塊 40
4.3交互界面實現 43
4.3.1主頁 44
4.3.2系統管理 44
4.3.3倉儲檢測 46
4.3.4交易管理 48
4.3.5資產管理 50
4.4合約部署與調用 52
4.4.1合約部署 52
4.4.2合約調用 53
4.5IPFS 部署與調用 54
4.5.1IPFS 部署 55
4.5.2IPFS 調用 55
4.6系統測試 57
4.6.1智能合約測試 57
4.6.2功能測試 59
4.6.3性能測試 60
4.7本章小結 63
第五章 基于區塊鏈的Raft共識算法的改進 64
5.1Raft共識算法改進方案 64
5.1.1傳統 Raft 算法瓶頸 64
5.1.2BFT-Raft 算法模型 65
5.2BFT-Raft的設計與實現 66
5.2.1Leader 選舉 66
5.2.2日志復制 69
5.3安全性證明 73
5.4算法性能測試與分析 74
5.4.1測試環境與實施細節 74
5.4.2性能分析 75
5.4.3拜占庭容錯 78
5.5本章小結 80
總結與展望 81
參考文獻 83
攻讀學位期間取得的成果 87
致謝 88
第一章 緒論
1.1研究背景和意義
一直以來,糧食作為國家的戰略物資、特殊商品,關系著社會的安全和穩定。糧倉 的精準化管理和智能化控制則是實現安全高效儲糧的關鍵[1]。一個健全的智慧糧倉綜合 管理系統可以牢牢穩住糧食安全壓艙石,加快糧食倉儲和流通現代化,在減少人力和物 力的同時,提高糧食供應鏈韌性和質量安全追力[2]。“十三五”以來,為著力提高糧食 儲備服務水平和管理效率,政府出臺的一系列政策,推動和保障了糧倉信息管理的有效 開展。
農業相關人員一直都在探索糧倉信息化管理體系,以期解決糧食倉儲和交易安全問 題。而且糧食儲備庫分布散落,技術水平、管理水平參差不齊,傳統系統架構都是中心 化的[3]。技術創新和數據資源流通共享方面仍有一些問題亟須解決和完善。由于物聯網 設備的與日俱增,基于中心化的管理維護的成本越來越難以估算[4]。總體上存在以下問 題:信息存儲在中心化的數據庫中,數據孤立地由市場參與者各自分散地記錄和管理, 當真實信息危害企業或個人利益時,利益相關方很可能會篡改數據,數據的真實可靠性 無法保證。信息的整體可信度不高,追溯的源頭可能就是一個虛假的源頭[5]。
近幾年,區塊鏈技術浪潮漸漸來襲,從技術創新到應用實踐不斷推陳出新,中儲糧、 中糧、中化、中供銷、中農發等涉糧央企擔負著保障國家糧食安全的重要使命,正積極 憑借區塊鏈技術共識、互信、防篡改、可追溯的特點,提升監管水平、保障糧食安全。 通過區塊鏈技術,單個糧庫的數據可以在上級監管單位和其他諸多糧庫等多個主體方進 行數據存儲。
利用區塊鏈去中心化和防篡改的特點,可夯實智慧農業底層基礎,促進其穩健發展
[6]。建立基于區塊鏈的智慧糧倉綜合信息管理系統的意義如下:
(1) 糧食倉儲監管方式落后,倉儲管理和作業大多采用人工操作方式,存在極大的 人為篡改或造假風險。利用區塊鏈以及物聯網技術,將糧倉環境監測、交易情況和出入 庫信息等數據,第一時間同步上鏈,能夠避免單個糧倉隨意更改數據的現象,保障糧庫 原始數據的真實性,助力產業鏈管理升級。
(2) 糧食信息管理數字化水平發展不均衡,既缺乏成熟的統一標準,又存在嚴重的 信息孤島問題。利用區塊鏈的分布式賬本技術,可以有效的解決行業痛點,通過多節點 存儲和驗證,保證了業務數據的完整性;智能合約機制保證了信息的安全性和不可變更 性;便于糧食供應鏈上下游企業數據共享和存證,助力行業數字化改造和創新。
(3)區塊鏈智能合約驅動業務流轉,將倉單生成、流轉、監控記錄在鏈,能實現糧 食倉單全生命流程可追溯[7]。接入糧食來源數據、貿易數據、發票數據等,助力糧食企 業增信。
在節點地位對等的情況下,為了保證數據統一性,糧食數據的管理與記錄,交易的 驗證和確認需全網達成共識,共識機制是區塊鏈網絡安全穩定運行的核心,杜絕了構造 虛假信息的可能。就圖 1.1 所示的中國通信院2020 對共識機制支持率的調查顯示, Raft 已經成為支持率最高的共識機制之一,其憑借著高可拓展性和高吞吐量的優勢在聯盟鏈 中得到了應用。
圖 1.1 2020 共識機制支持率
分布式共識中經典的拜占庭將軍問題(Byzantine Generals Problem )討論了當分布 式系統中存在少數惡意節點時,集群如何達成信息一致的問題[8]。長久以來,拜占庭容 錯(Byzantine Fault Tolerance,BFT)共識算法,一直存在復雜度過高的問題,應用也受到 了限制。因此,尋求一種在Raft算法基礎上既能保證算法的強一致性和可理解性,又能 解決分布式網絡的容錯問題的算法同樣具有深遠意義。
1.2國內外研究現狀及發展態勢分析
1.2.1區塊鏈應用研究現狀
自誕生以來,十年間,國內外對區塊鏈應用的研究呈現幾何態勢的增長。其經歷了 以數字加密貨幣體系為代表的區塊鏈1.0階段,和依托智能合約、以可編程金融系統為 主要特征區塊鏈2.0階段,到現在的全球性的公共服務上,能夠滿足更加復雜的商業邏 輯的區塊鏈 3.0 階段[9],基于區塊鏈的應用研究已經觸及了智能資產、眾籌、供應鏈、 醫療醫藥、產權等諸多領域,正在向社會生活的各方面延伸。
浪潮2015年也已開始探索研究區塊鏈技術,在糧食領域,浪潮云ERP率先提出和 創新了“區塊鏈+糧食監管”、“區塊鏈+糧食質量追溯”、“區塊鏈+糧食物流”等應用,助力 糧食企業更好地保障“糧食安全”。
2017年3月,中國聯通與眾多公司和研究機構合作,在ITU-T SG20成立了全球首 個物聯網區塊鏈(Blockchain of Things,BOT)標準項目,該項目定義了去中心化的可 信物聯網服務平臺[10]。
2017 年,Feng Tian 結合射頻識別(Radio Frequency Identification,RFID)和區塊鏈 技術,通過收集、傳輸與分享農產品的真實數據,并引入 BigchainDB 數據庫緩解了區 塊鏈存儲壓力,實現農產品信息的可追溯性與真實有效性[11]。
Vishal Naidu構建了一個使用區塊鏈+物聯網的完全可觀察的供應鏈管理系統,改進 了對數據流的監視,橋接了實體之間的不連續性[12]。 Xu Xiwei 等人設計出基于區塊鏈的 可跟蹤系統originChain,使用區塊鏈替換中央數據庫,提供具有高可用性的透明防篡改 可追溯性數據[13]。 Kentaroh Toyoda 等人使用以太坊架構為供應鏈管理創建了區塊鏈智 能合約模型,同時設計了項目級智能合約來管理供應鏈中產品的事件信息[14]。
Chao Xie等人提出了 一種雙鏈存儲結構,并基于以太坊架構設計了一種安全的數據 存儲方案,方案分析和封裝了傳感器上傳的數據,并寫入區塊鏈,用于農產品的數據管 理。同時,協同數據庫提高了系統I/O的效率[15]。
日前,京東為加強食品安全,已將區塊鏈與物流結合。沃爾瑪從進貨、管理、配送 的各個環節全面擁抱區塊鏈變革,并自 2019 年 9 月開始,超市和山姆會員店的蔬菜供 應商使用了 IBM 開發的數字分類賬技術,實現了產品數據的實時獲取、端到端的管理 追溯。許繼平等人針對稻米倉儲業務主體復雜、信息流轉冗長、數據利用率低、監管覆 蓋性差等問題,構建了區塊鏈驅動的信息監管模型[16]。金會芳等人研究了基于物聯網+ 區塊鏈的糧食數據管理的新模式[17]。安徽省農業科學院也曾多次探討了區塊鏈技術在糧 食安全中的應用場景,通過設計糧食產品安全信息區塊鏈架構及應用方案,保證了糧食 收購與智慧信息管理[18]。
綜上,本文將在現有的研究基礎上,利用區塊鏈作為信息管理總賬本,記錄物聯網 采集的數據和設備狀態、設備標識、設備信息等數據,為傳感器設備的互聯互通、自我 管理提供安全可靠的保障。另外還記錄糧食的儲藏、出入庫、交易等過程數據,用以確 保數據透明性,從而增加糧食企業之間的信任,拓展市場空間。
1.2.2區塊鏈共識機制研究現狀
共識機制作為區塊鏈核心層的重要組件,決定了節點記賬權的歸屬。目標是使所有 的誠實節點保存一致的區塊鏈視圖,共識算法則用來保證分布式系統的一致性。
1998年, Lamport 提出了 Paxos 共識算法[19], Paxos 的提出為構建可靠的大型分布 式系統提供了理論基礎,并被廣泛應用,此后共識的大多數實現都基于Paxos。但Paxos 算法結構復雜不易理解,其體系結構在實際應用中需要進行復雜的更改。
1999年,Castr 和 Lisko 提出了 實用拜占庭容錯(Practical Byzantine Fault Tolerance,PBFT)算法,實現了拜占庭算法復雜度由指數級至多項式級的轉變,可應對全 網三分之一節點以下的惡意攻擊[20]。不過需要較大的網絡帶寬來保證副本的復制,在多 節點情況下,通信復雜度仍較高[21]。
2006年,Google在松耦合分布式系統的鎖服務Chubby論文中指出:Paxos描述的 理論系統與實際情況存在差別,其不需要計時假設來維持安全性,但必須引入時鐘來確 保活性,這克服了 Fischer提出的FLP不可能性[22][23]。
2008 年,工作量證明(Proof ofWork,PoW)算法通過對節點算力(哈希率)的限制, 提升作惡成本,解決了拜占庭容錯問題[24]。后來為減少PoW共識過程的資源浪費問題, 研究者們對PoW進行改進產生了一系列改進算法,其中權益證明(Proof-of-Stake,PoS)和 委托權益證明(Delegated Proof of Stake,DPoS)利用節點權益代替工作量證明,在減少資 源浪費的同時提高了共識效率[25]。
2014 年,在 Paxos 基礎上 Diego Ongaro 和 John Ousterhout 提出了 Raft 算法, Raft 分離了共識的關鍵要素,并加強了一致性程度,以減少必須考慮的狀態空間,并且Raft 比Paxos有更易理解和實施的優點,且與Paxos具備同量級的性能[26]。這促使Raft算法 產生了大量的開源實現,并在聯盟鏈中獲得大規模應用。近年來,為提升共識過程的安 全性,大部分聯盟鏈的共識算法需采用拜占庭容錯或其改進方法[27]。
綜上,亟須設計一種拜占庭容錯Raft,并應用于以太坊架構基礎上的Quorum聯盟 鏈[28]中。通過對各共識機制的一致性算法的研究和比較,并在更復雜區塊鏈網絡內將 Raft進行拜占庭容錯和效率優化,賦予一致性協議Raft算法拜占庭容錯能力,是科研工 作者仍需繼續思考和研究的任務。
1.3論文工作和結構安排
本論文一方面針對糧食倉儲管理體系中的不足,基于區塊鏈搭建了一個去中心化、 安全可靠、低成本、智慧的糧倉綜合信息管理系統,實現了糧倉信息系統內數據的分布 式存儲與資源共享,為糧食加工、倉儲和供應提供了安全保障。另一方面,對于使用 Raft 算法作為共識機制的聯盟區塊鏈,無法容忍拜占庭節點的問題,提出了 BFT-Raft算法, 并對改進后的算法進行安全性和活性驗證。
本論文的組織結構劃分如下:
第一章,緒論。交代了本論文的研究背景和意義,區塊鏈應用和共識機制的國內外 研究現狀及發展態勢分析,并簡要介紹了論文的工作和結構。
第二章,對區塊鏈工作原理與關鍵技術進行分析,給出以太坊架構的層級結構、智 能合約的創建與調用、共識算法流程、密碼學技術特點以及IPFS協議棧。
第三章,基于區塊鏈的智慧糧倉綜合信息管理系統的設計,本章首先分析管理系統 的功能性需求和非功能性需求,接著給出整個系統的總體架構設計并對各個部分功能進 行概括,然后詳盡地開展系統前后端架構和智能合約數據結構的設計過程。
第四章,基于區塊鏈的智慧糧倉綜合信息管理系統的實現。本章首先進行系統功能 模塊的開發,給出模塊開發過程。然后對所有合約的部署方式和調用、IPFS的部署和調 用過程進行實現,接著是對實現的前端交互界面進行效果展示。最后對開發的智能合約 使用Solidity集成開發工具Remix進行單元測試、使用靜態分析工具Slither[29]對智能合 約進行漏洞分析、并對系統的功能與性能進行了驗證。
第五章,基于區塊鏈的Raft共識算法的拜占庭容錯式改進。本章首先描述BFT-Raft 共識算法改進方案,然后對算法的Leader選舉和日志復制過程進行設計與實現,最后進 行算法性能測試與分析。
第六章,總結與展望。對論文的工作總結和前景展望。
第二章 區塊鏈工作原理與關鍵技術
2.1區塊鏈架構
區塊鏈作為一種分布式、去中心化的計算與存儲架構,目的是用一種可信的方式記 錄數據。其利用了分布式數據存儲、共識算法、智能合約和密碼學技術分別實現了對數 據的存儲和檢驗、衍生和更新、自動化編程和操作以及安全傳輸和訪問。運行過程中, 區塊鏈系統里的交易會被逐步打包成區塊,各區塊緊密連接,在P2P網絡的點對點傳輸 中不存在中心化的概念,因而具有極高的魯棒性。
2.1.1以太坊
以太坊(Ethereum)是一種能被重編程用以實現任意復雜計算功能的單一區塊鏈, 其實質上是一種確定但實際無界的狀態機[30][31]。通過以太坊虛擬機(Ethereum Virtual Machine,EVM),以太坊具備了對自身單例狀態提供訪問和更改的基本功能。其架構 如圖2.1所示。
( 1 )底層服務
該層囊括了 P2P網絡服務、密碼學算法、LevelDB數據庫和分片(Sharding)優化 等[32]。P2P網絡布景中,各節點彼此對等且獨立,生成或審核新數據-LevelDB和密碼 學算法分別用于區塊數據的存儲和隱私性、安全性的保障。Sharding優化能夠對交易進 行并行檢驗,使得區塊生成效率有所提升[33]。正因有這些底層服務的存在,區塊鏈系 統整體才能平穩運行。
(2)核心層
該層是構成以太坊的核心內容。元件包括區塊鏈,共識算法、EVM等。其以區塊鏈 技術為主,輔以共識算法, EVM 作為運行智能合約的載體。共識算法保證了 P2P 節點 賬本數據的一致與正確性,作為智能合約運行環境的EVM,幫助以太坊實現了復雜的 業務邏輯。
( 3)頂層應用
該層包含API接口、智能合約與去中心化應用(DApp)等。智能合約層的信息交 互過程主要通過Web3js,并且融入RPC的調用。企業可結合自身業務邏輯創建智能合
約,高效率地執行去中心化業務。
智能合約
頂層應用 Solidity ][去中心化應用(DAPP)]以太坊域名服務(ENS)
API 接口
底層服務]P2P網絡][LevelDB數據庫]—密碼學算法— 分片優化'
I 丿 / k J k >
圖 2.1 以太坊架構
以太坊在數據架構方面的重大變化即新增對狀態樹、交易樹和收據樹這三棵梅克爾 (Merkle)樹的存儲,賬戶因此獲得更多的查詢。區塊鏈上第一個被構建的區塊為創世 區塊,除創世區塊,其余區塊都存在父區塊,所有區塊有效連接組成了完整的區塊鏈。 綜上,不同層級結構各自獨立,在功能上協同發展,組成了一個完整的以太坊系統。
縱觀以太坊的P2P網絡,所有成節點中都涵蓋一個EVM,EVM是圖靈完備的,運 行智能合約的有效載體[34]。內部結構如2.2所示。
EVM
Stack Storage Memory
2.2EVM 內部結構圖
EVM包含三種數據存儲方式:內存(Memory)、賬戶存儲(Storage)和棧(Stack)。 內存存儲空間被臨時分配,其數據也是易失的,在合約調用結束后將自動回收。賬戶存 儲中的所有數據應當處于非易失狀態下,并且成為系統一部分,能夠實現長久的存儲。
棧主要應用于虛擬機中的相關計算。依據EVM設計,棧的最大深度為16,智能合約編
程時需注意一個function里面的變量數量不能超過16,包括入參和返回值。
2.1.2智能合約
智能合約(Smart Contract)即一套以數字形式定義的承諾,包括合約參與方可以在 上面執行這些承諾的協議[35]。作為一種合約代碼控制交易執行邏輯的技術,智能合約作 用機理是一段可執行程序。設計過程中,需綜合考慮整體目標,減少異常與對可信中介 的依賴,確保常規的合約條件能夠滿足整個操作流程的嚴密性、支付條款和留置權等。
實質上,智能合約本身就是系統的參與者,不但能接收和存儲價值,也能對外發送 信息和價值[36]。合約的行為通過代碼進行操控,而且在整個網絡中,對所有共識節點可 見[37]。在使用過程中開發者需保證代碼功能的邏輯不發生錯誤和缺失[38]。智能合約的創 建和調用流程如圖 2.3 所示。
合約的創建先后經過:編寫,編譯,部署。編譯完成后,生成包含數據操作邏輯的 EVM 字節碼。通過交易部署至區塊鏈后,區塊鏈上將存在特定的合約地址與數據。合 約調用時,將合約需要的參數作為字段,通過遠程過程調用API (PRC API)向合約地 址發起交易,開展數據交互。
為了便于合約的調用和參數的傳遞,以太坊使用程序二進制接口(ABI)作為交互 標準。ABI中含有合約函數信息,作為服務提供者,合約創建者需向用戶提供ABI的合 約地址,如此用戶便能使用合約預定義的功能。
ABI可由Solidity編寫的智能合約編譯而成,Solidity作為當前合約編寫中應用范圍 最廣,穩定性最強的高級語言[39],大大提升了合約開發與運行效率。該語言中合約與面 向對象編程中類(Class)的概念類似,同一份合約中能夠對多種成員進行聲明,內容有 狀態變量、事件、函數、函數修改器等,此外合約具備可繼承性屬性。
2.2共識機制
由于P2P網絡中延遲的存在,各節點接收到事務的先后順序有所差異,當節點間決 策出現分歧時,為保證區塊鏈系統正常穩定地運行,共識機制是區塊鏈事務達成共識的 核心。當前,廣泛應用于聯盟鏈的共識機制有PBFT、Raft等。
2.2.1PBFT
拜占庭將軍問題是Leslie Lamport在同名論文中提出的分布式對等網絡通信容錯問 題[40]。即集群節點可能出錯而發送錯誤的惡意信息,這將使系統的一致性受到干擾和破 壞。
PBFT假設在節點總數為N的通信網絡中,在(N-1)/3個節點同時為拜占庭節點情況 下,依舊能保證分布式網絡中達成共識。算法設計了視圖更換、檢查點和一致性協議, 規定主節點和副本之間編號的一次快照稱為視圖。共識基本流程為:
1)客戶端向主節點發送調用服務操作的請求。
2)某一視圖中,主節點接收到客戶端請求后,組播請求給系統所有備份節點。
3)節點執行 PBFT 算法三階段共識流程。
4)各節點處理完請求后,將結果反饋給客戶端。客戶端會對接收到的結果進行檢查, 如果得到大于1N個不同節點的相同回復,則將其作為最終結果。
3
2.2.2Raft
基于簡化操作和效率等因素,Raft算法主要應用了非對稱節點關系模型。集群中節 點角色分為領導者(Leader)、追隨者(Follower)和候選人(Candidate),各自職責如 下。
Leader:接收到客戶需求,向Follower同步請求日志,倘若日志同步到大多數(N2+1 個及以上,N為節點總數)節點上后,告知Follower提交日志。
Follower:接收并持久化Leader同步的日志到狀態機,從Leader處得知可以提交日 志后進行日志提交。
Candidate:Leader 選舉過程中節點的臨時角色。 其中主節點掌控著決策權,客戶端只與主節點進行交互,無論哪一時間段都只有一個主 節點。一致性被分解為一系列子問題:Leader選舉、日志復制、安全性和成員變更等。
( 1 )集群角色轉換
如圖2.4所示,當服務器啟動時,全部的Raft節點最初都處于Follower角色,隨后 定時器觸發Leader選舉。選舉執行步驟如下:
1)將自己本地維護的當前任期號(current_term_id)加1。
2)將自己的狀態轉換成為Candidate并為自己投票。
3)將 RequestVote RPC 消息傳送給集群中其他節點,告知其為自己投票。一個候 選人在收集選票的過程中,有三種狀態遷移的可能性。
4)得到大多數節點的選票(包括自己),成為 Leader。
5)發現其他節點贏得了選舉,主動切換為 Follower。
6)持續一段時間之后,若并節點贏得選舉。系統會發起第二次選舉。
圖 2.4 Raft 集群三類角色切換示意圖
Leader 會向所有 Follower 呈現規律性的心跳輸送。假使超出了預定的選舉時間, Follower還是沒有得到Leader的心跳信號,系統將會等待一段隨機的時間(150?300ms), 重新發起 Leader 選舉,如此往復。
( 2)數據交換
數據交換示意圖如2.5所示。一次正常的Raft日志復制流程包括以下步驟:
1) 客戶端向Leader發送寫請求。
2) Leader對請求進行解析,將其轉化成的操作指令追加到本地日志文件中。
3) Leader 為每個 Follower 廣播 AppendEntries RPC。
4) Follower經過一致性檢驗以后,會選取從適宜位置開始追加Leader的日志條目
5) 日志項被提交成功后,Leader會對日志條目相匹配的指令應用到本地狀態機中, 最終將操作結果反饋給客戶端。
6) Leader借助AppendEntries RPC指揮多個節點將提交日志的信息傳輸給Follower。
7) Follower 接收到提交的日志項后,將其應用到本地狀態機。
圖 2.5 Raft 算法數據交換示意圖
2.3密碼學技術
2.3.1加密算法
區塊鏈底層使用了非對稱加密技術。在非對稱加密體制中,明文加解密的關鍵是公、 私鑰的配對使用,如果加密者(發信方)想要發送僅有解密者(收信方)才能夠解讀到 的信息,加密者需知道解密者的公鑰密碼,并且對公鑰進行加密處理。該操作下,只有 解密者(收件方)通過私鑰解密才能看見明文信息。根據公鑰推出私鑰極為困難,這也 就有效地保證了數據的嚴密性和安全性。
比特幣和以太坊的橢圓曲線加密(Elliptic curve cryptography)中使用了 secp256k1 橢圓曲線,用二元三階方程可表示為:y2=x3 + ax + b.其中a、b為系數,同時滿足。
當 a=-3、 b=7 時,橢圓曲線如圖 2.6 所示。
橢圓曲線有如下特點:任何一條直線,最多與曲線有三點相交。且交點P、Q、R三 點滿足 P + Q + R = 0 。
數字簽名則應用了公鑰密碼體制,公鑰加密系統的加入保證了消息的不可抵賴性和 信息的完整性。常見的簽名算法有 RSA、 DSA、 ECDSA, RSA 是完成數字簽字最為簡 單的方法。DSA區別于RSA的關鍵在于其不能夠應用于加密和解密,也不能夠對密鑰 進行交換處理,只能夠進行簽名操作。ECDSA是ECC與DSA的結合,相比RSA也有 傳輸帶寬更低、空間占用更少、簽名速度更快、安全性能更強等諸多優勢[41]。
簽名步驟如下:
1) 在{1,…,九一 1}范圍內選取一個隨機數k (n是子群的階)。
2) 計算點P = kG (G是子群的基點)。
3) 計算數字r = xp mod n(xp是p的x軸坐標)。
4) 如果r = 0,另選一個k并重新計算。
5) 計算s = k-1(z + rdA) mod n (右是私鑰,k-1是k mod九的乘法逆元)。
6) 如果s = 0,另選一個k并重新計算。
(r,s)即為簽名。為了驗證簽名,收信方需要公鑰禺,被截斷的哈希值z。 簽名驗證過程如下:
1) 計算整數u1 = s-1z mod Ho
2) 計算整數u2 = s-1r mod九。
3) 計算點 P = UjG + u2Ha。
只有當r = xp mod九的時候,簽名才被成功驗證。
2.3.2哈希算法
哈希算法能夠將任意長度的二進制數據加以映射,生成較短的二進制串 Hash 值, 表示形式為:
h = H (m ) (2.1)
其中,h為固定長度的哈希值,m為任意長度消息,H為哈希函數。目前被廣泛使用 的哈希算法有:MD5、SHA-1、SHA-256、SM3等如表2.1所示。
表 2.1 典型散列算法特點
加密算法 安全性 運算速度 輸出大小(位)
MD5 低 快 128
SHA-1 低 中 160
SHA-256 高 比 SHA-1 略低 256
SM3 高 比 SHA-1 略低 256
散列算法包含兩個處理階段:先通過預處理進行消息填充和分割,之后哈希計算迭
代生成一系列信息摘要(Message Digest)。總體上,哈希計算具備以下特點:
1、 正向快速:當明文和Hash算法被給定時,可在一定時間內借助有限資源將Hash值計 算出來。
2、 逆向困難:給出多個Hash值作為已知條件,在一定時間內計算出明文的可能性極低 (基本不可能)。
3、 輸入敏感:如果對初始輸入信息進行一點調整,最終得到的Hash值會出現很大不同。
4、 沖突避免:極難尋求到兩段內容有差異的明文,使銘文的散列值相同(發生沖突)。
區塊鏈節點將數據在全網廣播時,若對原數據進行任何改動,得到的消息摘要都會 有所差異,因此散列算法實現了實體認證,充分確保了原始數據的完整性。
2.4星際文件系統
由于數據上鏈需要成本,在以太坊中需要消耗掉Gas,在EOS中需要占用Ram,而 訪問的速度更是不允許大數據的記錄。所以區塊鏈中不能直接保存大文件。這種情況下 可以選取星際文件系統(IPFS)作為去中心化的文件系統。IPFS憑借分布式哈希表和默
克爾有向無環圖的數據結構,解決了數據的傳輸和定位問題,把單點傳輸改變成類似于 比特流(BitTorrent)的協議的P2P傳輸[42]。
不同于傳統的基于域名尋址的HTTP (HyperText Transfer Protocol)協議,IPFS基 于文件內容尋址。當一個文件被IPFS存儲時,會被拆分成多個空間占比小于256KB的 數據塊(chunk),并對每個chunk生成哈希值。哈希會按照文件內容生成,即使兩個文 件內容存在一個比特的差異,最終的哈希值也會有所不同[43]。圖 2.7 為 IPFS 七層協議
棧。
身份層(Identity)
S/Kademlia算法增加創建信息身份的成本 . 對等節點身份信息生成、驗證 -
圖 2.7 IPFS 協議棧
在這些協議棧當中,節點的身份生成和驗證由身份層負責。多種底層網絡協議被應 用于網絡層當中,用于管理節點間的連接。路由層響應本地和遠端節點發出的查詢請求。 交換層弱化數據復制并防止了作弊現象。對象層提供內容尋址和防冗余特性。文件層包 含版本快照,為blob、commit、list、tree這些數據結構提供功能上的支持。命名層則是 有自驗特性的可變名稱系統。
2.5 本章總結
本章闡述了區塊鏈工作原理與關鍵技術。首先概括了區塊鏈的技術特性、以太坊架
構的組成、以太坊虛擬機和智能合約的創建與調用過程。然后研究了聯盟區塊鏈中常用
的共識機制,剖析共識流程。之后分析了密碼學相關的技術,對非對稱加密算法以及常 用的哈希函數做了描述和比較。最后,從分布式角度探討了 IPFS 存儲系統的協議棧、
工作原理以及其對區塊鏈的重要性。為后續基于區塊鏈的智慧糧倉綜合信息管理系統的
設計與實現和 Raft 共識算法的改進奠定基礎。
第三章 基于區塊鏈的智慧糧倉綜合信息管理系統設計
相較于傳統的信息管理系統彼此獨立,互不相通的弊端,本章旨在研究并設計一種 基于“區塊鏈+物聯網”的智慧糧倉綜合信息管理方案。在此應用場景下,一方面,通過 對用糧/儲糧企業交易數據和倉儲傳感器設備數據的存證和溯源,完成對倉儲環境的有 效監控,保障糧食在倉儲過程中質量的安全。另一方面,完成對企業內糧食資產的閉環 管理和嚴格把控,促進倉儲監管與信息管理良性發展。本章首先對系統進行了需求分析, 之后展開了系統的總體架構、前后端架構和智能合約數據結構的設計。要求系統在滿足 各類功能的同時,還應采取科學的數理統計來展示糧倉數據特征,界面盡量簡化高效, 做到實用、方便,避免不必要的邏輯冗余。
3.1功能性需求分析
3.1.1系統管理需求分析
系統管理是整個系統的門戶,涉及用戶的狀態轉換,信息的更改和管理員授權等相 關操作。應具備主體登記注冊與審核、用戶資料修改、子用戶授權與用戶登錄、登出等 功能。
主體登記注冊:規范新用戶注冊所需條件,系統要求不同用戶群應提供不同的注冊 信息。例如個體戶或企業需輸入統一社會信用代碼并選擇企業類型,而其他社會組織需 輸入許可證編號并上傳證件。相關的圖片信息上傳到IPFS集群,并返回文件哈希值。這 些數據都將上鏈。
注冊審核:要求提供的材料符合格式且真實有效,否則不通過系統審核。 用戶資料修改:非唯一性信息的二次提交。例如聯系電話、郵箱、地址等。 子用戶授權:通過管理員認定后,修改系統用戶的權限,向已有用戶分配子用戶。 登錄、登出:用戶的登錄與注銷功能,登錄時需提供以太坊賬戶地址和密鑰。
3.1.2倉儲檢測需求分析
倉儲檢測作為儲藏環境的監控者,包含倉儲設備的管理、各類環境指標的檢測和歷 史數據管理等相關操作。系統要求完成對設備的創建與錄入、狀態盤點、糧堆和倉庫內 外溫濕度指標的實時檢測、數據清晰且直觀的可視化顯示、歷史記錄的保存和溯源。根 據實時搜集的數據對于突發情況及時智能提醒并響應預防措施。
設備創建:倉庫管理者為指定倉庫綁定IoT設備,用于后期環境檢測。設備類型多 樣,包括溫濕度、除塵、水分等。
設備錄入:根據選擇的設備類型可以批量導入或單個錄入設備。設備的錄入同樣需 要管理員的審核。
設備列表:顯示所有設備的名稱、類型、網絡狀態(在線/下線)以及和倉庫的匹配 關系。
溫濕度檢測:傳感器溫度檢測范圍在[-40弋,85弋],精度控制在土0.5弋區間,濕度檢 測范圍在[0%RH,100%RH],精度為5%RHo糧堆平均糧溫常年保持<20^,局部最高糧 溫<25弋。溫濕度值一經檢測后立即將傳感器數據同步到區塊鏈和分布式數據庫中。
數據操作:支持對傳感器數據的存證和溯源。選擇時間戳區間后,可查看測試數據 的歷史信息、趨勢信息、完成當日或時間段內的報表下載。
預警信息:對設備斷線、超出閾值的溫濕度等異常數據的實時顯示。當事務的預警 級別高時立刻以郵箱或短信的形式進行遠程推送。
3.1.3交易管理需求分析
交易管理是糧食數據轉移里的重要一環,控制糧食的流向、交易的發起與創建、訂 單的分發等流程。具有交易的發布、創建、修改、記錄、溯源查詢等功能。
交易創建與發布:向上下游企業發布需求訂單,其中包括貨物名稱和購買量,購買 方的收貨信息。在訂單有效期截至之前,等待系統響應。
交易接收:上下游企業同意并接收訂單后,開始糧食出庫。并將交易雙方信息、交 易哈希和交易日期等信息寫入區塊。
交易修改:在訂單未被接收前,若發起者由于人為原因錄入錯誤可以進行訂單內容 的修改,當訂單審核不通過時,仍能根據系統反饋意見修改后提交,如果被接受則說明 已經全網共識,訂單信息不能再被修改。
交易查詢:查詢已錄入訂單,可以根據交易時間、交易哈希、糧食的溯源編碼或收 貨人進行關聯搜索,然后顯示詳情頁。
對公轉賬:輸入發送方和接收方的區塊鏈地址,完成虛擬貨幣的轉賬。
3.1.4資產管理需求分析
資產管理模塊通過嚴格規范糧食閉環管理,不僅要完成對糧食出入庫環節前后的信 息登記和存證,還負責反饋整個主體企業內部資產的變化情況。
糧食入庫:填寫糧食入庫信息、上游企業信息、入庫規格、檢測人員、管理人員等 信息,入庫量較多時,可以分批次進行入庫,確保糧食的安全入庫。相關圖片信息需存 入 IPFS。
糧食出庫:響應訂單的需求,完成糧食出庫,該模塊包含出庫信息填寫、出庫完成 操作,最終輸出到運輸部門開展配送。上游企業發貨給下游企業后,下游企業在產品入 庫之前,上游企業可以發起發貨的撤銷,從而撤銷本次產品的出庫。
庫存調整:進入倉庫下的產品列表,選擇要調整的產品,填寫產品實際的庫存信息 進行庫存產品的調整。
資產管理總覽:顯示糧食資產總分布,實時更新糧食品類數目與倉儲設備的數量和 狀態。顯示不同時間段內交易額、各倉庫出入庫概況、交易趨勢圖。
區塊鏈賬戶錢包信息更新:實時監聽賬戶所屬的區塊鏈網絡和以太坊錢包的在線情 況、更新賬戶地址以及其所對應余額數據的變化。
3.2非功能性需求分析
(1) 安全性需求:合理的設置狀態變量和函數的可見范圍,函數權限及變量邊界 檢查。利用智能合約靜態分析工具,避免合約漏洞,對區塊鏈中數據的寫入應具有規范 性,保證系統的安全性、數據的機密性和完整性。
(2) 性能需求:由于大量復雜計算會對區塊鏈網絡以及性能造成很大影響,在區塊 鏈智能合約里盡量不出現復雜計算和驗證邏輯,而是于鏈下或前端業務中實現。為了提 升用戶體驗,系統繁忙時界面響應時間不應高于 5 秒,系統各個界面的響應時間不應高 于 1 秒,高可用。 CPU 占有率和內存占用率低于 60%,并避免內存泄露情況發生。減 少不必要的計算和驗證邏輯,減少 CPU 開銷。
(3) 可靠性:系統需要較高的公正性和可靠性,用戶權限劃分清晰,因為軟件失效 而造成的用戶業務停滯概率要低于5%。。系統連續正常運行的時間大于7x24小時。
(4) 擴展性需求:系統使用主流的設計模式,降低模塊耦合度。為了能更好地進行
二次開發,系統需要保證良好的可擴展性。
3.3系統總體設計
本節依據現有區塊鏈應用的設計模式,綜合使用區塊鏈、 IPFS 和數據庫技術設計了
智慧糧倉綜合信息管理系統。如圖 3.1 所示。
互聯網
圖 3.1 系統總體架構
根據需求目標,對系統總體框架進行設計,該框架主要由Web應用層、區塊鏈業務 層、Server服務層、數據采集模塊層組成。系統前后端的業務邏輯封裝了具體的操作流 程,將數據請求和用戶操作進行處理完成對數據的系統調用。Server服務層向上提供了 Restful接口,區塊鏈、IPFS和MongoDB數據庫的存取操作最終將由Web應用層實施 [44]。
Web 應用層:專注于模塊頁面的樣式與動態數據的解析和渲染,處理少部分的業務 邏輯。通過路由的配置,各頁面按需加載,單頁面無需一次性加載網站上所有的資源, 在交互性能和用戶體驗上有所提升。高內聚低耦合,減少后端的并發/負載壓力。為了保 障數據的安全性和隱私性,圖片類信息存儲在私有IPFS集群。
區塊鏈業務層:該層是系統的核心,實現了系統數據的永久存儲以及不可篡改。通 過合約接口,應用層可以便捷地調用對應智能合約。關鍵業務數據直接與智能合約交互 存儲至區塊鏈,包括管理系統的信息更新、交易數據的存證、傳感器數據的記錄、圖片 的 IPFS 地址和數字指紋的生成。區塊鏈的搭建以及智能合約具體實現將在第四章里做 詳細贅述。
Server服務層:作為數據采集模塊層和Web應用層數據交換樞紐。由Web后端以 及與其所關聯的MongoDB數據庫集群組成。Server服務層一方面負責Web應用層的邏 輯請求,完成對現場數據采集設備的指令下發和數據庫操作。另一方面還負責從數據采 集模塊得到倉儲環節所涉及的所有現場數據信息,完成解析和數據緩存。
數據采集模塊層:數據設備使用 NB-IoT 模塊,能支持低功耗設備在廣域網中的蜂 窩數據連接。通過無線網側和 EPC 架構核心網的組網方式,完成對各類傳感器設備對現 場環境質量的檢測。與Server服務層通信進行數據上傳和及時預警。
3.4前端架構設計
前端設計架構圖如3.2所示。系統前端使用Vue作為漸進式框架,基于MVVM的 開發模式,核心思想是組件化和數據驅動[45]。因而可以組件復用并且相對容易地進行 DOM操作。App.vue單頁應用自定義組件裝載,各模塊按需加載。單頁應用通過路由切 換相關組件,刷新局部資源。
使用 vue-cli 初始化基于 webpack 打包規則的項目架構, Vue-router 作為路由工具, 完成頁面跳轉。Vuex作為狀態管理工具實現多組件內變量數據共享。UI組件庫包含 ElementUI和Echarts。為避免組件文件代碼過于冗余,將css樣式、javaScript代碼從vue 文件中抽離形成形如 name.js、 name.less 的獨立文件。
瀏覽器 HTML\JS\CSS (單頁面應用,各模塊按需加載)
生成各頁面
JS模塊 系統管理 倉儲檢測 交易管理 資產信息
Vue Component Vue Router Vuex
圖 3.2 前端設計架構
Browser Server
用戶使用賬號和密碼發出pos t請求I
服務端使用私鑰
服務器返回這個JWT給瀏覽器 創建 個冋丁
將JWT串在請求頭中向服務器發送請求
返回響應的資源給瀏覽器
同時需注入以太坊相關的Web3和Truffle依賴。網絡交互分為與后臺接口和區塊鏈 節點交互,分別通過 Axios 的 Http 和 Web3.js 的 JSON-RPC 請求完成。根據請求方式, 前端對于異步請求使用 Promise 回調。
通過集成JWT (JSON Web Token)中間件,該協議基于token的鑒權,JWT鑒權令 牌用于限制多點登錄。認證機制如圖3.3所示。相比于session認證,服務端不需要保留 用戶的認證信息或會話信息,為應用的擴展提供了便利。
3.5后端架構設計
通過前兩節對系統功能需求和非功能需求的分析可知,后端在滿足高并發和性能穩 定的情況下,還需要協同區塊鏈進行各個模塊的業務處理。系統后端開發過程中,本文 使用Golang語言編寫的主流Web框架Gin快速搭建基于restful風格的API,go-logging 實現日志記錄, MongoDB 集群完成分布式數據存儲,最后使用 docker-compose 進行部
其中 Gin 框架包含 Engine、 Router、 Context、 Bind 四種模型,如圖 3.4 所示為其生 命周期。
開發過程中將后端架構分為四層,分別是接口層、應用層、基礎層和數據層。每層
獨立存在, “分而治之”,有利于程序開發、維護和擴展。設計架構圖如圖3.5所示。
圖 3.5 服務端架構設計
API接口層:Gin Router向客戶端提供HTTP請求的諸多接口,用于前端與后端的 數據交互,負責對用戶提交的數據做相應的處理,包括數據過濾、數據解析、錯誤反饋。 數據過濾校驗是否為有效數據,保證數據的正確性,根據前端上傳的json數據格式解析 出需要執行的指令,對于錯誤的請求做出反饋。
業務邏輯層:對前端發送過來的各種請求進行相應的邏輯處理。處理完成后,分發 到基礎服務層。同時使用靜態化技術減少對后端的壓力,提供日志收集用于查看運行狀 態和發生異常狀況后,快速排查問題。
基礎服務層:消息隊列機制緩存并快速處理業務邏輯層產生的指令,同時采用IO模 型結合多線程的方式,高效地處理多個用戶的請求信息,通過MQTT代理完成測控指令 的下發和對傳感器數據的解析,實現對網絡業務數據的讀寫。
數據資源層:這一層級所有的操作都是針對數據庫的,下發指令用于從數據庫讀取 數據,然后發送給前端和終端,收集數據就是將前端或者終端提供的數據寫入到數據庫 當中。MongoDB作為分布式集群與區塊鏈底層P2P網絡高度契合。
3.6智能合約數據結構設計
智能合約負責業務數據的處理、存儲與讀取,因此合約的核心在于邏輯處理并將業 務數據抽象為合約可存取的數據結構。作為一門靜態類型語言, Solidity 中每個變量的 類型都必須指定,否則將不能正確編譯。
根據參數傳遞方式的不同將變量類型分為兩類:值類型和引用類型。其中值類型包 括枚舉、地址、整型、布爾、固定長度字節數組等類型。引用類型包括數組、映射、結 構體等。系統中數據的存儲多以復雜的引用數據類型保存在賬戶存儲中,而且復雜的變 量數據類型由基礎類型組合而成。本節根據需求和業務流程將實際業務數據抽象為結構 體,映射(mapping)或事件(event)數據,進行系統的合約數據結構設計。
(1)注冊、登錄
該子模塊的合約結構體包含UserStruct和RegisterStruct,分別負責新用戶的注冊上 鏈和用戶信息的保存。設計如 3.1 表所示。
表 3.1 注冊、登錄結構體設計
名稱 數據 類型 說明
UserStruct userAddr address 20位以太坊地址
userName string 用戶名
index uint16 用戶所在索引
registerStruct RegisterStruct 注冊結構體
RegisterStruct enterpriseName string 企業名
creditCode string 統一社會信用代碼
enterpriseType enum 企業類型
representative string 法定代表人
premises string 經營場所
scope string 經營范圍
businessYear uint8 營業期限
verificationStatus bool 核驗狀態
phoneNumber string 手機號
passWord string 密碼
time uint256 注冊時間戳
2)資料修改、子用戶授權
資料修改負責非唯一性信息的二次提交,是管理系統的基本性功能。企業為便于管 理,會進行子用戶授權,將不同職能賦予多個子用戶。其中,資料修改的 ModifyStruct 結構體與注冊階段的RegisterStruct數據類型一致,子用戶授權的合約結構體Subuser設
計如表 3.2 所示。
表 3.2 子用戶授權結構體設計
數據 類型 說明
subuserAddr address 子用戶區塊鏈地址
subuserName string 子用戶名
passWord string 密碼
time uint256 當前區塊的時間戳
3)環境檢測數據
環境檢測數據用于環境檢測數據的存證和歷史記錄的溯源查詢,用于提供監測數據 變化的趨勢分析、報表的顯示和打印數據源。鑒于Solidity參數無法傳遞結構體數組。 對環境檢測數據結構體進行拆分。環境監測 MeaureMgr 合約結構體設計如表 3.3 所示。
表 3.3 環境監測合約結構體設計
名稱 數據 類型 說明
TempAndHumi date string 測試日期
meaureTime uint256 當前區塊的時間戳
datas Data 溫濕度數據結構體
indoorTemperature string 室外溫度值
outdoorHumidity string 室外濕度值
Data deviceN ameArr string [] 設備名稱數組
singleData SingleData 單次檢測結果
SingleData deviceName string 設備名稱
singleTempData string [][] 單次檢測溫度結果
singleHumiData string [] 單次檢測濕度結果
4)設備管理
設備管理子模塊負責為倉庫綁定用于實時環境監測的 IoT 設備,并動態更新設備的 名稱、類型、狀態以及和倉庫的匹配關系。該模塊智能合約的設備錄入結構體Deviceinfo 設計如表 3.4 所示。
表 3.4 設備信息結構體設計
數據 類型 說明
deviceName string 設備名稱
protocolType enum 協議類型
deviceType enum 設備類型
belong_depot string 所屬倉庫
highWran string 高溫預警值
5)交易創建
系統通過 mapping 數據結構將訂單發布時間與訂單內容形成一一映射的關系。訂單 結構體設計如表 3.5 所示。
表 3.5 訂單結構體設計
數據 類型 說明
companyAddr address 訂單發布者賬戶地址
tel string 聯系方式
postalCode string 郵政編碼
upstreamFirm address 上游企業區塊鏈賬戶地址
weight uint16 糧食重量
deliveryAddr string 配送地址
訂單被上/下游企業接收后,儲糧與用糧企業的糧食交易正式開展。交易觸發時間與 交易結構體同樣以mapping結構形成映射的關系。交易結構體Transaction設計如表3.6 所示。
表 3.6 交易結構體設計
數據 類型 說明
transactionIndex uint64 交易索引
transactionHash bytes32 交易哈希值
time uint256 當前區塊的時間戳
seller address 下游企業區塊鏈賬戶地址
表 3.6 交易結構體設計(續)
數據 類型 說明
buyer address 上游企業區塊鏈賬戶地址
payMethod string 支付方式enum (線上、線下)
tracingCode bytes 糧食溯源碼
order Order 每條交易包含的訂單結構體數據
(6)出入庫 糧食流通環節中,智慧糧倉根據上下游企業的交易訂單,完成糧食的出入庫登記。
糧食入庫包含 InDepotInfo、 InDepotDetail 兩個結構體。具體設計如表 3.7 所示。
表 3.7 糧食入庫結構體設計
名稱 數據 類型 說明
InDepotInfo goodKind string 糧食種類
inDepotDetail InDepotDetail 入庫詳情結構體
InDepotDetail upStreamFirm address 上游企業區塊鏈地址
origin string 糧食產地
enterWareHouse string 入庫倉庫名
inDepotDate uint256 入庫日期
harvestDate uint256 收成日期
inspector string 檢測員
custodian string 保管員
foodPicturePath bytes32 糧食圖片ipfs地址
description string 入庫描述
糧食出庫時可以直接導入訂單,方便快捷。根據企業要求,可能要開具發票。因此 出庫登記時包含了 OutDepotInfo、 OutDepotDetail 和 InvoiceDetail 三個結構體。具體設 計如表 3.8 所示。
表 3.8 糧食出庫結構體設計
名稱 數據 類型 說明
OutDepotInfo goodKind string 糧食種類
outDepotDetail OutDepotDetail 出庫詳情結構體
OutDepotDetail downStreamFirm address 下游企業區塊鏈地址
payMethod PayMethod 支付方式
order Order 訂單結構體對象
leaveWareHouse string 出庫倉庫名
invoiceOrNot bool 有無發票
invoiceDetail InvoiceDetail 發票結構體對象
description string 出庫詳情備注
InvoiceDetail invoiceType string 發票類型
firmName string 抬頭
cost uint16 金額
tni string 11位納稅號
3.7本章小結
本章首先對系統展開需求分析,之后根據需求,從系統總體架構、前后端架構、智 能合約數據結構設計四個方面出發詳盡地給出了設計方案。將系統分為 Web 應用層、 區塊鏈業務層、Server服務層、數據采集模塊層四層架構。系統依靠以太坊區塊鏈、IPFS 和 MongoDB 實現數據的永久存儲以及不可篡改。通過前后端分離, Web 應用層基于 MVVM 的開發模式向下將數據請求和用戶操作封裝成業務邏輯, Server 服務層基于主 流 Web 框架 Gin 向上提供 Restful 接口完成協同智能合約對數據的系統調用。智能合約 數據結構設計通過對底層區塊鏈數據層封裝,將業務數據抽象為合約可存取的數據結構, 用于對業務數據的處理、存儲與讀取,簡化了對底層區塊鏈的操作過程。
第四章 基于區塊鏈的智慧糧倉綜合信息管理系統實現
根據上一章的設計方案,系統被劃分為系統管理模塊、倉儲檢測模塊、交易管理模 塊、資產管理模塊四大功能模塊。而且每個模塊細化出不同的子模塊,總體組成如圖 4.1 所示。
'基于區塊鏈的智慧糧倉綜合信息管理系統)
交易管理
模塊
圖 4.1 系統模塊組成
系統功能模塊中智能合約對數據存儲采取了定長型數據存儲和動態型數據存儲兩種數 據存儲方式。開發時不僅大量使用數組、映射和結構體等引用類型,通過使用EVM提 供的日志功能,完成合約代碼運行過程中各類事件的日志記錄,達到監聽和追蹤數據的 目的,合約繼承實現智能合約之間的方法復用和數據共享。交互界面使用 Vue 結合 Web3.js 接口和 Truffle 框架完成與區塊鏈層的對接,然后實現了智能合約和 IPFS 的部 署與開發邏輯與方法,最后對開發完成的系統展開測試。
4.1系統開發環境
系統的所有開發均在Windows平臺下,主要軟件以及語言工具如表4.1所示。
表 4.1 系統開發環境
名稱 版本 說明
Truffle v5.1.28 智能合約編譯、測試框架
Ganache v2.4.0 私有鏈環境
Solidity vO.5.16 智能合約開發環境
MetaMask v9.0.5 開源的以太坊錢包
Web3.js v1.3.4 以太坊節點進行交互的JavaScript API
IPFS v0.&0 星際文件存儲系統
Node.js v12.16.2 JavaScript運行環境
Vue v2.6.10 構建用戶界面的漸進式框架
Visual Studio Code v1.54.1 代碼編譯器
Dapp開發中使用Truffle框架完成對Solidity智能合約的編譯、測試、部署;Ganache 負責以太坊私有網絡的搭建,通過其可視化界面能設置網絡交互參數、查看賬戶和日志 數據;使用輕量級的以太坊錢包MetaMask,進行以太坊節點在瀏覽器中的交易與轉賬 操作。其中Web3.js API用于連接以太坊節點(如testrpc、geth等),并通過以太坊節點 操作以太坊網絡。
4.2功能模塊實現
以太坊智能合約的調用與節點交互過程中,使用到的核心Web3.js接口函數如表4.2 所示。以下幾個小節將會詳細介紹各模塊的開發與實現細節。
表 4.2 主要 Web3.js 接口
方法 作用
web3.eth.personal. newAccount 根據加密賬戶的密碼創建一個新賬戶
web3.eth.personal. unlockAccount 根據加密賬戶的密碼解鎖賬戶
web3.utils. fromWei 將任意數量的wei轉換為ether
web3.utils. toWei 將任意ether值轉換為wei
web3.eth.getAccounts 返回節點所控制的賬戶列表
web3.eth.getCoinbase 獲取當前接收挖礦獎勵的賬戶地址
表 4.2 主要 Web3.js 接口(續)
方法 作用
web3.eth.getBalance 返回地址在指定區塊的余額
web3.eth.net.getId 獲取當前的網絡ID
web3.eth.Contract 創建合約實例,參數定義所有的方法和事件
web3.eth.net.isListening 查看當前節點是否正在連接其他對等節點
web3.utils. isAddress 判斷給定的地址是否是一個有效的以太坊地址
web3.utils. toChecksumAddress 將一個只有大寫或小寫字符的以太坊地址轉換為
一個校驗和地址
4.2.1系統管理模塊
(1)注冊、登錄
系統管理模塊完成了用戶的注冊、登錄登出、信息數據的修改與子用戶授權任務。
其中,合約將注冊信息、用戶資料、權限信息等永久保存于區塊鏈的賬戶存儲(Storage) 中。合約實現類圖如圖 4.2 所示。該模塊合約代碼文件內包含 Login 和 Register 兩個智 能合約
Register
Public Functions:
isExitEnterpriseName(string) isExitRegisterAddress(address) in itRegister(string,string,string,string,string,string,uint&bo okaddress) findRegister(address)
Private Functions:
RegisterUser(Register.RegisterStruct,address)
Private Variables:
registerAddressArr
regis terName An-
Regis terMap
圖 4.2 注冊與登錄模塊合約類圖
isExit 類型的函數用于判斷該模塊合約中是否包含某目標參數:判斷企業是否已被 注冊、注冊地址是否已分配,用戶名、用戶地址是否存在。find類型的函數用于從合約 中讀取被保存的數據存儲項:根據用戶注冊地址查找注冊信息、根據以太坊地址查找用 戶名、根據用戶名查找用戶以太坊地址、根據以太坊地址查找用戶信息。RegisterUser用 于以太坊地址與企業注冊信息的綁定以及數組的push操作。initRegister和initUser分別
用于企業注冊信息的初始化和注冊審核通過后的用戶信息初始化。
用戶在注冊時,通過assert語句對信息合法性進行判斷。信息審核無誤后將該用戶 信息寫入區塊鏈。與區塊鏈賬戶綁定的注冊事件registerCreate定義如下:
event registerCreate (string enterpriseName, bool verificationstatus, uint index) 之后系統結合用戶填寫的注冊密碼使用 web3.eth. personal. newAccount (password, [callback])函數為用戶分配以太坊賬戶。合約定義mapping結構的緩沖隊列,在數據未 被審核之前,對企業的注冊信息進行緩存,避免同一用戶對企業信息的多次注冊。登錄 時,提供“以太坊地址/用戶名+密碼”的登錄方式。由于注冊階段,所有以太坊地址與密 碼都已存儲在定義如下的全局性用戶地址映射列表userStructInfo中,定義如下:
mapping (address => UserStruct) private userStructInfo
合約將確認列表中是否包含登錄的以太坊地址,若存在,使用web3.eth.personal.unlock Account(address,password,[callback])函數解鎖賬戶并與后端建立連接。
(2)資料修改與子用戶授權
模塊合約代碼文件內包含 Modify_UserInfo 和 Modify_Authorization 兩個智能合約,
合約實現類圖如圖4.3所示。
圖 4.3 資料修改與子用戶授權模塊合約類圖
Modify_UserInfo 重定義用戶在區塊鏈上的數據信息, 結合登錄時同步到的
permissionList 權限列表,用戶信息修改通過更新結構體內容來完成。普通用戶只能修改 權限內的個人信息。對于唯一性標識例如區塊鏈地址、企業或個體戶名稱一經全網共識 無法二次更改。由于以太坊智能合約內的一切都是公開的,并且還有“canoe-solidity”這 類的解密模塊。因此系統未在智能合約中對敏感信息進行加密,而是于合約之外對明文 使用web3j.utils.Sha3(string)函數進行加密得到密文,再將其傳入合約。既保證了加密一 致性,又保證了數據的私密性。
Modify_Authorization 中 initSubuserStruct 和 initdistroDepots 用于初始化子用戶結構 體、 子用戶與子倉庫映射并調用 push 方法在子用戶地址數組尾部添加元素。 getdistroDepots 和 getSubuserInfo 分別用于獲得子用戶倉庫信息和子倉庫名。子用戶授權 時需要權限驗證,合約通過自定義修飾符modifier對函數修改器限定,結合raquire語句 作為函數執行的前置條件,派生類可以繼承并覆蓋重寫函數修改器。子用戶分配時的管 理員認證修改器定義如下:
modifier onlyAdmins {
require (isAllowed (msg. sender, admins),
"Only owner can call this function");
_ ;
}
部署合約時構造器constructor()保存部署合約的賬戶,在授權時檢測當前msg.sender是 否是合約創建者,如果不是,終止授權過程。
( 3) IPFS 圖片存儲
圖片信息上傳至IPFS,核心代碼如下:
pragma solidity >=0.4.22 <0.9.0;
contract ImgStorage {
〃會有多處ipfs圖片上傳
mapping(string=>bytes32) imgHashs;
function setHash (string memory imgName, bytes32 ipfsHash) public {
imgHashs[imgName]=ipfsHash;
}
function getHash (string memory _imgName) view public returns (bytes32 _ipfsHash) {
return imgHashs^imgN ame];
}
}
將IPFS圖片地址字符串轉換成bytes32,合約以bytes32的形式存儲地址。相對于 直接以string的形式存儲IPFS地址,占用更小的空間和消耗更少的gas。
4.2.2倉儲檢測模塊
倉儲檢測模塊實現了各類環境指標的檢測、數據的趨勢分析、倉儲設備的管理和歷 史數據的溯源等功能。
( 1 )環境檢測
環境檢測子模塊負責糧堆、倉庫內外溫濕度指標的實時檢測,清晰且直觀的數據顯 示。前后端交互使用一種基于Promise的HTTP庫一Axios進行網絡請求,終端與服務 端通信之間的網絡傳輸使用的是消息隊列遙測傳輸協議(Message Queuing Telemetry Transport,MQTT)。MQTT傳輸的消息分為:主題(Topic)和負載(Payload)兩部分。 Topic為消息的類型,Payload為消息的內容。模塊運行時序如圖4.4所示。
寫入智能合約
圖 4.4 環境檢測模塊時序圖
Stepl:前端向Axios對象傳遞相關配置來創建請求,配置項包括method、url、headers 和data參數。method使用post方法?headers放入登錄認證時返回的token值,productKey 和 deviceKeyList 作為請求主體,通過全局 store 向服務端發送請求。
Step2:服務端初始化一個MQTT訂閱者sub,然后連接Broker并根據ID生成器配置 ID 號,最后訂閱相關主題。核心代碼如下:
options: = mqtt. NewClientOptions (). AddBroker (MQTTAddr)
id: = clientName + "-" + xid. New (). String ()
options. SetClientID(id)
sub: = mqtt. NewClient(options)
sub. Subscribe (Topic, Qos, Callback)
其中訂閱 Topic 為 productKey/deviceKey/update,服務質量(QoS)為 0。
Step3、4: IoT設備上報數據,服務端對原始負載進行JSON規整。整合后的單個Payload 消息內容包括productKey、deviceKey、設備名、測試unix時間戳、日期字符串、溫度 和濕度值。
Step5、6: Axios API將JSON反序列化成Dto對象之后,環境檢測模塊進行組件渲染完 成結果顯示。
Step7:區塊鏈業務層調用智能合約進行相關邏輯處理并將檢測數據存入區塊,待區塊出 塊成功后數據便永久保存,無法篡改。
( 2)檢測數據溯源
該模塊合約實現類圖如圖4.5所示。
MeaureHistoryMgr
Public Functions:
setMeaureDatas(string,string[],uint256»string,string[][],string[],string,string,string) findRecordThnesQ find MeaureDataByT ime(string,uint256)
Private Functions:
getAUMeaureDatas()
getDatas ByDep o tN ame(s tring)
Public Variables:
MeaureDatas
Private Variables:
RecordTimes depotNames
圖 4.5 檢測數據溯源模塊合約類圖
溫度測試數據使用二位數組存放, Solidity 中二維數組的定義不同其他語言如 Java 的定義方式,被定義的數組string[n][m]在存放過程中,n表示的是一維數組的長度而不 是個數,m表示的是二維數組中可以存放多少個一維數組而不是一維數組的長度。但是 讀取方式卻和 Java 相同。
3)設備管理
合約代碼文件內包含 DeviceConfigMgr 和 DeviceStatusMgr 兩個智能合約,合約實現 類圖如圖 4.6 所示。
圖 4.6 設備管理模塊合約類圖
其中 DeviceConfigMgr 用于創建設備、存儲設備信息、初始化三種映射并完成與用 戶以太坊地址的數據綁定。DeviceStatusMgr用于對設備信息的獲取、設備列表中設備狀 態的保存和展示。而且 DeviceStatusMg r 和 DeviceConfigMgr 均繼承至 DeviceCommonlnfo, 用于共享userDepots (倉庫設備映射)和depotNameArr (倉庫名)數據。合約的繼承方 式使用 is 關鍵字指定,繼承的優勢在于減少跨合約調用。在編譯階段, DeviceStatusMgr 會連同父合約一起編譯。父合約的ABI數據融入子合約里。當調用父合約時,就相當于 調用自身。
由于智能合約尚未提供遍歷mapping中key和value的接口。為遍歷userDepots映 射的value,需要根據業務需求對該數據結構進一步封裝。DeviceStatusMgr初始化了一 個 string]]類型的數組 depotNameArr,在映射添加 value 為 mapping(string=>DeviceInfo [])值時,數組也同步添加string數據,通過遍歷數組里字符串,從而達到遍歷映射的目 的。
① 設備錄入
由于Solidity目前并沒有完全支持浮點型,fixed變量可以被定義,但不能賦值或獲 得值。設備錄入時智能合約未對設備的高、低溫預警值以浮點類型初始化,而是改用 string 類型存儲。由于設備和設備屬性、倉庫和設備、用戶與倉庫皆是一對多的關系。 為保證數據唯一性,合約分別定義了如下mapping映射:
mapping (string=>string []) private deviceInfo
mapping (string => DeviceInfo []) private depotDeviceMgr
mapping(address=> mapping (string => DeviceInfo [])) private userDepots
其中:userDepots的Key為用戶以太坊地址,value為倉庫列表;deviceinfo的Key為倉 庫名,Value為設備列表;depotDeviceMgr的Key為傳感器設備的deviceKey, Value為 設備屬性。數據約束時,針對合約中字符串類型值不能直接比較的問題,使用 keccak256 函數將string類型值轉換為bytes32類型的值,再進行比較。
② 設備狀態列表 列表中設備的名稱、類型、倉庫的匹配關系等設備屬性可直接從區塊鏈上獲取,但 設備運行狀態需要從終端處同步再上鏈。與溫濕度檢測子模塊類似,獲取設備狀態的 Topic 格式為“productKey/deviceKey/status”, Payload 數據內容如下所示:
{
"productKey": "bneei1k55k32jrcv4vmg",
"deviceKey": "bneej1c55k32jrcv4vn01",
"deviceName": "1 號平方倉",
"time":1574648328,
"date": "2019-11-25 10:18:48",
"status":"online"
}
status字段即為當前設備狀態。有online (在線)、o田ine (下線)、unknown (未知) 和fault (硬件故障)四種情況。
4.2.3交易管理模塊
交易管理模塊實現了訂單的管理、交易的存證和溯源等功能。訂單的管理包括訂單 的發起與創建、查看、修改和刪除。交易的存證和溯源包括對交易列表的實時更新和交 易數據的溯源搜索。模塊實現類圖如圖4.7所示。
Transaction Mgr
Public Functions:
c reatO rd cr(T rans actio nlnfb.O rder) ac c ep tingOrder(boo 1)
p ayO rder(ad d ress?add ress,uint256)
s endingG o o ds (bo o 1)
initT ranraiis actio n()
find Address ByName(s tring)
Private Functions:
ncxtPhascO
wani()
Modifiers:
atPhas e(T rans actionlnfo ,OrderPhas es) changeNext()
checkPhases ()
Public Varlables:
orderPhase
Private Variables:
is Created
is Ac cep ted
is Finished
is Payed
is Sent
createTiine
acceptT ime payTiine transferMgrAd dress
T ransactionlnfo
Public Variables: transactions
Private Variables: orders
OrderList
圖 4.7 交易管理模塊合約類圖
(1)交易合約的生命周期
在糧食交易過程中,智能合約TransactionMgr扮演了狀態機(State Machine)的角 色。代碼中聲明了枚舉類型變量OrderPhases,將合約的生命周期明確地劃分為5個固 定的階段。用下列枚舉項: CreatOrder、 OrderAccepted、 PayOrder、 SendingGoods、 Fini sh 分別代表訂單的創建、被接收、支付、發貨和完成的狀態。并且根據判斷條件,通過 modifier自動地進行狀態的切換。這些enum變量按照定義順序與uint整數類型之間顯 式轉化,通過orderPhase=OrderPhases(uint(orderPhase)+l)語句對狀態進行更新。核心代 碼如下:
modifier atPhase (OrderPhases _orderPhase) { require(orderPhase==_phase);
_;
}
modifier changeNext () {
_;
nextPhase ();
}
function nextPhase () internal {
orderPhase= OrderPhases (uint(orderPhase)+1);
}
modifier checkPhases () {
if (orderPhase == OrderPhases.CreatOrder) {...}
else if (orderPhase == OrderPhases.AcceptingOrder) {...}
else if (orderPhase == OrderPhases.PayOrder) {...}
_;
}
在TransactionMgr合約中定義的三種函數修改器功能如下。
1)atPhase :用來限制函數執行所處的合約狀態;
2)checkTransitions:在函數執行之前,根據當前的時間戳和bool類型變量isCreated、 isAccepted、 isFinished、 isPayed 和 isSent 升級合約狀態;
3)changeNext :在函數執行之后立即更新合約狀態。適用于只能執行一次的函數 sendingGoods。
合約中的各函數皆先引用checkPhases,再引用atPhase修改器,先被引用的函數修 改器優先級高。根據先后順序,會先執行升級合約狀態的邏輯,再進行當前合約所處階 段狀態的判斷。
( 2)訂單管理
基于EPC 20代幣合約的標準,PayMgr負責訂單提交后下游企業對上游企業的支付 邏輯。其中getBalance函數入參為賬戶地址,用于查看目標賬戶的余額。payment函數 用于下游企業賬戶向上游企業賬戶的轉賬, transferFrom 函數用于子用戶從管理員賬戶 中獲得定額代幣。
OrderMgr 中 requireOder、 editOrder、 deleteOrder 函數分別對應訂單的查看、編輯、 刪除三種操作。訂單發布時,智能合約以當前區塊的 timestamp 為 key 為每條訂單自動 分配uint256類型時間戳。因此操作函數可以根據此條件從映射變量OrderList中獲得指
定的 Order 結構體數據。訂單編輯時只需重新初始化 Order 結構體,訂單刪除時通過 delete 關鍵字將結構體內成員變量置為初值。
(3)交易存證與溯源
由于合約交易的不可篡改性, EVM 日志事件的數據一旦寫入無法覆蓋,即便進行 了訂單修改,先前的訂單信息日志也會有留痕。Web3.js日志訂閱的filter過濾屬性支持 還不夠完善,為了靈活查詢,系統使用MongoDB在鏈下做一個同步的交易數據備份。 對 MongoDB 添加數據的過程如下。
Stepl:以emit()的方式觸發交易日志事件,監聽事件以“fromBlock: latest”為參數項,獲 得最近一次觸發的日志數據。
const {transactionCreate} = this. Dapp.meta. events;
const latest = await this. $store.state.web3Singleton.eth.getBlockNumber(); 〃區塊高度
await transactionCreate (
{
fromBlock: latest, 〃當前區塊編號下的最近一條數據
},
function (error, event) { if (error) { console.log(error);
return;
} else { saveProduct (event. returnValues);
}
});
Step2:通過http請求向服務端發送日志數據。
Step3:服務端以transactionHash作為主鍵對MongoDB進行查詢操作,若未發現記錄則 進行交易信息的數據存儲,若發現已存在記錄則進行數據更新。
4.2.4資產管理模塊
資產管理模塊一方面實現了糧倉企業用戶內部資產管理的把控,如糧食的出入庫、 庫存的調整;另一方面實現了對整體數據的匯總,如交易概況、趨勢圖和設備狀態總覽。 資產管理模塊負責企業內部資產管理和整體數據的嚴格把控和匯總。
( l )出入庫
入庫合約類圖如 4.8所示。
InDepotMgr
Public Functions:
getlmgHash(string) initInputDetail(address»string,string,string,uint256,uint256»string»string»string) initlnputlnfo(bytes 3 2,string)
Private Variables:
inDepotMessage
imag S to rage Ad d res s
inDepotDetail
圖 4.8 入庫模塊合約類圖
入庫時InputDepotMgr將糧食圖片上傳至IPFS,獲得bytes32類型返回值后將其存 入結構體。過程使用到了 ImgStorage.sol 中的 getImageHash 方法。調用方式如下所示。
address imagStorageAddress;
constructor (address _inDepotMgrAddress) public {
im agStorageAddres s = _inDepotMgrAddress;
}
ImgStorage imgStorage= ImgStorage(imagStorageAddress);
引用前需將ImgStorage的部署地址作為參數在InputDepotMgr的構造函數內創建合 約實例。
出庫合約 OutDepotMgr.sol 類圖如 4.9 所示。
OutDepotMgr
Public Functions:
getOrderlnfo(TransactionMgr.Order)
initDeliverylnfb(bytes32,string,Order,string,bool,PayMethod,lnvoic eDetail)
Private Variables:
inDep otMes s age
圖 4.9 出庫模塊合約類圖
核心函數如下:
function initDeliveryInfo (
bytes32 hash,
string memory goodKind,
TransactionMgr.Order memory _order, // 訂單結構體對象 string memory leaveWareHouse,
bool invoiceOrNot,
PayMethod payMethod,
InvoiceDetail memory invoiceDetail// 發票結構體對象
)public {
OutDepotDetail memory outDepotDetail= OutDepotDetail (_order, leaveWareHouse,
payMethod, invoiceOrNot, invoiceDetail);// 出庫詳情結構體對象
OutDepotlnfo memory outDepotInfo=OutDepotInfo (goodKind, outDepotDetail); inDepotMess age[hash] =outDepotInfo;
emit OutDepot (hash, outDepotlnfo);
}
首先通過 tuple 元數據先后初始化 OutDepotDetail 和 OutDepotInfo 結構體對象,然 后將交易哈希值與出庫數據形成mapping鍵值對,最后觸發出庫日志事件。
(2)區塊鏈賬戶錢包信息更新
賬戶錢包中包含MetaMask狀態(是否在線)、NetWork (以太坊賬戶所屬網絡)、 Account(當前賬戶地址)和Balance(地址在指定區塊以wei或eth為單位的余額)四項指 標。有助于用戶實時了解區塊鏈余額數據的變化。
開發過程中主要借助 Vuex 完成數據更新, Vuex 五個核心屬性包含: Module、 Action、
Mutation、 Getter、 State。
setinterval()函數按照指定的周期500ms進行數據刷新核心代碼如下: web3.eth.getBalance(store. state. web3.coinbase, (err, polledBalance) => {
if (err) { console.log(err)
} else if ( 'selnt (polledBalance, 10)! == store. state. web3.balance) { store. dispatch (pollWeb? , {
coinbase: store. state. web3.coinbase,
balance: polledBalance
})
}
})
dispatch 語句通過 Actions 里的 commit 項可間接調用 Mutations 里的 State 參數, 從 而進行State中數據的更改。組件更新后,頁面被重新渲染。
(3)權限控制 智能合約中用于改變合約狀態的函數,都會自動對每筆交易進行簽名,簽名的驗證 保證了當前調用者不可偽造性。而對于 constant、 view、 pure 類型的讀數據函數,只讀 取合約狀態而不改變合約狀態,任意的 msg.sender 可通過 eth_call 的底層方法不需要任 何簽名同樣能得到結果。此時,資產管理模塊中只允許管理員可讀的信息如庫存調整、 出庫撤銷等信息的安全性無法保證。為了實現更好的權限控制,系統在智能合約內部使 用簽名來驗證調用者身份,核心代碼如下:
modifier veri& (uint8 v, ytes32 r, bytes32 s) {
bytes32 hash=msg.sig;
address addr = ecrecover (hash, v, r, s);
require (isAllowed (addr, admins));
_;
}
首先調用者在調用各類讀數據函數前,用自身的以太坊地址通過secp256kl簽名算 法對msg.sig (calldata的前4個字節)進行簽名。然后分解出出簽名數據的(r,v,s)三元 組。最后將簽名對象連同三元組以參數傳入 Solidity 的內置函數 ecrecover 中進行解簽 名。若addr與調用者地址一致,可以確定調用者的身份是真實的。
4.3交互界面實現
根據第三章前端架構設計,本節主要利用Vue+Vue-router+Vuex+Axios進行用戶交 互模塊的構建,并簡要描述基于Vue.js進行前端搭建的實現過程。
開發過程中首先使用 vue init webpack 指令快速創建項目,然后根據需要使用 npm install -save安裝系統運行時的依賴,依賴除了 Vue全家桶之外還包括element-ui、echarts、 font-awesome 、ipfs-api、truffle-contract、web3 等。使用 npm 依賴安裝成功后和在 main.js 文件中進行正確掛載。最后使用路由守衛配合權限、白名單控制單頁面應用的界面跳轉。 全局路由守衛核心代碼如下:
const whiteList = ['/login','/register'] 〃設置白名單
router. beforeEach (async (to, from, next) => {//注冊一個全局前置守衛
NProgress.start() //進度條開始
document. title = getPageTitle (to. meta. title) // 設置頁面標題
if (getToken ()) {// 判斷用戶是否有 token
if (to. path === '/login') {//路由是/login頁,那么直接跳轉到首頁
next ({path: '/')
NProgress.done()
}
} else {
if (whiteLi st.indexOf(to. path)! == -1) {
next () //白名單中有的路由,可以繼續訪問
} else {
next('/login') //沒有的路由,跳回首頁
NProgress.done()
}
}
})
項目框架使用vue-element-admin,左側菜單用于讀取路由配置。在側邊欄中配置外 鏈,并在path中填寫了合法的url路徑。對于三級路由的添加,需在二級組件的<template> 下手動添加一個<router-view>,如此實現children嵌套。
本文實現的系統交互界面由主頁、系統管理頁、倉儲檢測頁、交易管理頁、資產管 理頁五個部分組成。由于交互界面較多,因此只通過系統截圖的形式對主要頁面進行了 展示。
4.3.1主頁
主頁負責匯總系統模塊的簡要信息,頁面的上中下部由三個組件組成。分別負責顯 示糧食品類、檢測設備、在線設備、離線設備的數量,設備預警、出入庫信息和糧食交 易數據統計。實現效果圖如4.10所示。
圖 4.10 主頁實現效果圖
4.3.2系統管理
系統管理包含多個子頁面,用戶注冊、用戶登錄、子用戶授權等。實現效果如下。
安徽省淮南省級糧食儲備庫
19840178119
經營范圍
糧食收購、儲存、代儲、銷售及代 轉運服務
法定代表人
經營場所
安徽省淮南市田家庵區田大北路1號
確認
取消
(a) 注冊頁
(b) 登錄頁
(c) 子用戶授權頁
圖 4.11 系統管理頁面實現效果圖
用戶注冊頁面如圖4.11 (a)所示。儲糧企業需要提供有效、清晰的營業執照與身份證 圖片。使用表單驗證,對 el-form-item 設置 rules 屬性,用于限制數據輸入格式,發現并 提示錯誤。對el-upload設置:befbre-upload="beforeAvatarUpload"屬性,判斷圖片上傳的 格式和大小。通過比較 fileList.length 設定上傳個數上限值。
用戶登錄頁面如圖4.11 (b)所示。企業登錄時,需提供20位以太坊地址,以供智能 合約數據驗證。
子用戶授權頁面如圖4.11 (c)所示。添加子用戶需要驗證管理員權限,并且要求子用 戶地址已經成功注冊。確認添加時將表單數據格式化成智能合約中對應函數形參的數據 類型,調用智能合約寫入數據。
4.3.3倉儲檢測
倉儲檢測分為對倉儲設備的管理和倉儲環境的檢測。包含設備列表、倉庫選擇、 檢測結果顯示、監測數據溯源等子頁面,設備列表實現效果如圖 4.12 所示。
設備錄入完成后,可通過設備列表查看設備信息并實時監控設備狀態。頁面顯示了 企業所持各倉的溫濕度傳感器設備名稱、設備類型、網絡類型以及倉庫內容。點擊操作 按鈕可查看設備詳情或編輯設備信息。對el-table設置:span-method="arraySpanMethod" 方法實現行數據合并。
(a)倉庫選擇頁
溫腿甌 打印
1號倉溫濕度報表
檢測賬號: 「中糧(0xcbbAaA08b3BFb911429E7852400F1 Dc98C8Beaf3) 檢測日期:2021/03/18 12:10:43
電纜號 第1層 第2層 第3層 第4層 第5層 第6層 第7層 第8層 第9層 第10層
第1根 *12.8 20.7 19.6 20.6 19.6 20.8 193 21.0 20.8 #21.3
第2根 *12.3 20.6 19.0 19.0 #20.9 19.9 20.4 20.1 207 19.9
第3根 *13.4 19.8 19.0 19.2 19.6 19.1 #20.2 18.8 #20.2 20.1
第4根 *12.6 19,9 192 19.6 19.3 19.3 20.0 19.1 #20.1 19.6
第5根 *11.5 19.8 18.6 17.1 #20.8 19.0 19.4 17.6 19.3 17.8
最高溫度 13.4 20.7 19.6 20.6 20.9 20.8 20.4 21.0 20.8 21.3
最低溫度 11.5 19.8 18.6 17.1 19.3 19.0 193 17.6 193 17.8
平均題 12.5 20.2 19.1 19.1 20.0 19.6 19.9 193 202 19.7
全倉 21.3 11.5 19.0
(b)檢測結果顯示頁
溫濕度記最
它 ■e
2碗 3電 4碗 5碗 6碗
日期:12021-03-18
全選 I 穌
顯示記錄 I 單條記錄導出到excel I 當月記錄導岀到excel
(c)監測數據溯源頁
圖 4.13 環境監測頁面實現效果圖
倉庫選擇頁面如圖4.13 (a)所示。該頁面通過卡片顯示用戶所持的倉庫集合,用戶通 過單個選中或全選倉庫開展對糧倉溫濕度的檢測。
檢測結果顯示頁面如圖4.13 (b)所示。結合功能模塊的測試結果,一個倉房對應多 個檢測設備,而且每個設備有多個數據采集點。報表匯總出全倉的最高溫度、最低溫度、 平均溫度、室內溫度、室外溫度、室內濕度和室外濕度值。
監測數據溯源頁面如圖4.13 (c)所示。該頁面主要負責的功能為查看倉庫指定時間 段內的測試記錄以及測試報告的導出。選中倉庫并選擇時間區間,點擊顯示記錄,從數 據庫或智能合約中獲取歷史數據。
4.3.4交易管理
交易管理模塊包含交易列表、糧食溯源碼查詢等子頁面。實現效果如下。
交易列表頁面如圖4.14 (a)所示。該頁面負責交易數據的查詢搜索和顯示。訂單發布 成功并被上下游企業接收后,交易正式開展。數據列表包含每筆糧食交易的交易哈希、 提交時間、接收者地址和訂單狀態。列表顯示結合自定義過濾器(filter),進行數據格 式化。
Q篩^^ £3
TxHash:
供應商:
目纏列表 0x454be7795af0ba502a201 糧食溯源碼: 356452596966771626 采購方:
提交時間: 訂單狀態:
編號 交易哈希 提交時間 接收者地址 訂單狀態 撮作
1 0x887e3520f06156498d2d8320f7ef96d6 b83c5ea001ce8072e0f89fca7982c50d 2021-02-15 12:24:27 0x1BB611c5e9cEF84aCF3065B1b1eb128e3057E665 待發貨
2 0x721fa75f639162569d99d082f6f2M500
94e850414 31 c4445f88db3d06dc2cea 2021-02-16 14:24:29 0xADe2DEa5c8A206C69778836dEE9986FbACcbD4B 已S貨
3 0x454be7795af0ba502a2016c5cd30859d ad29c86f2e3968d4e1171 a5a 1 fa3e5cf 2021-02-16 16:57:40 0x2C363d44B2AEf98A1 F 14e6EEF4E32E7fd97B 12a3 已關創
4 0x65d11a914e1f16872d917776f4e340aff
3dcf3613f8873d0d8232cc540de 1 c83 2021-02-18 17:03:00 0x0Deb70EadC75240592ebAa8B4Af35BeCd0705F16 已換
5 0xbd7b11337e3be9a8476b8fd2c9dde41 c
d7c2cft)7028a7d07613ac9b4858a3ee5 2021-02-19 16:16:16 0x52C208c108FA23D 1 B0d4e518871 c4aa8024ca9e4 待發貨
6 0x3d6ca4f91812996af3d1d53905f2e591
32ddae5dc6ac38c3b 1 cbd8ebf4ddca0c 2021-02-20 12:24:27 0xcB2D1eB7A5a06FD9CB2bA4D29B82Ea0634074462 待接單
7 0xdff65919451173000cc8c85fb53f79fcff0
12c210e9ffffa303c4130a3d07802 2021-02-21 14:24:29 Oxb 1 B4688Ed098fBAD682EeBA2A96Cc3066e5EcDC7 已關閉 詳情
8 0x657d66e736972d8cac9b20b97fe8e4(a 2021-02-22 16 57:40 0xfCb7604A4887f465a794D25D8c67F0D69bcD5A75 待發貨
共114條 5條/頁 | 2 3 4 5 6 - 23 > 鴿往 1 頁
(a) 交易列表
(b) 糧食溯源查詢
圖 4.14 交易管理頁面實現效果圖
糧食溯源查詢頁面如圖4.14 (b)所示。鍵入byte32類型TxHash或糧食溯源碼,實 現數據檢索。溯源信息顯示了糧食在供應鏈上流通數據信息。
4.3.5資產管理
資產管理模塊包含糧食資產管理的總覽、出入庫信息登記、區塊鏈錢包信息等子頁 面。實現效果如下。
資產管理總覽頁面如圖4.15 (a)所示。該頁面負責顯示企業糧食品類的庫存分布和 倉庫數據的詳細信息。模塊根據糧食占比使用echarts繪制分布圖,設置el-table的expand- change 屬性,完成倉庫信息的折疊顯示。
區塊鏈錢包信息頁面如圖4.15 (b)所示。該頁面負責動態顯示包括Metamask導入狀 態,區塊鏈網絡類型、當前區塊鏈賬號以及賬戶余額等區塊鏈錢包信息。
(a) 資產管理總覽
區塊鏈錢包
7 Metamask installed
Q Network: Ganache Blockchain
O Account: 0xcbbaaa08b3bfb911429e7852400f 1 dc98c8beaf3
⑥ Balance: 99692792900000000000 Wei //99 6927929 Eth
(b) 區塊鏈錢包信息
重量
糧食名稱
當即優質麥
上游企業
0x1 BB611 c5e9cEF84aCF3065B11
入庫備注
來自十八里鋪農莊
產地
阜陽市
安徽省
潁上縣
存入指定倉庫
[駝
12000kg
入倉日期
收成日期
同 2021-03-01
2020-06-10
檢測員
保管員
王超
大梨
上傳食品圖片
取消
確認入庫
(c) 糧食入庫
城市
街道
區f縣
稅額
操作
無
無。有
確認出庫
糧食名稱
出庫備注
訂貨人
指定出貨倉庫
結算方式
類型
個人
出庫信息
取消
安徽省
苞無發票
岀庫給臨泉雙全食品加工廠
當季優質稻
下游企業 0xADe2DEa5c8A206C69778836(
李林
聯系方式 19840176581
重量 11000 kg
2況
解放路1仁號
臨泉雙丹品加15800 工廠
納稅人識別號 備注
497792193095
8146724
阜陽市
臨泉縣
抬頭
編輯
(d) 糧食出庫
圖 4.15 資產管理頁面展示圖
糧食出、入庫頁面如圖4.15(c)(d)所示。頁面輸入糧食名稱,上/下游企業區塊鏈地 址、出入庫重量、備注等信息,點擊確認,之后系統通過智能合約將出入庫數據存入 mapping,并觸發對應event事件向用戶返回提交結果。完成對出入庫信息的登記。
4.4合約部署與調用
4.4.1合約部署
如本章4.1節所言,智能合約的開發框架基于Truffle。合約部署時需要注意文件的 名稱定義,合約之間的引用依賴關系以及配置文件的參數配置。詳細步驟如下:
Step1 :使用Ganache快速搭建一個以太坊私有鏈網絡。該網絡包含10個測試賬戶, 每個賬戶擁有100個以太幣。默認RPC Server地址為HTTP://127.0.0.1:7545,網絡ID是 5777,默認參數可以更改。
Step2:在Truffle項目中打開配置文件truffle-config.js,指定networks配置項里 development的網絡信息。其中host和port應與Ganache 一致。配置內容如下: networks: {
development: {
host: "127.0.0.1",
port: 8545,
network_id: "*",//任意以太坊網絡id
}
}
Step3:在工程的migrations文件夾下添加js腳本文件,文件名前綴必須為數字。
Truffle 按照部署文件名的數字前綴,從小到大地順序執行部署文件。部署文件格式如下 const MyContract = artifacts. require ( MyContract ) module. exports = function (deployer) { deployer.deploy (MyContract);
};
對于復雜的智能合約依賴關系:
1)若合約 a 的部署,需要在合約 b 部署成功之后進行。應將合約 b 的部署命令作為合 約a部署命令的回調:
deployer.deploy (ContractA). then (function () {
return deployer.deploy (ContractB, ContractA.address);
}). then (function () {})
2)若智能合約a與合約b之間存在著引用依賴,需通過link函數建立鏈接關系。調用
語句使用 depolyer.link(ContractA,ContractB)。
Step4:在VSCode終端里先后鍵入truffle的compile、migrate命令實現合約文件的編
譯和部署,部署完成后會生成含有合約地址和合約ABI等數據的JSON文件。圖4.16是
通過 Ganache 查看到的合約部署結果。
圖 4.16 合約部署成功
4.4.2合約調用
系統運行過程中,合約調用產生的交易需通過 MetaMask 錢包進行確認。因此 MetaMask 中區塊鏈網絡應與合約部署時 Ganache 的測試網絡參數一致。為保證合約調 用前端Web3接口與geth通信鏈路正常。根據調用邏輯需要,選擇性使用async異步方 法,完成智能合約方法對于區塊鏈的數據請求,詳細步驟如下。
Stepl :在工程入口文件main.js中引入全局變量Web3。根組件App.vue在mounted 生命周期鉤子中調用initWeb3()函數,完成對單例對象web3Singleton的初始化。函數核 心代碼如下:
const Web3 = this. $Web3;
if (window. ethereum) {
// use MetaMask's provider
this. $store. state. web3Singleton = new Web3(window. ethereum);
await window. ethereum. enable ();
} else {
//use Ganache
this. $store. state. web3Singleton = new Web3(new Web3.providers.
HttpProvider("http://127.0.0.1:8545")
);
}
Step2:各界面組件使用API: new web3.eth.Contract(abi,adress)創建合約實例。其中 abi是合約實例化的JSON接口,adress是合約地址。核心代碼如下所示。
try {
const networkId = await this.$store.state.web3Singleton.eth.net.getId();
const deployedNetwork = userMgArtifact.networks[networkId];
this. Dapp.meta = new this. $store.state.web3Singleton.eth.Contract(
userMgArtifact.abi, deployedNetwork.address);
} catch (error) {
console. error ("Could not connect to contract or chain.");
}
Step3 :合約實例調用合約方法。根據合約函數類型,調用方法無非就兩種:
Methods.myMethod.call 與 Methods.myMethod.send。 call 方式是本地調用,無需發送任何 交易,不會消耗Gas,不能更改智能合約狀態。而send方式會創建交易,調用之后會返 回交易hash值,解碼過的事件、交易收據receipto并廣播到網絡,等待礦工打包,并消 耗一定量的 Gas。
Step4: MetaMask 確認。如圖 4.17 所示,顯示了合約調用時 MetaMask 的通知和合
約交互詳情頁面。
圖 4.17 MetaMask 錢包交互通知與詳情
4.5IPFS 部署與調用
系統協同IPFS與智能合約進行用糧/儲糧企業或個體戶的營業執照、食品經營許可 證、法人身份證件等圖片類數據的去中心化存儲。存儲過程分為兩步:寫數據時,通過
異步請求將圖片上傳到IPFS集群,將得到圖片的Hash地址存儲到區塊鏈。取數據時, 先從區塊鏈讀取圖片Hash地址,再根據其從集群讀取數據。go-ipfs是IPFS的Golang 語言版本實現,本文使用 go-ipfs 完成 ipfs 環境搭建,使用 ipfs-api 實現功能模塊對 ipfs 網絡的訪問。
4.5.1IPFS 部署
首先在環境變量path中添加go-ipfs目錄,配置IPFS主節點的地址為本機IP地址。 鍵入ipfs init子命令可在本地初始化一個IPFS節點,使用ipfs add子命令將指定的文件 添加到 IPFS, IPFS 會根據文件的內容生成一個哈希值。
IPFS網絡只能通過內容的哈希值來訪問文件,使用ipfs cat子命令即可完成對文件 內容的查看。執行ipfs daemon子命令則以守護進程的方式將節點接入IPFS網絡。如圖 4.18展示了 IPFS網絡節點的啟動。
lwhODESKTOP-lUEOKJS MINGW64 -/Desktop $ ipfs daemon
Initializing daemon… go-ipfs version: 0.8.0 Repo version: 11 System version: Golang version: Swarm listening Swarm listening Swarm listening Swarm listerring Swarm listerring Swarm listening Swarm listening Swarm listening Swarm listening Swarm listerring Swarm listerring Swarm listerring Swarm listening Swarm listening Swarm listening
圖 4.18 IPFS 節點啟動成功
盡管可以以命令行形式操作 IPFS 節點進行文件的上傳與下載操作,但是為簡化操 作,系統在開發過程中采用了封裝更友好的ipfs-api(版本號:V26.1.2)。
4.5.2IPFS 調用
圖片上傳時的核心代碼如下。根據ip、端口和傳輸協議形式,定義ipfsAPI對象, 然后以buffer數據流的形式寫入進行異步請求。在添加成功后,response[0].Hash即為返
回的日志哈希值。
upload2ipfs(render) {
let that = this;
// connect to ipfs daemon API server
let ipfs = ipfsAPI ("localhost", "5001", {protocol: ""http”}); let buffer = Buffer.from(render. result);
ipfs.add(buffer). then((response) => {
//use contract method
that. saveImgHash (imrgName, response [0]. hash)
}). catch((err) => {
console. error(err);
});
為解決IPFS跨域時的net::ERR_CONNECTION_TIMED_OUT錯誤,進行了跨域資 源共享 CORS 配置。分別鍵入 ipfs config 子命令“ipfs config -json API.HTTP Headers. Access-Control:”依次配置如下參數:
-Allow-Methods '["PUT", "GET", "POST", "OPTIONS"]'
-Allow-Origin '["*"]'
-Allow-Credentials '["true"]'
-Allow-Headers '["Authorization"]'
-Expose-Headers '["Location"]'
如圖4.19所示是通過IPFS的Web可視化界面觀測到的被固定的文件hash列表。
QmcYDBF4FeY9pv5nnDyzyzhFMNF89z6jgwkpALiY5Zjt2C
I_I QmcYDBF4FeY9pv5nnDyzyzhFMNF89z6jgwkpALiY5Zjt2C
H QmNhrdvHWUiYJZfLuGxu2J7kc57UvHDl6M3i7kYFbtxbmR
I―I QmNhrdvHWUiYJZfLuGxu2J7kc57llvHol6M3j7kYFbtxbmR
QmQPeNsJPyVWPFDVHb77w8G42Fvo15z4bG2X8D2GhfbSXc
I 1 QmQPeNsJ PyVWPFDVHb77w8G42Fvol5z4-bG2X8D2GhfbSXc
QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn
I > QmUNLLsPACCzlvLxQVkXqqLX5RlX345q時
QmVZJb3qEKF1CPfYWZasorwR5XuvL4dinULfzbMkQEYAs8
QmVZ3 b3qEKF !CPfYWZasorwR5Xuv L4dinll Lfz bMkQEYAsS
QmfQS4vm9YZTAyGZEkDqm81xripwsK3NgqfNkbCdoeEw5i
QmfQS4vm9YZTAyGZEkDqm81xripwsK3NgqfNkb€doeEw5i
圖 4.19 IPFS 內文件哈希列表
從IPFS讀取數據的核心代碼如下,其中getImgHash()是用于獲取圖片的Hash地址 的智能合約函數,response是從IPFS網絡獲得的原始數據,格式是8位無符號整型數組 類型,然后使用uint8ArrayToStr方法將其轉換為string字符串。轉換成的字符是8Bit字
節碼的 Base64 編碼數據。最后通過 v-show 方法完成界面上 el-upload 控件圖片的顯示。 getlmg () {
ipfs.cat (contract. getImgHash (). call ()). then((response) => {
let strContent = this. uint8ArrayToStr (response);
this. imgSrc = strContent;
this. show = true;
});
}
4.6系統測試
4.6.1智能合約測試
(1 )Remix 測試
插件配置完成后,首先通過compile菜單進行智能合約的編譯,該模塊可切換部署 環境,鏈接到本地Ganache或MetaMask測試鏈網絡。編譯無誤后,Remix部署結果如 圖4.20所示,輸入各類函數的參數,完成賦值,進行合約函數的測試。
圖 4.20 Remix 編譯部署結果
根據智能合約的設計方案,實現的合約有DeviceMgr、AuthorizationMgr、TransferMgr、 OrderMgr、 MeaureMgr、 OutDepotMgr、 InDepotMgr、 StockControlMgr、 ImgStorage、 UserMgr和TransactionMgr。通過Remix對所有合約進行編譯、部署和方法調用的執行 結果表明,所有智能合約編譯、部署和調用皆無誤。
為驗證智能合約函數調用結果是否符合預期,使用 Remix 的 SOLIDITY UNIT
TESTING模塊生成行測試腳本對合約進行單元測試。編寫測試內容時在beforeAll函數 體內創建被測試合約的對象,在各類check方法中調用合約函數并傳入參數。假設合約 函數返回值是a,期望值是b,使用Assert.equal(a,b)語句判斷合約函數返回值是否與預 期值相等,若不等表明測試不通過并且產生錯誤提醒。如圖 4.21 所示,顯示了對系統的 11 個合約源文件進行單元測試的結果, 11 個源文件均已測試通過。
曲度:10/10
PASS testSuite (browserrtests/UserMgc_test.sol) d Before all
•/ Check init register
•/ Check register user
J Check find register
•J Check init user
/ Check find user
/ Check is exit user address
J Check is exit username
•J Check find user address by username
/ Check find user username by address
Result for browser/testsAJserMgr_test.sol
Passing: 10
總用時:2.11s
testSuite (browserrtests/MeaureMgr_test.sol)
圖 4.21 合約源文件測試結果
(2)自動化漏洞檢測
通過以太坊官方推薦的一款靜態智能合約分析工具一Slither對智能合約進行自動化 漏洞檢測和自動優化檢測。Slither是一種用Python 3編寫的靜態分析框架。相較于其他 安全性檢測工具,提供超70多項的漏洞檢查模型,而且具有速度快、檢測準確性高的 先天優勢。以UserMgr為例,經過72個檢測器分析結果如圖4.22所示,該合約并未存 在漏洞項。依次測試其他合約,均未發現漏洞。
L WH: - / 桌 面 / Ma i rt/ Di s s e r t a t i onDapp / cont r acts$ s I i t h e r UserMgr. s o I Compilation warni rtgs/errors o n User Mgr. sol :
Wa r n i ng: S P DX license i d e nt i f i er not p r o v i d e d i n source file. Be f or e publishing, cons
i d e r adding a c o mme nt c o n t a i n i ng "SPDX- Li cense-l denti fi er: <SPDX- Li cense>" t o each s o
u r c e file. Us e "SPDX - Li cense - I dent i f i er: UNLI CENSED" for non - open - source code. PI ease
see https://spdx.or咅 for mo re i nformati on.
--> UserMgr. sol
I NFO: SI i t her: UserMgr. sol analyzed ( 1 co nt ract s wi t h 7 2 detectors), 0 result(s) found INFO: Slither: Use https://crytic.io/ t o get access t o additional det ect ors and Gi t h u b integration
L WH: ~/桌 面 / Ma i n/ Di ssertati onDapp/contracts$ |
圖 4.22 Slither 對智能合約漏洞檢測結果
4.6.2功能測試
上一節中智能合約的Remix單元測試和漏洞測試結果滿足設計要求,本節將智能 合約部署到以太坊測試鏈中展開功能測試。
系統的測試用例和測試結果如表4.11所示。
表 4.11 功能測試用例及結果
測試單元 測試方法 預期結果 實際結果
注冊 填寫注冊信息進
行新用戶注冊 對注冊信息校驗并將 新用戶注冊上鏈。智能 合約注冊日志內均能 查到注冊信息 符合設計要求
登錄/登出 多次登錄登出 在智能合約映射列表 內 查找 出 用 戶 信息 成 功登錄登出 符合設計要求
用戶資料修改和子
用戶授權 分別修改用戶所
在權限內外的資
料 成功修改用戶資料且
對子用戶授權過程權
限限定 符合設計要求
檢測設備管理 多次錄入設備信
息,批量監控設備
狀態 監控設備狀態,向區塊
鏈錄入設備信息 符合設計要求
環境監測 多次檢測糧食儲
藏環境溫度濕度
數據 檢測過程流暢, 智能 合約對環境檢測數據 寫入正常 符合設計要求
檢測數據存證與操
作 查詢倉庫指定時
段的溫濕度歷史
數據 從智能合約讀取到測 試數據,協同數據庫精 準查詢。報表和趨勢圖 顯示無誤 符合設計要求
交易發起 錄入訂單,向上游
企業發布需求 系 統響 應 請 求并向 上 游企業推送訂單 符合設計要求
表 4.11 功能測試用例及結果(續)
訂單管理 查看、修改、刪除
訂單信息 完成訂單數據的相關
操作 符合設計要求
交易溯源 對交易列表進行
交易溯源查詢 觸發智能合約交易事
件保存交易哈希值和
交易數據 符合設計要求
出/入庫信息錄入 進行糧食的出入
庫數據錄入 出 / 入庫信息保存到智 能合約 storage 結構體 中,永久保存 符合設計要求
庫存調整 企業管理員發出
調整糧食庫存請 求并模擬監管機 構同意該請求 庫存數據成功更新 符合設計要求
糧食溯源 根據溯源碼對糧
食進行溯源查詢 得到該糧食在供應鏈
上的出入站信息 符合設計要求
資產管理匯總 錄入訂單,觸發出
入庫交易 交易概況、趨勢圖和設
備狀態整體資產數據
匯總 符合設計要求
功能測試表明,系統的各項用例測試的結果符合設計要求,實現了需求分析中的各 項功能,能夠完全支撐業務邏輯。
4.6.3性能測試
本系統使用區塊鏈作為核心技術的目的是為了保證業務信息的去中心化存儲與防 篡改。本節首先采用多線程模擬請求測試多用戶下的系統性能,然后使用 ETH 官方客 戶端 Geth 提供的交互式命令控制功能,搭建區塊鏈節點測試系統的去中心化存儲與防 篡改性能。
(1)多用戶請求下的性能測試。
通過創建500個虛擬用戶發起糧食入庫請求,測試得到了 Dapp的響應時間、事件 響應率、CPU占用率和內存使用率。測試結果如表4.12所示。
表 4.12 多用戶請求下的性能測試結果
測試指標 實際值 預期值 測試結果
響應時間 2.9s <5s 符合性能需求
事件響應率 99.7% 100% 符合性能需求
CPU 占用率 48.6% <60% 符合性能需求
內存使用率 41.2% <60% 符合性能需求
對比可知,系統各項測試指標均在預期范圍內,滿足實際應用場景。
(2)基于區塊鏈的數據去中心化存儲與防篡改測試。
account balance:25000000000000000000
gas:115847
C經發送交易,交易地址:0x55e51cd241a08bb25d0a5bfaed4fa2bd4119f5ecc229e549e5f869a320d26313正在等待挖礦.… 智能合約部署成功,地址:0xa93faae4clec9e0602b21ed8e39a2030b803e892
圖 4.23 發起交易
圖 4.24 節點共同記賬
> INFO [04-02119:50:55. 937] Looking for peers
[04-02119:50:55. 937] Block synchronisation started
[04-02119:50:56. 271] Importing sidechain segment
圖4.25節點下線再次啟動時的數據同步
首先通過 geth 初始化創世區塊,之后成功搭建了本地 5 節點以太坊聯盟鏈。圖 4.23 是系統對區塊鏈節點部署合約并發起交易時的控制臺輸出。節點開展的交互數據,并不 單一存儲在某一個節點上,每一筆的交易信息都將打包成區塊同步到其余節點。圖 4.24 顯示了礦工挖礦時,各節點之間共同記賬的情況。先保持其中一個節點為關閉狀態,然 后與其余節點交互以向區塊鏈寫入數據,之后再將關閉的節點啟動,如圖 4.25 所示,節 點再次啟動后,會對區塊鏈賬本自動復制,同步其他節點的數據。系統的去中心化和共 同記賬屬性得以驗證。
(3)IPFS 去中心化存儲與對區塊鏈存儲效率的改善測試
選取系統的實際場景,驗證 IPFS 的去中心化存儲特性。注冊時,將儲糧企的營業 執照上傳至IPFS網絡。之后關閉本地IPFS節點,如圖4.26所示。根據圖片數據的哈希 值,使用其他物理機對 IPFS 集群進行訪問,仍然能夠訪問到上傳的原始圖片文件。如 圖4.27所示,系統圖片數據的成功訪問,表明了本地節點的宕機并不會影響IPFS網絡 的運行情況,其他節點對目標節點上數據的成功訪問,也驗證了 IPFS 的去中心化存儲 特點。
API server listening on /ip4/127. 0. 0. l/tcp/5001
WebUI: http://127. 0. 0. 1:5001/webui
Gateway (readonly) server listening on /ip4/127. 0. 0. l/tcp/8080 Daemon is ready
Received interrupt signal, shutting down…
(Hit ctrl-c again to force-shutdown the daemon.)
PS C:\Windows\system32>
圖 4.26 關閉 IPFS 集群節點
圖 4.27 IPFS 網絡去中心化測試
為檢驗IPFS對存儲效率的改善效果,測試對比系統單獨使用區塊鏈與結合IPFS共 同存儲數據時的空間占用與 Gas 消耗情況。由于智能合約未提供直接操縱文件的接口, 加之gasLimit的限制,鏈上一次性無法存入整個圖片數據。因此先將圖片轉換成base64 字符串,上傳時再將字符串分段逐個調用合約方法。糧食入庫過程中,糧食圖片大小為 21.2KB,先后經過兩次上傳。從Ganache控制臺觀測到的Gas消耗如圖4.28所示。
[下午2:03:47] eth_sendRawTransaction
[下午2:03:49] Transaction: 0x6c699b9a5Oiefe3396d6c23d8ce75ce96bceae8c3d543398ieefb2ebea6fadlb
[下午2:03:54] Gas usage: 2574662
[下午2:03:54] Block Number: 98
[下午2:03:54] Block Time: Tue Apr 13 2021 14:03:49 GMT+e80e (中國標準時間)
[下午2:84:58] eth_sendRawTransaction
[下午2:05:01] Transaction: exa48b81bfdf7ed2947e78e2b2cbee43e98alfba29c982b7b2582ceiea5efale9a
[下午2:85:86] Gas usage: 1383962
[下午2:05:06] Block Number: 99
[下午2:05:06] Block Time: Tue Apr 13 2021 14:05:01 GMT+08ee (中國標準時間)
圖 4.28 圖片分段上傳時的 Ganache 日志輸出
使用區塊鏈存儲圖片時一共消耗3958624 gas,而結合IPFS的共同存儲只消耗了 803376 gas。相比原始base64字符串數據,IPFS集群的文件哈希值大小僅為54B。無論是在存 儲容量還是Gas消耗,兩者性能指標都不在同一量級上。而這僅僅是大小為21.2KB對 一個區塊鏈節點上產生的影響,鑒于系統以后的擴展性,若同一份數據被重復存儲到諸 多用戶將耗費巨大的存儲空間。而且對空間占用更大的數據進行分片同樣會因操作繁瑣, 導致效率低下。綜上, IPFS 能從一定程度上緩解了區塊鏈的數據爆炸問題。
4.7本章小結
本章開發并實現了基于區塊鏈的智慧糧倉綜合信息管理系統,結合智能合約,運用 函數修改器和可見性限定符規范訪問權限,完成了對不同值類型、引用類型和映射數據 的鏈上存儲。除此之外,還有恰當的錯誤和異常處理、事件與日志捕獲。結合靜態分析 工具Slither繪制了智能合約的繼承拓撲圖,合約方法調用關系圖,完成了代碼優化。
利用去中心化的文件系統IPFS,把用糧/儲糧企業或個體戶的營業執照、食品經營 許可證、法人身份證件等圖片類信息存儲在IPFS網絡中并把文件的Hash值保存在區塊 鏈上,做到大容量數據的永久存儲和有效追蹤,緩解了區塊鏈系統的存儲壓力。通過對 糧倉出入庫、糧情監測和糧食交易等信息的實時上鏈,實現糧食資產可計量、可估價。 結合 MongoDB 完成信息化管理過程中數據在鏈上和鏈下的雙重存證和溯源,使查詢效 率明顯提升。
系統測試中首先通過Remix對智能合約開展了方法測試、單元測試和自動化漏洞檢 測,然后對系統功能和性能進行了測試。測試結果表明系統的智能合約準確無誤,系統 各項功能符合設計要求并且具有去中心化和防篡改特點,能夠滿足實際需求。
第五章基于區塊鏈的Raft共識算法的改進
第三、四章所提出的系統以聯盟鏈作為依托要求各區塊鏈節點同步記賬,由于網絡 節點的位置分散,可靠的網絡和節點才能使消息穩定傳遞。為使共識算法具備較低的復 雜度和較高的容錯性用以確保糧倉信息的安全傳輸。在保證Raft清晰的算法邏輯之下, 本章提出了 Raft共識算法的拜占庭容錯優化一BFT-Raft算法,該算法既保持了 Raft的 強一致性和可理解性,又在集群存在拜占庭式故障的情況下具有安全性,容錯性。
5.1Raft共識算法改進方案
5.1.1傳統Raft算法瓶頸
傳統 Raft 算法中 Leader 選舉和日志復制共同為 Raft 提供安全保證。即使集群中的 任意少數節點發生故障,Raft也可確保系統的正確性和可用性。但是,在存在拜占庭節 點的情況下,Raft的安全性和可用性會受到損害。
(1)Leader 選舉:按照傳統 Raft 算法,當 Leader 發生故障無法向 Follower 發送心 跳時,Follower將開始新的任期并觸發新的選舉。由于超時時間于[150ms,300ms]內隨機 選擇,所以任何節點都可以隨時觸發選舉并終止當前任期,拜占庭節點可以毫不費力地 通過永久選舉或偽造選票成為集群中的領導者。此外拜占庭式的追隨者即便是在接收當 前領導者的心跳信號時也仍可通過觸發選舉增加成為領導者的可能。這些都將破壞 Raft 的可用性。
(2)日志復制:因為Raft算法是強領導人模型,Leader作為客戶端和集群其余節 點之間的單向聯系,在接收客戶端請求后,負責日志條目復制,指示副本存儲和提交日 志條目,最后做出響應。拜占庭 Leader 可能會修改客戶的請求并違反正確性。其能在 一定數量的副本安全地記錄之前,指示集群提前提交日志條目,如果其他節點發生故 障并且該條目未成功復制到狀態機內,則該條目將會永遠消失,從而導致節點間的正 確性沖突,破壞Raft的安全性。
由于Raft不能阻止拜占庭式節點成為領導者,因此如果曾經選舉過拜占庭節點成為 領導者,則系統可能會對客戶端提供錯誤響應或忽略客戶端請求。此外,即使非惡意的 拜占庭節點如果不按預期方式處理RPC,也可以輕松地破壞協議。上述示例表明,拜占
庭節點可以通過多種方式破壞Raft算法,算法需針對上述情況進行相應改進。
5.1.2BFT-Raft 算法模型
BFT-Raft旨在創建一個在f個故障節點面前仍保持安全的協議,錯誤節點可以任意 行為并發送不正確的消息。
算法假設拜占庭節點具有網絡控制權:即可以任意延遲來自任何節點的消息(包括 來自非故障節點的消息)。假設同步性很弱,由于消息不能無限期地延遲,算法在每個 任期的超時中引入指數回退,以便最終存在一個任期,必須在此時間區間內選舉一名無 過失的領導者。假設客戶端是受信任的,并且客戶端提出的任何真實請求都可以應用于 狀態機中。
對于BFT-Raft算法,不僅要容錯故障節點,還要容錯作惡節點。當集群節點數為N, 存在f個拜占庭節點時,為使異步系統仍保持活性和安全性,需至少Q個節點對消息達 成共識。N和Q應滿足下列關系,這點和PBFT類似。
N = 3 f +1
\Q = 2f +1
不同與傳統Raft算法,選舉階段Candidate所需獲得的票數并非半數以上,而是Q 數目以上才有當選為Leader的能力。在日志復制階段,同樣需至少收集2f+1個節點成 功追加的消息才能確定日志被安全復制。這樣可以確保即使出現f個拜占庭節點,也至 少包含一個非拜占庭節點使集群達成共識。
圖5.1給出了 BFT-Raft集群的網絡拓撲結構。為防止拜占庭節點制造投票消息以人 為地滿足定額Q,算法為每個服務器和客戶端預先配置了自己的唯一私鑰以及所有其他 服務器和客戶端的公用密鑰集。使用橢圓曲線加密技術進行非對稱簽名和驗證,無論何 時通過服務器或客戶端在網絡中發送消息,都將使用發送方的私鑰對其進行簽名。通過 使用發送方對應的公鑰,任何接收者都能夠驗證其接收到的消息所屬發件人的身份。
將D(m)定義為消息m的SHA-256哈希,計算出消息的哈希并對哈希簽名。將<m> 表示為節點i在此簽名下發出的消息。<m>L是由當前Leader簽名的消息,<m>c是由 客戶端簽名的消息。每當成員a從節點B接收到消息<m> p時,a都會使用0的公鑰來 驗證消息實際上是否是由0發送的。如果驗證失敗,則a將忽略該消息。這樣,惡意節 點無法欺騙其他節點的消息,防止拜占庭式服務器偽裝成服務器或客戶端。
5.2BFT-Raft的設計與實現
5.2.1Leader 選舉
在含有惡意節點的系統中,傳統 Raft 算法的 Leader 選舉可能存在以下問題:
(1)若Leader是拜占庭節點,其可以很好地維持心跳。避免觸發“time out”條件,這 樣便不會頻繁地觸發 Leader 選舉,從而一個 Leader 可能延續多個任期。
( 2)即便觸發 Leader 變更,如果多個 Follower 在同一時刻都成了候選人。盡管系統 隨機重試后,不同候選人被設置不同的超時時間‘Leader也可能使其消息是首先發送出去, 因此將始終被選中。或把該時間拉長,以便增加選舉成功的概率。
(3)若部分Follower節點是拜占庭節點,其可以在選舉過程中多次投票或不做任何舉 動,以此造成一個任期內選舉出多個Leader或Cadidate瓜分選票的情況,阻止系統的正常 運行。
(4)故障節點可以忽略超時并立即觸發Leader選舉,小概率情況下會通過兩個故障節 點的協調,在兩個節點之間來回切換Leader,防止任何工作被提交。
因此, BFT-Raft 放棄了原 Raft 的領導人選舉的方式,轉而采用受 VIEW-CHANGE 過程影響的循環算法。為每個節點分配一個標識號。Leader選舉發生在每個節點固定的超 時時間之后,若N為節點總數(即3f+1),對于每個提議的項t,只有具有標識符t mod N 的節點才能成為Leader。由于Cadidate在節點之間循環,因此故障節點無法控制Leader 的選舉。每個節點的投票方式增加了形成共識的可能性。
原 Leader 選舉方式雖改變,但選票的收集過程仍被延續使用。算法保留原遠程調用 協議RequestVote RPC并增加參數,而且相對之前要至少多收集f個來自Follower節點 的投票才能保證選舉成功。 Leader 的選舉按照以下步驟進行:
Step1 :
a) 當系統初始化時,集群節點均為Follower,所有節點公平競爭。在選舉時間段內隨機 重試進行選舉請求。
b) 在系統運行過程中,當Leader收到客戶端請求后在一定時間段內客戶端未收到其請 求操作的結果,則客戶端會將請求廣播到所有節點,該廣播會在Leader出現故障的 情況下觸發領導人的超時選舉。此時的Leader變更如圖5.2所示。
圖 5.2 BTF-Raft 響應超時后的 Leader 變更 上述兩種情況均向集群服務器 id n = t mod N(t 是新任期)發送一個 StartElection RPC 請求,請求參數如表 5.1 所示。
表 5.1 StartElection RPC 請求參數說明
參數 描述
type 消息類型
term 候選人的任期號
start_term 開始選票任期
Step2:服務器接收2f+1個StartElection請求并成為t期的候選人。廣播一個包含/、 對 t 的 2f+1 個簽名的 StartElection 請求以及最新追加的日志條目等信息的 RequestVote
RPC。請求參數如表5.2所示。
表 5.2 RequestVote RPC 請求參數說明
參數 描述
type 消息類型
term 候選人最新日志條目對應的任期號
start_term 開始投票的任期
start_votes 節點對應的票數
last_commit 候選人最新日志條目的索引值
last_entry 候選人最新追加的日志條目
last sig 簽名的請求
Step3: Follower節點收到RequestVote,如果term較低則忽略。若該term更高, Follower將驗證2f+1個簽名的StartElection請求并轉換為Follower。節點驗證附加的日 志條目,并檢查其是否至少比自己追加過的日志條目索引一樣最新。若驗證通過,以 GrantVote 答復,響應參數如表 5.3 所示。
表 5.3 RequestVote RPC 響應參數說明
參數 描述
type 消息類型
term 當前任期號,用于候選人更新自己本地的term值
voteGranted 若候選人得到了 Follower的選票,則為true,否則為false
start_term 開始投票的任期
Step4:候選人接收到2f+1個GrantVote消息后,候選人轉換為Leader,并立即通過 2f+1個GrantVote消息將appendEntry發送給彼此的服務器,以證明其身份。
對于Step1,可能會發生超時是因為Follower未從Leader處收到appendEntry,候選 人無法獲得所需數量的 GrantVote 消息,或者客戶端廣播了請求已超時的消息。每次超 時后,t都會增加。每個term只有一個有效的候選人。通過使用方程候選人九=t mod N, 算法有效地遍歷了集群中的每個節點。
對于Step2,服務器等待一定數量的StartElection請求,以確保拜占庭服務器無法連 續觸發選舉周期。
對于Step3,保留原Raft屬性,算法在Leader選舉部分加入了一個限制:任何Leader 都應擁有之前任期提交的全部日志條目。如果候選人沒有最新的日志,則服務器可以拒 絕對其投票。
對于Step4, 一旦服務器收到帶有有效證明和較高term的appendEntry,其將立即轉 換為 Follower 并相應地更新任期號。
5.2.2日志復制
與傳統Raft相同,條目(entry)有以下定義:
•data :請求的數據,由客戶端簽名。
•term:發出請求時的任期。
•index ;任期號內日志條目索引。
不同于傳統Raft,單個條目可以處于以下三個階段之一:
•PreAppended :預追加的條目是出現在日志中的條目。
•Appended:追加好的條目是指已經至少在2f+1個節點上被預追加的條目。追加好的 條目只能被 Appended 消息覆蓋。
•Commited:已提交的條目已在2f+1個節點上穩定地復制(追加)。提交的條目可以 應用于狀態機,并外部化到客戶端。
日志復制分為三個階段:PreAppend、Append和Commito BFT-Raft將Raft的Log Matching 安全性重新定義為:
1) 如果兩個節點在相同索引處包含具有相同 append term 的條目,則在該索引之前,日志 是相同的。
2) 每個節點都跟蹤currentTerm,這是其收到TERM CHANGE消息的最后一個任期。就像 原 Raft 協議一樣,Leader 跟蹤每個 Follower 的 Nextindex。NextIndex 最初設置為 Leader 日志的最后一個條目,并進行回溯以覆蓋 Follower 的日志。
當客戶端與集群進行交互時,會創建一個請求<r>c并將其發送到被認為是當前 Leader的位置。在驗證了客戶的簽名后,接收請求的節點i會檢查該請求是否已經提交。 若請求已提交且節點i是Leader,該節點直接回復客戶端,并提供操作已提交的證明。 如果節點i不是當前Leader,將使用<REDIRECT,leader_addr>回復給客戶端,其中 leader_addr是當前Leader的地址,因此,客戶可以重定向Leader本身。
當Leader收到<r>c后進行簽名驗證,判斷消息是否被篡改。若驗證無誤將請求作 為預備條目附加到其日志中。并將<PRE-APPEND,term,e,prevLogIndex,prevLogTerm>L 廣 播給Follower。如果滿足以下所有條件,則Follower將接受PRE-APPEND。
1) e具有有效的客戶簽名。
2) term 等于 currentTerm。
3) Follower 日志中有一個條目,其索引為 prevLogIndex 和任期 prevLogTerm。
4) 若 e 正在覆蓋另一個條目,則不得追加或提交該條目。
根據條件4, Leader不能用PRE-APPEND覆蓋追加好的條目。如果Follower i接受 PRE-APPEND,刪除該索引處的現有條目(及其后的所有條目),并將e附加到其日志 中。然后,把<ACK_PRE-APPEND,e>發送回給Leader。如果由于條件3不成立而導致 PRE-PREPARE失敗,備份節點會通知Leader,Leader遞減跟隨者的NextIndex,并嘗試 對失敗的PRE-APPEND之前的條目進行PRE-APPEND -這種回溯機制的發生與原始 Raft 協議中的發生完全相同。
Request PreAppend Append Commit
圖 5.3 BTF-Raft 日志復制三階段
日志復制的三階段如圖5.3所示。Leader從其跟隨者(包括其自身)收集2/ + 1個 <ACK_PRE-APPEND,e>i。這些消息被組裝到對象Pe中,并提供證明網絡中2+1個節 點已經預先追加了 e。 Leader 然后在追加好的自己的日志上標記該條目,并向其 Follower 廣播 <APPEND,e,Pe>L。
如果證明Pe包含來自不同節點的該條目的至少2f +1個有效ACK PRE-APPEND消 息,則Follower i接受<APPEND,e,Pe>L。然后,使用e (如果e尚未在該索引處)覆蓋 該索引處的現有條目,并將e標記為已追加好。最后發回<ACK」PPEND,e〉i響應oLeader 收集2f+1<ACK_APPEND,e>消息。將消息組合成Ce,以證明網絡中2/+1個對等體已 經追加好e。至此,條目已經被穩定地追加可以提交和外部化。Leader將該條目標記為 已提交,將其應用于其狀態機,然后將<RESULT,Ce>L發送回客戶端。
在下一個PRE-APPEND中,將提交的通知以及證明Ce回帶給Follower,這時 Follower將提交條目,將e應用于其狀態機,并存儲Ce以供將來參考。
日志復制算法可以將這些階段按如下方式捆綁到單個 Update 消息中。每個節點不 跟蹤每個條目的復制狀態(預先追加,追加和提交),而是跟蹤三個索引:
•CommitIndex:最后一次提交的索引
•AppendIndex:最后一次追加的索引
•PreAppendIndex :最后一次預追加的索引
而且 CommitlndexSAppendlndexSPreAppendlndex。小于并包括 CommitIndex 的條目 為已提交。間隔(CommitIndex, PreAppendIndex]中的條目為已追加。AppendIndex之后 的條目為預先追加的。
日志復制過程中Leader的Update PRC請求參數及說明如表5.4所示。
表 5.4 Update PRC 請求參數說明
參數 描述
type 消息類型
term 領導人的任期號
prevLogIndex 領導人最新日志前一個位置日志的索引值
leaderId 領導人 ID
leaderAppend 領導人的追加索引
leaderCommit 領導人的提交索引
將要追加到 Follower 上的日志條目。發送心跳包時為
entries []
空,有時會為了效率而向多個節點并發發送
proof 每個 follower 的最新更新響應
給 Follower 的 Update 消息包含將要追加到 Follower 上的日志條目, Leader 的 AppendIndex 和 CommitIndex 以及證明 P。 P 包含對等方對 Leader Update 的最新響應, 并證明兩者的 AppendIndex 和 CommitIndex 有效。然后, Follower 執行驗證的三個階段, 更新其日志并適當地移動其AppendIndex和CommitIndexo
Follower節點對Leader的Update PRC的響應參數及說明如表5.5所示。
表 5.5 Update PRC 響應參數說明
參數 描述
preAppendIndex 該節點日志更新的預追加索引
logHash 通過 preAppendIndex 記錄日志的 SHA-256 摘要
appendIndex 該節點更新的追加索引
logAppendHash 通過 appendIndex 記錄的 SHA-256 摘要
status_code 狀態碼:0, 1, 2
日志復制算法實現流程如表5.6所示。
表 5.6 Log Appending algorithm 算法流程
Algorithm: 日志復制算法
Input: Update RPC arugments// Update RPC 參數
Output:Update RPC response// Update RPC 返回值
1Validate the signatures and the proof;//驗證日志條目和 proof 參數的簽名
2Create a hypotheticalLog;
3make HashOperate;// 進行哈希運算計算
4time++;//time_out定時器計時開始
5if hypotheticalLog Hash==logAppendHash then
6if preAppendIndex> leaderAppend and AppendlndeX^LeaderCommit then
7the peer's Log reaplce as hypotheticalLog
8Append—leaderAppend; // Append 轉換為 leaderAppend
9nextIndex—LeaderCommit; // 提交索引增加到 LeaderCommit
10sent commit.
11else
12refused; //接收者拒絕響應;
13end
14else
15ignore; //忽略該 proof 消息;
16end
17go back to the beginning of append section;
5.3安全性證明
在任何場景下,BFT-Raft都應保證被篡改的日志項不被應用到復制狀態機oBFT-Raft 通過以下三種策略保證算法安全性。
term 變更協議:通過 term 變更,故障節點無法輕易地在一個任期內成為 Leader。 而且任期號是單調遞增的,只能有一個Leader被分配到一個特定的任期。拜占庭Leader 無法左右f+1個集群節點在一個term內達成一致選舉。如果拜占庭Leader忽略客戶端 請求,客戶端觸發超時選舉。BFT-Raft使用客戶端干預來恢復系統可用性。
消息簽名:無論是來自客戶端還是節點的 RPC 消息均由僅對該客戶端或節點已知 的私鑰簽名。收到消息的節點都可以使用公鑰來驗證這些RPCo此外,客戶端公用密鑰 與節點公用密鑰是分開的,因此拜占庭Leader無法偽造客戶端命令,BFT-Raft算法基于 穩固的密碼學基礎。
日志匹配:Append命令包含2f+1個preAppend命令,如果Leader預追加日志,則 直到該日志索引為止,Follwer必須具有與追加證明相同的日志項。即直到該term為止 日志都是一致的,則可以滿足日志匹配屬性。拜占庭Leader可能決定覆蓋一個值,但是 不能寫入被外部化的條目。
首先證明以下屬性:如果一個條目由任何非故障節點提交,其他2f個節點必須已追 加好或提交了該條目,并且(至少對于這些節點中的 f+1 個)該條目將永遠不會被覆蓋。
由于提交的索引必須由2f +1個節點追加,且只能被APPEND消息覆蓋。為了覆蓋 被追加的條目,Leader必須有證據使2f +1個節點愿意對該條目進行PRE-APPEND。但 任何Leader都不可能獲得2f +1個PRE-APPEND的投票,因為只有f個可能是錯誤的, 3f+1個節點中的2f +1個將不會對條目進行PRE-APPEND的投票。有了此屬性,現在 可以證明領導者完整性和狀態機安全性。
領導者完整性:假設Leader已經提交了條目e。這意味著集群中2f + 1個節點已穩 定提交或追加好eo新的Leader需要2+1 TERM-CHANGE消息才能開始新的任期。由 于存在兩個Follower節點在一個無故障節點處相交,因此將有一個非拜占庭節點(稱為 i)來穩定地提交或準備e并參與term更改,不存在一個比i有更高日志索引但不包含e 的節點。無故障Leader將使用e構造日志。即使新的Leader出現故障,但e不會被覆 蓋,e將繼續存在于2f+1個副本上,因此相同的日志項將繼續保留,直到非拜占庭Leader 開始選舉領導者為止。領導者的完整性得以保持。
狀態機安全性:狀態機安全性是上面證明屬性的直接結果。條目只會在提交時被非 拜占庭節點應用。由于不能覆蓋已提交的條目或使用更高的值來追加已提交的條目,因 此,條目如果被應用于非故障節點的狀態機,則其他任何節點都不會在該索引處應用其 他條目。
5.4算法性能測試與分析
5.4.1測試環境與實施細節
采用Raft作為可拔插共識算法的聯盟區塊鏈共識效率較高,但不具備拜占庭容錯特 性o前文針對該問題,設計了一種拜占庭容錯Rafto本節使用Python語言實現了 Raft算 法,并在改進 Raft 算法的基礎上完成 BFT-Raft 算法。搭建了一個小型的多節點區塊鏈 網絡,采用本地多節點模擬共識過程,實現了領導者選舉,動態添加節點,節點之間同 步數據,領導者提交事務等功能。對Raft算法、PBFT算法和本文提出的BFT-Raft算法 進行了仿真實驗。在通信開銷、容錯性、吞吐量和交易時延這幾個方面對算法進行了比 較分析。仿真實驗環境如表5.7所示。
表 5.7 BFT-Raft 算法實驗環境
操作系統 Ubuntu 18.04.4 LTS
內存 &0 GiB
處理器 Intel Core i5-7500 CPU @ 3.40GHz x 4
代碼編譯器 PyCharm Professional 2020.2
編程語言 Python 3.6
編碼過程中單元測試框架使用unittest,將ECC密鑰長度設定為secp384r1,數字簽 名使用ECDSA (橢圓曲線數字簽名算法),SHA-256生成哈希散列,asyncio執行異步 I/O操作,節點通信通過Python socket實現。
服務器節點啟動時,每個服務器節點將加載一個JSON配置文件,其中包含群集的 IP和端口以及日志存儲的位置,還包含指定節點的私鑰,每個節點的公鑰以及任何受信 任客戶端的公鑰。
客戶端通過Python用戶字典(Dictionary)進行簡單的鍵值存儲類型對象,當將條 目添加到字典中或從字典中刪除時,客戶端會將請求發送到其認為是領導者的節點,以 將該條目添加到狀態機以用于該請求。如果客戶端收到重定向響應,將相應地更新其認 為是當前領導者的值。如果客戶端在一定時間后未收到有效的響應,則會將請求廣播到 群集中的所有節點。
5.4.2性能分析
(1)通信復雜度
對于 PBFT 算法,日志復制主線流程包含為預準備,準備和提交三階段。接收到客 戶端請求后,預準備階段主節點廣播<<PRE-PRAPARE,v,n,d>,m>到所有備份節點,通信 次數nJ次。對于準備階段,備份節點若同意請求,會向集群內其他節點廣播 <PREPARE,v,n,d,i>的準備消息,該過程的通信次數為nx(n-l)。若各節點達均準備好, 在提交階段,每個節點會向其余節點廣播<COMMIT,v,n,D(m)>消息,主節點接收到包括 自己的2f+1個commit消息,,集群達成共識。該階段的通信次數同為nx(n-l)。總通信 次數為2n2-n-1,復雜度為0(干)。
對于BFT-Raft,核心共識流程分為PreAppend、Append和Commit三階段。由于仍延 續傳統Raft的強領導人模型,這些過程仍需要Leader節點發送RPC消息給Follower節 點,Follower驗證并處理日志。但共識過程廣播新增至兩輪RPC,對于日志追加階段通 信次數為2x(n-1),Commit階段通信次數為n-1。總通信次數為3x(n-1),復雜度為O(n)。
但PBFT可拓展性較差,當集群擁有100左右的節點個數時,性能急劇下降,在網 絡不穩定的情況下延遲較高。BFT-Raft使用ECC簽名驗證,通過新增RPC和客戶端干 預的Leader重選等機制保證復制狀態機安全,而且通信復雜度比PBFT低。
(2)Leader 選舉
如圖5.4顯示了當集群節點數從5 到 30個不等時,領導者選舉耗時的變化趨勢。可 以看到BFT-Raft和Raft的Leader選舉時間均隨著節點數量的增加而增加。且他們都在 一個任期內選舉了一位領導人,因此他們有著相似的趨勢。然而,為達到拜占庭容錯的 目標,BFT-Raft在VIEW-CHANGE時新增了一輪RPC并且要收集更多的選票,該過程 還伴隨著數字簽名的驗證,會額外花費一定的時間。但是,BFT-Raft Leader選舉階段的 通信復雜度相對于 PBFT 仍具優勢。
10 20 30 10 20 30
節點數 節點數
圖 5.4 不同數量節點下的 Leader 選舉耗時
(3)日志復制
實驗模擬出在100個客戶端事務請求下,Raft和BFT-Raft的耗時情況。如圖5.5所 示,隨著節點數目的增加,節點達成共識的時間都有所增加。Raft在[8.51ms,158.48ms] 之間,BFT-Raft 在[44.07ms,620.25ms]之間。且當 n 為 30 時 BFT-Raft 耗時 620.25ms。這 是由于 BFT-Raft 將日志復制劃分成 PreAppend、Append 和 Commit 三個階段,而且日志 提交條件是要求Leader在當前任期至少有一條日志被提交,即被超過2/3的節點應用到 狀態機。雖然有額外的通信開銷,但算法中的RPC仍然是幕等的。
圖 5.5 不同數量節點下的日志復制耗時
(4)吞吐量
吞吐量是衡量分布式一致性算法效率的關鍵指標。本實驗用于對比的PBFT算法通 過Docker部署,實現來自于Hyperledger Fabric v0.6。設置單節點客戶端發送2000條事 務請求,兩者集群節點數和數據吞吐量的關系如圖5.6所示。實驗結果顯示:由于通信 量的增多,算法的吞吐量都有所下降,隨著節點數量的增加, Leader 節點必須等待來 Follower節點的更多提交確認。然而PBFT的平均吞吐量為147.2TPS, BFT-Raft將平均 吞吐量提高至252.1TPS,在相同節點數目下BFT-Raft吞吐量始終高于PBFT。導致吞吐 量差異的原因一方面是由于 BFT-Raft 算法保留了 Raft 高效的共識邏輯,另一方面算法 相對PBFT具有較低通信復雜度。綜上表明BFT-Raft仍然具有較高的可擴展性。
(5)交易時延
時延表示的是客戶端向集群發送請求直到接收到響應為止的時間間隔,這里指的主 要是節點處理時延,隨著節點數的增長,兩種算法的時延均有所增加,但PBFT上升的 更加陡峭。為了更加有可比性,系統模擬了集群在 10 個節點下單客戶端讀數據時的交 易時延,隨機選取測試數據中的 20組進行比較。
如圖5.7所示,BFT-Raft時延范圍在[228.76ms,356.33ms], PBFT時延范圍在 [370.30ms,566.72ms]。在請求過程中,由于BFT-Raft延續原Raft的數據交換方式,即便 是在存在惡意節點的情況下,客戶端也僅需要接收到Leader節點的響應,而PBFT集群 中需收集到至少 f+1 個任意節點的一致響應,不可避免地存在更多的傳輸時延。
圖 5.7 10 節點下的交易時延
5.4.3 拜占庭容錯
在拜占庭容錯環境下,BFT-Raft算法使用term變更協議確保選舉階段Leader節點 的輪詢;使用客戶端干預機制確保異常Leader的及時發現;使用橢圓加密和SHA256算 法確保消息的不可偽造。為驗證算法的拜占庭容錯特性,本節模擬 Leader 篡改日志情 況,得出Leader重新選舉和日志項共識所需要的時間。
( 1 )重新選舉
若Leader篡改日志項,在日志追加過程中,日志項的Hash簽名驗證不通過。Follower 節點根據t modN開始向服務器發送StartElection請求。指定節點收集2f+1個重選請求 后成為t期的候選人。此時,Cadidate將增加自身term,開始向集群廣播RequestVote RPC。
當自身term和index是最新,Follower節點參與投票。Cadidate收集到Q個選票后 將成為Leader,開始新的任期。如果節點因為之前發生宕機而不具備有完備的日志項, Follower節點將拒絕該請求。Cadidate未獲得Q數目的選票,集群將再次開展重選過程 直到找到符合條件的Cadidate為止。因為增加了一次選舉過程,該情況將相對一般選舉 多增加兩輪RPC,耗時也將相應增加。
Leader 重選耗時隨著節點數量的增加而呈遞增趨勢。重選過程包括 RPC 傳輸、簽名 驗證和選票收集各階段。其隨節點數量的變化如圖 5.8 所示。
圖 5.8 Leader 重選耗時
(2)日志共識
BFT-Raft 算法通過 PreAppend、 Append 和 Commit 三階段協議確保了在拜占庭容錯 環境下日志項被安全提交(committed)。圖5.9描述了在不同節點數目下,集群從單個 日志項被添加至Leader日志列表開始,直到日志項在節點間達成共識所需的時間間隔。
隨著節點數的增加,Q增加,節點間的RPC消息變多,日志項被確認為已提交所需 的確認次數亦隨之增加,總體呈現線性變化的趨勢。
日志復制
800 -I
• 實際數據 —擬合曲線
5 10 15 20 25 30
節點數
5.5 本章小結
本章首先討論了聯盟鏈中傳統Raft共識算法的瓶頸。即在集群包含拜占庭節點的情 況下,Raft的安全性和可用性會受到損害。針對該問題,設計了具備拜占庭容錯能力的 BFT-Raft算法。在拜占庭容錯環境下,BFT-Raft通過限制增加定額數量Q至2/+1.新 增并更改原 RPC 交互格式和客戶端干預方面設計策略保證了算法的可用性與安全性: 通過 term 變更協議保證使拜占庭節點無法阻止系統進度;利用數字簽名判斷日志是否 被篡改;利用日志匹配屬性保證集群日志項的正確追加。同時,本章還搭建了集群節點 并模擬客戶端與BFT-Raft集群交互過程,論證了 BFT-Raft作為拜占庭容錯分布式共識 算法的安全性。
性能測試表明:BFT-Raft相對于傳統的Raft算法,雖損失了一定的性能,但具備了 拜占庭容錯特性。同時,比同為拜占庭容錯的區塊鏈共識算法PBFT,在吞吐量和時延 方面有更好的性能表現。而且始終能夠保持算法的安全性和同Raft 一致的可理解性。
總結與展望
糧食安全關乎國計民生,針對傳統糧倉信息化管理數據檢測不透明、缺乏信任、信 息不對稱和效率低下的問題,結合區塊鏈、IPFS和數據庫技術,設計并實現了一種智慧 糧倉綜合信息管理系統。在區塊鏈節點同步記賬過程中,為確保糧食數據的安全傳輸, 共識算法應具備較高容錯性,本文還對Raft算法進行了改進。
本文首先闡述了基于區塊鏈的智慧糧倉綜合信息管理系統的研究背景和意義以及 國內外研究現狀。在第二章中概括了區塊鏈工作原理與關鍵技術,主要包含區塊鏈架構、 共識機制、密碼學技術和IPFS,為解決傳統的管理系統的中心化問題提供基礎。第三章 首先開展了系統的需求分析,接著提出了系統的總體架構,設計了綜合管理系統中數據 的采集、存儲和保護。隨后進行了前、后端架構和智能合約數據結構的詳細設計工作, 前端的核心思想是組件化和數據驅動,后端接口借鑒REST理念,協同區塊鏈進行各個 模塊的業務處理。第四章展開了系統中區塊鏈業務層各功能模塊的實現過程與整體測試。 開發并完成了智能合約、 IPFS 的部署與調用和交互界面,對本系統進行智能合約測試、 系統功能測試和性能分析的測試結果表明,基于智慧糧倉綜合信息管理系統開發符合設 計要求,解決了傳統糧倉信息管理系統的數據中心化與易篡改問題。第五章對基于區塊 鏈的 Raft 共識算法進行改進,在保證傳統 Raft 清晰的算法邏輯之下,提出的 BFT-Raft 仍具有強一致性和可理解性。主要工作如下:
(1)結合區塊鏈技術,在充分考慮用戶者的實際需求下,設計出糧智慧糧倉綜合信 息管理系統的系統架構。以Vue作為前端開發框架。Restful Api結合JWT認證機制與 Axios網絡請求實現前后端交互。Tru田e框架完成以太坊Solidity編程語言開發與部署。 Web3.js的JSON-RPC接口操作以太坊網絡。MQTT協議進行網絡傳輸,實現倉儲環境 檢測設備的數據采集。
(2)通過以太坊、IPFS和MongoDB實現數據的永久存儲和不可篡改。其中智能 合約的開發,運用函數修改器和可見性限定符規范訪問權限,完成了對不同值類型、引 用類型和映射數據的鏈上存儲。除此之外,還有恰當的錯誤和異常處理實現合約穩固性、 事件與日志捕獲實現數據溯源。單元測試完成合約功能測試,自動漏洞檢測避免合約漏 洞。
(3)通過限制增加定額數量Q至2/+1、新增并更改原RPC交互格式和客戶端干 預策略保證了 BFT-Raft算法的可用性與安全性:利用數字簽名檢測日志是否被篡改,并 做出應對策略;通過term變更協議保證使拜占庭節點無法阻止系統進度;利用日志匹配 屬性保證集群日志項的正確追加。以少量時延為代價,提升了在拜占庭環境下的容錯能 力。相較于PBFT算法,BFT-Raft具有復雜性低的優點。
本文基于“區塊鏈+物聯網”技術設計并實現的智慧糧倉綜合信息管理系統,使整個 信息化管理過程透明,不可篡改,提高了信息的可靠性。通過對用糧企業和糧倉進行智 能化監控和管理,使糧倉和用糧企業的資源可控。一方面加強了對糧食與物質儲備信息 的集中管理,促進了數據資源的匯聚共享,另一方面有望逐步形成全省糧倉聯盟鏈,有 助于政府監管部門完善區域糧食數據存儲、處理、動態監管和協同調度,促進信息系統 數據化、平臺化、規范化集成。在保證Raft清晰的算法邏輯之下,本文提出的BFT-Raft 仍具有強一致性和可理解性,并提升了 Raft拜占庭容錯特性。不過仍存在著一些不足與 待改進的地方:
(1) 因為邏輯不像中心化應用,出現特殊情況時,在決策的速度方面,本文實現的 去中心化系統在業務處理方面的性能要低于中心化系統。操作流程有待于豐富,界面友 好性和系統性能還有待提升。
(2) 如上文所述,智能合約在數據格式方面支持有限,例如浮點型數據的賦值, mapping 數據的遍歷等。這就造成數據上鏈后數據讀取和修改受到了一定限制。后續有 待于對智能合約數據結構二次封裝。
(3) 本文只對 Raft 進行拜占庭容錯,在算法的效率方面沒有做過多研究。后續可 以對算法的日志復制和快照方面進行性能優化。
(4) 由于以太坊可插拔架構支持有限,本文提出的優化共識算法只是在實驗環境 下進行了測試,并沒有在去中心化應用中使用,在接下來的研究中,應將本文提出的共 識算法與該區塊鏈系統相結合,在實際應用環境中對算法的性能進行驗證。
參考文獻
[1]羅山,張紅建,王乃,等.智慧糧庫綜合管理系統的設計和研究J].現代食品,2019, 5:108-111.
[2]孫源.現代倉儲管理現狀及科學儲糧發展分析[J].中國市場,2020, 35:165-166.
[3]戶啟松,薛俊偉.智慧糧倉信息化建設研究[J].信息技術與信息化,2020, 04:207- 209.
[4]Patil P, Sangeetha M., Bhaskar V. Blockchain for IoT Access Control, Security and Privacy: A Review[J]. Wireless Personal Communications, 2021,117(03): 1-20.
[5]肖風.區塊鏈如何賦能數字經濟J].信息化建設,2019,249(06):34-35.
⑹孫忠富,李永利,鄭飛翔,等.區塊鏈在智慧農業中的應用展望J].大數據, 2019,5(02):116-124.
[7]吳曉柯,管孝鋒,黃海龍,等.基于區塊鏈技術的智慧農業發展研究J].南方農機, 2020,51(22):10-11.
[8]Drdobbs D. The Byzantine General's problem[J]. Acm Transactions on Programming Languages & Systems, 1982,4(3):382-401.
[9]Androulaki E., Barger A., Bortnikov V., et al. Hyperledger fabric: a distributed operating system for permissioned blockchains[A]. Proceedings of the thirteenth EuroSys conference[C]. 2018: 1-15.
[10]李董,魏進武.區塊鏈技術發展助力運營商支撐產業互聯網J].信息通信技術, 2018,12(03):8-12.
[11]Naidu V., Mudliar K., Naik A., et al. A Fully Observable Supply Chain Management System Using Block Chain and IOT[R], Pune, India: International Conference for Convergence in Technology, 2018.
[12]Tian F. A supply chain traceability system for food safety based on HACCP, blockchain & Internet of things[R], Dalian, China: International Conference on Service Systems and Service Management, 2017.
[13]Xu Xiwei, Lu Qinghua, Liu Yue, et al. Designing blockchain-based applications a case study for imported product traceability[J]. Future Generation Computer Systems, 2019, 92:399-406.
[14]Toyoda K., Mathiopoulos P.T., Sasase I., et al. A Novel Blockchain-Based Product Ownership Management System (POMS) for Anti-Counterfeits in the Post Supply Chain[J], IEEE Access, 2017, 5:17465-17477.
[15]Xie.C., Sun.Y., Luo.H. Secured Data Storage Scheme Based on Block Chain for Agricultural Products Tracking[R], Chengdu, China: 3rd International Conference on Big Data Computing and Communications (BIGCOM), 2017.
[16]許繼平,王健,張新,等.區塊鏈驅動的稻米供應鏈信息監管模型研究[J].農業機 械學報, 2020,51(08):328-335.
[17]金會芳,呂宗旺,甄彤.基于物聯網+區塊鏈的糧食供應鏈金融的新模式研究[J]. 計算機科學, 2020,47(S2):604-608.
[18]吳文革,季雅嵐,孫雪原,等.區塊鏈技術在優質安全糧食產業中應用與挑戰[J]. 浙江農業科學, 2020,61(09):1942-1946.
[19]Leslie Lamport. The part-time parliament[J]. ACM Transactions on Computer Systems (TOCS),1998,16(2): 133-169.
[20]Castro M., Liskov B. Practical Byzantine fault tolerance[J]. OSDI, 1999, 99(1999): 173186.
[21]Castro M., Liskov B. Practical byzantine fault tolerance and proactive recovery[J]. ACM Transactions on Computer Systems (TOCS), 2002, 20(4): 398-461.
[22]Burrows M. The Chubby lock service for loosely-coupled distributed systems[A]. Proceedings of the 7th symposium on Operating systems design and implementation[C]. 2006: 335-350.
[23]Fischer M.J., Lynch N.A., Paterson M.S. Impossibility of distributed consensus with one faulty process[J]. Journal of the ACM(JACM), 1985,32(2): 374-382.
[24]Nakamoto S. Bitcoin: A Peer-to-peer Electronic Cash System [EB/OL], Manubot, 2019.
[25]Tschorsch F, Scheuermann B. Bitcoin and beyond: A technical survey on decentralized digital currencies[J]. IEEE Communications Surveys & Tutorials, 2016,18(3): 2084-2123.
[26]Ongaro D., Ousterhout J. In search of an understandable consensus algorithm[A]
{USENIX} Annual Technical Conference[C] ({USENIX}{ATC} 14). 2014: 305-319.
[27]劉虹男,魏凱.聯盟鏈技術測試觀察與分析[J].信息通信技術與政策, 2020,46(1):35-45.
[28]Morgan J.P. Quorum: A Permissioned Implementation of Ethereum Supporting Data Privacy [EB/OL]. https://github.com/jpmorganchase/quorum, 2018-02-20.
[29]Feist J., Grieco G., Groce A. Slither: A Static Analysis Framework for Smart Contracts[R]. Montreal, QC, Canada: IEEE/ACM 2nd International Workshop on Emerging Trends in Software Engineering for Blockchain, 2019.
[30]袁勇,王飛躍.區塊鏈技術發展現狀與展望[J].自動化學報,2016,42(04):481-494.
[31]何蒲,于戈,張巖峰,等.區塊鏈技術與應用前瞻綜述[J].計算機科學, 2017,44(04):1-7.
[32]Poerwawinata G.W., Kistijantoro A.I. Memcachedb persistent implementation using leveldb[R]. Denpasar, Indonesia: International Conference on Electrical Engineering and Informatics (ICEEI), 2015: 283 -287.
[33]田娜,李志淮,李華威.以太坊2.0的狀態容量問題的分析[J].計算機科學與應用, 2019, 009(009):1655-1666.
[34]Hirai Y Defining the ethereum virtual machine for interactive theorem provers[A] International Conference on Financial Cryptography and Data Security[C]. Springer, Cham, 2017: 520-535.
[35]Szabo N. Formalizing and securing relationships on public networks[J]. First monday, 1997, 2(9): 1-9.
[36]Buterin V. A next-generation smart contract and decentralized application platform [J]. white paper, 2014, 3(37).
[37]Jiao LIANG, Weili HAN, Zeqing GUO, et al. DESC: enabling secure data exchange based on smart contracts[J]. Science China (Information Sciences),2018,61(04):262-264.
[38]畢曉冰,馬兆豐,徐明昆.區塊鏈智能合約安全開發技術研究與實現[J].信息安全與 通信保密, 2018, 12:63-73.
[39]Dannen C. Introducing Ethereum and solidity[M]. Berkeley: Apress, 2017.
[40]Rivest R.L., Shamir A., Adleman L.M. Cryptographic communications system and method[P]. U.S. Patent:4405829, 1983 -9-20.
[41]張偉.ECDSA算法實現及其安全性分析J].信息與電子工程,2003(02):7-12.
[42]Sicilia M.A., Sanchez-Alonso S., Garci a-B arriocanal E. Sharing linked open data over peer-to-peer distributed file systems: the case of IPFS[R] Springer, Cham: Research Conference on Metadata and Semantics Research, 2016.
[43]馮毅.基于區塊鏈的智能物流系統的研究與實現[D].成都:電子科技大學,2019.
[44]趙哲.基于區塊鏈的檔案管理系統的研究與設計[D].合肥:中國科學技術大學, 2018.
[45]呂英華.漸進式JavaScript框架Vue.js的全家桶應用[J].電子技術與軟件工程,2019, 22:39-40.