Python 是一門簡單易學、語法優美且功能強大的編程語言。它擁有一個自由開放的社區環境,該社區提供了諸如 Web、爬蟲、數據分析、機器學習等方面的開發框架和類庫,可直接使用進行快速開發。另外,Python 代碼也被稱為是可執行偽代碼,好的 Python 代碼就像偽代碼一樣,乾淨、簡潔、一目了然,所以這裡選擇 Python 作為開發語言實現一個區塊鏈原型。
Python 是一種廣泛使用的高級編程語言,由荷蘭人吉多・范羅蘇姆發明,第一版發布於 1991 年。之所以選中 Python 作為這門開發語言的名字,是因為范羅蘇姆是 BBC 電視劇《Monty Python》的愛好者,故選取了 Python 一詞作為這門語言的名字。范羅蘇姆對 Python 的定位是 “優雅”“明確”“簡單”,
所以 Python 程序語法簡單易懂,即使是編程初學者,也能輕易上手,而且 Python 內置了豐富的數據結構和類庫,即便是初學者也能通過 Python 輕鬆實現功能非常複雜的程序。
Python 開發者的理念是:用一種方法,最好是只有一種方法來做一件事,這種理念深刻體現在 Python 程序的設計中。在開發 Python 程序時,如果面臨多種選擇,Python 開發者一般會拒絕花俏的語法,而選擇明確沒有或者很少有歧義的語法。這些 Python 程序開發中的準則被稱為 “Python 之禪”。Python 開發者蒂姆・彼得斯對 “Python 之禪” 的總結如下。
●Beautiful is better than ugly. 美比醜好。
●Explicit is better than implicit. 直言不諱比心照不宣好。
●Simple is better than complex. 簡單比內部複雜更好。
●Complex is better than complicated. 內部複雜比外部複雜好。
●Flat is better than nested. 平面的比嵌套的好。
●Sparse is better than dense. 錯落有致比密密匝匝的好。
●Readability counts. 可讀性很重要。
●Special cases aren’t special enough to break the rules. 特殊情況不能特殊到打破規律。
●Although practicality beats purity. 雖然實用比純粹更重要。
●Errors should never pass silently. 永遠別讓錯誤悄悄地溜走。
●Unless explicitly silenced. 除非是你故意的。
●In the face of ambiguity,refuse the temptation to guess. 碰到模稜兩可的地方,絕對不要去作猜測。
●There should be one——and preferably only one——obvious way to do it. 什麼事情都應該有一個,而且最好只有一個顯而易見的解決辦法。
●Although that way may not be obvious at first unless you’re Dutch. 一開始並不容易,因為你不是 Python 之父(這裡 Dutch 指 Python 之父)。
●Now is better than never. 現在就開始要比永遠都不做好。
●Although never is often better than right now. 很多時候永遠都不做要比匆匆忙忙去做要好。
●If the implementation is hard to explain,it’s a bad idea. 如果一個想法實現起來很困難,那它本身就不是一個好想法。
●If the implementation is easy to explain,it may be a good idea. 如果一個想法實現起來很容易,那它或許就是一個好想法。
●NameSpaces are one honking great idea——let’s do more of those!名字空間是個了不起的想法,所以我們現在就開始吧。
這些準則讓 Python 開發者傾向於注重簡單,避免複雜,更加關注如何高效地解決問題,是值得每個開發者思考和遵循的。
下面讓我們開始進入 Python 的世界,首先要做的是搭建一個 Python 開發環境。
1.Python 安裝
Python 的安裝過程比較簡單,前往 Python 官網:https://www.python.org/downloads/ 下載對應操作系統的 Python 安裝文件進行安裝即可,Python 安裝文件的下載頁面如示。
1)選擇 Python 代碼編輯器
首先是選擇一款合適的 Python 代碼編輯器。
工欲善其事,必先利其器。雖然說用操作系統中自帶的文本編輯器,比如記事本這種編輯器也可以用來編寫 Python 代碼,但這樣的編輯器沒有代碼高亮、自動補全和代碼錯誤提示等功能,會大大降低開發效率。所以,需要選擇一款功能比較全面的 Python 代碼編輯器,這樣可以有效地提升開發效率和代碼質量。這裡對 PyCharm、Sublime Text 3、Visual Studio Code、Atom、Jupyter Notebook 等這幾個主流的 Python 代碼編輯器做一下簡單比較,讀者可結合自己的需求選擇一款適合自己的編輯器。
●PyCharm,專門面向 Python 的全功能集成開發環境。不論是在 Windows、Mac OS X 系統中,還是在 Linux 系統中都可以快速安裝和使用。PyCharm 中集成了與 Python 開發相關的編輯、調試、代碼管理等各項功能,打開一個新的文件就可以開始編寫代碼。PyCharm 啟動的時候稍微有點慢,比較適合開發和管理大型項目
Atom 的下載地址是 https://atom.io/。
●Jupyter Notebook,是一款網頁版的 Python 編輯器,可以在瀏覽器中編寫和執行代碼,執行結果會以 HTML 等富媒體格式進行展示。另外,Jupyter Notebook 還支持使用 LaTeX 編寫數學公式和使用 Markdown 編寫文檔。
Jupyter Notebook 無須額外下載安裝文件,只需要在終端(Linux 和 Mac OS)或命令行窗口(Windows)下使用 Python 包管理工具進行安裝即可,安裝命令如下:
pip install jupyter
本書將使用 Jupyter Notebook 進行 Python 代碼的開發和調試。
介紹完編輯器後,再簡單了解一下 Python 的包管理工具。
(2)安裝 Python 包管理工具
目前最流行的 Python 包管理工具是 pip 命令,當使用 Python 安裝文件安裝完成後,pip 也會一起安裝到系統中。
其他的命令可以使用 piphelp 進行查看,如圖所示。
介紹了包管理工具以後,再來了解一下 Python 的虛擬環境。
(3)創建 Python 虛擬環境
在 Python 的開發過程中需要安裝第三方包和依賴庫,而開發不同的項目需要安裝的包和依賴庫通常各不相同。為了防止不同的應用之間包和依賴庫衝突,最好能創建一個獨立的 Python 開發環境,也就是 Python 的虛擬環境。這樣可以使每個項目的環境與其他項目獨立開來,保證開發環境不受其他項目影響,解決包衝突的問題。而創建獨立環境的方法就是使用虛擬環境管理工具。
當前最流行的 Python 虛擬環境管理工具叫 virtualenv,它是 Python 的一個第三方工具。安裝命令如下:
pip install virtualenv
安裝完成後就可以創建一個獨立的 Python 虛擬開發環境了。將這個虛擬環境命名為 venv,創建命令是 virtualenv venv -p python3,其中 “-p python3” 是指定 python 的版本為 python 3。
要使用這個虛擬環境需要先用 source venv/bin/activate 命令將其激活,激活成功後會在當前行的最前面顯示當前虛擬環境的名字
至此,當前的 Python 開發環境就是前面創建的 venv 這個虛擬環境了。若想退出當前虛擬環境,可使用 deactivate 命令進行操作,退出後(venv)這個虛擬環境的名字也會消失,
4)Jupyter Notebook 的啟動和使用
下面在 Python 虛擬開發環境中安裝 jupyter 並啟動 Jupyter Notebook,安裝和啟動 Jupyter Notebook 的命令及執行過程如圖 4-12 和圖 4-13 所示,啟動命令是 jupyter notebook。
啟動 Jupyter Notebook 後會自動在瀏覽器中打開一個頁面(啟動後程序默認監聽 8888 端口),如圖 4-14 所示。
該頁面顯示的是 “Files” 標籤下的內容,其中列出當前文件夾下的文件目錄結構,第 2 個標籤 “Running” 顯示的是當前運行的 notebook 頁面,第 3 個標籤 “Clusters” 顯示的是集群功能。要編寫 Python 代碼可以選擇右上角的 “New” 菜單,在下拉框中選擇 “Python 3” 來新建一個 notebook 頁面,如圖 4-15 所示。
新建的 notebook 頁面主要可分為 4 塊區域,名稱、菜單欄、工具條和編輯區域,如圖 4-16 所示。
圖 4-16 Jupyter Notebook 編輯頁面
標題默認是 “Untitled”,可以通過雙擊標題位置對其進行修改,菜單欄包括了所有對 notebook 的操作,工具條顯示的是常用的命令。
下面開始編寫第一個 Python 程序。
3. 第一個 Python 程序
第一個 Python 程序的功能比較簡單,就是輸出 “你好,區塊鏈” 這幾個字,使用 Python 中的打印函數 print 函數實現,輸入代碼 print(“你好,區塊鏈”)後,單擊 “工具條” 上的 “Run” 按鈕或使用快捷鍵<Shift+Enter>執行代碼,如圖 4-17 所示,可以看到下面打印了結果 “你好,區塊鏈”。
區塊包括區塊頭和區塊體兩個部分,區塊頭由版本、父區塊哈希值、數據、Merkle 根、時間戳、目標難度、Nonce 值組成;區塊體實際上可以包含任何內容,在比特幣中包括交易輸入數量、交易輸出數量和長度不定的交易記錄等信息。在以太坊中的區塊體中除了交易數據還包含智能合約。為方便開發和理解,這裡要開發的區塊鏈系統簡化了區塊的結構,只使用最關鍵的幾個字段,其他非必要的字段先忽略。簡化後的區塊包括父區塊哈希值、數據、時間戳、哈希值這四個字段,區塊的哈希值由區塊中父區塊哈希值、數據和時間戳這 3 個字段拼接起來通過哈希算法計算而成。通過 Python 定義區塊的結構,如圖
(2)定義區塊鏈的構造
區塊鏈是由區塊組成的鏈條,定義了區塊的結構後還需要定義一個區塊鏈的結構。將各個區塊通過哈希值前後依次相連,然後將這些區塊都放到一個數組中,初始化時列表為空,新的區塊依次放到這個列表中,再定義一個函數來實現向這個列表中添加區塊的功能,從而定義了這個區塊鏈的結構
區塊鏈結構
以上就完成了最簡單的區塊鏈結構,下面在此基礎上一步步對其完善直至實現一個真正的區塊鏈系統。
(3)實現區塊鏈原型
1)先來創建第 1 個區塊,或者叫作創世區塊,代碼如圖 4-34 所示,創世區塊沒有父區塊,所以 prev_hash 的值為空。
2)再創建兩個區塊,數據是關於張三的轉賬記錄,prev_hash 依次是前一個區塊的哈希值,如圖
3)然後新建一個區塊鏈並將上面的區塊添加到區塊鏈中,如圖 4-36 所示。
4)最後打印輸出當前區塊鏈的信息,可以看到這個區塊鏈包含了 3 個區塊,如圖
以上就實現了一個最簡單的區塊鏈原型,但它缺少了區塊鏈的核心功能,比如共識機制、賬戶和交易、去中心化網絡等,不能算是一個真正的區塊鏈。接下來會在這個原型基礎上一步步添加區塊鏈的各種特性,直至實現一個完整的區塊鏈。首先是為其加入共識機制 —PoW(工作量證明)
共識機制是區塊鏈技術的重要組成部分,在 3.1 共識機制中已經介紹過常見的幾種共識機制。這裡將使用 Python 實現比較簡單的 PoW,即工作量證明機制。PoW 的原理是通過不斷計算,直到找到一個隨機數(Nonce)的值使得生成的哈希值滿足一定的條件,如圖
下面我們將工作量證明機制加入上面的區塊鏈原型中。
1)首先更新區塊的結構,加入 Nonce 字段,如圖
2. 哈希算法庫
在 Python 中已經內置了一個哈希庫 ——hashlib,它提供了常見的哈希算法,如 MD5,SHA256 等,以下為 MD5 和 SHA256 的使用方法,如圖所示。
Base64 是一種用 64 個字符來表示任意二進制數據的方法,Python 中內置了 Base64 庫以供使用,下面內容是將字符串 “你好,區塊鏈” 進行 Base64 加密和解密的過程,代碼如圖
在 Python 中使用非對稱加密算法,比如椭圓曲線算法時,需要安裝第三方庫。在此簡單講解如何在 Python 中使用椭圓曲線算法。要用椭圓曲線算法,需要先安裝第三方庫 ECDSA,安裝命令命令如下:
pip install ecdsa
安裝完成後先導入算法庫,生成一對私鑰和公鑰,然後用私鑰進行簽名,用公鑰進行簽名驗證,如圖 4-29 所示,先使用 SigningKey.generate()方法生成一個私鑰,由這個私鑰可以生成一個唯一的公鑰。然後使用私鑰對 “Something” 這個字符串生成簽名,而由私鑰生成的公鑰就可以用來驗證這個簽名是否正確
最後介紹 Python 的繪圖庫 Matplotlib,這個庫用來生成常用的圖表和進行數據可視化。Matplotlib 支持各種平台,並且功能強大,能夠輕易繪製出各種專業的圖形。要使用這個庫需要先進行安裝,安裝命令如下:
pip install matplotlib
Matplotlib 庫的使用方法如圖
已詳細介紹過區塊的結構,區塊包括區塊頭和區塊體兩個部分,區塊頭由版本、父區塊哈希值、數據、Merkle 根、時間戳、目標難度、Nonce 值組成;區塊體實際上可以包含任何內容,在比特幣中包括交易輸入數量、交易輸出數量和長度不定的交易記錄等信息。在以太坊中的區塊體中除了交易數據還包含智能合約。為方便開發和理解,這裡要開發的區塊鏈系統簡化了區塊的結構,只使用最關鍵的幾個字段,其他非必要的字段先忽略。簡化後的區塊包括父區塊哈希值、數據、時間戳、哈希值這四個字段,區塊的哈希值由區塊中父區塊哈希值、數據和時間戳這 3 個字段拼接起來通過哈希算法計算而成。通過 Python 定義區塊的結構,如圖
區塊鏈是由區塊組成的鏈條,定義了區塊的結構後還需要定義一個區塊鏈的結構。將各個區塊通過哈希值前後依次相連,然後將這些區塊都放到一個數組中,初始化時列表為空,新的區塊依次放到這個列表中,再定義一個函數來實現向這個列表中添加區塊的功能,從而定義了這個區塊鏈的結構,具體代碼如圖
以上就完成了最簡單的區塊鏈結構,下面在此基礎上一步步對其完善直至實現一個真正的區塊鏈系統。
(3)實現區塊鏈原型
1)先來創建第 1 個區塊,或者叫作創世區塊,代碼如圖 4-34 所示,創世區塊沒有父區塊,所以 prev_hash 的值為空。
2)再創建兩個區塊,數據是關於張三的轉賬記錄,prev_hash 依次是前一個區塊的哈希值,如圖
3)然後新建一個區塊鏈並將上面的區塊添加到區塊鏈中,如圖所示。
4)最後打印輸出當前區塊鏈的信息,可以看到這個區塊鏈包含了 3 個區塊,如圖所示。
幾個重要的共識機制曾提到,在工作量證明的計算過程中,“挖礦” 的計算量很大,而驗證的方法很簡單,計算量很小。從上圖中的代碼中也可以看到,“挖礦” 消耗的時間為 1.42s,而驗證時間只需要 0.026s(26μs),很明顯驗證比計算工作量證明簡單得多。
4)完成工作量證明機制後,再生成一個新的加入工作量證明機制的區塊鏈,如圖所示。
將上述區塊鏈的區塊信息打印出來可以看到,區塊的哈希值都是以 “00000” 開頭,如圖所示。
已經介紹過區塊鏈技術中賬戶其實就是區塊鏈網絡中的一個地址,用來標示區塊鏈網絡中的某個結點。而錢包是用來存放賬戶的工具。賬戶的本質是一對唯一的私鑰和公鑰,也就是說錢包的本質是生成和管理這些密鑰對的工具。以下是創建錢包、賬戶並實現其交易功能的步驟。
(1)創建錢包及賬戶
首先定義一個 Wallet 的類用來代表錢包,Wallet 初始化時會生成一對唯一的私鑰和公鑰,即一個賬戶,生成的算法基於椭圓曲線算法,具體代碼如圖所示。
2)生成簽名
創建賬戶後還需要提供這個賬戶的地址和公鑰並利用賬戶的私鑰生成簽名。其中,地址由公鑰先經哈希算法再進行 Base64 算法計算而成,簽名生成的是一串二進制字符串,為便於查看,這裡將這個二進制字符串轉換成 ASCII 字符串進行輸出,具體代碼如圖
賬戶的地址、公鑰和簽名
(3)生成驗證函數
然後還需要實現一個驗證函數用來驗證簽名是否正確,生成驗證函數的代碼如圖
(4)測試錢包的功能
接下來對錢包功能進行測試,包括:賬戶的生成、賬戶的地址、公鑰信息以及簽名功能是否正常,如圖 4-48 所示。
基於上面的公鑰和簽名,可驗證簽名的正確性,如圖所示,代碼執行的返回結果為 True,說明這個簽名是基於和這個公鑰配對的私鑰生成的,也就是說錢包(賬戶)功能正常。
錢包和賬戶的功能實現後還需要加入交易的功能。為了支持交易,這裡需要再定義一個交易的數據結構。
在前面的步驟中,區塊結構中的數據只是個簡單的字符串,而在實際的區塊鏈中,數據是一個個的交易記錄,這些交易記錄需要包含交易的發送方、接收方、交易數量,以及用來驗證交易的發送方公鑰和發送方簽名,這裡定義一個包含這幾個字段的 Python 類 Transaction,如圖
(6)整合錢包和交易功能
完成了錢包和交易的功能後,將這兩個功能更新到前面完成的區塊鏈原型中。
1)首先,將區塊結構中的數據替換為交易列表,如圖
2)接著,在工作量證明中添加獎勵機制,這個獎勵機制為挖礦成功後可以獲得加密數字貨幣作為獎勵。這裡假定為每完成一個區塊可獲得 1 個加密數字貨幣,代碼如圖
3)然後,為了方便獲取區塊鏈中賬號的加密數字貨幣情況,這裡再添加一個名為 get_balance 的查詢函數,該函數會遍歷整個區塊鏈的交易數據,通過匹配賬號獲取與這個賬號相關的所有交易記錄,然後累加這個賬號接收到的金額,並減去所有的支出金額,計算出該賬戶的當前餘額,如圖
7)測試區塊鏈交易功能
最後來測試一下區塊鏈的交易功能能否正常運行。先初始化一個空的區塊鏈和 3 個錢包賬戶(alice、tom、bob),如圖所示,可以看到初始化錢包中餘額都是 0。
下面假設 alice 生成了創世區塊並將創世區塊添加到區塊鏈中。根據工作量證明機制,alice 將獲得 1 個加密數字貨幣,代碼
alice 獲得獎勵後可以向 tom 進行轉賬,這裡轉賬了 0.3 個加密數字貨幣,代碼如圖
假設這筆轉賬交易被廣播到區塊鏈網絡後由 bob 進行驗證並生成一個新的區塊添加到了網絡上,那麼 bob 也將獲得 1 個加密數字貨幣,代碼如圖
再次打印此時的錢包餘額。此時可以看到 alice 轉給 tom 0.3 個加密數字貨幣後變成了 0.7 個,tom 因此擁有 0.3 個加密數字貨幣,bob 挖礦獲得了 1 個加密數字貨幣。如圖
至此,這個區塊鏈系統可以支持挖礦獎勵和交易的功能了!但實際的區塊鏈是運行在一個去中心化網絡中的,在下一節中,將實現一個簡單的去中心化的區塊鏈網絡。