服務項目

需求溝通

怎么開發區塊鏈礦機

  大家都無不驚呼比特幣、以太坊及其他加密電子貨幣的持續狂熱,特別是對于剛接觸這個領域的新手,不斷得聽到張三李四通過 GPU “挖礦”而聚集價值數萬乃至數百萬加密電子貨幣。那么“挖礦”到底是什么? 它是如何工作的? 相信對于程序員來說,沒有什么比自己動手實踐一遍“挖礦”算法更好的學習辦法了。

  在這篇文章中,讓我們一起逐個解讀每一個問題,并最終編寫出自己的“挖礦”算法。這個算法稱為工作證明算法(Proof-of-Work)[3],它是比特幣和以太坊這兩種最流行的加密貨幣的基礎。

  什么是“挖礦”?

  加密電子貨幣因為稀缺才具有價值。以現在的比特幣為例,如果任何人任何時候都可以隨意“制造”比特幣,那么作為電子貨幣它會變得毫無價值。比特幣通過算法來控制產出的速率并在大約122年內達到最大量。這種隨著時間推移緩慢、穩定并逐步產出的方式有效避免了通貨膨脹。

  比特幣的產出是通過給予“獲勝礦工”獎勵來實現,為了獲取比特幣獎勵礦工之間會進行競爭。這個過程之所以被稱為“挖礦”,是因為它類似于“Gold Rush”[4]時每個黃金礦工通過辛苦勞作并最終(希望)找到一點黃金。

  “挖礦”是如何工作的?

  如果 Google 一下這個問題,你會得到大量的結果。簡單來說,“挖礦”就是“解決一個數學難題”的過程。我們先來了解一些密碼學和哈希算法的知識。

  密碼學簡要介紹

  單向加密以人類可讀的文本(明文)作為輸入,比如“Hello world”這個字符串,再通過一個數學函數產生出難以辨認的輸出(密文)。 這類函數或算法的性質和復雜性各不相同。 算法越復雜,逆向工程就越困難。

  以流行的 SHA-256 算法為例。 通過這個網站[5]可以讓你計算任意給定輸入的輸出,也就是 SHA-256 哈希值。比如讓我們輸入“Hello world”,看看得到了什么:

  通過不斷嘗試計算“Hello world”的哈希值。你會發現每次的結果都完全相同。 這個過程稱為冪等性。

  加密算法一個最基本的特性是,非常難以通過反向工程來求解輸入,但是非常容易驗證輸出。比如上面的例子,你可以很容易驗證給定輸入“Hello world”的SHA-256哈希值是否正確,但很難通過給定的哈希值判斷它的輸入是什么。這就是為什么將這種類型的算法稱為單向加密。

  比特幣使用 Double SHA-256,它將 SHA-256 求得的哈希值作為輸入再次計算 SHA-256 哈希值。 為了簡化,我們只使用一次SHA-256。

  挖礦

  回到加密電子貨幣中,比特幣就是通過讓參與者利用這樣的加密算法求解出符合特定條件的哈希值來實現“挖礦”過程。具體來說,比特幣要求參與者通過 double SHA-256 算法計算出“前導0”超過若干位的哈希值,第一個求解出來的參與者就是“獲勝的礦工”。

  比如,我們求“886”這個字符串的 SHA-256 哈希值:

  可以看到,是一個“前導0”為3位的哈希值(前三位是0)。

  回憶我們前面說到的“單向加密”的特點:

  任何人都可以很容易地驗證“886”是否產生3位“前導0”的哈希值。但為了找到這樣一個能產生3位“前導0”的輸入(就是這里的“886”),我們做了大量繁瑣的計算工作:從一個很大的數字和字母集合中逐個計算它們的哈希值并判斷是否滿足上述條件。如果我是第一個找到“886”的人,那其他人通過驗證就能判斷我做了這樣大量繁瑣的工作。在比特幣、以太坊中這樣的過程就稱為工作證明算法。

  “如果我運氣非常好,第一次嘗試就找到了一個符合條件的(輸入)值呢?” —— 這是非常不可能的,你可以試試隨意輸入一些字母和數字。

  比特幣中實際的算法和約束要比上說要求復雜,當然也更難(要求更多位的“前導0”)。同時它也可以動態調整難度,目標是確保每隔10分鐘產出一次比特幣,不管參與“挖礦”的人多還是少。

  差不多可以動手了

  了解了足夠的背景知識,接著我們就用 Go 語言來編碼實踐下工作量證明(Proof-of-Work)算法。

  建議你閱讀之前的《用200行Go代碼實現自己的區塊鏈》系列文章,因為下面工作證明算法部分會涉及之前的代碼。

  Proof-of-work

  創建新塊并加入到鏈上之前需要完成“工作量證明”過程。我們先寫一個簡單的函數來檢查給定的哈希值是否滿足要求。

  哈希值必須具有給定位的“前導0”

  “前導0”的位數是由難度(difficulty)決定的

  可以動態調整難度(difficulty)來確保 Proof-of-Work 更難解

  下面就是 isHashValid 這個函數:

  func isHashValid(hash string, difficulty int) bool { prefix := strings.Repeat("0", difficulty) return strings.HasPrefix(hash, prefix)}

  Go 語言的 strings 包中提供了方便的 Repeat 和 HasPrefix 函數。我們定 prefix 變量,它代表“前導0”,接著檢查哈希值是否具有滿足條件的“前導0”,然后返回 True或 False 。

  我們修改之前生成塊的generateBlock 函數:

  func generateBlock(oldBlock Block, BPM int) Block { var newBlock Block t := time.Now() newBlock.Index = oldBlock.Index + 1 newBlock.Timestamp = t.String() newBlock.BPM = BPM newBlock.PrevHash = oldBlock.Hash newBlock.Difficulty = difficulty for i := 0; ; i++ { hex := fmt.Sprintf("%x", i) newBlock.Nonce = hex if !isHashValid(calculateHash(newBlock), newBlock.Difficulty) { fmt.Println(calculateHash(newBlock), " do more work!") time.Sleep(time.Second) continue } else { fmt.Println(calculateHash(newBlock), " work done!") newBlock.Hash = calculateHash(newBlock) break } } return newBlock}

  創建一個新塊 newBlock ,里面的 PrevHash 包含前一個塊的哈希值,Timestamp 是時間戳,BPM 是心率數據,Difficulty 就是前面提到的難度,它的值決定了“前導0”的位數。

  這里的 for 循環很重要:

  獲得 i 的十六進制表示 ,將 Nonce 設置為這個值,并傳入 calculateHash 計算哈希值。之后通過上面的 isHashValid 函數判斷是否滿足難度要求,如果不滿足就重復嘗試。

  這個計算過程會一直持續,知道求得了滿足要求的 Nonce 值,之后通過 handleWriteBlock 函數將新塊加入到鏈上。

  篇幅有限,我們已經將完整代碼發布在 Github上,可以從這里[6]獲得。

  跑起來看看

  啟動程序:

  go run main.go

  在瀏覽器中訪問 http://localhost:8080

  接著通過 Postman 來發送一個包含心率數據的POST 請求。

  接著我們觀察命令行窗口,不斷得計算哈希值,如果不滿足難度要求就繼續重試,直到找到滿足要求的哈希值及 Nonce

  可以看到最后一個哈希值滿足我們設定的難度要求(1位“前導0”)。我們再來刷新下瀏覽器:

  可以看到第二個塊創建成功并加到鏈上了,其中Nonce 就是通過Proof-of-Work計算出來滿足難度要求的值。

  下一步

  到這里要先祝賀你,上面的內容很有價值。盡管我們的示例中使用了非常低的難度,但本質上,工作證明算法就是比特幣、以太坊等區塊鏈的重要組成。

  對于下一步應該深入區塊鏈的哪個方向,我們推薦可以學習如何通過 IPFS [7]存取大文件并與區塊鏈打通。

  此外相比 Proof-of-Work,Proof-of-Stake 算法[8]正越來越受到關注和青睞,你也可以學習如何將本文的 PoW 算法改為實現 PoS 算法。


        溫馨提示:大連仟源科技有限公司以“專注網站,用心服務”為核心價值,一切以用戶需求為中心,希望通過專業水平和不懈努力,重塑企業網絡形象,為企業產品推廣文化發展提供服務指導;公司主要產品:主要為企業提供游戲開發,手機APP開發,定制系統開發,區塊鏈系統開發,小程序開發,網站開發。

文章標簽:
文章評論:

專業的游戲開發/系統開發、品牌設計/網站建設,選仟源!

選擇專業的企業服務公司,服務更靠譜!

立即點擊咨詢>
客服圖標
客服圖標
118旺角心水论坛