707
Python
用 Python 擼一個區塊鏈
相信你和我一樣對數字貨幣的崛起感到新奇,並且想知道其背後的技術——區塊鏈是怎樣實現的。
但是理解區塊鏈並非易事,至少對於我來說是如此。晦澀難懂的視頻、漏洞百出的教程以及示例的匱乏令我倍受挫折。
我喜歡在實踐中學習,通過寫代碼來學習技術會掌握得更牢固。如果你也這樣做,那麼讀完本文,你將獲得一個可用的區塊鏈以及對區塊鏈的深刻理解。
開始之前...
首先你需要知道區塊鏈是由被稱為區塊的記錄構成的不可變的、有序的鏈式結構,這些記錄可以是交易、文件或任何你想要的數據,最重要的是它們是通過 Hash 連接起來的。
如果你不了解 Hash,這裏有個例子
其次,你需要安裝 Python3.6+,Flask,Request
同時你還需要一個 HTTP 客戶端,比如 Postman,cURL 或任何其它客戶端。
最終的源代碼在這裏:
第一步: 打造一個 Blockchain
新建一個文件 blockchain.py,本文所有的代碼都寫在這一個文件中。首先創建一個 Blockchain 類,在構造函數中我們創建了兩個列表,一個用於儲存區塊鏈,一個用於儲存交易。
一個區塊有五個基本屬性:index,timestamp(in Unix time),transaction 列表,工作量證明(稍後解釋)以及前一個區塊的 Hash 值。
到這裏,區塊鏈的概念應該比較清楚了:每個新的區塊都會包含上一個區塊的 Hash 值。這一點非常關鍵,它是區塊鏈不可變性的根本保障。如果攻擊者破壞了前麵的某個區塊,那麼後麵所有區塊的 Hash 都會變得不正確。不理解?慢慢消化~
我們需要一個向區塊添加交易的方法:
new_transaction() 方法向列表中添加一個交易記錄,並返回該記錄將被添加到的區塊——下一個待挖掘的區塊——的索引,稍後在用戶提交交易時會有用。
當 Blockchain 實例化後,我們需要創建一個初始的區塊(創世塊),並且給它預設一個工作量證明。
除了添加創世塊的代碼,我們還需要補充 newblock(), newtransaction() 和 hash() 方法:
上麵的代碼應該很直觀,我們基本上有了區塊鏈的雛形。但此時你肯定很想知道一個區塊究竟是怎樣被創建或挖掘出來的。
新的區塊來自工作量證明(PoW)算法。PoW 的目標是計算出一個符合特定條件的數字,這個數字對於所有人而言必須在計算上非常困難,但易於驗證。這就是工作量證明的核心思想。
舉個例子:
假設一個整數 x 乘以另一個整數 y 的積的 Hash 值必須以 0 結尾,即 hash(x * y) = ac23dc...0。設 x = 5,求 y?
結果是 y = 21 // hash(5 * 21) = 1253e9373e...5e3600155e860
在比特幣中,工作量證明算法被稱為 Hashcash,它和上麵的問題很相似,隻不過計算難度非常大。這就是礦工們為了爭奪創建區塊的權利而爭相計算的問題。通常,計算難度與目標字符串需要滿足的特定字符的數量成正比,礦工算出結果後,就會獲得一定數量的比特幣獎勵(通過交易)。
網絡要驗證結果,當然非常容易。
讓我們來實現一個 PoW 算法,和上麵的例子非常相似,規則是:尋找一個數 p,使得它與前一個區塊的 proof 拚接成的字符串的 Hash 值以 4 個零開頭。
衡量算法複雜度的辦法是修改零的個數。4 個零足夠用於演示了,你會發現哪怕多一個零都會大大增加計算出結果所需的時間。
我們的 Blockchain 基本已經完成了,接下來我們將使用 HTTP requests 來與之交互。
第二步:作為 API 的 Blockchain
我們將使用 Flask 框架,它十分輕量並且很容易將網絡請求映射到 Python 函數。
我們將創建三個接口:
我們的服務器將扮演區塊鏈網絡中的一個節點。我們先添加一些常規代碼:
這是用戶發起交易時發送到服務器的請求:
我們已經有了向區塊添加交易的方法,因此剩下的部分就很簡單了:
挖掘端正是奇跡發生的地方,它隻做三件事:計算 PoW;通過新增一個交易授予礦工一定數量的比特幣;構造新的區塊並將其添加到區塊鏈中。
需注意交易的接收者是我們自己的服務器節點,目前我們做的大部分事情都隻是圍繞 Blockchain 類進行交互。到此,我們的區塊鏈就算完成了。
第三步:交互演示
使用 Postman 演示,略。
第四步:一致性
這真的很棒,我們已經有了一個基本的區塊鏈可以添加交易和挖礦。但是,整個區塊鏈係統必須是分布式的。既然是分布式的,那麼我們究竟拿什麼保證所有節點運行在同一條鏈上呢?這就是一致性問題,我們要想在網絡中添加新的節點,就必須實現保證一致性的算法。
在實現一致性算法之前,我們需要找到一種方式讓一個節點知道它相鄰的節點。每個節點都需要保存一份包含網絡中其它節點的記錄。讓我們新增幾個接口:
注意到我們用 set 來儲存節點,這是一種避免重複添加節點的簡便方法。
前麵提到的衝突是指不同的節點擁有的鏈存在差異,要解決這個問題,我們規定最長的合規的鏈就是最有效的鏈,換句話說,隻有最長且合規的鏈才是實際存在的鏈。
讓我們再添加兩個方法,一個用於添加相鄰節點,另一個用於解決衝突。
現在你可以新開一台機器,或者在本機上開啟不同的網絡接口來模擬多節點的網絡,或者邀請一些朋友一起來測試你的區塊鏈。
我希望本文能激勵你創造更多新東西。我之所以對數字貨幣入迷,是因為我相信區塊鏈會很快改變我們看待事物的方式,包括經濟、政府、檔案管理等。
題圖:pexels,CC0 授權。
最後更新:2017-10-18 13:29:32