區塊鏈概念 That You Must Know 第四期(3)

kakushao發表於2018-05-10

第四期 簡介go語言下挖礦難度的程式碼實現(3)

卡酷少

Wechat:13260325501


經過之前所有的鋪墊,這一期我們將對難度的程式碼實現作出簡單演示。(以下是在不考慮近期各機構對於區塊儲存資訊改進的情況下。對於區塊資訊的調整,有比如“隔離驗證”等方法。暫時不瞭解沒有關係,本期並不涉及這點。之後隨著學習的深入,我們會一一介紹給大家。)

本期我們將對上期圖二中幾項資訊給出示例,然後程式碼模擬難度的實現。

區塊裡的雜湊是如何產生的?

  • 如第四期(1)篇裡講到的,每個區塊裡包含了index,current hash,previous hash,timestamp,data,nounce等資訊。current hash,就是將剩下的其他資訊拼接成字串,然後將這個字串進行雜湊的結果。正如上一個區塊的當前雜湊也是由它之前的區塊的這些資訊雜湊生成的。
  • 其中,nounce作為計算機窮舉的隨機數,不斷變化,形成字串的變化,產生了不同的雜湊值。這個雜湊值不斷去匹配現階段的雜湊難度。當nounce值取到某數,並使之形成的雜湊值匹配上了當前的有效雜湊難度,雜湊碰撞就成功了。
  • 以下為程式碼實現

雜湊sha256

  • 先給出程式碼
/*
程式碼邏輯:
    第一步:匯入crypto/sha256庫
    第二步:宣告字串
    第三步:sha256.New()建立一個物件
    第四步:將字串轉換為位元組陣列
    第五步:使用物件呼叫write方法
    第六步:first.Sum(nil) 返回hash值
*/

package main

import (
    //第1步
    "crypto/sha256"
    "fmt"
    "bytes"
)

func main() {
    //第2步
    const input1 = "199778A - > B 100"
    //第3步
    first := sha256.New()
    //第4步
    //第5步
    first.Write([]byte(input1))
    //第6步
    fmt.Printf("%x
", first.Sum(nil))


    const input2 = "Hello"
    second := sha256.New()
    second.Write([]byte(input2))
    fmt.Printf("%x
", second.Sum(nil))


    //輸出兩個雜湊是否相等,bytes.Equal()
    fmt.Println(bytes.Equal(first.Sum(nil), second.Sum(nil)))

}
  • ==sha256== 輸出結果:
0000e1343c8d9ec8a8996f0c1c8d1f9f1d954a750c3db5525205f401c516222d
185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969
false

Process finished with exit code 0
  • 其中一些函式大家一定急於瞭解,但這些函式的封裝過於艱深,我們在此不作深究。主要的是大家要記住四個關鍵步驟3,4,5,6,並熟練使用。其中包括以下幾點:
  1. ==sha256.New()== 有返回值,需要宣告變數並接收。且它的返回值一個是雜湊物件,而且是一個指標物件。它可以呼叫一些方法,其中有write方法。——第3步
  2. 雜湊物件呼叫 ==obj.Write()== 方法是需要傳參,且引數型別為位元組陣列。所以涉及到要將雜湊的字串先轉化為 ==[ ]byte== 型別——第4步第5步
  3. 雜湊物件呼叫 ==first.Sum(nil)== 方法返回雜湊值,方法有引數且引數固定為==nil==;可以宣告變數接收或者直接輸出。——第6步

關於雜湊難度的判斷

  • 要寫出挖礦難度的完整程式碼,其中有一環節必須要解決。那就是如何判斷雜湊難度是否是有效的呢?下面我們先給出程式碼
/*
程式碼邏輯:
(我們將程式碼)
    第一步:宣告一個隨機取的雜湊值,來在之後測驗isValidDifficulty是否有效
    第二步:設定當前雜湊難度,difficulty
    第三步:寫入一個迴圈來迭代匹配雜湊值對應位置的值,檢視是否這個位置是否是雜湊難度要求的值
    第四步:列印對這個雜湊值的判斷
*/

package main

import "fmt"

func main() {
    h := "0000e1343c8d9ec8a8996f0c1c8d1f9f1d954a750c3db5525205f401c516222d"
    //h1 := "0033e1343c8d9ec8a8996f0c1c8d1f9f1d954a750c3db5525205f401c516222d"
    //h2 := "0003e1343c8d9ec8a8996f0c1c8d1f9f1d954a750c3db5525205f401c516222d"
    difficulty := 4
    var i int
    for i = 0; i < len(h); i++ {
        if h[i] != `0` {
            break
        }
    }
    fmt.Print( i >= difficulty)
}
  • h 執行結果
true
Process finished with exit code 0
  • h1 執行結果
false
Process finished with exit code 0
  • h2 執行結果
false
Process finished with exit code 0
  • 於是我們將程式碼封裝一下,使它看起來更清晰,更便於呼叫。
package main

import "fmt"

func main() {
    h := "0000e1343c8d9ec8a8996f0c1c8d1f9f1d954a750c3db5525205f401c516222d"
    fmt.Println(isValidHashDifficulty(h, 4))
}

func isValidHashDifficulty(h string, difficulty int) bool {
    b := len(h) // 64
    var i int
    for i = 0; i < b; i++ {
        if h[i] != `0` {
            break
        }
    }
    return i >= difficulty
}
  • 下一篇給出完整程式碼

相關文章