使用 Go 語言打造區塊鏈(二)

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

使用 Go 語言打造區塊鏈(二)

介紹

在上一篇文章中,我們構建了一個非常簡單的資料結構,這是塊鏈資料庫的本質。 而且我們可以用它們之間的鏈式關係向它添加區塊:每個區塊與前一個連結。 唉,然而在現實中添加一個區塊添加到鏈是艱巨的工作。

工作證明

塊鏈的一個關鍵思想是,必須通過工作證明才能將資料放入其中。這是一個艱巨的工作,使塊鏈安全和一致。此外,這筆辛苦的工作也得到了獎勵(這是人們獲得採礦硬幣的方式)。

這種機制與現實生活中的機制非常相似:人們必須工作獲酬勞勵並維持生命。在網路中,網路的一些參與者(礦工)努力維持網路,為其添加新的塊,並為他們的工作獲得獎勵。作為其工作的結果,塊以安全的方式併入到塊鏈中,這保持了整個塊鏈資料庫的穩定性。值得注意的是,完成工作的人必須證明這一點。

這個整體“努力工作和證明工作價值”機制被稱為工作證明。這很難因為它需要很多的計算能力:即使是高效能的電腦也不能很快的完成。此外,這項工作的難度不時增加,以保持新的塊率每小時大約6個塊。在比特幣,這樣的工作的目標是找到一個塊的雜湊,滿足一些要求。這是散列,作為證明。因此,找到證據是實際工作。

最後要注意的事情。工作證明演算法必須滿足要求:做完工作不易完成,證明工作容易完成。證明通常交給非工作者,所以對他們來說,驗證它不應該花太多的時間。

雜湊演算法加密

在本文中,我們將討論雜湊值。 如果你熟悉這個概念,你可以跳過這個部分。

雜湊是擷取指定資料的雜湊值的過程。 雜湊值是對其計算的資料的唯一表示。 雜湊函數是一個擷取任意大小的資料併產生固定大小的雜湊的函數。 以下是雜湊的一些主要功能:

  • 未經處理資料無法從雜湊值恢複。 因此,散列不是加密。
  • 資料只能有一個雜湊值,散列是唯一的。
  • 更改輸入資料中的一個位元組將導致完全不同的散列。

雜湊函數被廣泛用於檢查資料的一致性。在區塊鏈中,使用雜湊來保證塊的一致性。 雜湊演算法的輸入資料包含前一個塊的雜湊值,從而使得已經產生的鏈難以修改之前產生的區塊(或至少相當困難):必須重新計算其後的所有塊的雜湊值。

雜湊現金 、 Hashcash

比特幣使用Hashcash,雜湊現金的發明最初是為防止電子郵件垃圾郵件而開發的。它可以分為以下幾個步驟:

  1. 擷取公開的資料(在電子郵件的情況下,它是接收者的電子郵件地址;在比特幣的情況下,它是塊標題)。
  2. 添加一個計數器。計數器從0開始。
  3. 擷取資料+計數器組合的散列。
  4. 檢查雜湊值是否符合要求。
    1. 如果滿足要求,結束過程。
    2. 如果不滿足要求,增加計數器並重複步驟3和4。

因此,這是一個強力演算法:您更改計數器,計算一個新的雜湊,檢查它,增加計數器,計算雜湊等。這就是為什麼它在計算上是昂貴的。

現在讓我們看看一個雜湊必須滿足的要求。在原來的Hashcash實現中“雜湊的前20位必須是零”。然而在比特幣中,雜湊要求是不時進行調整的,因為儘管計算能力隨著時間的推移而增加,越來越多的礦工加入網路,因此設計必須每10分鐘產生一個塊

為了示範這個演算法,我從前面的例子中擷取了資料(“我喜歡甜甜圈”),並發現一個以0個零位元組開頭的雜湊:

編寫代碼

程式員小提醒:go和python都是不用加分號的語言

好的,我們完成了理論,讓我們編寫代碼! 首先,我們來定義挖掘的難度:

const targetBits = 24

In Bitcoin, “target bits” is the block header storing the difficulty at which the block was mined. We won’t implement a target adjusting algorithm, for now, so we can just define the difficulty as a global constant.

24 is an arbitrary number, our goal is to have a target that takes less than 256 bits in memory. And we want the difference to be significant enough, but not too big, because the bigger the difference the more difficult it’s to find a proper hash.

在比特幣中,“目標位(target bit)”是儲存塊被挖掘的困難的塊頭。 我們現在不會實現目標調整演算法,所以我們可以將難度定義為全域常數

24是一個任一數字,我們的目標是在記憶體中佔用少於256位的目標。 而且我們希望差異足夠大,但不要太大,因為差異越大,找到合適的雜湊越難。

type ProofOfWork struct {    block  *Block     target *big.Int //定義目標位}func NewProofOfWork(b *Block) *ProofOfWork {    target := big.NewInt(1)    target.Lsh(target, uint(256-targetBits))  //左移256個 target bits位    pow := &ProofOfWork{b, target}    return pow}

這裡建立儲存指向塊的指標的工作證明結構和指向目標的指標。 “目標”是上一段所述要求的另一個名稱。 我們使用一個大整數,因為我們將雜湊與目標進行比較:我們將雜湊轉換為一個大整數,並檢查它是否小於目標。

big: https://golang.org/pkg/math/big/

在新的工作證明的函數中,我們初始化一個值為1的big.Int,並將其左移256個 - targetBits位。 256是SHA-256雜湊的長度,以位元為單位,它是我們要使用的SHA-256散列演算法。 目標的十六進位表示為:

0x10000000000000000000000000000000000000000000000000000000000

它在記憶體中佔用29個位元組。 這是與以前的例子中的雜湊的比較:

0fac49161af82ed938add1d8725835cc123a1a87b1b196488360e58d4bfb51e300000100000000000000000000000000000000000000000000000000000000000000008b0f41ec78bab747864db66bcb9fb89920ee75f43fdaaeb5544f7f76ca

第一個雜湊(以“我喜歡甜甜圈”計算)大於目標,因此它不是有效工作證明。 第二個雜湊(以“我喜歡甜甜圈ca07ca”計算)小於目標,因此這是一個有效證明。

您可以將目標視為範圍的上限:如果數字(雜湊)低於邊界,則它是有效,反之亦然。 降低邊界將導致有效數量減少,因此找到有效數量所需的工作更加困難。

現在,對資料進行雜湊處理。

func (pow *ProofOfWork) prepareData(nonce int) []byte {    data := bytes.Join(        [][]byte{            pow.block.PrevBlockHash,            pow.block.Data,            IntToHex(pow.block.Timestamp),            IntToHex(int64(targetBits)),            IntToHex(int64(nonce)),        },        []byte{},    )    return data}

我們只是將塊地區與目標和隨機數合并。 nonce這裡是從上面的Hashcash描述的計數器,這是加密術語。

好的,所有的準備工作都完成了,我們來實現PoW演算法的核心:

func (pow *ProofOfWork) Run() (int, []byte) {    var hashInt big.Int    var hash [32]byte    nonce := 0    fmt.Printf("Mining the block containing \"%s\"\n", pow.block.Data)    for nonce < maxNonce {        data := pow.prepareData(nonce) // 準備資料        hash = sha256.Sum256(data) // SHA-256加密        fmt.Printf("\r%x", hash)        hashInt.SetBytes(hash[:])  // 講hash轉換成Big Integer        if hashInt.Cmp(pow.target) == -1 {            break        } else {            nonce++        }    }    fmt.Print("\n\n")    return nonce, hash[:]}

首先,我們初始設定變數:hashInt是雜湊的整數表示; nonce是櫃檯。 接下來,我們運行一個“無限”迴圈:它受限於maxNonce,它等於math.MaxInt64; 這樣做是為了避免可能的隨機數溢出。 雖然我們的PoW實施的難度太低,以至於防止溢出,但最好是進行此檢查,以防萬一。

在迴圈中我們:

  • 準備資料
  • 用SHA-256進行雜湊。
  • 將散列轉換為大整數。
  • 將整數與目標進行比較。

現在我們可以刪除BlockSetHash方法並修改NewBlock函數:

func NewBlock(data string, prevBlockHash []byte) *Block {    block := &Block{time.Now().Unix(), []byte(data), prevBlockHash, []byte{}, 0}    pow := NewProofOfWork(block)    nonce, hash := pow.Run()    block.Hash = hash[:]    block.Nonce = nonce    return block}

Here you can see that nonce is saved as a Block property. This is necessary because nonce is required to verify a proof. The Block structure now looks so:

type Block struct {    Timestamp     int64    Data          []byte    PrevBlockHash []byte    Hash          []byte    Nonce         int}

驗證工作證明

func (pow *ProofOfWork) Validate() bool {    var hashInt big.Int    data := pow.prepareData(pow.block.Nonce)    hash := sha256.Sum256(data)    hashInt.SetBytes(hash[:])    isValid := hashInt.Cmp(pow.target) == -1    return isValid}

主函數代代碼再次檢查

func main() {    ...    for _, block := range bc.blocks {        ...        pow := NewProofOfWork(block)        fmt.Printf("PoW: %s\n", strconv.FormatBool(pow.Validate()))        fmt.Println()    }}

結論

我們的塊鏈是一個更接近其實際架構的一步:添加塊現在需要努力工作,因此挖掘是可能的。 但是它仍然缺乏一些關鍵的特徵:塊鏈資料庫不是持久的,沒有錢包,地址,交易,沒有共識機制。 所有這些我們將在以後的文章中實現的,現在,開採開採!

連結:
  1. 原始碼,Full source codes
  2. 雜湊演算法,Blockchain hashing algorithm
  3. 工作證明,Proof of work
  4. 雜湊現金,Hashcash
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.