天天看點

學習區塊鍊的捷徑:建構一個屬于自己的區塊鍊

你願意閱讀這篇文章,是因為你對加密貨币的崛起感到興奮,你想知道它們背後的基層技術——區塊鍊是怎樣運作的。

但想要了解區塊鍊并不是一件易事,至少于我而言是這樣的。在艱難跋涉般浏覽了大量的視訊并學習很多教程後,我開始親手進行實踐。

我喜歡通過動手來學習,它迫使我從代碼層來了解區塊鍊的本質,如果你也做同樣的事情,在學習完這個指南之後,你就會紮實地掌握區塊鍊的基本運作原理。

在你開始之前……

記住,我們所謂的區塊鍊,是一種由不易篡改的資料區塊,按順序連結而形成的記錄賬本。它們可以包含交易、檔案或任何你想要的資料。重要的是,它們被連結到一起的過程,是使用了哈希(hash)。

如果你并不清楚哈希是什麼鬼,這篇文章會給你一個很好的解釋。

這篇指南文章面向的讀者是?你應該能熟練閱讀并能編寫基本的Python語言,并且能夠對 HTTP請求的工作原理有一些了解,因為我們會通過HTTP來和我們的區塊鍊對話。

我需要準備些什麼?確定你安裝了Python 3.6+ 。你還需要安裝Flask以及 Requests library:

pip install Flask==0.12.2 requests==2.18.4

哦,對了,你還需要一個 HTTP用戶端,例如Postman或者cURL 。當然,其他的用戶端也是可以的。 最終的代碼在哪裡?這裡可以找到:https://github.com/dvf/blockchain

步驟一:建構一個區塊鍊

打開你最喜歡的文本編輯器或IDE,我個人喜歡用PyCharm。建立一個新的檔案,并命名為blockchain.py 。我們隻使用一個檔案,但如果你搞丢了它,你可以随時引用源代碼。 我們建立了一個區塊鍊類,其構造函數建立了一個初始空清單(存儲我們的區塊鍊),而另一個則用于存儲交易。下面是我們的類設計大綱:

區塊鍊類設計大綱

我們的區塊鍊類負責管理這個區塊鍊。它将用于存儲交易,并具有一些輔助方法為區塊鍊添加新區塊。讓我們開始執行一些方法。 一個區塊看起來是怎樣的? 每一個區塊都有一個

索引

,一個

時間戳

( Unix時間),

一系列交易

證明

(稍後會提到),以前

之前區塊的哈希

。 下面就是一個區塊所包含的一些資訊:在這一點上,區塊鍊的概念應該是明顯的,每一個新區塊除了其本身的資訊,還包括之前區塊的哈希。這是關鍵的,因為是它使得區塊鍊不可更改:如果攻擊者破壞了區塊鍊當中之前的一個區塊,那麼所有後續的區塊都會包含不正确的哈希。 這有什麼用嗎?如果你覺得沒有,花一點時間好好思考一下,這是區塊鍊背後的核心理念。 将交易添加到一個區塊當中 我們需要一種方式将交易添加到一個區塊當中。我們的

new_transaction()

代碼就是負責做這個的,它也是非常簡單的:在 

new_transaction()

 指令将一筆交易添加到清單後,它會傳回添加交易區塊(也就是下一個有待挖出的區塊)的索引。之後,這對于送出交易的使用者而言是有用的。 建立新區塊 當我們的區塊鍊部署完之後,我們需要生成創始區塊(最初的區塊)來啟動它。我們還需要為我們的創始區塊添加一個“證明”,也就是挖礦的結果(或者說工作量證明)。我們之後會談到更多關于挖礦的問題。 除了用我們的構造函數來建立創始區塊,我們還會詳細了解 

new_block()

new_transaction()

 和 

hash()

:上述的代碼應該說是簡單的,我添加了一些注釋和文檔字元串,讓代碼更容易閱讀。我們幾乎完成了區塊鍊的構造部分工作。但在這一點上,你一定想知道新的區塊是如何建立或者挖取的。 了解工作量證明(pow) 所謂工作量證明,就是發現一個解決數學問題的字元串。這個字元串必需很難找到,但易于被網絡上的所有人所驗證。這就是工作量證明背後的核心思想。 我們來看看一個非常簡單的例子,幫助你去了解工作量證明。 我們決定,某些整數

x

乘以另一個整數

y

的哈希,其結果的末尾必需是0.是以, 

hash(x * y) = ac23dc...0

。為了簡化,我們把x設為5.然後用Python來實作它:

from hashlib import sha256     x = 5     y = 0  # We don't know what y should be yet...     while sha256(f'{x*y}'.encode()).hexdigest()[-1] != "0":         y += 1     print(f'The solution is y = {y}')           

在這裡的解, y = 21 ,是以,其生成的哈希末尾為0:

hash(5 * 21) = 1253e9373e...5e3600155e860           

在比特币當中,它的工作量證明算法被稱為Hashcash(哈希現金算法)。這個算法和我們上述的基本例子沒有太多的差別。在這個算法下,礦工為建立一個新區塊而去争相解決這個新的解。礦工們在得出這個新解之後,就會收到比特币代币的獎勵。

網絡可以很容易地驗證它們的解。

部署基本的工作量證明

讓我們來為區塊鍊部署一種類似的算法。我們的規則将類似于上面的例子:

想要調整算法的難度,我們可以修改前導零的數字。不過4就已經足夠了。你會發現,加上一個前導零,就會導緻找到一個解所需的時間大為不同。

我們的類幾乎已經完成了,我們準備開始用HTTP請求來進行互動。

步驟二:區塊鍊作為一個API

我們要使用的是Python Flask架構。這是一個微架構,這讓我們可以通過HTTP請求來和我們的區塊鍊談話。

我們有三種建立方式:

  1.  /transactions/new 為一個區塊建立一筆新的交易;
  2.  /mine告知我們的伺服器挖取一個新區塊
  3.  /chain來傳回整個區塊鍊

設定Flask

我們的“伺服器”将在我們的區塊鍊網絡中形成一個單一節點。讓我們建立一些樣闆代碼:

以上代碼的部分說明:

第15行:執行個體化我們的節點。你可以在這裡閱讀更多關于Flask的資訊:http://flask.pocoo.org/docs/0.12/quickstart/#a-minimal-application

第18行:為我們的節點建立一個随機名稱

第21行:執行個體化我們的區塊鍊類

第24-26行:建立/mine 端點,這是一個GET 請求;

第28-30行:建立 /transactions/new 端點,這是一個POST請求,因為我們會把資料發送給它;

第32-38行:建立/chain 端點,它會傳回整個區塊鍊;

第40-41行:在端口5000上運作伺服器;

交易端點

這是一筆交易請求的樣子,它是使用者發給伺服器的資訊:

{     "sender": "my address",     "recipient": "someone else's address",     "amount": 5     }           

因為我們已經有了添加區塊交易的類,剩下的工作就很容易了。讓我們來編寫下添加交易的函數:

挖礦端點

我們的挖礦端點是魔法所發生的地方,實際上它也很容易。它要做的是三件事:

  1. 計算工作量證明
  2. 通過一筆交易授予礦工(我們)代币,以作為獎勵;
  3.  創造新區塊,并将其添至區塊鍊;

注意,挖取區塊的接收方正是我們的節點位址。到了這一步,我們可以說已經完成了,可以開始和我們的區塊鍊進行互動。

步驟3:和我們的區塊鍊進行互動

你可以使用普通的 cURL或者Postman來互動我們的API 。

啟動伺服器:

$ python blockchain.py     * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)           

讓我們試着通過一個 GET 請求挖取一個區塊

http://localhost:5000/mine:           

使用Postman 來建立一個GET請求

讓我們通過建立一個 POST請求來建立一筆新的交易

http://localhost:5000/transactions/new           

其包含着我們的交易結構:

使用Postman來建立一個POST請求

如果你使用的并不是Postman,那麼你可以使用cURL來建立等效的請求;

$ curl -X POST -H "Content-Type: application/json" -d '{     "sender": "d4ee26eee15148ee92c6cd394edd974e",     "recipient": "someone-other-address",     "amount": 5     }' "http://localhost:5000/transactions/new"           

我重新啟動了我的伺服器,并挖取了兩個區塊,使得總共挖取的區塊數為3.

讓我們通過http://localhost:5000/chain: 請求來檢查整個區塊鍊:

{     "chain": [     {     "index": 1,     "previous_hash": 1,     "proof": 100,     "timestamp": 1506280650.770839,     "transactions": []     },     {     "index": 2,     "previous_hash": "c099bc...bfb7",     "proof": 35293,     "timestamp": 1506280664.717925,     "transactions": [     {     "amount": 1,     "recipient": "8bbcb347e0634905b0cac7955bae152b",     "sender": "0"     }     ]     },     {     "index": 3,     "previous_hash": "eff91a...10f2",     "proof": 35089,     "timestamp": 1506280666.1086972,     "transactions": [     {     "amount": 1,     "recipient": "8bbcb347e0634905b0cac7955bae152b",     "sender": "0"     }     ]     }     ],     "length": 3     }           

步驟4:共識

這是非常酷的一部分。我們已經有了一個接受交易的基礎區塊鍊,它允許我們挖取新的區塊。但區塊鍊的靈魂在于它要實作去中心化。如果其實作了去中心化,我們究竟如何才能確定所有參與者所用的鍊是相同的呢?這就是所謂的共識問題,如果我們想要網絡當中存在多個節點,我們就必須部署一種共識算法。

注冊新節點

在我們部署一種共識算法之前,我們需要一種讓節點能夠識别網絡相鄰節點的方法。我們網絡上的每一個節點,應該有網絡其他節點的登記表。是以,我們需要更多的端點:

1 、 

/nodes/register

 來接受一系列URL形式的新節點;

2、 

/nodes/resolve

 來部署我們的共識算法,其負責解決任何沖突,確定節點所在的鍊是正确的。

我們需要修改我們的區塊鍊構造函數,并為注冊節點提供一個方法:

注意,我們使用了一個

set()

 來持有節點清單。這是一種確定新添加的節點是幂等的的廉價方法。這意味着無論我們添加一個特定的節點多少次,其出現的次數都隻有1 。

部署共識算法

如前所述,沖突是當一個節點與另一個節點所在的鍊不同時的情況。為了解決這個問題,我們将制定一條規則,即最長有效鍊是權威鍊。換句話說,網絡上最長的鍊就是有效的區塊鍊。使用這種算法,我們網絡中的節點之間就達成了共識。

第一種方法

valid_chain()

 是通過周遊每個區塊并驗證哈希和證明,其負責檢查一條鍊是否是有效的;

resolve_conflicts()

則是周遊所有我們的相鄰節點,下載下傳它們的鍊,并使用上述方法來驗證它們。如果一個有效鍊被找到了,其長度要高于我們所在的鍊,我們就用這個新鍊取代我們所在的舊鍊。

讓我們将這兩個端點注冊到我們的API中,一個用于添加相鄰節點,另一個用于解決沖突:

在這一點上,如果你喜歡的話,你可以使用不同的機器,并在你的網絡上啟動不同的節點。或者你可以使用相同的機器,使用不同的端口來啟動程式。我在我的機器上用不同的端口啟動了另一個節點,并用我目前的節點進行了注冊。是以,我有了兩個節點:

http://localhost:5000 

和 

http://localhost:5001

.

注冊一個新節點

然後我在節點2上挖取了一些新的區塊,確定鍊更長。之後,我在節點1上調用

GET /nodes/resolve

 函數,然後節點1所在的鍊就被共識算法替換成節點2的鍊了。

你也可以找一些朋友,幫你一起測試你的區塊鍊……

我希望這能夠啟發你創造出新的東西。我相信,區塊鍊會迅速改變我們思考經濟、政府以及記錄的方式。

原文釋出時間為:2018年03月28日

本文作者:智能計算時代

本文來源:

CSDN區塊鍊大學營

,如需轉載請聯系原作者。